├── README.md └── assets ├── js └── tokenize │ ├── jquery.tokenize.css │ └── jquery.tokenize.js └── tvs └── selector ├── ajax.php ├── css ├── style.css └── styles.json ├── js ├── scripts.json └── selector.js ├── lib ├── controller.class.php └── selector.class.php ├── selector.customtv.php └── tpl └── selector.tpl /README.md: -------------------------------------------------------------------------------- 1 | # Selector 2 | custom TV to replace mm_ddSelectDocuments 3 | Based on [Tokenize](https://www.zellerda.com/projects/jquery/tokenize) 4 | 5 | Selector allows to choose documents from dropdown list and save their ids in TV. 6 | 7 | You can modify it via config files and custom controllers. 8 | 9 | Config file contains an array with some Tokenize options and token template: 10 | ``` 11 | 0, 14 | 'nbDropdownElements' => 10, 15 | 'searchMaxLength' => 30, 16 | 'searchMinLength' => 0, 17 | 'textField' => 'text', 18 | 'valueField' => 'id', 19 | 'htmlField' => 'html', 20 | 'tokenConfig' => array( 21 | 'tpl' => '@CODE: ' 22 | ) 23 | ); 24 | ``` 25 | 26 | If your TV's name is "related" then config file is "assets/tvs/selector/config/related.php". 27 | 28 | With custom controllers you can modify the dropdown list data. For TV named "related" you should create "assets/tvs/selector/lib/related.controller.class.php" file (for autoload with Selector; if you want to use arbitrary file name and location then load class file manually with OnManagerPageInit plugin) with controller class that extends \Selector\SelectorController in it: 29 | ``` 30 | dlParams['parents'] = 5; 36 | $this->dlParams['addWhereList'] = 'c.published = 1'; 37 | } 38 | } 39 | ``` 40 | 41 | Pay attention that class name is "RelatedController". 42 | 43 | Request to the controller contains the following data in $_REQUEST: 44 | * doc_id - document id (0 for new documents); 45 | * doc_parent - document parent id; 46 | * doc_template - document template id; 47 | * tvid - TV id; 48 | * tvname - TV name; 49 | * search - query string. 50 | 51 | Selector is discussed [here](https://community.evocms.ru/blog/addons/4166-selector-custom-tv-dlya-sostavleniya-spiska-dokumentov.html) 52 | -------------------------------------------------------------------------------- /assets/js/tokenize/jquery.tokenize.css: -------------------------------------------------------------------------------- 1 | div.TokenizeMeasure, 2 | div.Tokenize ul li span, 3 | div.Tokenize ul.TokensContainer li.TokenSearch input { 4 | font-family: Arial, Helvetica, sans-serif; 5 | font-size: 12px; 6 | } 7 | 8 | div.Tokenize { 9 | position: relative; 10 | display: inline-block; 11 | zoom: 1; 12 | } 13 | 14 | div.Tokenize ul { 15 | list-style: none; 16 | padding: 0; 17 | margin: 0; 18 | } 19 | 20 | div.Tokenize ul li { 21 | white-space: nowrap; 22 | } 23 | 24 | div.Tokenize ul.TokensContainer { 25 | cursor: text; 26 | padding: 0 5px 5px 0; 27 | height: 100px; 28 | overflow-y: auto; 29 | background-color: white; 30 | -webkit-touch-callout: none; 31 | -webkit-user-select: none; 32 | -moz-user-select: none; 33 | -ms-user-select: none; 34 | user-select: none; 35 | } 36 | 37 | div.Tokenize ul.TokensContainer.Autosize { 38 | height: auto; 39 | } 40 | 41 | div.Tokenize.Disabled ul.TokensContainer, 42 | div.Tokenize.Disabled ul.TokensContainer input { 43 | cursor: not-allowed; 44 | } 45 | 46 | div.Tokenize ul.TokensContainer li.Token { 47 | border: 1px solid #ccd5e3; 48 | background-color: #eff2f7; 49 | padding: 0 5px; 50 | line-height: 18px; 51 | } 52 | 53 | div.Tokenize ul.TokensContainer.ui-sortable:not(.ui-sortable-disabled) li.Token { 54 | cursor: move; 55 | } 56 | 57 | div.Tokenize ul.TokensContainer li.Token.MovingShadow { 58 | border: 1px solid #fcefa1; 59 | background-color: #fbf9ee; 60 | } 61 | 62 | div.Tokenize ul.TokensContainer li.Token.PendingDelete { 63 | opacity : 0.5; 64 | -moz-opacity : 0.5; 65 | -ms-filter: "alpha(opacity=50)"; 66 | filter : alpha(opacity=50); 67 | } 68 | 69 | div.Tokenize ul.TokensContainer li.Token, 70 | div.Tokenize ul.TokensContainer li.TokenSearch { 71 | margin: 5px 0 0 5px; 72 | height: 18px; 73 | float: left; 74 | } 75 | 76 | div.Tokenize ul.TokensContainer li.TokenSearch input { 77 | margin: 0; 78 | padding: 1px 0; 79 | background-color: transparent; 80 | line-height: 18px; 81 | border: none; 82 | outline: none; 83 | } 84 | 85 | div.Tokenize ul.TokensContainer li.Placeholder { 86 | color: #ddd; 87 | position: absolute; 88 | line-height: 20px; 89 | padding: 5px 0 0 5px; 90 | display: none; 91 | } 92 | 93 | div.Tokenize ul.TokensContainer, 94 | div.Tokenize ul.Dropdown { 95 | border: 1px solid #ccc; 96 | } 97 | 98 | div.Tokenize ul.TokensContainer li.Token a.Close { 99 | font-family: Arial, Helvetica, sans-serif !important; 100 | font-size: 16px !important; 101 | line-height: 18px; 102 | float: right; 103 | margin: 1px 0 0 5px; 104 | padding: 0; 105 | cursor: pointer; 106 | color: #a6b4ce; 107 | } 108 | 109 | div.Tokenize.Disabled ul.TokensContainer li.Token a.Close { 110 | display: none; 111 | } 112 | 113 | div.Tokenize ul.TokensContainer li.Token a.Close:hover { 114 | background: transparent; 115 | text-decoration: none; 116 | } 117 | 118 | div.Tokenize ul.Dropdown { 119 | -webkit-box-sizing: border-box; 120 | -moz-box-sizing: border-box; 121 | -ms-box-sizing: border-box; 122 | box-sizing: border-box; 123 | 124 | display: none; 125 | width: 100%; 126 | padding: 5px 0; 127 | margin: -1px 0 0 0; 128 | position: absolute; 129 | background-color: white; 130 | overflow-y: auto; 131 | 132 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 133 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 134 | -o-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 135 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 136 | 137 | -webkit-background-clip: padding-box; 138 | -moz-background-clip: padding; 139 | background-clip: padding-box; 140 | 141 | -webkit-border-radius: 0 0 6px 6px; 142 | -moz-border-radius: 0 0 6px 6px; 143 | border-radius: 0 0 6px 6px; 144 | 145 | z-index: 20; 146 | } 147 | 148 | div.Tokenize ul.Dropdown li { 149 | padding: 5px 20px; 150 | overflow: hidden; 151 | cursor: pointer; 152 | } 153 | 154 | div.Tokenize ul.Dropdown li.Hover { 155 | color: white; 156 | text-decoration: none; 157 | background-color: #0081c2; 158 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 159 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 160 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 161 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 162 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 163 | background-repeat: repeat-x; 164 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); 165 | } -------------------------------------------------------------------------------- /assets/js/tokenize/jquery.tokenize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 4 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 5 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 6 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 7 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 8 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 9 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 10 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 11 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 12 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | * 14 | * This software consists of voluntary contributions made by many individuals 15 | * and is licensed under the new BSD license. 16 | * 17 | * @author David Zeller 18 | * @license http://www.opensource.org/licenses/BSD-3-Clause New BSD license 19 | * @version 2.6 20 | */ 21 | (function($, tokenize){ 22 | 23 | // Keycodes 24 | var KEYS = { 25 | BACKSPACE: 8, 26 | TAB: 9, 27 | ENTER: 13, 28 | ESCAPE: 27, 29 | ARROW_UP: 38, 30 | ARROW_DOWN: 40 31 | }; 32 | 33 | // Debounce timeout 34 | var debounce_timeout = null; 35 | 36 | // Data storage constant 37 | var DATA = 'tokenize'; 38 | 39 | /** 40 | * Get Tokenize object 41 | * 42 | * @param {Object} options 43 | * @param {jQuery} el 44 | * @returns {$.tokenize} 45 | */ 46 | var getObject = function(options, el){ 47 | 48 | if(!el.data(DATA)){ 49 | var obj = new $.tokenize($.extend({}, $.fn.tokenize.defaults, options)); 50 | el.data(DATA, obj); 51 | obj.init(el); 52 | } 53 | 54 | return el.data(DATA); 55 | 56 | }; 57 | 58 | /** 59 | * Tokenize constructor 60 | * 61 | * @param {Object} opts 62 | */ 63 | $.tokenize = function(opts){ 64 | 65 | if(opts == undefined){ 66 | opts = $.fn.tokenize.defaults; 67 | } 68 | 69 | this.options = opts; 70 | }; 71 | 72 | $.extend($.tokenize.prototype, { 73 | 74 | /** 75 | * Init tokenize object 76 | * 77 | * @param {jQuery} el jQuery object of the select 78 | */ 79 | init: function(el){ 80 | 81 | var $this = this; 82 | this.select = el.attr('multiple', 'multiple').css({margin: 0, padding: 0, border: 0}).hide(); 83 | 84 | this.container = $('
') 85 | .attr('class', this.select.attr('class')) 86 | .addClass('Tokenize'); 87 | 88 | if(this.options.maxElements == 1){ 89 | this.container.addClass('OnlyOne'); 90 | } 91 | 92 | this.dropdown = $('