diff --git a/src/inputs/select2/lib/README.md b/src/inputs/select2/lib/README.md index 9e5b64e..12e2492 100644 --- a/src/inputs/select2/lib/README.md +++ b/src/inputs/select2/lib/README.md @@ -34,6 +34,7 @@ Integrations * [Django](https://github.com/applegrew/django-select2) * [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin) * [Bootstrap](https://github.com/t0m/select2-bootstrap-css) (CSS skin) +* [Yii](https://github.com/tonybolzan/yii-select2) Internationalization (i18n) --------------------------- diff --git a/src/inputs/select2/lib/component.json b/src/inputs/select2/lib/component.json index 2a46b66..4c7337f 100644 --- a/src/inputs/select2/lib/component.json +++ b/src/inputs/select2/lib/component.json @@ -1,8 +1,8 @@ { "name": "select2", - "version": "3.3.2", - "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "spinner.gif"], + "version": "3.4.0", + "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"], "dependencies": { - "jquery": "~1.4.4" + "jquery": ">= 1.7.1" } } diff --git a/src/inputs/select2/lib/select2.css b/src/inputs/select2/lib/select2.css index 36324d6..abe59c9 100644 --- a/src/inputs/select2/lib/select2.css +++ b/src/inputs/select2/lib/select2.css @@ -1,7 +1,8 @@ /* -Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 +Version: 3.4.0 Timestamp: Tue May 14 08:27:33 PDT 2013 */ .select2-container { + margin: 0; position: relative; display: inline-block; /* inline-block for ie7 */ @@ -81,6 +82,10 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 background-image: linear-gradient(top, #eeeeee 0%,#ffffff 90%); } +.select2-container.select2-allowclear .select2-choice span { + margin-right: 42px; +} + .select2-container .select2-choice span { margin-right: 26px; display: block; @@ -94,11 +99,11 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 } .select2-container .select2-choice abbr { - display: block; + display: none; width: 12px; height: 12px; position: absolute; - right: 26px; + right: 24px; top: 8px; font-size: 1px; @@ -109,6 +114,11 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 cursor: pointer; outline: 0; } + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + .select2-container .select2-choice abbr:hover { background-position: right -11px; cursor: pointer; @@ -119,11 +129,6 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 left: 0; top: 0; z-index: 9998; - background-color: #fff; - opacity: 0; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; /* works in IE 8 */ - filter: "alpha(opacity=0)"; /* expected to work in IE 8 */ - filter: alpha(opacity=0); /* IE 4-7 */ } .select2-drop { @@ -147,6 +152,15 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 box-shadow: 0 4px 5px rgba(0, 0, 0, .15); } +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + .select2-drop.select2-drop-above { margin-top: 1px; border-top: 1px solid #aaa; @@ -162,7 +176,7 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 } .select2-container .select2-choice div { - display: block; + display: inline-block; width: 18px; height: 100%; position: absolute; @@ -209,12 +223,6 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 white-space: nowrap; } -.select2-search-hidden { - display: block; - position: absolute; - left: -10000px; -} - .select2-search input { width: 100%; height: auto !important; @@ -292,6 +300,20 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); } +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, white), color-stop(0.5, #eeeeee)); + background-image: -webkit-linear-gradient(center top, white 0%, #eeeeee 50%); + background-image: -moz-linear-gradient(center top, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: -ms-linear-gradient(bottom, #ffffff 0%,#eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); + background-image: linear-gradient(bottom, #ffffff 0%,#eeeeee 50%); +} + .select2-dropdown-open .select2-choice div { background: transparent; border-left: none; @@ -314,6 +336,7 @@ Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 .select2-results ul.select2-result-sub { margin: 0; + padding-left: 0; } .select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } @@ -420,7 +443,7 @@ disabled look for disabled choices in the results dropdown } .select2-container.select2-container-disabled .select2-choice abbr { - display: none + display: none; } @@ -579,8 +602,8 @@ disabled look for disabled choices in the results dropdown background-color: #f4f4f4; } -.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { - display: none; +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background:none; } /* end multiselect */ @@ -590,17 +613,31 @@ disabled look for disabled choices in the results dropdown text-decoration: underline; } -.select2-offscreen { - border: 0; +.select2-offscreen, .select2-offscreen:focus { clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; width: 1px; + height: 1px; + border: 0; + margin: 0; + padding: 0; + overflow: hidden; + position: absolute; + outline: 0; + left: 0px; } +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} /* Retina-ize icons */ @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { diff --git a/src/inputs/select2/lib/select2.jquery.json b/src/inputs/select2/lib/select2.jquery.json index 2a539e7..b9b114d 100644 --- a/src/inputs/select2/lib/select2.jquery.json +++ b/src/inputs/select2/lib/select2.jquery.json @@ -11,7 +11,7 @@ "tag", "tagging" ], - "version": "3.3.2", + "version": "3.4.0", "author": { "name": "Igor Vaynberg", "url": "https://github.com/ivaynberg" @@ -31,6 +31,6 @@ "docs": "http://ivaynberg.github.com/select2/", "download": "https://github.com/ivaynberg/select2/tags", "dependencies": { - "jquery": ">=1.4.6" + "jquery": ">=1.7.1" } } diff --git a/src/inputs/select2/lib/select2.js b/src/inputs/select2/lib/select2.js index 093d7fb..992ba8b 100644 --- a/src/inputs/select2/lib/select2.js +++ b/src/inputs/select2/lib/select2.js @@ -1,7 +1,7 @@ /* Copyright 2012 Igor Vaynberg -Version: 3.3.2 Timestamp: Mon Mar 25 12:14:18 PDT 2013 +Version: 3.4.0 Timestamp: Tue May 14 08:27:33 PDT 2013 This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU General Public License version 2 (the "GPL License"). You may choose either license to govern your @@ -47,7 +47,7 @@ the specific language governing permissions and limitations under the Apache Lic } var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, - lastMousePosition, $document; + lastMousePosition, $document, scrollBarDimensions, KEY = { TAB: 9, @@ -95,7 +95,8 @@ the specific language governing permissions and limitations under the Apache Lic k = k.which ? k.which : k; return k >= 112 && k <= 123; } - }; + }, + MEASURE_SCROLLBAR_TEMPLATE = "
"; $document = $(document); @@ -109,6 +110,19 @@ the specific language governing permissions and limitations under the Apache Lic return -1; } + function measureScrollbar () { + var $template = $( MEASURE_SCROLLBAR_TEMPLATE ); + $template.appendTo('body'); + + var dim = { + width: $template.width() - $template[0].clientWidth, + height: $template.height() - $template[0].clientHeight + }; + $template.remove(); + + return dim; + } + /** * Compares equality of a and b * @param a @@ -143,12 +157,12 @@ the specific language governing permissions and limitations under the Apache Lic function installKeyUpChangeEvent(element) { var key="keyup-change-value"; - element.bind("keydown", function () { + element.on("keydown", function () { if ($.data(element, key) === undefined) { $.data(element, key, element.val()); } }); - element.bind("keyup", function () { + element.on("keyup", function () { var val= $.data(element, key); if (val !== undefined && element.val() !== val) { $.removeData(element, key); @@ -157,7 +171,7 @@ the specific language governing permissions and limitations under the Apache Lic }); } - $document.bind("mousemove", function (e) { + $document.on("mousemove", function (e) { lastMousePosition = {x: e.pageX, y: e.pageY}; }); @@ -168,7 +182,7 @@ the specific language governing permissions and limitations under the Apache Lic * the elements under the pointer are scrolled. */ function installFilteredMouseMove(element) { - element.bind("mousemove", function (e) { + element.on("mousemove", function (e) { var lastpos = lastMousePosition; if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { $(e.target).trigger("mousemove-filtered", e); @@ -213,7 +227,7 @@ the specific language governing permissions and limitations under the Apache Lic function installDebouncedScroll(threshold, element) { var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); - element.bind("scroll", function (e) { + element.on("scroll", function (e) { if (indexOf(e.target, element.get()) >= 0) notify(e); }); } @@ -248,6 +262,23 @@ the specific language governing permissions and limitations under the Apache Lic }, 0); } + function getCursorInfo(el) { + el = $(el)[0]; + var offset = 0; + var length = 0; + if ('selectionStart' in el) { + offset = el.selectionStart; + length = el.selectionEnd - offset; + } else if ('selection' in document) { + el.focus(); + var sel = document.selection.createRange(); + length = document.selection.createRange().text.length; + sel.moveStart('character', -el.value.length); + offset = sel.text.length - length; + } + return { offset: offset, length: length }; + } + function killEvent(event) { event.preventDefault(); event.stopPropagation(); @@ -328,11 +359,11 @@ the specific language governing permissions and limitations under the Apache Lic * Produces an ajax-based query function * * @param options object containing configuration paramters + * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax * @param options.url url for the data * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified - * @param options.traditional a boolean flag that should be true if you wish to use the traditional style of param serialization for the ajax request * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2. * The expected format is an object containing the following keys: @@ -355,9 +386,15 @@ the specific language governing permissions and limitations under the Apache Lic var requestNumber = requestSequence, // this request's sequence number data = options.data, // ajax data function url = ajaxUrl, // ajax url string or function - transport = options.transport || $.ajax, - type = options.type || 'GET', // set type of request (GET or POST) - params = {}; + transport = options.transport || $.fn.select2.ajaxDefaults.transport, + // deprecated - to be removed in 4.0 - use params instead + deprecated = { + type: options.type || 'GET', // set type of request (GET or POST) + cache: options.cache || false, + jsonpCallback: options.jsonpCallback||undefined, + dataType: options.dataType||"json" + }, + params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated); data = data ? data.call(self, query.term, query.page, query.context) : null; url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url; @@ -376,8 +413,6 @@ the specific language governing permissions and limitations under the Apache Lic url: url, dataType: options.dataType, data: data, - type: type, - cache: false, success: function (data) { if (requestNumber < requestSequence) { return; @@ -427,7 +462,7 @@ the specific language governing permissions and limitations under the Apache Lic text = dataItem.text; // if text is not a function we assume it to be a key name if (!$.isFunction(text)) { - dataText = data.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available + dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available text = function (item) { return item[dataText]; }; } } @@ -590,7 +625,7 @@ the specific language governing permissions and limitations under the Apache Lic // abstract init: function (opts) { - var results, search, resultsSelector = ".select2-results", mask; + var results, search, resultsSelector = ".select2-results", disabled, readonly; // prepare options this.opts = opts = this.prepareOpts(opts); @@ -603,7 +638,6 @@ the specific language governing permissions and limitations under the Apache Lic this.destroy(); } - this.enabled=true; this.container = this.createContainer(); this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()); @@ -618,14 +652,12 @@ the specific language governing permissions and limitations under the Apache Lic this.container.css(evaluate(opts.containerCss)); this.container.addClass(evaluate(opts.containerCssClass)); - this.elementTabIndex = this.opts.element.attr("tabIndex"); + this.elementTabIndex = this.opts.element.attr("tabindex"); // swap container for the element this.opts.element .data("select2", this) - .addClass("select2-offscreen") - .bind("focus.select2", function() { $(this).select2("focus"); }) - .attr("tabIndex", "-1") + .attr("tabindex", "-1") .before(this.container); this.container.data("select2", this); @@ -636,8 +668,6 @@ the specific language governing permissions and limitations under the Apache Lic this.results = results = this.container.find(resultsSelector); this.search = search = this.container.find("input.select2-input"); - search.attr("tabIndex", this.elementTabIndex); - this.resultsPage = 0; this.context = null; @@ -645,10 +675,14 @@ the specific language governing permissions and limitations under the Apache Lic this.initContainer(); installFilteredMouseMove(this.results); - this.dropdown.delegate(resultsSelector, "mousemove-filtered touchstart touchmove touchend", this.bind(this.highlightUnderEvent)); + this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent)); installDebouncedScroll(80, this.results); - this.dropdown.delegate(resultsSelector, "scroll-debounced", this.bind(this.loadMoreIfNeeded)); + this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded)); + + // do not propagate change event from the search field out of the component + $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();}); + $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();}); // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel if ($.fn.mousewheel) { @@ -665,11 +699,11 @@ the specific language governing permissions and limitations under the Apache Lic } installKeyUpChangeEvent(search); - search.bind("keyup-change input paste", this.bind(this.updateResults)); - search.bind("focus", function () { search.addClass("select2-focused"); }); - search.bind("blur", function () { search.removeClass("select2-focused");}); + search.on("keyup-change input paste", this.bind(this.updateResults)); + search.on("focus", function () { search.addClass("select2-focused"); }); + search.on("blur", function () { search.removeClass("select2-focused");}); - this.dropdown.delegate(resultsSelector, "mouseup", this.bind(function (e) { + this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) { if ($(e.target).closest(".select2-result-selectable").length > 0) { this.highlightUnderEvent(e); this.selectHighlighted(e); @@ -679,7 +713,7 @@ the specific language governing permissions and limitations under the Apache Lic // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's // dom it will trigger the popup close, which is not what we want - this.dropdown.bind("click mouseup mousedown", function (e) { e.stopPropagation(); }); + this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); }); if ($.isFunction(this.opts.initSelection)) { // initialize selection based on the current value of the source element @@ -690,7 +724,24 @@ the specific language governing permissions and limitations under the Apache Lic this.monitorSource(); } - if (opts.element.is(":disabled") || opts.element.is("[readonly='readonly']")) this.disable(); + if (opts.maximumInputLength !== null) { + this.search.attr("maxlength", opts.maximumInputLength); + } + + var disabled = opts.element.prop("disabled"); + if (disabled === undefined) disabled = false; + this.enable(!disabled); + + var readonly = opts.element.prop("readonly"); + if (readonly === undefined) readonly = false; + this.readonly(readonly); + + // Calculate size of scrollbar + scrollBarDimensions = scrollBarDimensions || measureScrollbar(); + + this.autofocus = opts.element.prop("autofocus") + opts.element.prop("autofocus", false); + if (this.autofocus) this.focus(); }, // abstract @@ -706,15 +757,37 @@ the specific language governing permissions and limitations under the Apache Lic select2.opts.element .removeClass("select2-offscreen") .removeData("select2") - .unbind(".select2") - .attr({"tabIndex": this.elementTabIndex}) + .off(".select2") + .attr({"tabindex": this.elementTabIndex}) + .prop("autofocus", this.autofocus||false) .show(); } }, + // abstract + optionToData: function(element) { + if (element.is("option")) { + return { + id:element.prop("value"), + text:element.text(), + element: element.get(), + css: element.attr("class"), + disabled: element.prop("disabled"), + locked: equal(element.attr("locked"), "locked") + }; + } else if (element.is("optgroup")) { + return { + text:element.attr("label"), + children:[], + element: element.get(), + css: element.attr("class") + }; + } + }, + // abstract prepareOpts: function (opts) { - var element, select, idKey, ajaxUrl; + var element, select, idKey, ajaxUrl, self = this; element = opts.element; @@ -733,7 +806,7 @@ the specific language governing permissions and limitations under the Apache Lic opts = $.extend({}, { populateResults: function(container, results, query) { - var populate, data, result, children, id=this.opts.id, self=this; + var populate, data, result, children, id=this.opts.id; populate=function(results, container, depth) { @@ -807,10 +880,10 @@ the specific language governing permissions and limitations under the Apache Lic var group; if (element.is("option")) { if (query.matcher(term, element.text(), element)) { - collection.push({id:element.attr("value"), text:element.text(), element: element.get(), css: element.attr("class"), disabled: equal(element.attr("disabled"), "disabled") }); + collection.push(self.optionToData(element)); } } else if (element.is("optgroup")) { - group={text:element.attr("label"), children:[], element: element.get(), css: element.attr("class")}; + group=self.optionToData(element); element.children().each2(function(i, elm) { process(elm, group.children); }); if (group.children.length>0) { collection.push(group); @@ -881,7 +954,7 @@ the specific language governing permissions and limitations under the Apache Lic monitorSource: function () { var el = this.opts.element, sync; - el.bind("change.select2", this.bind(function (e) { + el.on("change.select2", this.bind(function (e) { if (this.opts.element.data("select2-change-triggered") !== true) { this.initSelection(); } @@ -893,19 +966,13 @@ the specific language governing permissions and limitations under the Apache Lic // sync enabled state - enabled = this.opts.element.attr("disabled") !== "disabled"; - readonly = this.opts.element.attr("readonly") === "readonly"; - - enabled = enabled && !readonly; - - if (this.enabled !== enabled) { - if (enabled) { - this.enable(); - } else { - this.disable(); - } - } + var disabled = el.prop("disabled"); + if (disabled === undefined) disabled = false; + this.enable(!disabled); + var readonly = el.prop("readonly"); + if (readonly === undefined) readonly = false; + this.readonly(readonly); syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); this.container.addClass(evaluate(this.opts.containerCssClass)); @@ -916,17 +983,31 @@ the specific language governing permissions and limitations under the Apache Lic }); // mozilla and IE - el.bind("propertychange.select2 DOMAttrModified.select2", sync); + el.on("propertychange.select2 DOMAttrModified.select2", sync); + + + // hold onto a reference of the callback to work around a chromium bug + if (this.mutationCallback === undefined) { + this.mutationCallback = function (mutations) { + mutations.forEach(sync); + } + } + // safari and chrome if (typeof WebKitMutationObserver !== "undefined") { if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } - this.propertyObserver = new WebKitMutationObserver(function (mutations) { - mutations.forEach(sync); - }); + this.propertyObserver = new WebKitMutationObserver(this.mutationCallback); this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false }); } }, + // abstract + triggerSelect: function(data) { + var evt = $.Event("select2-selecting", { val: this.id(data), object: data }); + this.opts.element.trigger(evt); + return !evt.isDefaultPrevented(); + }, + /** * Triggers the change event on the source element */ @@ -950,24 +1031,46 @@ the specific language governing permissions and limitations under the Apache Lic this.opts.element.blur(); }, - // abstract - enable: function() { - if (this.enabled) return; - - this.enabled=true; - this.container.removeClass("select2-container-disabled"); - this.opts.element.removeAttr("disabled"); + //abstract + isInterfaceEnabled: function() + { + return this.enabledInterface === true; }, // abstract - disable: function() { - if (!this.enabled) return; + enableInterface: function() { + var enabled = this._enabled && !this._readonly, + disabled = !enabled; + if (enabled === this.enabledInterface) return false; + + this.container.toggleClass("select2-container-disabled", disabled); this.close(); + this.enabledInterface = enabled; - this.enabled=false; - this.container.addClass("select2-container-disabled"); - this.opts.element.attr("disabled", "disabled"); + return true; + }, + + // abstract + enable: function(enabled) { + if (enabled === undefined) enabled = true; + if (this._enabled === enabled) return false; + this._enabled = enabled; + + this.opts.element.prop("disabled", !enabled); + this.enableInterface(); + return true; + }, + + // abstract + readonly: function(enabled) { + if (enabled === undefined) enabled = false; + if (this._readonly === enabled) return false; + this._readonly = enabled; + + this.opts.element.prop("readonly", enabled); + this.enableInterface(); + return true; }, // abstract @@ -977,22 +1080,37 @@ the specific language governing permissions and limitations under the Apache Lic // abstract positionDropdown: function() { - var offset = this.container.offset(), + var $dropdown = this.dropdown, + offset = this.container.offset(), height = this.container.outerHeight(false), width = this.container.outerWidth(false), - dropHeight = this.dropdown.outerHeight(false), + dropHeight = $dropdown.outerHeight(false), viewPortRight = $(window).scrollLeft() + $(window).width(), viewportBottom = $(window).scrollTop() + $(window).height(), dropTop = offset.top + height, dropLeft = offset.left, enoughRoomBelow = dropTop + dropHeight <= viewportBottom, enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(), - dropWidth = this.dropdown.outerWidth(false), + dropWidth = $dropdown.outerWidth(false), enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, - aboveNow = this.dropdown.hasClass("select2-drop-above"), + aboveNow = $dropdown.hasClass("select2-drop-above"), bodyOffset, above, - css; + css, + resultsListNode; + + if (this.opts.dropdownAutoWidth) { + resultsListNode = $('.select2-results', $dropdown)[0]; + $dropdown.addClass('select2-drop-auto-width'); + $dropdown.css('width', ''); + // Add scrollbar width to dropdown if vertical scrollbar is present + dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width); + dropWidth > width ? width = dropWidth : dropWidth = width; + enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight; + } + else { + this.container.removeClass('select2-drop-auto-width'); + } //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove); @@ -1022,11 +1140,11 @@ the specific language governing permissions and limitations under the Apache Lic if (above) { dropTop = offset.top - dropHeight; this.container.addClass("select2-drop-above"); - this.dropdown.addClass("select2-drop-above"); + $dropdown.addClass("select2-drop-above"); } else { this.container.removeClass("select2-drop-above"); - this.dropdown.removeClass("select2-drop-above"); + $dropdown.removeClass("select2-drop-above"); } css = $.extend({ @@ -1035,7 +1153,7 @@ the specific language governing permissions and limitations under the Apache Lic width: width }, evaluate(this.opts.dropdownCss)); - this.dropdown.css(css); + $dropdown.css(css); }, // abstract @@ -1044,7 +1162,9 @@ the specific language governing permissions and limitations under the Apache Lic if (this.opened()) return false; - event = $.Event("opening"); + if (this._enabled === false || this._readonly === true) return false; + + event = $.Event("select2-opening"); this.opts.element.trigger(event); return !event.isDefaultPrevented(); }, @@ -1067,7 +1187,7 @@ the specific language governing permissions and limitations under the Apache Lic if (!this.shouldOpen()) return false; - window.setTimeout(this.bind(this.opening), 1); + this.opening(); return true; }, @@ -1083,17 +1203,14 @@ the specific language governing permissions and limitations under the Apache Lic orient = "orientationchange."+cid, mask; - this.clearDropdownAlignmentPreference(); - this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); + this.clearDropdownAlignmentPreference(); if(this.dropdown[0] !== this.body().children().last()[0]) { this.dropdown.detach().appendTo(this.body()); } - this.updateResults(true); - // create the dropdown mask if doesnt already exist mask = $("#select2-drop-mask"); if (mask.length == 0) { @@ -1101,7 +1218,7 @@ the specific language governing permissions and limitations under the Apache Lic mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); mask.hide(); mask.appendTo(this.body()); - mask.bind("mousedown touchstart", function (e) { + mask.on("mousedown touchstart", function (e) { var dropdown = $("#select2-drop"), self; if (dropdown.length > 0) { self=dropdown.data("select2"); @@ -1109,6 +1226,8 @@ the specific language governing permissions and limitations under the Apache Lic self.selectHighlighted({noFocus: true}); } self.close(); + e.preventDefault(); + e.stopPropagation(); } }); } @@ -1135,14 +1254,12 @@ the specific language governing permissions and limitations under the Apache Lic // the position of the dropdown to be updated as well so it does not come unglued from the container var that = this; this.container.parents().add(window).each(function () { - $(this).bind(resize+" "+scroll+" "+orient, function (e) { + $(this).on(resize+" "+scroll+" "+orient, function (e) { $("#select2-drop-mask").css(_makeMaskCss()); that.positionDropdown(); }); }); - this.focusSearch(); - function _makeMaskCss() { return { width : Math.max(document.documentElement.scrollWidth, $(window).width()), @@ -1161,7 +1278,7 @@ the specific language governing permissions and limitations under the Apache Lic orient = "orientationchange."+cid; // unbind event listeners - this.container.parents().add(window).each(function () { $(this).unbind(scroll).unbind(resize).unbind(orient); }); + this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); }); this.clearDropdownAlignmentPreference(); @@ -1170,9 +1287,11 @@ the specific language governing permissions and limitations under the Apache Lic this.dropdown.hide(); this.container.removeClass("select2-dropdown-open"); this.results.empty(); + + this.clearSearch(); this.search.removeClass("select2-active"); - this.opts.element.trigger($.Event("close")); + this.opts.element.trigger($.Event("select2-close")); }, // abstract @@ -1203,7 +1322,7 @@ the specific language governing permissions and limitations under the Apache Lic return; } - children = this.findHighlightableChoices(); + children = this.findHighlightableChoices().find('.select2-result-label'); child = $(children[index]); @@ -1231,7 +1350,6 @@ the specific language governing permissions and limitations under the Apache Lic // abstract findHighlightableChoices: function() { - var h=this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)"); return this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)"); }, @@ -1272,7 +1390,7 @@ the specific language governing permissions and limitations under the Apache Lic data = choice.data("select2-data"); if (data) { - this.opts.element.trigger({ type: "highlight", val: this.id(data), choice: data }); + this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data }); } }, @@ -1394,6 +1512,7 @@ the specific language governing permissions and limitations under the Apache Lic } else { render(""); } + if (initial) this.showSearch(true); return; } @@ -1467,7 +1586,7 @@ the specific language governing permissions and limitations under the Apache Lic postRender(); - this.opts.element.trigger({ type: "loaded", data:data }); + this.opts.element.trigger({ type: "select2-loaded", data:data }); })}); }, @@ -1537,18 +1656,18 @@ the specific language governing permissions and limitations under the Apache Lic attrs = style.split(';'); for (i = 0, l = attrs.length; i < l; i = i + 1) { matches = attrs[i].replace(/\s/g, '') - .match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/); + .match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i); if (matches !== null && matches.length >= 1) return matches[1]; } } - if (this.opts.width === "resolve") { - // next check if css('width') can resolve a width that is percent based, this is sometimes possible - // when attached to input type=hidden or elements hidden via css - style = this.opts.element.css('width'); - if (style.indexOf("%") > 0) return style; + // next check if css('width') can resolve a width that is percent based, this is sometimes possible + // when attached to input type=hidden or elements hidden via css + style = this.opts.element.css('width'); + if (style && style.length > 0) return style; + if (this.opts.width === "resolve") { // finally, fallback on the calculated width of the element return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'); } @@ -1577,13 +1696,13 @@ the specific language governing permissions and limitations under the Apache Lic "class": "select2-container" }).html([ "", - " ", + "  ", "
" , "
", "", - "