├── MIT-LICENSE.txt ├── README.md ├── css ├── common.css └── jquery.uix.multiselect.css ├── index.html └── js ├── jquery.uix.multiselect.js ├── jquery.uix.multiselect.min.js └── locales ├── jquery.uix.multiselect_de.js ├── jquery.uix.multiselect_en.js ├── jquery.uix.multiselect_es.js ├── jquery.uix.multiselect_et.js ├── jquery.uix.multiselect_fr.js ├── jquery.uix.multiselect_it.js ├── jquery.uix.multiselect_nl.js ├── jquery.uix.multiselect_pt.js ├── jquery.uix.multiselect_ru.js └── jquery.uix.multiselect_sv.js /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 yanick.rochon at gmail.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jQuery UIx Multiselect 2 | ================== 3 | Version 2.0 4 | 5 | ![Preview](http://mind2soft.com/labs/jquery/multiselect/preview.png) 6 | 7 | Introduction 8 | ------------ 9 | 10 | This widget is a complete rewrite of the [previous version](https://github.com/michael/multiselect). Why a new rewrite? Because the original widget's attempt was to create a all-in-one-out-of-the-box-multi-featured SELECT replacement and thus failed to be compliant with the DOMElement's behavior and limitations. Notably, it failed to : 11 | 12 | * update the option items when modifying the SELECT element directly 13 | * didn't support disabled items 14 | * didn't support item groups 15 | * etc. 16 | 17 | Also, it quickly became slow when loading a few hundred items and some branches had [drag](https://github.com/michael/multiselect/issues/91) [and](https://github.com/michael/multiselect/issues/124) [drop](https://github.com/michael/multiselect/issues/8) issues. 18 | 19 | Release notes 20 | ------------- 21 | 22 | This widget is stable enough to be used in staging environments. However it is *still* under development, in testing phase, as some features may require more feedbacks yet! (Mainly browser compatiblity.) At this point, expect minor bug fixes within 72 hours, and there will be no more features planned at this point. 23 | 24 | The compressed (minified) version is created using the [YUI Compressor](http://refresh-sf.com/yui/). 25 | 26 | Requirements 27 | ------------ 28 | 29 | * jQuery 1.8+ 30 | * jQuery UI 1.9+ 31 | 32 | Features 33 | -------- 34 | 35 | * Support for disabled options 36 | * Support for option groups 37 | * Option group collapsable 38 | * Draggable drop and/or sortable enabled 39 | * Mouse selection mode (click, dblclick) 40 | * Support for predefined or custom sort functions 41 | * Searchable 42 | * List layout and select direction (horizontal or vertical) 43 | * Custom item renderer 44 | 45 | 46 | Usage 47 | ----- 48 | 49 | **Note :** Even though it is a complete rewrite of the widget, I kept the `multiselect` widget name (but it is declared as `uix.multiselect` instead of [`ui.multiselect`](http://ajpiano.com/widgetfactory/#slide22)). 50 | 51 | $('selector').multiselect(); 52 | 53 | To programmatically select/deselect, add/modify/remove items, you may access and modify the DOMElement directly, then call the `refresh` widget method to update it. 54 | 55 | $('selector').append("") 56 | .multiselect('refresh'); 57 | 58 | // manually filter available options 59 | // This will only render visible the available items containing 'My Item' (case insensitive) 60 | $('selector').multiselect('search', 'my item'); 61 | 62 | $('selector').multiselect('destroy'); // restore original element 63 | 64 | See [wiki documentation](https://github.com/yanickrochon/jquery.uix.multiselect/wiki) for more information. 65 | 66 | 67 | TODO 68 | ---- 69 | 70 | * add custom item rendering support *(needs more tests)* 71 | * HTML5 ARIA attributes 72 | * Make all options as mutable as possible after initialization. 73 | * Test in all major browsers *(not fully tested)* 74 | * Mobile support 75 | * Code cleanup 76 | * etc. 77 | 78 | 79 | Limitations 80 | ----------- 81 | 82 | * When setting `sortable` option to `true`, options can only be reordered within their own groups. That is, an option cannot be 83 | reordered between two options of a different group. As this widget's purpose is not to extend the original element's behaviour 84 | beyound user interaction and presentation, this limitation shall not be lifted for the time being. 85 | * This widget was designed for modern browsers usage. It is working fine in IE7+, Firefox and Chrome. Note that it 86 | *will not work* in quirks mode. There will be little to no support for [non standards compliant browsers](http://www.ie6countdown.com/). 87 | -------------------------------------------------------------------------------- /css/common.css: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2007, Yahoo! Inc. All rights reserved. 4 | Code licensed under the BSD License: 5 | http://developer.yahoo.net/yui/license.txt 6 | version: 2.2.0 7 | */ 8 | body {font:13px 'Helvetica',arial,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}pre, code {font:115% monospace;*font-size:100%;}body * {line-height:1.22em;} 9 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}/*ol,ul {list-style:none;}*/caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;} 10 | 11 | /* end of yahoo reset and fonts */ 12 | 13 | body {color:#333; background: #232f2e; line-height:1.3;} 14 | p {margin:0 0 20px;} 15 | a {color:#636363;} 16 | a:hover {text-decoration:none;} 17 | strong {font-weight:bold;} 18 | em {font-style: italic;} 19 | h1,h2,h3,h4,h5,h6 {font-weight:bold;} 20 | h1 {font-size:197%; margin:30px 0; color: #4f6f6c;} 21 | h2 {font-size:174%; margin:20px 0; color:#4f6f6c;} 22 | h3 {font-size:152%; margin:10px 0;} 23 | h4 {font-size:129%; margin:10px 0;} 24 | pre {background:#eee; margin:0 0 20px; padding:20px; border:1px solid #ccc; font-size:100%; overflow:auto;} 25 | code {font-size:100%; margin:0; padding:0;} 26 | ul, ol {margin:10px 0 10px 25px;} 27 | ol li {margin:0 0 10px;} 28 | 29 | div#wrapper {background:#fff; width:560px; margin:0 auto; padding:20px; border:10px solid #0f1616; border-width:0 10px 10px 10px;} 30 | div#header {position:relative; border-bottom:1px dotted; margin:0 0 10px; padding:0 0 10px;} 31 | div#header p {margin:0; padding:0;} 32 | div#header h1 {margin:0; padding:0;} 33 | ul#nav {position:absolute; top:0; right:0; list-style:none; margin:0; padding:0;} 34 | ul#nav li {display:inline; padding:0 0 0 5px;} 35 | ul#nav li a {} 36 | div#content {} 37 | div#footer {margin:40px 0 0; border-top:1px dotted; padding:10px 0 0;} 38 | .left {float:left;} 39 | .right {float:right;} 40 | .clear {clear:both;} 41 | 42 | 43 | #content { width: 900px; margin: auto; padding: 1px 16px 64px 16px; background-color: white; } 44 | 45 | /* multiselect styles */ 46 | #switcher { 47 | 48 | } 49 | 50 | form {margin: 0; padding: 0;} 51 | -------------------------------------------------------------------------------- /css/jquery.uix.multiselect.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .uix-multiselect-original { position: absolute; left:-999999px; } 4 | .uix-multiselect { position: relative; float:left; } 5 | .uix-multiselect .multiselect-selected-list, .uix-multiselect .multiselect-available-list { position:absolute; overflow:hidden; } 6 | .uix-multiselect .ui-widget-header { overflow:hidden; white-space:nowrap; padding:2px 4px; } 7 | .uix-multiselect .ui-widget-header div.header-text { white-space: nowrap; } 8 | .uix-multiselect .ui-widget-header .uix-control-right, .uix-multiselect .ui-widget-header .uix-control-left { width:16px; height:16px; } 9 | .uix-multiselect .ui-widget-header .uix-control-right { float:right; } 10 | .uix-multiselect .ui-widget-header .uix-control-left { float:left; } 11 | .uix-multiselect .ui-widget-header .uix-search { float:right; height:14px; font-size:80%; } 12 | .uix-multiselect .uix-list-container { position:relative; overflow:auto; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } 13 | .uix-multiselect .uix-list-container .ui-priority-secondary { padding-right:0; } 14 | .uix-multiselect .group-element { position:relative; padding-left:0; white-space:nowrap; overflow:hidden; } 15 | .uix-multiselect .group-element-collapsable { padding-left:16px; } 16 | .uix-multiselect .group-element span.collapse-handle { position:absolute; margin-top:-8px; top:50%; left:0; } 17 | .uix-multiselect .group-element .label { margin:0 3px; white-space:nowrap; overflow:hidden; } 18 | .uix-multiselect .group-element .ui-icon { float:left; cursor:pointer; } 19 | .uix-multiselect .option-element, .dragged-element { cursor:pointer; padding:0 2px; } 20 | .uix-multiselect .option-element.ui-state-disabled { font-style:italic; } 21 | .dragged-element, .dragged-grouped-element { padding:1px 3px; } 22 | .dragged-grouped-element { padding-left:16px; } 23 | .uix-multiselect .grouped-option { position:relative; padding-left:16px } 24 | .uix-multiselect .grouped-option .ui-icon { position:absolute; left:0; } 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery Multiselect 2.0 Example Page 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 120 | 141 | 142 | 143 | 144 |
145 | 146 | 147 | Fork me on GitHub 148 | 149 | 150 |

Welcome to the jQuery Multiselect 2.0 Widget !

151 | 152 |
153 |
154 | 155 |
156 | 157 |
158 |
159 |

Simple usage

160 |
161 | 408 |
409 | 410 |
411 | 412 | 413 | 414 | 415 |
416 |
417 | 418 |
419 |
420 | 421 |
422 |
423 |

Disabled options

424 |
425 | 514 |
515 | 516 |
517 | 518 | 519 | 520 | 521 |
522 |
523 | 524 |
525 |
526 | 527 |
528 |
529 |

Group related options

530 |
531 | 743 |
744 | 745 |
746 | 747 | 748 | 749 | 750 |
751 |
752 | 753 |
754 |
755 | 756 |
757 |
758 |

Dynamic usage

759 |
760 | 761 |
762 | 763 |
764 | 765 | 766 | 767 | 768 | 769 | 770 |
771 |
772 | 773 |
774 |
775 | 776 | 777 |
778 | 779 | 780 | 781 | -------------------------------------------------------------------------------- /js/jquery.uix.multiselect.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UIx Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Licensed under the MIT (MIT-LICENSE.txt) license. 8 | * 9 | * http://mind2soft.com/labs/jquery/multiselect/ 10 | * 11 | * 12 | * Depends: 13 | * jQuery UI 1.8+ 14 | * 15 | */ 16 | 17 | ;(function($, window, undefined) { 18 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 19 | "use strict"; 20 | 21 | // Each instance must have their own drag and drop scope. We use a global page scope counter 22 | // so we do not create two instances with mistankenly the same scope! We do not support 23 | // cross instance drag and drop; this would require also copying the OPTION element and it 24 | // would slow the component down. This is not the widget's contract anyhow. 25 | var globalScope = 0; 26 | 27 | var DEF_OPTGROUP = ''; 28 | var PRE_OPTGROUP = 'group-'; 29 | 30 | // these events will trigger on the original element 31 | //var NATIVE_EVENTS = ["change"]; // for version 2.1 32 | 33 | // a list of predefined events 34 | //var EVENT_CHANGE = 'change'; // for version 2.1 35 | var EVENT_CHANGE = 'multiselectChange'; 36 | //var EVENT_SEARCH = 'beforesearch'; // for version 2.1 37 | var EVENT_SEARCH = 'multiselectSearch'; 38 | var EVENT_REORDERED = 'multiselectReordered'; 39 | 40 | // The jQuery.uix namespace will automatically be created if it doesn't exist 41 | $.widget("uix.multiselect", { 42 | options: { 43 | availableListPosition: 'right',// 'top', 'right', 'bottom', 'left'; the position of the available list (default: 'right') 44 | // beforesearch: null, // a funciton called before searching. If the default is prevented, search will not happen (for version 2.1) 45 | collapsableGroups: true, // tells whether the option groups can be collapsed or not (default: true) 46 | created: null, // a function called when the widget is done loading (default: null) 47 | defaultGroupName: '', // the name of the default option group (default: '') 48 | filterSelected: false, // when searching, filter selected options also? (default: false) 49 | locale: 'auto', // any valid locale, 'auto', or '' for default built-in strings (default: 'auto') 50 | moveEffect: null, // 'blind','bounce','clip','drop','explode','fold','highlight','puff','pulsate','shake','slide' (default: null) 51 | moveEffectOptions: {}, // effect options (see jQuery UI documentation) (default: {}) 52 | moveEffectSpeed: null, // string ('slow','fast') or number in millisecond (ignored if moveEffect is 'show') (default: null) 53 | optionRenderer: false, // a function that will return the item element to be rendered in the list (default: false) 54 | optionGroupRenderer: false, // a function that will return the group item element to be rendered (default: false) 55 | searchDelay: 500, // the search delay in ms (default: 500) 56 | searchField: 'toggle', // false, true, 'toggle'; set the search field behaviour (default: 'toggle') 57 | searchPreFilter: null, // prepare the search term before filtering. 58 | searchFilter: null, // a search filter. Will receive the term and OPTION element and should return a boolean value. 59 | searchHeader: 'available', // 'available', 'selected'; set the list header that will host the search field (default: 'available') 60 | selectionMode: 'click,d&d', // how options can be selected separated by commas: 'click', "dblclick" and 'd&d' (default: 'click,d&d') 61 | showDefaultGroupHeader: false, // show the default option group header (default: false) 62 | showEmptyGroups: false, // always display option groups even if empty (default: false) 63 | splitRatio: 0.55, // % of the left list's width of the widget total width (default 0.55) 64 | sortable: false, // if the selected list should be user sortable or not 65 | sortMethod: null, // null, 'standard', 'natural'; a sort function name (see ItemComparators), or a custom function (default: null) 66 | selectAll: 'both' // 'available', 'selected', 'both', 'none' - Whether or not to display a select or deselect all icon (default: 'both') 67 | }, 68 | 69 | _create: function() { 70 | var that = this; 71 | var selListHeader, selListContent, avListHeader, avListContent; 72 | var btnSelectAll, btnDeselectAll; 73 | 74 | this.scope = 'multiselect' + (globalScope++); 75 | this.optionGroupIndex = 1; 76 | this._setLocale(this.options.locale); 77 | 78 | this.element.addClass('uix-multiselect-original'); 79 | this._elementWrapper = $('
').addClass('uix-multiselect ui-widget') 80 | .css({ 81 | width: this.element.css('width'), 82 | height: this.element.css('height') 83 | }) 84 | .append( 85 | $('
').addClass('multiselect-selected-list') 86 | .append( $('
').addClass('ui-widget-header') 87 | .append( btnDeselectAll = $('', { type:"button" }).addClass('uix-control-right') 88 | .attr('data-localekey', 'deselectAll') 89 | .attr('title', this._t('deselectAll')) 90 | .button({icons:{primary:'ui-icon-arrowthickstop-1-e'}, text:false}) 91 | .click(function(e) { e.preventDefault(); e.stopPropagation(); that.optionCache.setSelectedAll(false); return false; }) 92 | ['both,selected'.indexOf(this.options.selectAll)>=0 ? 'show' : 'hide']() 93 | ) 94 | .append( selListHeader = $('
').addClass('header-text') ) 95 | ) 96 | .append( selListContent = $('
').addClass('uix-list-container ui-widget-content') ) 97 | ) 98 | ['right,top'.indexOf(this.options.availableListPosition)>=0?'prepend':'append']( 99 | $('
').addClass('multiselect-available-list') 100 | .append( $('
').addClass('ui-widget-header') 101 | .append( btnSelectAll = $('', { type:"button" }).addClass('uix-control-right') 102 | .attr('data-localekey', 'selectAll') 103 | .attr('title', this._t('selectAll')) 104 | .button({icons:{primary:'ui-icon-arrowthickstop-1-w'}, text:false}) 105 | .click(function(e) { e.preventDefault(); e.stopPropagation(); that.optionCache.setSelectedAll(true); return false; }) 106 | ['both,available'.indexOf(this.options.selectAll)>=0 ? 'show' : 'hide']() 107 | ) 108 | .append( avListHeader = $('
').addClass('header-text') ) 109 | 110 | ) 111 | .append( avListContent = $('
').addClass('uix-list-container ui-widget-content') ) 112 | ) 113 | .insertAfter(this.element) 114 | ; 115 | 116 | this._buttons = { 117 | 'selectAll': btnSelectAll, 118 | 'deselectAll': btnDeselectAll 119 | }; 120 | this._headers = { 121 | 'selected': selListHeader, 122 | 'available': avListHeader 123 | }; 124 | this._lists = { 125 | 'selected': selListContent.attr('id', this.scope+'_selListContent'), 126 | 'available': avListContent.attr('id', this.scope+'_avListContent') 127 | }; 128 | 129 | this.optionCache = new OptionCache(this); 130 | this._searchDelayed = new SearchDelayed(this); 131 | 132 | this._initSearchable(); 133 | 134 | this._applyListDroppable(); 135 | 136 | this.refresh(this.options.created); 137 | }, 138 | 139 | /** 140 | * *************************************** 141 | * PUBLIC 142 | * *************************************** 143 | */ 144 | 145 | /** 146 | * Refresh all the lists from the underlaying element. This method is executed 147 | * asynchronously from the call, therefore it returns immediately. However, the 148 | * method accepts a callback parameter which will be executed when the refresh is 149 | * complete. 150 | * 151 | * @param callback function a callback function called when the refresh is complete 152 | */ 153 | refresh: function(callback) { 154 | this._resize(); // just make sure we display the widget right without delay 155 | asyncFunction(function() { 156 | this.optionCache.cleanup(); 157 | 158 | var opt, options = this.element[0].childNodes; 159 | 160 | for (var i=0, l1=options.length; i').addClass('uix-search ui-widget-content ui-corner-' + (isToggle ? 'left' : 'all'))[isToggle ? 'hide' : 'show']() 281 | .insertBefore( this._headers[searchHeader] ) 282 | .focus(function() { $(this).select(); }) 283 | .on("keydown keypress", function(e) { if (e.keyCode == 13) { e.preventDefault(); e.stopPropagation(); return false; } }) 284 | .keyup($.proxy(this._searchDelayed.request, this._searchDelayed)); 285 | } 286 | }, 287 | 288 | _applyListDroppable: function() { 289 | if (this.options.selectionMode.indexOf('d&d') == -1) return; 290 | 291 | var _optionCache = this.optionCache; 292 | var currentScope = this.scope; 293 | 294 | var getElementData = function(d) { 295 | return _optionCache._elements[d.data('element-index')]; 296 | }; 297 | 298 | var initDroppable = function(e, s) { 299 | e.droppable({ 300 | accept: function(draggable) { 301 | var eData = getElementData(draggable); 302 | return eData && (eData.selected != s); // from different seleciton only 303 | }, 304 | activeClass: 'ui-state-highlight', 305 | scope: currentScope, 306 | drop: function(evt, ui) { 307 | ui.draggable.removeClass('ui-state-disabled'); 308 | ui.helper.remove(); 309 | _optionCache.setSelected(getElementData(ui.draggable), s); 310 | } 311 | }); 312 | } 313 | 314 | initDroppable(this._lists['selected'], true); 315 | initDroppable(this._lists['available'], false); 316 | 317 | if (this.options.sortable) { 318 | var that = this; 319 | this._lists['selected'].sortable({ 320 | appendTo: 'parent', 321 | axis: "y", 322 | containment: $('.multiselect-selected-list', this._elementWrapper), //"parent", 323 | items: '.multiselect-element-wrapper', 324 | handle: '.group-element', 325 | revert: true, 326 | stop: $.proxy(function(evt, ui) { 327 | var prevGroup; 328 | $('.multiselect-element-wrapper', that._lists['selected']).each(function() { 329 | var currGroup = that.optionCache._groups.get($(this).data('option-group')); 330 | if (!prevGroup) { 331 | that.element.append(currGroup.groupElement); 332 | } else { 333 | currGroup.groupElement.insertAfter(prevGroup.groupElement); 334 | } 335 | prevGroup = currGroup; 336 | }); 337 | }, this) 338 | }); 339 | } 340 | }, 341 | 342 | _search: function(term, silent) { 343 | if (this._searchField.is(':visible')) { 344 | if (typeof term === "string") { // issue #36 345 | this._searchField.val(term); 346 | } else { 347 | term = this._searchField.val(); 348 | } 349 | } 350 | 351 | this.optionCache.filter(term, silent); 352 | }, 353 | 354 | _setLocale: function(locale) { 355 | if (locale == 'auto') { 356 | locale = navigator.userLanguage || 357 | navigator.language || 358 | navigator.browserLanguage || 359 | navigator.systemLanguage || 360 | ''; 361 | } 362 | if (!$.uix.multiselect.i18n[locale]) { 363 | locale = ''; // revert to default is not supported auto locale 364 | } 365 | this.options.locale = locale; 366 | }, 367 | 368 | _t: function(key, plural, data) { 369 | return _({locale:this.options.locale, key:key, plural:plural, data:data}); 370 | }, 371 | 372 | _updateControls: function() { 373 | var that = this; 374 | $('.uix-control-left,.uix-control-right', this._elementWrapper).each(function() { 375 | $(this).attr('title', that._t( $(this).attr('data-localekey') )); 376 | }); 377 | }, 378 | 379 | _updateHeaders: function() { 380 | var t, info = this.optionCache.getSelectionInfo(); 381 | 382 | this._headers['selected'] 383 | .text( t = this._t('itemsSelected', info.selected.total, {count:info.selected.total}) ) 384 | .parent().attr('title', 385 | this.options.filterSelected 386 | ? this._t('itemsSelected', info.selected.count, {count:info.selected.count}) + ", " + 387 | this._t('itemsFiltered', info.selected.filtered, {count:info.selected.filtered}) 388 | : t 389 | ); 390 | this._headers['available'] 391 | .text( this._t('itemsAvailable', info.available.total, {count:info.available.total}) ) 392 | .parent().attr('title', 393 | this._t('itemsAvailable', info.available.count, {count:info.available.count}) + ", " + 394 | this._t('itemsFiltered', info.available.filtered, {count:info.available.filtered}) ); 395 | }, 396 | 397 | // call this method whenever the widget resizes 398 | // NOTE : the widget MUST be visible and have a width and height when calling this 399 | _resize: function() { 400 | var pos = this.options.availableListPosition.toLowerCase(); // shortcut 401 | var sSize = ('left,right'.indexOf(pos) >= 0) ? 'Width' : 'Height'; // split size fn 402 | var tSize = ('left,right'.indexOf(pos) >= 0) ? 'Height' : 'Width'; // total size fn 403 | var cSl = this.element['outer'+sSize]() * this.options.splitRatio; // list container size selected 404 | var cAv = this.element['outer'+sSize]() - cSl; // ... available 405 | var hSl = (tSize === 'Width') ? cSl : this.element.outerHeight(); // scrollable area size selected 406 | var hAv = (tSize === 'Width') ? cAv : this.element.outerHeight(); // ... available 407 | var styleRule = ('left,right'.indexOf(pos) >= 0) ? 'left' : 'top'; // CSS rule for offsetting 408 | var swap = ('left,top'.indexOf(pos) >= 0); // true if we swap left-right or top-bottom 409 | var isToggle = ('toggle' === this.options.searchField); // true if search field is toggle-able 410 | var headerBordersBoth = 'ui-corner-tl ui-corner-tr ui-corner-bl ui-corner-br ui-corner-top'; 411 | var hSlCls = (tSize === 'Width') ? (swap ? '' : 'ui-corner-top') : (swap ? 'ui-corner-tr' : 'ui-corner-tl'); 412 | var hAvCls = (tSize === 'Width') ? (swap ? 'ui-corner-top' : '') : (swap ? 'ui-corner-tl' : 'ui-corner-tr'); 413 | 414 | // calculate outer lists dimensions 415 | this._elementWrapper.find('.multiselect-available-list') 416 | [sSize.toLowerCase()](cAv).css(styleRule, swap ? 0 : cSl) 417 | [tSize.toLowerCase()](this.element['outer'+tSize]() + 1); // account for borders 418 | this._elementWrapper.find('.multiselect-selected-list') 419 | [sSize.toLowerCase()](cSl).css(styleRule, swap ? cAv : 0) 420 | [tSize.toLowerCase()](this.element['outer'+tSize]() + 1); // account for borders 421 | 422 | // selection all button 423 | this._buttons['selectAll'].button('option', 'icons', {primary: transferIcon(pos, 'ui-icon-arrowthickstop-1-', false) }); 424 | this._buttons['deselectAll'].button('option', 'icons', {primary: transferIcon(pos, 'ui-icon-arrowthickstop-1-', true) }); 425 | 426 | // header borders 427 | this._headers['available'].parent().removeClass(headerBordersBoth).addClass(hAvCls); 428 | this._headers['selected'].parent().removeClass(headerBordersBoth).addClass(hSlCls); 429 | 430 | // make both headers equal! 431 | if (!isToggle) { 432 | var h = Math.max(this._headers['selected'].parent().height(), this._headers['available'].parent().height()); 433 | this._headers['available'].parent().height(h); 434 | this._headers['selected'].parent().height(h); 435 | } 436 | // adjust search field width 437 | if (this._searchField) { 438 | this._searchField.width( (sSize === 'Width' ? cAv : this.element.width()) - (isToggle ? 52 : 26) ); // issue #50 439 | } 440 | 441 | // calculate inner lists height 442 | this._lists['available'].height(hAv - this._headers['available'].parent().outerHeight() - 2); // account for borders 443 | this._lists['selected'].height(hSl - this._headers['selected'].parent().outerHeight() - 2); // account for borders 444 | }, 445 | 446 | /** 447 | * return false if the event was prevented by an handler, true otherwise 448 | */ 449 | _triggerUIEvent: function(event, ui) { 450 | var eventType; 451 | 452 | if (typeof event === 'string') { 453 | eventType = event; 454 | event = $.Event(event); 455 | } else { 456 | eventType = event.type; 457 | } 458 | 459 | //console.log($.inArray(event.type, NATIVE_EVENTS)); 460 | 461 | //if ($.inArray(event.type, NATIVE_EVENTS) > -1) { 462 | this.element.trigger(event, ui); 463 | //} else { 464 | // this._trigger(eventType, event, ui); 465 | //} 466 | 467 | return !event.isDefaultPrevented(); 468 | }, 469 | 470 | _setOption: function(key, value) { 471 | // Use the _setOption method to respond to changes to options 472 | switch(key) { 473 | // TODO 474 | } 475 | if (typeof(this._superApply) == 'function'){ 476 | this._superApply(arguments); 477 | }else{ 478 | $.Widget.prototype._setOption.apply(this, arguments); 479 | } 480 | } 481 | }); 482 | 483 | 484 | 485 | /** 486 | * Comparator registry. 487 | * 488 | * function(a, b, g) where a is compared to b and g is true if they are groups 489 | */ 490 | var ItemComparators = { 491 | /** 492 | * Naive general implementation 493 | */ 494 | standard: function(a, b) { 495 | if (a > b) return 1; 496 | if (a < b) return -1; 497 | return 0; 498 | }, 499 | /* 500 | * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license 501 | * Author: Jim Palmer (based on chunking idea from Dave Koelle) 502 | */ 503 | natural: function naturalSort(a, b) { 504 | var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi, 505 | sre = /(^[ ]*|[ ]*$)/g, 506 | dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, 507 | hre = /^0x[0-9a-f]+$/i, 508 | ore = /^0/, 509 | i = function(s) { return naturalSort.insensitive && (''+s).toLowerCase() || ''+s }, 510 | // convert all to strings strip whitespace 511 | x = i(a).replace(sre, '') || '', 512 | y = i(b).replace(sre, '') || '', 513 | // chunk/tokenize 514 | xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), 515 | yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), 516 | // numeric, hex or date detection 517 | xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)), 518 | yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null, 519 | oFxNcL, oFyNcL; 520 | // first try and sort Hex codes or Dates 521 | if (yD) 522 | if ( xD < yD ) return -1; 523 | else if ( xD > yD ) return 1; 524 | // natural sorting through split numeric strings and default strings 525 | for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { 526 | // find floats not starting with '0', string or 0 if not defined (Clint Priest) 527 | oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; 528 | oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; 529 | // handle numeric vs string comparison - number < string - (Kyle Adams) 530 | if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; } 531 | // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' 532 | else if (typeof oFxNcL !== typeof oFyNcL) { 533 | oFxNcL += ''; 534 | oFyNcL += ''; 535 | } 536 | if (oFxNcL < oFyNcL) return -1; 537 | if (oFxNcL > oFyNcL) return 1; 538 | } 539 | return 0; 540 | } 541 | }; 542 | 543 | 544 | var transferDirection = ['n','e','s','w']; // button icon direction 545 | var transferOrientation = ['bottom','left','top','right']; // list of matching directions with icons 546 | var transferIcon = function(pos, prefix, selected) { 547 | return prefix + transferDirection[($.inArray(pos.toLowerCase(), transferOrientation) + (selected ? 2 : 0)) % 4]; 548 | }; 549 | 550 | /** 551 | * setTimeout on steroids! 552 | */ 553 | var asyncFunction = function(callback, timeout, self) { 554 | var args = Array.prototype.slice.call(arguments, 3); 555 | return setTimeout(function() { 556 | callback.apply(self || window, args); 557 | }, timeout); 558 | }; 559 | 560 | 561 | var SearchDelayed = function(widget, options) { 562 | this._widget = widget; 563 | this._options = options; 564 | this._lastSearchValue = null; 565 | }; 566 | 567 | SearchDelayed.prototype = { 568 | request: function() { 569 | if (this._widget._searchField.val() == this._lastSearchValue) return; // prevent searching twice same term 570 | 571 | this.cancelLastRequest(); 572 | 573 | this._timeout = asyncFunction(function() { 574 | this._timeout = null; 575 | this._lastSearchValue = this._widget._searchField.val(); 576 | 577 | this._widget._search(); 578 | }, this._widget.options.searchDelay, this); 579 | }, 580 | cancelLastRequest: function() { 581 | if (this._timeout) { 582 | clearTimeout(this._timeout); 583 | } 584 | } 585 | }; 586 | 587 | /** 588 | * Map of all option groups 589 | */ 590 | var GroupCache = function(comp) { 591 | // private members 592 | 593 | var keys = []; 594 | var items = {}; 595 | var comparator = comp; 596 | 597 | // public methods 598 | 599 | this.setComparator = function(comp) { 600 | comparator = comp; 601 | return this; 602 | }; 603 | 604 | this.clear = function() { 605 | keys = []; 606 | items = {}; 607 | return this; 608 | }; 609 | 610 | this.containsKey = function(key) { 611 | return !!items[key]; 612 | }; 613 | 614 | this.get = function(key) { 615 | return items[key]; 616 | }; 617 | 618 | this.put = function(key, val) { 619 | if (!items[key]) { 620 | if (comparator) { 621 | keys.splice((function() { 622 | var low = 0, high = keys.length; 623 | var mid = -1, c = 0; 624 | while (low < high) { 625 | mid = parseInt((low + high)/2); 626 | var a = items[keys[mid]].groupElement; 627 | var b = val.groupElement; 628 | c = comparator(a ? a.attr('label') : DEF_OPTGROUP, b ? b.attr('label') : DEF_OPTGROUP); 629 | if (c < 0) { 630 | low = mid + 1; 631 | } else if (c > 0) { 632 | high = mid; 633 | } else { 634 | return mid; 635 | } 636 | } 637 | return low; 638 | })(), 0, key); 639 | } else { 640 | keys.push(key); 641 | } 642 | } 643 | 644 | items[key] = val; 645 | return this; 646 | }; 647 | 648 | this.remove = function(key) { 649 | delete items[key]; 650 | return keys.splice(keys.indexOf(key), 1); 651 | }; 652 | 653 | this.each = function(callback) { 654 | var args = Array.prototype.slice.call(arguments, 1); 655 | args.splice(0, 0, null, null); 656 | for (var i=0, len=keys.length; i').appendTo(this._widget._lists['selected']), 670 | 'available': $('
').appendTo(this._widget._lists['available']) 671 | }; 672 | 673 | this._elements = []; 674 | this._groups = new GroupCache(); 675 | 676 | this._moveEffect = { 677 | fn: widget.options.moveEffect, 678 | options: widget.options.moveEffectOptions, 679 | speed: widget.options.moveEffectSpeed 680 | }; 681 | 682 | this._selectionMode = this._widget.options.selectionMode.indexOf('dblclick') > -1 ? 'dblclick' 683 | : this._widget.options.selectionMode.indexOf('click') > -1 ? 'click' : false; 684 | 685 | this.reset(); 686 | }; 687 | 688 | OptionCache.Options = { 689 | batchCount: 200, 690 | batchDelay: 50 691 | }; 692 | 693 | OptionCache.prototype = { 694 | _createGroupElement: function(grpElement, optGroup, selected) { 695 | var that = this; 696 | var gData; 697 | 698 | var getLocalData = function() { 699 | if (!gData) gData = that._groups.get(optGroup); 700 | return gData; 701 | }; 702 | 703 | var getGroupName = function() { 704 | return grpElement ? grpElement.attr('label') : that._widget.options.defaultGroupName; 705 | }; 706 | 707 | var labelCount = $('').addClass('label') 708 | .text(getGroupName() + ' (0)') 709 | .attr('title', getGroupName() + ' (0)'); 710 | 711 | var fnUpdateCount = function() { 712 | var gDataDst = getLocalData()[selected?'selected':'available']; 713 | 714 | gDataDst.listElement[(!selected && (gDataDst.count || that._widget.options.showEmptyGroups)) || (gDataDst.count && ((gData.optionGroup != DEF_OPTGROUP) || that._widget.options.showDefaultGroupHeader)) ? 'show' : 'hide'](); 715 | 716 | var t = getGroupName() + ' (' + gDataDst.count + ')'; 717 | labelCount.text(t).attr('title', t); 718 | }; 719 | 720 | var e = $('
') 721 | .addClass('ui-widget-header ui-priority-secondary group-element') 722 | .append( $('', { type:"button" }).addClass('uix-control-right') 723 | .attr('data-localekey', (selected?'de':'')+'selectAllGroup') 724 | .attr('title', this._widget._t((selected?'de':'')+'selectAllGroup')) 725 | .button({icons:{primary:transferIcon(this._widget.options.availableListPosition, 'ui-icon-arrowstop-1-', selected)}, text:false}) 726 | .click(function(e) { 727 | e.preventDefault(); e.stopPropagation(); 728 | 729 | var gDataDst = getLocalData()[selected?'selected':'available']; 730 | 731 | if (gData.count > 0) { 732 | var _transferedOptions = []; 733 | 734 | that._bufferedMode(true); 735 | for (var i=gData.startIndex, len=gData.startIndex+gData.count, eData; i').addClass('ui-icon collapse-handle') 763 | .attr('data-localekey', 'collapseGroup') 764 | .attr('title', this._widget._t('collapseGroup')) 765 | .addClass(grpCollapseIcon) 766 | .mousedown(function(e) { e.stopPropagation(); }) 767 | .click(function(e) { e.preventDefault(); e.stopPropagation(); fnToggle(grpElement); return false; }) 768 | .prependTo(e.addClass('group-element-collapsable')) 769 | ; 770 | 771 | fnToggle = function(grpElement) { 772 | var gDataDst = getLocalData()[selected?'selected':'available'], 773 | collapseIconAttr = (grpElement) ? grpElement.attr('data-collapse-icon') : null, 774 | expandIconAttr = (grpElement) ? grpElement.attr('data-expand-icon') : null, 775 | collapseIcon = (collapseIconAttr) ? 'ui-icon ' + collapseIconAttr : 'ui-icon ui-icon-triangle-1-s', 776 | expandIcon = (expandIconAttr) ? 'ui-icon ' + expandIconAttr : 'ui-icon ui-icon-triangle-1-e'; 777 | gDataDst.collapsed = !gDataDst.collapsed; 778 | gDataDst.listContainer.slideToggle(); // animate options? 779 | h.removeClass(gDataDst.collapsed ? collapseIcon : expandIcon) 780 | .addClass(gDataDst.collapsed ? expandIcon : collapseIcon); 781 | }; 782 | }else{ 783 | if (groupIcon) { 784 | $('').addClass('collapse-handle '+groupIcon) 785 | .css('cursor','default') 786 | .prependTo(e.addClass('group-element-collapsable')); 787 | } 788 | } 789 | return $('
') 790 | // create an utility function to update group element count 791 | .data('fnUpdateCount', fnUpdateCount) 792 | .data('fnToggle', fnToggle || $.noop) 793 | .append(e) 794 | ; 795 | }, 796 | 797 | _createGroupContainerElement: function(grpElement, optGroup, selected) { 798 | var that = this; 799 | var e = $('
'); 800 | var _received_index; 801 | 802 | if (this._widget.options.sortable && selected) { 803 | e.sortable({ 804 | tolerance: "pointer", 805 | appendTo: this._widget._elementWrapper, 806 | connectWith: this._widget._lists['available'].attr('id'), 807 | scope: this._widget.scope, 808 | helper: 'clone', 809 | receive: function(evt, ui) { 810 | var e = that._elements[_received_index = ui.item.data('element-index')]; 811 | 812 | e.selected = true; 813 | e.optionElement.prop('selected', true); 814 | e.listElement.removeClass('ui-state-active'); 815 | }, 816 | stop: function(evt, ui) { 817 | var e; 818 | if (_received_index != undefined) { 819 | e = that._elements[_received_index]; 820 | _received_index = undefined; 821 | ui.item.replaceWith(e.listElement.addClass('ui-state-highlight option-selected')); 822 | that._widget._updateHeaders(); 823 | that._widget._triggerUIEvent(EVENT_CHANGE, { optionElements:[e.optionElement[0]], selected:true } ); 824 | } else { 825 | e = that._elements[ui.item.data('element-index')]; 826 | if (e && !e.selected) { 827 | that._bufferedMode(true); 828 | that._appendToList(e); 829 | that._bufferedMode(false); 830 | } 831 | } 832 | if (e) that._reorderSelected(e.optionGroup); 833 | }, 834 | revert: true 835 | }); 836 | } 837 | 838 | if (this._selectionMode) { 839 | $(e).on(this._selectionMode, 'div.option-element', function() { 840 | var eData = that._elements[$(this).data('element-index')]; 841 | eData.listElement.removeClass('ui-state-hover'); 842 | that.setSelected(eData, !selected); 843 | }); 844 | } 845 | 846 | return e; 847 | }, 848 | 849 | _createElement: function(optElement, optGroup) { 850 | var o = this._widget.options.optionRenderer 851 | ? this._widget.options.optionRenderer(optElement, optGroup) 852 | : $('
').text(optElement.text()); 853 | var optIcon = optElement.attr("data-option-icon"); 854 | var e = $('
').append(o).addClass('ui-state-default option-element') 855 | .attr("unselectable", "on") // disable text selection on this element (IE, Opera) 856 | .data('element-index', -1) 857 | .hover( 858 | function() { 859 | if (optElement.prop('selected')) $(this).removeClass('ui-state-highlight'); 860 | $(this).addClass('ui-state-hover'); 861 | }, 862 | function() { 863 | $(this).removeClass('ui-state-hover'); 864 | if (optElement.prop('selected')) $(this).addClass('ui-state-highlight'); 865 | } 866 | ); 867 | if (this._widget.options.selectionMode.indexOf('d&d') > -1) { 868 | var that = this; 869 | e.draggable({ 870 | addClasses: false, 871 | cancel: (this._widget.options.sortable ? '.option-selected, ' : '') + '.ui-state-disabled', 872 | appendTo: this._widget._elementWrapper, 873 | scope: this._widget.scope, 874 | start: function(evt, ui) { 875 | $(this).addClass('ui-state-disabled ui-state-active'); 876 | ui.helper.width($(this).width()).height($(this).height()); 877 | }, 878 | stop: function(evt, ui) { 879 | $(this).removeClass('ui-state-disabled ui-state-active'); 880 | }, 881 | helper: 'clone', 882 | revert: 'invalid', 883 | zIndex: 99999, 884 | disabled: optElement.prop('disabled') 885 | }); 886 | if (optElement.prop('disabled')) { 887 | e.addClass('ui-state-disabled'); 888 | } 889 | if (this._widget.options.sortable) { 890 | e.draggable('option', 'connectToSortable', this._groups.get(optGroup)['selected'].listContainer); 891 | } 892 | } else if (optElement.prop('disabled')) { 893 | e[(optElement.prop('disabled') ? "add" : "remove") + "Class"]('ui-state-disabled'); 894 | } 895 | if (optIcon) { 896 | e.addClass('grouped-option').prepend($('').addClass('ui-icon ' + optIcon)); 897 | } 898 | return e; 899 | }, 900 | 901 | _isOptionCollapsed: function(eData) { 902 | return this._groups.get(eData.optionGroup)[eData.selected?'selected':'available'].collapsed; 903 | }, 904 | 905 | _updateGroupElements: function(gData) { 906 | if (gData) { 907 | gData['selected'].count = 0; 908 | gData['available'].count = 0; 909 | for (var i=gData.startIndex, len=gData.startIndex+gData.count; i= gData.startIndex) && 938 | (this._elements[insertIndex].selected != eData.selected)) { 939 | insertIndex--; 940 | } 941 | 942 | if (insertIndex < gData.startIndex) { 943 | gDataDst.listContainer.prepend(eData.listElement); 944 | } else { 945 | var prev = this._elements[insertIndex].listElement; 946 | // FIX : if previous element is animated, get it's animated parent as reference 947 | if (prev.parent().hasClass('ui-effects-wrapper')) { 948 | prev = prev.parent(); 949 | } 950 | eData.listElement.insertAfter(prev); 951 | } 952 | eData.listElement[(eData.selected?'add':'remove')+'Class']('ui-state-highlight option-selected'); 953 | 954 | if ((eData.selected || !eData.filtered) && !this._isOptionCollapsed(eData) && this._moveEffect && this._moveEffect.fn) { 955 | eData.listElement.hide().show(this._moveEffect.fn, this._moveEffect.options, this._moveEffect.speed); 956 | } else if (eData.filtered) { 957 | eData.listElement.hide(); 958 | } 959 | }, 960 | 961 | _reorderSelected: function(optGroup) { 962 | var e = this._elements; 963 | var g = this._groups.get(optGroup); 964 | var container = g.groupElement ? g.groupElement : this._widget.element; 965 | var prevElement; 966 | $('.option-element', g['selected'].listContainer).each(function() { 967 | var currElement = e[$(this).data('element-index')].optionElement; 968 | if (!prevElement) { 969 | container.prepend(currElement); 970 | } else { 971 | currElement.insertAfter(prevElement); 972 | } 973 | prevElement = currElement; 974 | }); 975 | this._widget._triggerUIEvent(EVENT_REORDERED, { selectElement:container.context } ); 976 | }, 977 | 978 | _bufferedMode: function(enabled) { 979 | if (enabled) { 980 | this._oldMoveEffect = this._moveEffect; this._moveEffect = null; 981 | 982 | // backup lists' scroll position before going into buffered mode 983 | this._widget._lists['selected'].data('scrollTop', this._widget._lists['selected'].scrollTop()); 984 | this._widget._lists['available'].data('scrollTop', this._widget._lists['available'].scrollTop()); 985 | 986 | this._listContainers['selected'].detach(); 987 | this._listContainers['available'].detach(); 988 | } else { 989 | // restore scroll position (if available) 990 | this._widget._lists['selected'].append(this._listContainers['selected']) 991 | .scrollTop( this._widget._lists['selected'].data('scrollTop') || 0 ); 992 | this._widget._lists['available'].append(this._listContainers['available']) 993 | .scrollTop( this._widget._lists['available'].data('scrollTop') || 0 ); 994 | 995 | this._moveEffect = this._oldMoveEffect; 996 | 997 | delete this._oldMoveEffect; 998 | } 999 | 1000 | }, 1001 | 1002 | reset: function(destroy) { 1003 | this._groups.clear(); 1004 | this._listContainers['selected'].empty(); 1005 | this._listContainers['available'].empty(); 1006 | 1007 | if (destroy) { 1008 | for (var i=0, e=this._elements, len=e.length; i -1)) { 1033 | this._elements.splice(i--, 1)[0].listElement.remove(); 1034 | } 1035 | } 1036 | for (var i=0, len=_groupsRemoved.length; i').addClass('multiselect-element-wrapper').data('option-group', g); 1123 | var wrapper_available = $('
').addClass('multiselect-element-wrapper').data('option-group', g); 1124 | wrapper_selected.append(v.selected.listElement.hide()); 1125 | if (g != DEF_OPTGROUP || (g == DEF_OPTGROUP && showDefGroupName)) { 1126 | wrapper_available.append(v['available'].listElement.show()); 1127 | } 1128 | wrapper_selected.append(v['selected'].listContainer); 1129 | wrapper_available.append(v['available'].listContainer); 1130 | 1131 | l['selected'].append(wrapper_selected); 1132 | l['available'].append(wrapper_available); 1133 | } 1134 | v.count = 0; 1135 | }, this._listContainers, this._widget.options.showDefaultGroupHeader); 1136 | 1137 | for (var i=0, eData, gData, len=this._elements.length; i= i) { 1143 | gData.startIndex = i; 1144 | gData.count = 1; 1145 | } else { 1146 | gData.count++; 1147 | } 1148 | 1149 | // save element index for back ref 1150 | eData.listElement.data('element-index', eData.index = i); 1151 | 1152 | if (eData.optionElement.data('element-index') == undefined || eData.selected != eData.optionElement.prop('selected')) { 1153 | eData.selected = eData.optionElement.prop('selected'); 1154 | eData.optionElement.data('element-index', i); // also save for back ref here 1155 | 1156 | this._appendToList(eData); 1157 | } 1158 | } 1159 | 1160 | this._updateGroupElements(); 1161 | this._widget._updateHeaders(); 1162 | this._groups.each(function(g,v,t) { t._reorderSelected(g); }, this); 1163 | 1164 | this._bufferedMode(false); 1165 | 1166 | }, 1167 | 1168 | filter: function(term, silent) { 1169 | 1170 | if (term && !silent) { 1171 | var ui = { term:term }; 1172 | if (this._widget._triggerUIEvent(EVENT_SEARCH, ui )) { 1173 | term = ui.term; // update term 1174 | } else { 1175 | return; 1176 | } 1177 | } 1178 | 1179 | this._bufferedMode(true); 1180 | 1181 | var filterSelected = this._widget.options.filterSelected; 1182 | var filterFn = this._widget.options.searchFilter || function(term, opt) { 1183 | return opt.innerHTML.toLocaleLowerCase().indexOf(term) > -1; 1184 | }; 1185 | term = (this._widget.options.searchPreFilter || function(term) { 1186 | return term ? (term+"").toLocaleLowerCase() : false; 1187 | })(term); 1188 | 1189 | for (var i=0, eData, len=this._elements.length, filtered; i 1 && i18n[p.key+'_plural']) { 1287 | t = i18n[p.key+'_plural']; 1288 | } else if (plural === 0 && i18n[p.key+'_nil']) { 1289 | t = i18n[p.key+'_nil']; 1290 | } else { 1291 | t = i18n[p.key] || ''; 1292 | } 1293 | 1294 | return t.replace(/\{([^\}]+)\}/g, function(m, n) { return data[n]; }); 1295 | }; 1296 | 1297 | /** 1298 | * Default translation 1299 | */ 1300 | $.uix.multiselect.i18n = { 1301 | '': { 1302 | itemsSelected_nil: 'No options selected', // 0 1303 | itemsSelected: '{count} selected option', // 0, 1 1304 | itemsSelected_plural: '{count} options selected', // n 1305 | //itemsSelected_plural_two: ... // 2 1306 | //itemsSelected_plural_few: ... // 3, 4 1307 | itemsAvailable_nil: 'No items available', 1308 | itemsAvailable: '{count} options available', 1309 | itemsAvailable_plural: '{count} options available', 1310 | //itemsAvailable_plural_two: ... 1311 | //itemsAvailable_plural_few: ... 1312 | itemsFiltered_nil: 'No options found', 1313 | itemsFiltered: '{count} option found', 1314 | itemsFiltered_plural: '{count} options found', 1315 | //itemsFiltered_plural_two: ... 1316 | //itemsFiltered_plural_few: ... 1317 | selectAll: 'Select All', 1318 | deselectAll: 'Deselect All', 1319 | search: 'Search Options', 1320 | collapseGroup: 'Collapse Group', 1321 | expandGroup: 'Expand Group', 1322 | selectAllGroup: 'Select All Group', 1323 | deselectAllGroup: 'Deselect All Group' 1324 | } 1325 | }; 1326 | 1327 | })(jQuery, window); 1328 | -------------------------------------------------------------------------------- /js/jquery.uix.multiselect.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UIx Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Licensed under the MIT (MIT-LICENSE.txt) license. 8 | * 9 | * http://mind2soft.com/labs/jquery/multiselect/ 10 | * 11 | * 12 | * Depends: 13 | * jQuery UI 1.8+ 14 | * 15 | */ 16 | 17 | (function(d,i,g){var k=0;var l="";var b="group-";var h="multiselectChange";var f="multiselectSearch";d.widget("uix.multiselect",{options:{availableListPosition:"right",collapsableGroups:true,defaultGroupName:"",filterSelected:false,locale:"auto",moveEffect:null,moveEffectOptions:{},moveEffectSpeed:null,optionRenderer:false,optionGroupRenderer:false,searchField:"toggle",searchFilter:null,searchHeader:"available",selectionMode:"click,d&d",showDefaultGroupHeader:false,showEmptyGroups:false,splitRatio:0.55,sortable:false,sortMethod:null},_create:function(){var x=this; 18 | var u,s,y,w;var t,v;this.scope="multiselect"+(k++);this.optionGroupIndex=1;this._setLocale(this.options.locale);this.element.addClass("uix-multiselect-original");this._elementWrapper=d("
").addClass("uix-multiselect ui-widget").css({width:this.element.outerWidth(),height:this.element.outerHeight()}).append(d("
").addClass("multiselect-selected-list").append(d("
").addClass("ui-widget-header").append(v=d("",{type:"button"}).addClass("uix-control-right").attr("data-localekey","deselectAll").attr("title",this._t("deselectAll")).button({icons:{primary:"ui-icon-arrowthickstop-1-e"},text:false}).click(function(z){z.preventDefault(); 19 | z.stopPropagation();x.optionCache.setSelectedAll(false);return false})).append(u=d("
").addClass("header-text"))).append(s=d("
").addClass("uix-list-container ui-widget-content")))["right,top".indexOf(this.options.availableListPosition)>=0?"prepend":"append"](d("
").addClass("multiselect-available-list").append(d("
").addClass("ui-widget-header").append(t=d("",{type:"button"}).addClass("uix-control-right").attr("data-localekey","selectAll").attr("title",this._t("selectAll")).button({icons:{primary:"ui-icon-arrowthickstop-1-w"},text:false}).click(function(z){z.preventDefault(); 20 | z.stopPropagation();x.optionCache.setSelectedAll(true);return false})).append(y=d("
").addClass("header-text"))).append(w=d("
").addClass("uix-list-container ui-widget-content"))).insertAfter(this.element);this._buttons={selectAll:t,deselectAll:v}; 21 | this._headers={selected:u,available:y};this._lists={selected:s.attr("id",this.scope+"_selListContent"),available:w.attr("id",this.scope+"_avListContent")};this.optionCache=new a(this);this._searchDelayed=new o(this,{delay:500});this._initSearchable();this._applyListDroppable(); 22 | this.refresh()},refresh:function(s){this._resize();n(function(){this.optionCache.cleanup();var y,w=this.element[0].childNodes;for(var x=0,u=w.length;x').addClass("uix-search ui-widget-content ui-corner-"+(u?"left":"all"))[u?"hide":"show"]().insertBefore(this._headers[t]).focus(function(){d(this).select() 30 | }).on("keydown keypress",function(v){if(v.keyCode==13){v.preventDefault();v.stopPropagation();return false}}).keyup(d.proxy(this._searchDelayed.request,this._searchDelayed))}},_applyListDroppable:function(){if(this.options.selectionMode.indexOf("d&d")==-1){return 31 | }var s=this.optionCache;var t=this.scope;var w=function(x){return s._elements[x.data("element-index")]};var v=function(y,x){y.droppable({accept:function(z){var A=w(z);return A&&(A.selected!=x)},activeClass:"ui-state-highlight",scope:t,drop:function(z,A){A.draggable.removeClass("ui-state-disabled"); 32 | A.helper.remove();s.setSelected(w(A.draggable),x)}})};v(this._lists.selected,true);v(this._lists.available,false);if(this.options.sortable){var u=this;this._lists.selected.sortable({appendTo:"parent",axis:"y",containment:d(".multiselect-selected-list",this._elementWrapper),items:".multiselect-element-wrapper",handle:".group-element",revert:true,stop:d.proxy(function(x,y){var z; 33 | d(".multiselect-element-wrapper",u._lists.selected).each(function(){var A=u.optionCache._groups.get(d(this).data("option-group"));if(!z){u.element.append(A.groupElement)}else{A.groupElement.insertAfter(z.groupElement)}z=A})},this)})}},_search:function(t,s){if(this._searchField.is(":visible")){if(typeof t==="string"){this._searchField.val(t) 34 | }else{t=this._searchField.val()}}this.optionCache.filter(t,s)},_setLocale:function(s){if(s=="auto"){s=navigator.userLanguage||navigator.language||navigator.browserLanguage||navigator.systemLanguage||""}if(!d.uix.multiselect.i18n[s]){s=""}this.options.locale=s 35 | },_t:function(t,s,u){return r({locale:this.options.locale,key:t,plural:s,data:u})},_updateControls:function(){var s=this;d(".uix-control-left,.uix-control-right",this._elementWrapper).each(function(){d(this).attr("title",s._t(d(this).attr("data-localekey"))) 36 | })},_updateHeaders:function(){var s,u=this.optionCache.getSelectionInfo();this._headers.selected.text(s=this._t("itemsSelected",u.selected.total,{count:u.selected.total})).parent().attr("title",this.options.filterSelected?this._t("itemsSelected",u.selected.count,{count:u.selected.count})+", "+this._t("itemsFiltered",u.selected.filtered,{count:u.selected.filtered}):s); 37 | this._headers.available.text(this._t("itemsAvailable",u.available.total,{count:u.available.total})).parent().attr("title",this._t("itemsAvailable",u.available.count,{count:u.available.count})+", "+this._t("itemsFiltered",u.available.filtered,{count:u.available.filtered})) 38 | },_resize:function(){var B=this.options.availableListPosition.toLowerCase();var w=("left,right".indexOf(B)>=0)?"Width":"Height";var v=("left,right".indexOf(B)>=0)?"Height":"Width";var F=this.element["outer"+w]()*this.options.splitRatio;var C=this.element["outer"+w]()-F; 39 | var s=(v==="Width")?F:this.element.outerHeight();var D=(v==="Width")?C:this.element.outerHeight();var E=("left,right".indexOf(B)>=0)?"left":"top";var u=("left,top".indexOf(B)>=0);var t=("toggle"===this.options.searchField);var x="ui-corner-tl ui-corner-tr ui-corner-bl ui-corner-br ui-corner-top"; 40 | var A=(v==="Width")?(u?"":"ui-corner-top"):(u?"ui-corner-tr":"ui-corner-tl");var z=(v==="Width")?(u?"ui-corner-top":""):(u?"ui-corner-tl":"ui-corner-tr");this._elementWrapper.find(".multiselect-available-list")[w.toLowerCase()](C).css(E,u?0:F)[v.toLowerCase()](this.element["outer"+v]()+1); 41 | this._elementWrapper.find(".multiselect-selected-list")[w.toLowerCase()](F).css(E,u?C:0)[v.toLowerCase()](this.element["outer"+v]()+1);this._buttons.selectAll.button("option","icons",{primary:q(B,"ui-icon-arrowthickstop-1-",false)});this._buttons.deselectAll.button("option","icons",{primary:q(B,"ui-icon-arrowthickstop-1-",true)}); 42 | this._headers.available.parent().removeClass(x).addClass(z);this._headers.selected.parent().removeClass(x).addClass(A);if(!t){var y=Math.max(this._headers.selected.parent().height(),this._headers.available.parent().height());this._headers.available.parent().height(y); 43 | this._headers.selected.parent().height(y)}if(this._searchField){this._searchField.width((w==="Width"?C:this.element.width())-(t?52:26))}this._lists.available.height(D-this._headers.available.parent().outerHeight()-2);this._lists.selected.height(s-this._headers.selected.parent().outerHeight()-2) 44 | },_triggerUIEvent:function(t,u){var s;if(typeof t==="string"){s=t;t=d.Event(t)}else{s=t.type}this.element.trigger(t,u);return !t.isDefaultPrevented()},_setOption:function(s,t){switch(s){}if(typeof(this._superApply)=="function"){this._superApply(arguments)}else{d.Widget.prototype._setOption.apply(this,arguments) 45 | }}});var m={standard:function(t,s){if(t>s){return 1}if(tG){return 1}}}for(var D=0,B=Math.max(u.length,E.length);Ds){return 1}}return 0}};var c=["n","e","s","w"];var j=["bottom","left","top","right"];var q=function(u,t,s){return t+c[(d.inArray(u.toLowerCase(),j)+(s?2:0))%4]};var n=function(v,u,s){var t=Array.prototype.slice.call(arguments,3); 49 | return setTimeout(function(){v.apply(s||i,t)},u)};var o=function(t,s){this._widget=t;this._options=s;this._lastSearchValue=null};o.prototype={request:function(){if(this._widget._searchField.val()==this._lastSearchValue){return}this.cancelLastRequest();this._timeout=n(function(){this._timeout=null; 50 | this._lastSearchValue=this._widget._searchField.val();this._widget._search()},this._options.delay,this)},cancelLastRequest:function(){if(this._timeout){clearTimeout(this._timeout)}}};var p=function(u){var v=[];var t={};var s=u;this.setComparator=function(w){s=w; 51 | return this};this.clear=function(){v=[];t={};return this};this.containsKey=function(w){return !!t[w]};this.get=function(w){return t[w]};this.put=function(w,x){if(!t[w]){if(s){v.splice((function(){var z=0,C=v.length;var B=-1,D=0;while(z0){C=B}else{return B}}}return z})(),0,w)}else{v.push(w)}}t[w]=x;return this};this.remove=function(w){delete t[w];return v.splice(v.indexOf(w),1) 53 | };this.each=function(z){var x=Array.prototype.slice.call(arguments,1);x.splice(0,0,null,null);for(var y=0,w=v.length;y").appendTo(this._widget._lists.selected),available:d("
").appendTo(this._widget._lists.available)}; 54 | this._elements=[];this._groups=new p();this._moveEffect={fn:s.options.moveEffect,options:s.options.moveEffectOptions,speed:s.options.moveEffectSpeed};this._selectionMode=this._widget.options.selectionMode.indexOf("dblclick")>-1?"dblclick":this._widget.options.selectionMode.indexOf("click")>-1?"click":false; 55 | this.reset()};a.Options={batchCount:200,batchDelay:50};a.prototype={_createGroupElement:function(y,G,v){var A=this;var E;var u=function(){if(!E){E=A._groups.get(G)}return E};var z=function(){return y?y.attr("label"):A._widget.options.defaultGroupName};var t=d("").addClass("label").text(z()+" (0)").attr("title",z()+" (0)"); 56 | var x=function(){var I=u()[v?"selected":"available"];I.listElement[(!v&&(I.count||A._widget.options.showEmptyGroups))||(I.count&&((E.optionGroup!=l)||A._widget.options.showDefaultGroupHeader))?"show":"hide"]();var H=z()+" ("+I.count+")";t.text(H).attr("title",H) 57 | };var C=d("
").addClass("ui-widget-header ui-priority-secondary group-element").append(d("",{type:"button"}).addClass("uix-control-right").attr("data-localekey",(v?"de":"")+"selectAllGroup").attr("title",this._widget._t((v?"de":"")+"selectAllGroup")).button({icons:{primary:q(this._widget.options.availableListPosition,"ui-icon-arrowstop-1-",v)},text:false}).click(function(M){M.preventDefault(); 58 | M.stopPropagation();var L=u()[v?"selected":"available"];if(E.count>0){var I=[];A._bufferedMode(true);for(var J=E.startIndex,H=E.startIndex+E.count,K;J").addClass("ui-icon collapse-handle").attr("data-localekey","collapseGroup").attr("title",this._widget._t("collapseGroup")).addClass(F).mousedown(function(H){H.stopPropagation()}).click(function(H){H.preventDefault();H.stopPropagation(); 61 | s(y);return false}).prependTo(C.addClass("group-element-collapsable"));s=function(M){var L=u()[v?"selected":"available"],J=(M)?M.attr("data-collapse-icon"):null,H=(M)?M.attr("data-expand-icon"):null,K=(J)?"ui-icon "+J:"ui-icon ui-icon-triangle-1-s",I=(H)?"ui-icon "+H:"ui-icon ui-icon-triangle-1-e"; 62 | L.collapsed=!L.collapsed;L.listContainer.slideToggle();w.removeClass(L.collapsed?K:I).addClass(L.collapsed?I:K)}}else{if(B){d("").addClass("collapse-handle "+B).css("cursor","default").prependTo(C.addClass("group-element-collapsable"))}}return d("
").data("fnUpdateCount",x).data("fnToggle",s||d.noop).append(C) 63 | },_createGroupContainerElement:function(x,w,t){var u=this;var v=d("
");var s;if(this._widget.options.sortable&&t){v.sortable({tolerance:"pointer",appendTo:this._widget._elementWrapper,connectWith:this._widget._lists.available.attr("id"),scope:this._widget.scope,helper:"clone",receive:function(y,z){var A=u._elements[s=z.item.data("element-index")]; 64 | A.selected=true;A.optionElement.prop("selected",true);A.listElement.removeClass("ui-state-active")},stop:function(y,z){var A;if(s){A=u._elements[s];s=g;z.item.replaceWith(A.listElement.addClass("ui-state-highlight option-selected"));u._widget._updateHeaders(); 65 | u._widget._triggerUIEvent(h,{optionElements:[A.optionElement[0]],selected:true})}else{A=u._elements[z.item.data("element-index")];if(A&&!A.selected){u._bufferedMode(true);u._appendToList(A);u._bufferedMode(false)}}if(A){u._reorderSelected(A.optionGroup)}},revert:true}) 66 | }if(this._selectionMode){d(v).on(this._selectionMode,"div.option-element",function(){var y=u._elements[d(this).data("element-index")];y.listElement.removeClass("ui-state-hover");u.setSelected(y,!t)})}return v},_createElement:function(t,x){var w=this._widget.options.optionRenderer?this._widget.options.optionRenderer(t,x):d("
").text(t.text()); 67 | var s=t.attr("data-option-icon");var v=d("
").append(w).addClass("ui-state-default option-element").attr("unselectable","on").data("element-index",-1).hover(function(){if(t.prop("selected")){d(this).removeClass("ui-state-highlight")}d(this).addClass("ui-state-hover") 68 | },function(){d(this).removeClass("ui-state-hover");if(t.prop("selected")){d(this).addClass("ui-state-highlight")}});if(this._widget.options.selectionMode.indexOf("d&d")>-1){var u=this;v.draggable({addClasses:false,cancel:(this._widget.options.sortable?".option-selected, ":"")+".ui-state-disabled",appendTo:this._widget._elementWrapper,scope:this._widget.scope,start:function(y,z){d(this).addClass("ui-state-disabled ui-state-active"); 69 | z.helper.width(d(this).width()).height(d(this).height())},stop:function(y,z){d(this).removeClass("ui-state-disabled ui-state-active")},helper:"clone",revert:"invalid",zIndex:99999,disabled:t.prop("disabled")});if(t.prop("disabled")){v.addClass("ui-state-disabled") 70 | }if(this._widget.options.sortable){v.draggable("option","connectToSortable",this._groups.get(x)["selected"].listContainer)}}else{if(t.prop("disabled")){v[(t.prop("disabled")?"add":"remove")+"Class"]("ui-state-disabled")}}if(s){v.addClass("grouped-option").prepend(d("").addClass("ui-icon "+s)) 71 | }return v},_isOptionCollapsed:function(s){return this._groups.get(s.optionGroup)[s.selected?"selected":"available"].collapsed},_updateGroupElements:function(u){if(u){u.selected.count=0;u.available.count=0;for(var t=u.startIndex,s=u.startIndex+u.count;t=v.startIndex)&&(this._elements[s].selected!=t.selected)){s-- 74 | }if(s-1)){this._elements.splice(t--,1)[0].listElement.remove()}}for(var t=0,s=v.length;t").addClass("multiselect-element-wrapper").data("option-group",C); 86 | var D=d("
").addClass("multiselect-element-wrapper").data("option-group",C);B.append(A.selected.listElement.hide());if(C!=l||(C==l&&y)){D.append(A.available.listElement.show())}B.append(A.selected.listContainer);D.append(A.available.listContainer); 87 | z.selected.append(B);z.available.append(D)}A.count=0},this._listContainers,this._widget.options.showDefaultGroupHeader);for(var u=0,w,x,s=this._elements.length;u=u){x.startIndex=u; 88 | x.count=1}else{x.count++}w.listElement.data("element-index",w.index=u);if(w.optionElement.data("element-index")==g||w.selected!=w.optionElement.prop("selected")){w.selected=w.optionElement.prop("selected");w.optionElement.data("element-index",u);this._appendToList(w) 89 | }}this._updateGroupElements();this._widget._updateHeaders();this._groups.each(function(A,y,z){z._reorderSelected(A)},this);this._bufferedMode(false)},filter:function(t,x){if(t&&!x){var y={term:t};if(this._widget._triggerUIEvent(f,y)){t=y.term}else{return}}this._bufferedMode(true); 90 | var s=this._widget.options.filterSelected;var z=this._widget.options.searchFilter||function(C,B){return B.innerHTML.toLowerCase().indexOf(C)>-1};t=(this._widget.options.searchPreFilter||function(B){return B?(B+"").toLowerCase():false})(t);for(var u=0,A,v=this._elements.length,w; 91 | u1&&x[y.key+"_plural"]){v=x[y.key+"_plural"]}else{if(u===0&&x[y.key+"_nil"]){v=x[y.key+"_nil"]}else{v=x[y.key]||""}}}}return v.replace(/\{([^\}]+)\}/g,function(t,z){return w[z]})}d.uix.multiselect.i18n={"":{itemsSelected_nil:"no selected option",itemsSelected:"{count} selected option",itemsSelected_plural:"{count} selected options",itemsAvailable_nil:"no item available",itemsAvailable:"{count} available option",itemsAvailable_plural:"{count} available options",itemsFiltered_nil:"no option filtered",itemsFiltered:"{count} option filtered",itemsFiltered_plural:"{count} options filtered",selectAll:"Select All",deselectAll:"Deselect All",search:"Search Options",collapseGroup:"Collapse Group",expandGroup:"Expand Group",selectAllGroup:"Select All Group",deselectAllGroup:"Deselect All Group"}} 98 | })(jQuery,window); 99 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_de.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : DE 14 | */ 15 | 16 | (function($) { 17 | 18 | $.uix.multiselect.i18n['de'] = { 19 | itemsSelected_nil: 'keine Option ausgewählt', // 0 20 | itemsSelected: 'eine Option ausgewählt', // 0, 1 21 | itemsSelected_plural: '{count} Optionen ausgewählt', // n 22 | itemsSelected_plural_two: '2 Optionen ausgewählt', // 2 23 | itemsSelected_plural_few: '{count} Optionen ausgewählt', // 3, 4 24 | itemsAvailable_nil: 'keine Option verfügbar', 25 | itemsAvailable: 'eine Option verfügbar', 26 | itemsAvailable_plural: '{count} Optionen verfügbar', 27 | itemsAvailable_plural_two: '2 Optionen verfügbar', 28 | itemsAvailable_plural_few: '{count} Optionen verfügbar', 29 | itemsFiltered_nil: 'keine Option gefiltert', 30 | itemsFiltered: 'eine Option gefiltert', 31 | itemsFiltered_plural: '{count} Optionen gefiltert', 32 | itemsFiltered_plural_two: '2 Optionen gefiltert', 33 | itemsFiltered_plural_few: '{count} Optionen gefiltert', 34 | selectAll: 'Alle Optionen auswählen', 35 | deselectAll: 'Komplette Auswahl aufheben', 36 | search: 'Suchen', 37 | collapseGroup: 'Gruppe ausblenden', 38 | expandGroup: 'Gruppe anzeigen', 39 | selectAllGroup: 'Gruppe auswählen', 40 | deselectAllGroup: 'Gruppenauswahl aufheben' 41 | }; 42 | 43 | // link locales 44 | $.uix.multiselect.i18n['de_DE'] = $.uix.multiselect.i18n['de']; 45 | $.uix.multiselect.i18n['de_CH'] = $.uix.multiselect.i18n['de']; 46 | $.uix.multiselect.i18n['de_AT'] = $.uix.multiselect.i18n['de']; 47 | // ... 48 | 49 | })(jQuery); 50 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_en.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : EN 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['en'] = { 20 | itemsSelected_nil: 'No options selected', // 0 21 | itemsSelected: '{count} selected option', // 0, 1 22 | itemsSelected_plural: '{count} options selected', // n 23 | //itemsSelected_plural_two: ... // 2 24 | //itemsSelected_plural_few: ... // 3, 4 25 | itemsAvailable_nil: 'No items available', 26 | itemsAvailable: '{count} options available', 27 | itemsAvailable_plural: '{count} options available', 28 | //itemsAvailable_plural_two: ... 29 | //itemsAvailable_plural_few: ... 30 | itemsFiltered_nil: 'No options found', 31 | itemsFiltered: '{count} option found', 32 | itemsFiltered_plural: '{count} options found', 33 | //itemsFiltered_plural_two: ... 34 | //itemsFiltered_plural_few: ... 35 | selectAll: 'Select All', 36 | deselectAll: 'Deselect All', 37 | search: 'Search Options', 38 | collapseGroup: 'Collapse Group', 39 | expandGroup: 'Expand Group', 40 | selectAllGroup: 'Select All Group', 41 | deselectAllGroup: 'Deselect All Group' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['en_CA'] = $.uix.multiselect.i18n['en']; 46 | $.uix.multiselect.i18n['en_GB'] = $.uix.multiselect.i18n['en']; 47 | $.uix.multiselect.i18n['en_US'] = $.uix.multiselect.i18n['en']; 48 | // ... 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_es.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : ES 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['es'] = { 20 | itemsSelected_nil: 'no hay opciones seleccionadas', // 0 21 | itemsSelected: '{count} opción seleccionada', // 0, 1 22 | itemsSelected_plural: '{count} opciones seleccionadas', // n 23 | //itemsSelected_plural_two: ... // 2 24 | //itemsSelected_plural_few: ... // 3, 4 25 | itemsAvailable_nil: 'no hay opciones disponibles', 26 | itemsAvailable: '{count} opción disponible', 27 | itemsAvailable_plural: '{count} opciones disponibles', 28 | //itemsAvailable_plural_two: ... 29 | //itemsAvailable_plural_few: ... 30 | itemsFiltered_nil: 'ninguna opción filtrada', 31 | itemsFiltered: '{count} opción filtrada', 32 | itemsFiltered_plural: '{count} opciones filtradas', 33 | //itemsFiltered_plural_two: ... 34 | //itemsFiltered_plural_few: ... 35 | selectAll: 'Seleccionar Todo', 36 | deselectAll: 'Deseleccionar Todo', 37 | search: 'Buscar opciones', 38 | collapseGroup: 'Plegar Grupo', 39 | expandGroup: 'Expandir Grupo', 40 | selectAllGroup: 'Seleccionar Grupo Entero', 41 | deselectAllGroup: 'Deseleccionar Grupo Entero' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['es_ES'] = $.uix.multiselect.i18n['es']; 46 | $.uix.multiselect.i18n['es_AR'] = $.uix.multiselect.i18n['es']; 47 | // ... 48 | 49 | })(jQuery); 50 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_et.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * karmux (https://github.com/karmux) 7 | * 8 | * Dual licensed under the MIT (MIT-LICENSE.txt) 9 | * and GPL (GPL-LICENSE.txt) licenses. 10 | * 11 | * http://mind2soft.com/labs/jquery/multiselect/ 12 | * 13 | * 14 | * Localization : ET 15 | * 16 | */ 17 | 18 | (function($) { 19 | 20 | $.uix.multiselect.i18n['et'] = { 21 | itemsSelected_nil: 'midagi pole valitud', // 0 22 | itemsSelected: '{count} valitud', // 0, 1 23 | itemsSelected_plural: '{count} valitud', // n 24 | //itemsSelected_plural_two: ... // 2 25 | //itemsSelected_plural_few: ... // 3, 4 26 | itemsAvailable_nil: 'valikuid pole saadaval', 27 | itemsAvailable: '{count} valik saadaval', 28 | itemsAvailable_plural: '{count} valikut saadaval', 29 | //itemsAvailable_plural_two: ... 30 | //itemsAvailable_plural_few: ... 31 | itemsFiltered_nil: 'valikuid pole filtreeritud', 32 | itemsFiltered: '{count} valik filtreeritud', 33 | itemsFiltered_plural: '{count} valikut filtreeritud', 34 | //itemsFiltered_plural_two: ... 35 | //itemsFiltered_plural_few: ... 36 | selectAll: 'Vali kõik', 37 | deselectAll: 'Tühista kõik', 38 | search: 'Otsi', 39 | collapseGroup: 'Kahanda grupp', 40 | expandGroup: 'Laienda grupp', 41 | selectAllGroup: 'Vali kogu grupp', 42 | deselectAllGroup: 'Tühista kogu grupp' 43 | }; 44 | 45 | // link locales 46 | $.uix.multiselect.i18n['et_EE'] = $.uix.multiselect.i18n['et']; 47 | // ... 48 | 49 | })(jQuery); 50 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_fr.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : FR 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['fr'] = { 20 | itemsSelected_nil: 'aucune option sélectionnée', // 0 21 | itemsSelected: '{count} option sélectionnée', // 0, 1 22 | itemsSelected_plural: '{count} options sélectionnées', // n 23 | //itemsSelected_plural_two: ... // 2 24 | //itemsSelected_plural_few: ... // 3, 4 25 | itemsAvailable_nil: 'aucune option disponible', 26 | itemsAvailable: '{count} option disponible', 27 | itemsAvailable_plural: '{count} options disponibles', 28 | //itemsAvailable_plural_two: ... 29 | //itemsAvailable_plural_few: ... 30 | itemsFiltered_nil: 'aucune option masquée', 31 | itemsFiltered: '{count} option masquée', 32 | itemsFiltered_plural: '{count} options masquées', 33 | //itemsFiltered_plural_two: ... 34 | //itemsFiltered_plural_few: ... 35 | selectAll: 'Sélectionner tout', 36 | deselectAll: 'Désélectionner tout', 37 | search: 'Rechercher les options', 38 | collapseGroup: 'Masquer le groupe', 39 | expandGroup: 'Afficher le groupe', 40 | selectAllGroup: 'Sélectionner tout le groupe', 41 | deselectAllGroup: 'Déselectionner tout le groupe' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['fr_CA'] = $.uix.multiselect.i18n['fr']; 46 | $.uix.multiselect.i18n['fr_FR'] = $.uix.multiselect.i18n['fr']; 47 | // ... 48 | 49 | })(jQuery); 50 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_it.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * Manuel Dalla Lana (endelwar[at]aregar[dot]it) 7 | * 8 | * Dual licensed under the MIT (MIT-LICENSE.txt) 9 | * and GPL (GPL-LICENSE.txt) licenses. 10 | * 11 | * http://mind2soft.com/labs/jquery/multiselect/ 12 | * 13 | * 14 | * Localization : IT 15 | * 16 | */ 17 | 18 | (function($) { 19 | 20 | $.uix.multiselect.i18n['it'] = { 21 | itemsSelected_nil: 'nessuna opzione selezionata', // 0 22 | itemsSelected: '{count} opzione selezionata', // 0, 1 23 | itemsSelected_plural: '{count} opzioni selezionate', // n 24 | //itemsSelected_plural_two: ... // 2 25 | //itemsSelected_plural_few: ... // 3, 4 26 | itemsAvailable_nil: 'nessuna opzione disponibile', 27 | itemsAvailable: '{count} opzione disponibile', 28 | itemsAvailable_plural: '{count} opzioni disponibili', 29 | //itemsAvailable_plural_two: ... 30 | //itemsAvailable_plural_few: ... 31 | itemsFiltered_nil: 'nessuna opzione filtrata', 32 | itemsFiltered: '{count} opzione filtrata', 33 | itemsFiltered_plural: '{count} opzioni filtrate', 34 | //itemsFiltered_plural_two: ... 35 | //itemsFiltered_plural_few: ... 36 | selectAll: 'Seleziona Tutto', 37 | deselectAll: 'Deseleziona Tutto', 38 | search: 'Cerca Opzioni', 39 | collapseGroup: 'Collassa Gruppo', 40 | expandGroup: 'Espandi Gruppo', 41 | selectAllGroup: 'Seleziona Tutto il Gruppo', 42 | deselectAllGroup: 'Deseleziona Tutto il Gruppo' 43 | }; 44 | 45 | // link locales 46 | $.uix.multiselect.i18n['it_IT'] = $.uix.multiselect.i18n['it']; 47 | $.uix.multiselect.i18n['it_CH'] = $.uix.multiselect.i18n['it']; 48 | // ... 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_nl.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : NL 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['nl'] = { 20 | itemsSelected_nil: 'Geen geselecteerde items', // 0 21 | itemsSelected: '{count} geselecteerde item', // 0, 1 22 | itemsSelected_plural: '{count} geselecteerde items', // n 23 | //itemsSelected_plural_two: ... // 2 24 | //itemsSelected_plural_few: ... // 3, 4 25 | itemsAvailable_nil: 'Geen item beschikbaar', 26 | itemsAvailable: '{count} beschikbare item', 27 | itemsAvailable_plural: '{count} beschikbare items', 28 | //itemsAvailable_plural_two: ... 29 | //itemsAvailable_plural_few: ... 30 | itemsFiltered_nil: 'Geen gefilterde item', 31 | itemsFiltered: '{count} item gefilterd', 32 | itemsFiltered_plural: '{count} items fgeilterd', 33 | //itemsFiltered_plural_two: ... 34 | //itemsFiltered_plural_few: ... 35 | selectAll: 'Selecteer Alles', 36 | deselectAll: 'Deselecteer Alles', 37 | search: 'Zoek opties', 38 | collapseGroup: 'Klap groep in', 39 | expandGroup: 'Klap Group uit', 40 | selectAllGroup: 'Selecteer alle groepen', 41 | deselectAllGroup: 'Deselecteer alle groepen' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['nl_NL'] = $.uix.multiselect.i18n['nl']; 46 | // ... 47 | 48 | })(jQuery); 49 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_pt.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * Translation: Alexander Bulei 7 | * 8 | * Dual licensed under the MIT (MIT-LICENSE.txt) 9 | * and GPL (GPL-LICENSE.txt) licenses. 10 | * 11 | * http://mind2soft.com/labs/jquery/multiselect/ 12 | * 13 | * 14 | * Localization : PT 15 | * 16 | */ 17 | 18 | (function($) { 19 | 20 | $.uix.multiselect.i18n['pt'] = { 21 | itemsSelected_nil: 'Nenhuma opção selecionada', // 0 22 | itemsSelected: '{count} opção seleccionada', // 0, 1 23 | itemsSelected_plural: '{count} opções seleccionadas', // n 24 | //itemsSelected_plural_two: ... // 2 25 | //itemsSelected_plural_few: ... // 3, 4 26 | itemsAvailable_nil: 'Nenhuma opção disponível', 27 | itemsAvailable: '{count} opção disponível', 28 | itemsAvailable_plural: '{count} opções disponíveis', 29 | //itemsAvailable_plural_two: ... 30 | //itemsAvailable_plural_few: ... 31 | itemsFiltered_nil: 'Nenhuma opção filtrada', 32 | itemsFiltered: '{count} opção filtrada', 33 | itemsFiltered_plural: '{count} opções filtradas', 34 | //itemsFiltered_plural_two: ... 35 | //itemsFiltered_plural_few: ... 36 | selectAll: 'Seleccionar todos', 37 | deselectAll: 'Desseleccionar todos', 38 | search: 'Opções de pesquisa', 39 | collapseGroup: 'Ocultar grupo', 40 | expandGroup: 'Expandir grupo', 41 | selectAllGroup: 'Seleccionar grupo', 42 | deselectAllGroup: 'Desseleccionar grupo' 43 | }; 44 | 45 | // link locales 46 | $.uix.multiselect.i18n['pt_PT'] = $.uix.multiselect.i18n['pt']; 47 | $.uix.multiselect.i18n['pt_BR'] = $.uix.multiselect.i18n['pt']; 48 | // ... 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_ru.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : RU 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['ru'] = { 20 | itemsSelected_nil: 'Варианты не выбраны', // 0 21 | itemsSelected: 'Выбран 1 вариант', // 1 22 | itemsSelected_plural: 'Выбрано {count} вариантов', // n 23 | itemsSelected_plural_two: 'Выбрано 2 варианта', // 2 24 | itemsSelected_plural_few: 'Выбрано {count} варианта',// 3, 4 25 | itemsAvailable_nil: 'Нет вариантов для выбора', 26 | itemsAvailable: 'Доступен один вариант', 27 | itemsAvailable_plural: 'Доступно {count} вариантов', 28 | itemsAvailable_plural_two: 'Доступно 2 варианта', 29 | itemsAvailable_plural_few: 'Доступно {count} варианта', 30 | itemsFiltered_nil: 'Нет отфильтрованных вариантов', 31 | itemsFiltered: 'Отфильтрован 1 вариант', 32 | itemsFiltered_plural: 'Отфильтровано {count} вариантов', 33 | itemsFiltered_plural_two: 'Отфильтровано 2 варианта', 34 | itemsFiltered_plural_few: 'Отфильтровано {count} варианта', 35 | selectAll: 'Выбрать все', 36 | deselectAll: 'Отменить выбор для всех', 37 | search: 'Поиск...', 38 | collapseGroup: 'Свернуть группу', 39 | expandGroup: 'Развернуть группу', 40 | selectAllGroup: 'Выбрать всю группу', 41 | deselectAllGroup: 'Отменить выбор группы' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['ru_RU'] = $.uix.multiselect.i18n['ru']; 46 | 47 | })(jQuery); 48 | -------------------------------------------------------------------------------- /js/locales/jquery.uix.multiselect_sv.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Multiselect 2.0 3 | * 4 | * Authors: 5 | * Yanick Rochon (yanick.rochon[at]gmail[dot]com) 6 | * 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | * 10 | * http://mind2soft.com/labs/jquery/multiselect/ 11 | * 12 | * 13 | * Localization : EN 14 | * 15 | */ 16 | 17 | (function($) { 18 | 19 | $.uix.multiselect.i18n['sv'] = { 20 | itemsSelected_nil: 'inga alternativ valda', // 0 21 | itemsSelected: '{count} valt alternativ', // 0, 1 22 | itemsSelected_plural: '{count} valda alternativ', // n 23 | //itemsSelected_plural_two: ... // 2 24 | //itemsSelected_plural_few: ... // 3, 4 25 | itemsAvailable_nil: 'inga alternativ tillgängliga', 26 | itemsAvailable: '{count} tillgängligt alternativ', 27 | itemsAvailable_plural: '{count} tillgängliga alternativ', 28 | //itemsAvailable_plural_two: ... 29 | //itemsAvailable_plural_few: ... 30 | itemsFiltered_nil: 'inga alternativ filtrerade', 31 | itemsFiltered: '{count} alternativ filtrerat', 32 | itemsFiltered_plural: '{count} alternativ filtrerade', 33 | //itemsFiltered_plural_two: ... 34 | //itemsFiltered_plural_few: ... 35 | selectAll: 'Markera alla', 36 | deselectAll: 'Avmarkera alla', 37 | search: 'Sök alternativ', 38 | collapseGroup: 'Dölj grupp', 39 | expandGroup: 'Visa grupp', 40 | selectAllGroup: 'Markera alla i gruppen', 41 | deselectAllGroup: 'Avmarkera alla i gruppen' 42 | }; 43 | 44 | // link locales 45 | $.uix.multiselect.i18n['sv_SE'] = $.uix.multiselect.i18n['sv']; 46 | // ... 47 | 48 | })(jQuery); 49 | --------------------------------------------------------------------------------