diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-03-05 21:21:35 +0100 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-03-05 21:21:35 +0100 |
commit | 27cbef194960af0c7f2e22e092c47db15284ec18 (patch) | |
tree | ea33ccd0e4cf6e1d50be49e932cd6ceb44e87a82 /module/web/static | |
parent | cleaned dashboard event code, preserve filtering across packages (diff) | |
download | pyload-27cbef194960af0c7f2e22e092c47db15284ec18.tar.xz |
fixed position of autocompletion, updated libraries
Diffstat (limited to 'module/web/static')
-rw-r--r-- | module/web/static/css/default/dashboard.less | 12 | ||||
-rw-r--r-- | module/web/static/css/select2.css | 32 | ||||
-rw-r--r-- | module/web/static/js/config.js | 2 | ||||
-rw-r--r-- | module/web/static/js/libs/require-2.1.5.js (renamed from module/web/static/js/libs/require-2.1.2.js) | 96 | ||||
-rw-r--r-- | module/web/static/js/libs/select2-3.3.1.js (renamed from module/web/static/js/libs/select2-3.2.js) | 601 | ||||
-rw-r--r-- | module/web/static/js/views/filterView.js | 17 |
6 files changed, 485 insertions, 275 deletions
diff --git a/module/web/static/css/default/dashboard.less b/module/web/static/css/default/dashboard.less index e2cc739c6..2a4adf0e7 100644 --- a/module/web/static/css/default/dashboard.less +++ b/module/web/static/css/default/dashboard.less @@ -279,6 +279,18 @@ FANCY CHECKBOXES Actionbar
*/
+.form-search {
+ position: relative;
+
+ .dropdown-menu {
+ min-width: 100%;
+ position: absolute;
+ right: 0;
+ left: auto;
+ }
+
+}
+
li.finished > a, li.finished:hover > a {
background-color: @green;
color: @light;
diff --git a/module/web/static/css/select2.css b/module/web/static/css/select2.css index d8b43d876..1ff2abb1b 100644 --- a/module/web/static/css/select2.css +++ b/module/web/static/css/select2.css @@ -1,5 +1,5 @@ /* -Version: @@ver@@ Timestamp: @@timestamp@@ +Version: 3.3.1 Timestamp: Wed Feb 20 09:57:22 PST 2013 */ .select2-container { position: relative; @@ -48,6 +48,13 @@ Version: @@ver@@ Timestamp: @@timestamp@@ -moz-background-clip: padding; background-clip: padding-box; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: #fff; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); @@ -133,7 +140,6 @@ Version: @@ver@@ Timestamp: @@timestamp@@ -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - -o-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); box-shadow: 0 4px 5px rgba(0, 0, 0, .15); } @@ -148,7 +154,6 @@ Version: @@ver@@ Timestamp: @@timestamp@@ -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); -moz-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); - -o-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); } @@ -256,16 +261,13 @@ Version: @@ver@@ Timestamp: @@timestamp@@ -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); -moz-box-shadow: 0 0 5px rgba(0,0,0,.3); - -o-box-shadow: 0 0 5px rgba(0,0,0,.3); box-shadow: 0 0 5px rgba(0,0,0,.3); } .select2-dropdown-open .select2-choice { - border: 1px solid #aaa; border-bottom-color: transparent; -webkit-box-shadow: 0 1px 0 #fff inset; -moz-box-shadow: 0 1px 0 #fff inset; - -o-box-shadow: 0 1px 0 #fff inset; box-shadow: 0 1px 0 #fff inset; -webkit-border-bottom-left-radius: 0; @@ -303,6 +305,7 @@ Version: @@ver@@ Timestamp: @@timestamp@@ position: relative; overflow-x: hidden; overflow-y: auto; + -webkit-tap-highlight-color: rgba(0,0,0,0); } .select2-results ul.select2-result-sub { @@ -331,6 +334,13 @@ Version: @@ver@@ Timestamp: @@timestamp@@ padding: 3px 7px 4px; margin: 0; cursor: pointer; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .select2-results .select2-highlighted { @@ -444,7 +454,6 @@ disabled look for disabled choices in the results dropdown -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); -moz-box-shadow: 0 0 5px rgba(0,0,0,.3); - -o-box-shadow: 0 0 5px rgba(0,0,0,.3); box-shadow: 0 0 5px rgba(0,0,0,.3); } .select2-container-multi .select2-choices li { @@ -458,7 +467,6 @@ disabled look for disabled choices in the results dropdown } .select2-container-multi .select2-choices .select2-search-field input { - height: 15px; padding: 5px; margin: 1px 0; @@ -469,7 +477,6 @@ disabled look for disabled choices in the results dropdown border: 0; -webkit-box-shadow: none; -moz-box-shadow: none; - -o-box-shadow: none; box-shadow: none; background: transparent !important; } @@ -504,6 +511,13 @@ disabled look for disabled choices in the results dropdown -moz-background-clip: padding; background-clip: padding-box; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: #e4e4e4; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0 ); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); diff --git a/module/web/static/js/config.js b/module/web/static/js/config.js index 86704740c..474a77dc3 100644 --- a/module/web/static/js/config.js +++ b/module/web/static/js/config.js @@ -10,7 +10,7 @@ require.config({ transit: "libs/jquery.transit-0.9.9", animate: "libs/jquery.animate-enhanced-0.99", omniwindow: "libs/jquery.omniwindow", - select2: "libs/select2-3.2", + select2: "libs/select2-3.3.1", bootstrap: "libs/bootstrap-2.3", underscore: "libs/lodash-1.0.1", diff --git a/module/web/static/js/libs/require-2.1.2.js b/module/web/static/js/libs/require-2.1.5.js index 0e7b81bc4..062516acd 100644 --- a/module/web/static/js/libs/require-2.1.2.js +++ b/module/web/static/js/libs/require-2.1.5.js @@ -1,18 +1,18 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ //Not using strict: uneven strict support in browsers, #392, and causes //problems with requirejs.exec()/transpiler plugins that may not be strict. /*jslint regexp: true, nomen: true, sloppy: true */ -/*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ +/*global window, navigator, document, importScripts, setTimeout, opera */ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.2', + version = '2.1.5', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -21,7 +21,6 @@ var requirejs, require, define; ostring = op.toString, hasOwn = op.hasOwnProperty, ap = Array.prototype, - aps = ap.slice, apsp = ap.splice, isBrowser = !!(typeof window !== 'undefined' && navigator && document), isWebWorker = !isBrowser && typeof importScripts !== 'undefined', @@ -192,15 +191,21 @@ var requirejs, require, define; var inCheckLoaded, Module, context, handlers, checkLoadedTimeoutId, config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. waitSeconds: 7, baseUrl: './', paths: {}, pkgs: {}, shim: {}, - map: {}, config: {} }, registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, undefEvents = {}, defQueue = [], defined = {}, @@ -296,7 +301,7 @@ var requirejs, require, define; } //Apply map config if available. - if (applyMap && (baseParts || starMap) && map) { + if (applyMap && map && (baseParts || starMap)) { nameParts = name.split('/'); for (i = nameParts.length; i > 0; i -= 1) { @@ -577,6 +582,7 @@ var requirejs, require, define; function cleanRegistry(id) { //Clean up machinery used for waiting modules. delete registry[id]; + delete enabledRegistry[id]; } function breakCycle(mod, traced, processed) { @@ -625,7 +631,7 @@ var requirejs, require, define; inCheckLoaded = true; //Figure out the state of all the modules. - eachProp(registry, function (mod) { + eachProp(enabledRegistry, function (mod) { map = mod.map; modId = map.id; @@ -806,7 +812,7 @@ var requirejs, require, define; }, /** - * Checks is the module is ready to define itself, and if so, + * Checks if the module is ready to define itself, and if so, * define it. */ check: function () { @@ -884,7 +890,7 @@ var requirejs, require, define; } //Clean up - delete registry[id]; + cleanRegistry(id); this.defined = true; } @@ -918,8 +924,7 @@ var requirejs, require, define; name = this.map.name, parentName = this.map.parentMap ? this.map.parentMap.name : null, localRequire = context.makeRequire(map.parentMap, { - enableBuildCallback: true, - skipMap: true + enableBuildCallback: true }); //If current map is not normalized, wait for that @@ -1017,8 +1022,11 @@ var requirejs, require, define; try { req.exec(text); } catch (e) { - throw new Error('fromText eval for ' + moduleName + - ' failed: ' + e); + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); } if (hasInteractive) { @@ -1048,6 +1056,7 @@ var requirejs, require, define; }, enable: function () { + enabledRegistry[this.map.id] = this; this.enabled = true; //Set flag mentioning that the module is enabling, @@ -1207,6 +1216,7 @@ var requirejs, require, define; Module: Module, makeModuleMap: makeModuleMap, nextTick: req.nextTick, + onError: onError, /** * Set a configuration for the context. @@ -1233,6 +1243,9 @@ var requirejs, require, define; eachProp(cfg, function (value, prop) { if (objs[prop]) { if (prop === 'map') { + if (!config.map) { + config.map = {}; + } mixin(config[prop], value, true, true); } else { mixin(config[prop], value, true); @@ -1344,7 +1357,7 @@ var requirejs, require, define; //Synchronous access to one module. If require.get is //available (as in the Node adapter), prefer that. if (req.get) { - return req.get(context, deps, relMap); + return req.get(context, deps, relMap, localRequire); } //Normalize module name, if it contains . or .. @@ -1395,16 +1408,20 @@ var requirejs, require, define; * plain URLs like nameToUrl. */ toUrl: function (moduleNamePlusExt) { - var index = moduleNamePlusExt.lastIndexOf('.'), - ext = null; - - if (index !== -1) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); moduleNamePlusExt = moduleNamePlusExt.substring(0, index); } return context.nameToUrl(normalize(moduleNamePlusExt, - relMap && relMap.id, true), ext); + relMap && relMap.id, true), ext, true); }, defined: function (id) { @@ -1449,10 +1466,11 @@ var requirejs, require, define; /** * Called to enable a module if it is still in the registry - * awaiting enablement. parent module is passed in for context, - * used by the optimizer. + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overriden by + * the optimizer. Not shown here to keep code compact. */ - enable: function (depMap, parent) { + enable: function (depMap) { var mod = getOwn(registry, depMap.id); if (mod) { getModule(depMap).enable(); @@ -1522,7 +1540,7 @@ var requirejs, require, define; * it is assumed to have already been normalized. This is an * internal API, not a public one. Use toUrl for the public API. */ - nameToUrl: function (moduleName, ext) { + nameToUrl: function (moduleName, ext, skipExt) { var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, parentPath; @@ -1571,7 +1589,7 @@ var requirejs, require, define; //Join the path parts together, then figure out if baseUrl is needed. url = syms.join('/'); - url += (ext || (/\?/.test(url) ? '' : '.js')); + url += (ext || (/\?/.test(url) || skipExt ? '' : '.js')); url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; } @@ -1810,7 +1828,7 @@ var requirejs, require, define; node.attachEvent('onreadystatechange', context.onScriptLoad); //It would be great to add an error handler here to catch //404s in IE9+. However, onreadystatechange will fire before - //the error handler, so that does not help. If addEvenListener + //the error handler, so that does not help. If addEventListener //is used, then IE will fire error before load, but we cannot //use that pathway given the connect.microsoft.com issue //mentioned above about not doing the 'script execute, @@ -1839,16 +1857,24 @@ var requirejs, require, define; return node; } else if (isWebWorker) { - //In a web worker, use importScripts. This is not a very - //efficient use of importScripts, importScripts will block until - //its script is downloaded and evaluated. However, if web workers - //are in play, the expectation that a build has been done so that - //only one script needs to be loaded anyway. This may need to be - //reevaluated if other use cases become common. - importScripts(url); - - //Account for anonymous modules - context.completeLoad(moduleName); + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } } }; diff --git a/module/web/static/js/libs/select2-3.2.js b/module/web/static/js/libs/select2-3.3.1.js index d41f090d7..8be2c7e9f 100644 --- a/module/web/static/js/libs/select2-3.2.js +++ b/module/web/static/js/libs/select2-3.3.1.js @@ -1,7 +1,7 @@ /* Copyright 2012 Igor Vaynberg -Version: @@ver@@ Timestamp: @@timestamp@@ +Version: 3.3.1 Timestamp: Wed Feb 20 09:57:22 PST 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 @@ -103,7 +103,9 @@ the specific language governing permissions and limitations under the Apache Lic function indexOf(value, array) { var i = 0, l = array.length; - for (; i < l; i = i + 1) if (value === array[i]) return i; + for (; i < l; i = i + 1) { + if (equal(value, array[i])) return i; + } return -1; } @@ -113,7 +115,12 @@ the specific language governing permissions and limitations under the Apache Lic * @param b */ function equal(a, b) { - return a===b; + if (a === b) return true; + if (a === undefined || b === undefined) return false; + if (a === null || b === null) return false; + if (a.constructor === String) return a === b+''; + if (b.constructor === String) return b === a+''; + return false; } /** @@ -211,6 +218,34 @@ the specific language governing permissions and limitations under the Apache Lic }); } + function focus($el) { + if ($el[0] === document.activeElement) return; + + /* set the focus in a 0 timeout - that way the focus is set after the processing + of the current event has finished - which seems like the only reliable way + to set focus */ + window.setTimeout(function() { + var el=$el[0], pos=$el.val().length, range; + + $el.focus(); + + /* after the focus is set move the caret to the end, necessary when we val() + just before setting focus */ + if(el.setSelectionRange) + { + el.setSelectionRange(pos, pos); + } + else if (el.createTextRange) { + range = el.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + + }, 0); + } + function killEvent(event) { event.preventDefault(); event.stopPropagation(); @@ -243,6 +278,32 @@ the specific language governing permissions and limitations under the Apache Lic return sizer.width(); } + function syncCssClasses(dest, src, adapter) { + var classes, replacements = [], adapted; + + classes = dest.attr("class"); + if (typeof classes === "string") { + $(classes.split(" ")).each2(function() { + if (this.indexOf("select2-") === 0) { + replacements.push(this); + } + }); + } + classes = src.attr("class"); + if (typeof classes === "string") { + $(classes.split(" ")).each2(function() { + if (this.indexOf("select2-") !== 0) { + adapted = adapter(this); + if (typeof adapted === "string" && adapted.length > 0) { + replacements.push(this); + } + } + }); + } + dest.attr("class", replacements.join(" ")); + } + + function markMatch(text, term, markup, escapeMarkup) { var match=text.toUpperCase().indexOf(term.toUpperCase()), tl=term.length; @@ -279,7 +340,9 @@ the specific language governing permissions and limitations under the Apache Lic var timeout, // current scheduled but not yet executed request requestSequence = 0, // sequence used to drop out-of-order responses handler = null, - quietMillis = options.quietMillis || 100; + quietMillis = options.quietMillis || 100, + ajaxUrl = options.url, + self = this; return function (query) { window.clearTimeout(timeout); @@ -287,31 +350,40 @@ the specific language governing permissions and limitations under the Apache Lic requestSequence += 1; // increment the sequence var requestNumber = requestSequence, // this request's sequence number data = options.data, // ajax data function - url = options.url, // ajax url string or function + url = ajaxUrl, // ajax url string or function transport = options.transport || $.ajax, - traditional = options.traditional || false, - type = options.type || 'GET'; // set type of request (GET or POST) + type = options.type || 'GET', // set type of request (GET or POST) + params = {}; - data = data ? data.call(this, query.term, query.page, query.context) : null; - url = (typeof url === 'function') ? url.call(this, query.term, query.page, query.context) : url; + 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; if( null !== handler) { handler.abort(); } - handler = transport.call(null, { + if (options.params) { + if ($.isFunction(options.params)) { + $.extend(params, options.params.call(self)); + } else { + $.extend(params, options.params); + } + } + + $.extend(params, { url: url, dataType: options.dataType, data: data, type: type, - traditional: traditional, + cache: false, success: function (data) { if (requestNumber < requestSequence) { return; } - // TODO 3.0 - replace query.page with query so users have access to term, page, etc. + // TODO - replace query.page with query so users have access to term, page, etc. var results = options.results(data, query.page); query.callback(results); } }); + handler = transport.call(self, params); }, quietMillis); }; } @@ -333,22 +405,33 @@ the specific language governing permissions and limitations under the Apache Lic function local(options) { var data = options, // data elements dataText, + tmp, text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search - if (!$.isArray(data)) { - text = data.text; + if ($.isArray(data)) { + tmp = data; + data = { results: tmp }; + } + + if ($.isFunction(data) === false) { + tmp = data; + data = function() { return tmp; }; + } + + var dataItem = data(); + if (dataItem.text) { + 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 - text = function (item) { return item[dataText]; }; + 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 + text = function (item) { return item[dataText]; }; } - data = data.results; } return function (query) { var t = query.term, filtered = { results: [] }, process; if (t === "") { - query.callback({results: data}); + query.callback(data()); return; } @@ -372,7 +455,7 @@ the specific language governing permissions and limitations under the Apache Lic } }; - $(data).each2(function(i, datum) { process(datum, filtered.results); }); + $(data().results).each2(function(i, datum) { process(datum, filtered.results); }); query.callback(filtered); }; } @@ -526,28 +609,7 @@ the specific language governing permissions and limitations under the Apache Lic // cache the body so future lookups are cheap this.body = thunk(function() { return opts.element.closest("body"); }); - // create the dropdown mask if doesnt already exist - mask = $("#select2-drop-mask"); - if (mask.length == 0) { - mask = $(document.createElement("div")); - mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); - mask.hide(); - mask.appendTo(this.body()); - mask.bind("mousedown touchstart", function (e) { - var dropdown = $("#select2-drop"), self; - if (dropdown.length > 0) { - self=dropdown.data("select2"); - if (self.opts.selectOnBlur) { - self.selectHighlighted({noFocus: true}); - } - self.close(); - } - }); - } - - if (opts.element.attr("class") !== undefined) { - this.container.addClass(opts.element.attr("class").replace(/validate\[[\S ]+] ?/, '')); - } + syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); this.container.css(evaluate(opts.containerCss)); this.container.addClass(evaluate(opts.containerCssClass)); @@ -558,7 +620,7 @@ the specific language governing permissions and limitations under the Apache Lic this.opts.element .data("select2", this) .addClass("select2-offscreen") - .bind("focus.select2", function() { $(this).select2("focus")}) + .bind("focus.select2", function() { $(this).select2("focus"); }) .attr("tabIndex", "-1") .before(this.container); this.container.data("select2", this); @@ -577,10 +639,9 @@ the specific language governing permissions and limitations under the Apache Lic // initialize the container this.initContainer(); - this.initContainerWidth(); installFilteredMouseMove(this.results); - this.dropdown.delegate(resultsSelector, "mousemove-filtered", this.bind(this.highlightUnderEvent)); + this.dropdown.delegate(resultsSelector, "mousemove-filtered touchstart touchmove touchend", this.bind(this.highlightUnderEvent)); installDebouncedScroll(80, this.results); this.dropdown.delegate(resultsSelector, "scroll-debounced", this.bind(this.loadMoreIfNeeded)); @@ -600,18 +661,15 @@ the specific language governing permissions and limitations under the Apache Lic } installKeyUpChangeEvent(search); - search.bind("keyup-change", this.bind(this.updateResults)); - search.bind("focus", function () { search.addClass("select2-focused"); if (search.val() === " ") search.val(""); }); + 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");}); this.dropdown.delegate(resultsSelector, "mouseup", this.bind(function (e) { if ($(e.target).closest(".select2-result-selectable").length > 0) { this.highlightUnderEvent(e); this.selectHighlighted(e); - } else { - this.focusSearch(); } - killEvent(e); })); // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening @@ -642,9 +700,10 @@ the specific language governing permissions and limitations under the Apache Lic select2.container.remove(); select2.dropdown.remove(); select2.opts.element + .removeClass("select2-offscreen") .removeData("select2") .unbind(".select2") - .attr("tabIndex", this.elementTabIndex) + .attr({"tabIndex": this.elementTabIndex}) .show(); } }, @@ -698,7 +757,7 @@ the specific language governing permissions and limitations under the Apache Lic label=$(document.createElement("div")); label.addClass("select2-result-label"); - formatted=opts.formatResult(result, label, query); + formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup); if (formatted!==undefined) { label.html(formatted); } @@ -771,7 +830,7 @@ the specific language governing permissions and limitations under the Apache Lic }); // this is needed because inside val() we construct choices from options and there id is hardcoded opts.id=function(e) { return e.id; }; - opts.formatResultCssClass = function(data) { return data.css; } + opts.formatResultCssClass = function(data) { return data.css; }; } else { if (!("query" in opts)) { @@ -780,7 +839,7 @@ the specific language governing permissions and limitations under the Apache Lic if (ajaxUrl && ajaxUrl.length > 0) { opts.ajax.url = ajaxUrl; } - opts.query = ajax(opts.ajax); + opts.query = ajax.call(opts.element, opts.ajax); } else if ("data" in opts) { opts.query = local(opts.data); } else if ("tags" in opts) { @@ -788,17 +847,19 @@ the specific language governing permissions and limitations under the Apache Lic if (opts.createSearchChoice === undefined) { opts.createSearchChoice = function (term) { return {id: term, text: term}; }; } - opts.initSelection = function (element, callback) { - var data = []; - $(splitVal(element.val(), opts.separator)).each(function () { - var id = this, text = this, tags=opts.tags; - if ($.isFunction(tags)) tags=tags(); - $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); - data.push({id: id, text: text}); - }); - - callback(data); - }; + if (opts.initSelection === undefined) { + opts.initSelection = function (element, callback) { + var data = []; + $(splitVal(element.val(), opts.separator)).each(function () { + var id = this, text = this, tags=opts.tags; + if ($.isFunction(tags)) tags=tags(); + $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); + data.push({id: id, text: text}); + }); + + callback(data); + }; + } } } } @@ -823,8 +884,13 @@ the specific language governing permissions and limitations under the Apache Lic })); sync = this.bind(function () { - var enabled = this.opts.element.attr("disabled") !== "disabled"; - var readonly = this.opts.element.attr("readonly") === "readonly"; + + var enabled, readonly, self = this; + + // sync enabled state + + enabled = this.opts.element.attr("disabled") !== "disabled"; + readonly = this.opts.element.attr("readonly") === "readonly"; enabled = enabled && !readonly; @@ -835,6 +901,14 @@ the specific language governing permissions and limitations under the Apache Lic this.disable(); } } + + + syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); + this.container.addClass(evaluate(this.opts.containerCssClass)); + + syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.addClass(evaluate(this.opts.dropdownCssClass)); + }); // mozilla and IE @@ -903,21 +977,21 @@ the specific language governing permissions and limitations under the Apache Lic height = this.container.outerHeight(false), width = this.container.outerWidth(false), dropHeight = this.dropdown.outerHeight(false), - viewPortRight = $(window).scrollLeft() + document.documentElement.clientWidth, - viewportBottom = $(window).scrollTop() + document.documentElement.clientHeight, + 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), - enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, + dropWidth = this.dropdown.outerWidth(false), + enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, aboveNow = this.dropdown.hasClass("select2-drop-above"), bodyOffset, above, css; - // 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); + //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); // fix positioning when body has an offset and is not position: static @@ -937,9 +1011,9 @@ the specific language governing permissions and limitations under the Apache Lic if (!enoughRoomBelow && enoughRoomAbove) above = true; } - if (!enoughRoomOnRight) { - dropLeft = offset.left + width - dropWidth; - } + if (!enoughRoomOnRight) { + dropLeft = offset.left + width - dropWidth; + } if (above) { dropTop = offset.top - dropHeight; @@ -966,7 +1040,7 @@ the specific language governing permissions and limitations under the Apache Lic if (this.opened()) return false; - event = $.Event("open"); + event = $.Event("opening"); this.opts.element.trigger(event); return !event.isDefaultPrevented(); }, @@ -1007,8 +1081,6 @@ the specific language governing permissions and limitations under the Apache Lic this.clearDropdownAlignmentPreference(); - if (this.search.val() === " ") { this.search.val(""); } - this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); @@ -1018,7 +1090,24 @@ the specific language governing permissions and limitations under the Apache Lic this.updateResults(true); + // create the dropdown mask if doesnt already exist mask = $("#select2-drop-mask"); + if (mask.length == 0) { + mask = $(document.createElement("div")); + mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); + mask.hide(); + mask.appendTo(this.body()); + mask.bind("mousedown touchstart", function (e) { + var dropdown = $("#select2-drop"), self; + if (dropdown.length > 0) { + self=dropdown.data("select2"); + if (self.opts.selectOnBlur) { + self.selectHighlighted({noFocus: true}); + } + self.close(); + } + }); + } // ensure the mask is always right before the dropdown if (this.dropdown.prev()[0] !== mask[0]) { @@ -1042,12 +1131,13 @@ the specific language governing permissions and limitations under the Apache Lic // attach listeners to events that can change the position of the container and thus require // 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) { $("#select2-drop-mask").css({ width:document.documentElement.scrollWidth, height:document.documentElement.scrollHeight}); - $("#select2-drop").data("select2").positionDropdown(); + that.positionDropdown(); }); }); @@ -1071,7 +1161,7 @@ the specific language governing permissions and limitations under the Apache Lic $("#select2-drop-mask").hide(); this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); + this.container.removeClass("select2-dropdown-open"); this.results.empty(); this.clearSearch(); @@ -1083,6 +1173,11 @@ the specific language governing permissions and limitations under the Apache Lic }, + //abstract + getMaximumSelectionSize: function() { + return evaluate(this.opts.maximumSelectionSize); + }, + // abstract ensureHighlightVisible: function () { var results = this.results, children, index, child, hb, rb, y, more; @@ -1150,7 +1245,9 @@ the specific language governing permissions and limitations under the Apache Lic // abstract highlight: function (index) { - var choices = this.findHighlightableChoices(); + var choices = this.findHighlightableChoices(), + choice, + data; if (arguments.length === 0) { return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); @@ -1161,8 +1258,15 @@ the specific language governing permissions and limitations under the Apache Lic this.results.find(".select2-highlighted").removeClass("select2-highlighted"); - $(choices[index]).addClass("select2-highlighted"); + choice = $(choices[index]); + choice.addClass("select2-highlighted"); + this.ensureHighlightVisible(); + + data = choice.data("select2-data"); + if (data) { + this.opts.element.trigger({ type: "highlight", val: this.id(data), choice: data }); + } }, // abstract @@ -1199,6 +1303,7 @@ the specific language governing permissions and limitations under the Apache Lic if (below <= this.opts.loadMorePadding) { more.addClass("select2-active"); this.opts.query({ + element: this.opts.element, term: term, page: page, context: context, @@ -1219,6 +1324,7 @@ the specific language governing permissions and limitations under the Apache Lic } self.positionDropdown(); self.resultsPage = page; + self.context = data.context; })}); } }, @@ -1255,10 +1361,11 @@ the specific language governing permissions and limitations under the Apache Lic postRender(); } - if (opts.maximumSelectionSize >=1) { + var maxSelSize = this.getMaximumSelectionSize(); + if (maxSelSize >=1) { data = this.data(); - if ($.isArray(data) && data.length >= opts.maximumSelectionSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { - render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(opts.maximumSelectionSize) + "</li>"); + if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { + render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(maxSelSize) + "</li>"); return; } } @@ -1291,7 +1398,9 @@ the specific language governing permissions and limitations under the Apache Lic } this.resultsPage = 1; + opts.query({ + element: opts.element, term: search.val(), page: this.resultsPage, context: null, @@ -1304,7 +1413,6 @@ the specific language governing permissions and limitations under the Apache Lic // save context, if any this.context = (data.context===undefined) ? null : data.context; - // create a default choice and prepend it to the list if (this.opts.createSearchChoice && search.val() !== "") { def = this.opts.createSearchChoice.call(null, search.val(), data.results); @@ -1350,28 +1458,15 @@ the specific language governing permissions and limitations under the Apache Lic this.close(); this.container.removeClass("select2-container-active"); - this.dropdown.removeClass("select2-drop-active"); // synonymous to .is(':focus'), which is available in jquery >= 1.6 if (this.search[0] === document.activeElement) { this.search.blur(); } this.clearSearch(); this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - this.opts.element.triggerHandler("blur"); }, // abstract focusSearch: function () { - // need to do it here as well as in timeout so it works in IE - this.search.show(); - this.search.focus(); - - /* we do this in a timeout so that current event processing can complete before this code is executed. - this makes sure the search field is focussed even if the current event would blur it */ - window.setTimeout(this.bind(function () { - // reset the value so IE places the cursor at the end of the input box - this.search.show(); - this.search.focus(); - this.search.val(this.search.val()); - }), 10); + focus(this.search); }, // abstract @@ -1388,14 +1483,6 @@ the specific language governing permissions and limitations under the Apache Lic // abstract getPlaceholder: function () { - - // if a placeholder is specified on a select without the first empty option ignore it - if (this.select) { - if (this.select.find("option").first().text() !== "") { - return undefined; - } - } - return this.opts.element.attr("placeholder") || this.opts.element.attr("data-placeholder") || // jquery 1.4 compat this.opts.element.data("placeholder") || @@ -1450,7 +1537,7 @@ the specific language governing permissions and limitations under the Apache Lic var width = resolveContainerWidth.call(this); if (width !== null) { - this.container.attr("style", "width: "+width); + this.container.css("width", width); } } }); @@ -1463,11 +1550,12 @@ the specific language governing permissions and limitations under the Apache Lic var container = $(document.createElement("div")).attr({ "class": "select2-container" }).html([ - " <a href='javascript:void(0)' onclick='return false;' class='select2-choice'>", + "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>", " <span></span><abbr class='select2-search-choice-close' style='display:none;'></abbr>", " <div><b></b></div>" , "</a>", - " <div class='select2-drop select2-offscreen'>" , + "<input class='select2-focusser select2-offscreen' type='text'/>", + "<div class='select2-drop' style='display:none'>" , " <div class='select2-search'>" , " <input type='text' autocomplete='off' class='select2-input'/>" , " </div>" , @@ -1478,34 +1566,59 @@ the specific language governing permissions and limitations under the Apache Lic }, // single + disable: function() { + if (!this.enabled) return; + + this.parent.disable.apply(this, arguments); + + this.focusser.attr("disabled", "disabled"); + }, + + // single + enable: function() { + if (this.enabled) return; + + this.parent.enable.apply(this, arguments); + + this.focusser.removeAttr("disabled"); + }, + + // single opening: function () { - this.search.show(); this.parent.opening.apply(this, arguments); - this.dropdown.removeClass("select2-offscreen"); + this.focusser.attr("disabled", "disabled"); + + this.opts.element.trigger($.Event("open")); }, // single close: function () { if (!this.opened()) return; this.parent.close.apply(this, arguments); - this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show(); + this.focusser.removeAttr("disabled"); + focus(this.focusser); }, // single focus: function () { - this.close(); - this.selection.focus(); + if (this.opened()) { + this.close(); + } else { + this.focusser.removeAttr("disabled"); + this.focusser.focus(); + } }, // single isFocused: function () { - return this.selection[0] === document.activeElement; + return this.container.hasClass("select2-container-active"); }, // single cancel: function () { this.parent.cancel.apply(this, arguments); - this.selection.focus(); + this.focusser.removeAttr("disabled"); + this.focusser.focus(); }, // single @@ -1516,8 +1629,12 @@ the specific language governing permissions and limitations under the Apache Lic dropdown = this.dropdown, clickingInside = false; + this.showSearch(this.opts.minimumResultsForSearch >= 0); + this.selection = selection = container.find(".select2-choice"); + this.focusser = container.find(".select2-focusser"); + this.search.bind("keydown", this.bind(function (e) { if (!this.enabled) return; @@ -1527,56 +1644,62 @@ the specific language governing permissions and limitations under the Apache Lic return; } - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.TAB: - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - } else { - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { + switch (e.which) { + case KEY.UP: + case KEY.DOWN: + this.moveHighlight((e.which === KEY.UP) ? -1 : 1); + killEvent(e); return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { + case KEY.TAB: + case KEY.ENTER: + this.selectHighlighted(); + killEvent(e); return; - } + case KEY.ESC: + this.cancel(e); + killEvent(e); + return; + } + })); + + this.focusser.bind("keydown", this.bind(function (e) { + if (!this.enabled) return; + + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { + return; + } + if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { + killEvent(e); + return; + } + + if (e.which == KEY.DOWN || e.which == KEY.UP + || (e.which == KEY.ENTER && this.opts.openOnEnter)) { this.open(); + killEvent(e); + return; + } - if (e.which === KEY.ENTER) { - // do not propagate the event otherwise we open, and propagate enter which closes - return; + if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { + if (this.opts.allowClear) { + this.clear(); } + killEvent(e); + return; } })); - this.search.bind("focus", this.bind(function() { - this.selection.attr("tabIndex", "-1"); - })); - this.search.bind("blur", this.bind(function() { - if (!this.opened()) this.container.removeClass("select2-container-active"); - window.setTimeout(this.bind(function() { - // restore original tab index - var ti=this.elementTabIndex || 0; - if (ti) { - this.selection.attr("tabIndex", ti); - } else { - this.selection.removeAttr("tabIndex"); - } - }), 10); + + installKeyUpChangeEvent(this.focusser); + this.focusser.bind("keyup-change input", this.bind(function(e) { + if (this.opened()) return; + this.open(); + if (this.showSearchInput !== false) { + this.search.val(this.focusser.val()); + } + this.focusser.val(""); + killEvent(e); })); selection.delegate("abbr", "mousedown", this.bind(function (e) { @@ -1584,7 +1707,6 @@ the specific language governing permissions and limitations under the Apache Lic this.clear(); killEventImmediately(e); this.close(); - this.triggerChange(); this.selection.focus(); })); @@ -1593,69 +1715,47 @@ the specific language governing permissions and limitations under the Apache Lic if (this.opened()) { this.close(); - this.selection.focus(); } else if (this.enabled) { this.open(); } + killEvent(e); + clickingInside = false; })); dropdown.bind("mousedown", this.bind(function() { this.search.focus(); })); - selection.bind("focus", this.bind(function() { - this.container.addClass("select2-container-active"); - // hide the search so the tab key does not focus on it - this.search.attr("tabIndex", "-1"); + selection.bind("focus", this.bind(function(e) { + killEvent(e); })); - selection.bind("blur", this.bind(function() { + this.focusser.bind("focus", this.bind(function(){ + this.container.addClass("select2-container-active"); + })).bind("blur", this.bind(function() { if (!this.opened()) { this.container.removeClass("select2-container-active"); } - window.setTimeout(this.bind(function() { this.search.attr("tabIndex", this.elementTabIndex || 0); }), 10); - })); - - selection.bind("keydown", this.bind(function(e) { - if (!this.enabled) return; - - if (e.which == KEY.DOWN || e.which == KEY.UP - || (e.which == KEY.ENTER && this.opts.openOnEnter)) { - this.open(); - killEvent(e); - return; - } - - if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { - if (this.opts.allowClear) { - this.clear(); - } - killEvent(e); - return; - } - })); - selection.bind("keypress", this.bind(function(e) { - if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE || e.which == KEY.TAB || e.which == KEY.ENTER || e.which == 0) { - return - } - var key = String.fromCharCode(e.which); - this.search.val(key); - this.open(); })); + this.search.bind("focus", this.bind(function(){ + this.container.addClass("select2-container-active"); + })) + this.initContainerWidth(); this.setPlaceholder(); - this.search.bind("focus", this.bind(function() { - this.container.addClass("select2-container-active"); - })); }, // single clear: function() { + var data=this.selection.data("select2-data"); this.opts.element.val(""); this.selection.find("span").empty(); this.selection.removeData("select2-data"); this.setPlaceholder(); + + this.opts.element.trigger({ type: "removed", val: this.id(data), choice: data }); + this.triggerChange({removed:data}); }, /** @@ -1711,6 +1811,18 @@ the specific language governing permissions and limitations under the Apache Lic }, // single + getPlaceholder: function() { + // if a placeholder is specified on a single select without the first empty option ignore it + if (this.select) { + if (this.select.find("option").first().text() !== "") { + return undefined; + } + } + + return this.parent.getPlaceholder.apply(this, arguments); + }, + + // single setPlaceholder: function () { var placeholder = this.getPlaceholder(); @@ -1747,21 +1859,31 @@ the specific language governing permissions and limitations under the Apache Lic // hide the search box if this is the first we got the results and there are a few of them if (initial === true) { - showSearchInput = this.showSearchInput = countResults(data.results) >= this.opts.minimumResultsForSearch; - this.dropdown.find(".select2-search")[showSearchInput ? "removeClass" : "addClass"]("select2-search-hidden"); - - //add "select2-with-searchbox" to the container if search box is shown - $(this.dropdown, this.container)[showSearchInput ? "addClass" : "removeClass"]("select2-with-searchbox"); + var min=this.opts.minimumResultsForSearch; + showSearchInput = min < 0 ? false : countResults(data.results) >= min; + this.showSearch(showSearchInput); } }, // single + showSearch: function(showSearchInput) { + this.showSearchInput = showSearchInput; + + this.dropdown.find(".select2-search")[showSearchInput ? "removeClass" : "addClass"]("select2-search-hidden"); + //add "select2-with-searchbox" to the container if search box is shown + $(this.dropdown, this.container)[showSearchInput ? "addClass" : "removeClass"]("select2-with-searchbox"); + }, + + // single onSelect: function (data, options) { var old = this.opts.element.val(); this.opts.element.val(this.id(data)); this.updateSelection(data); + + this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); + this.close(); if (!options || !options.noFocus) @@ -1833,7 +1955,9 @@ the specific language governing permissions and limitations under the Apache Lic self.opts.element.val(!data ? "" : self.id(data)); self.updateSelection(data); self.setPlaceholder(); - self.triggerChange(); + if (triggerChange) { + self.triggerChange(); + } }); } }, @@ -1841,6 +1965,7 @@ the specific language governing permissions and limitations under the Apache Lic // single clearSearch: function () { this.search.val(""); + this.focusser.val(""); }, // single @@ -1890,15 +2015,14 @@ the specific language governing permissions and limitations under the Apache Lic if (opts.element.get(0).tagName.toLowerCase() === "select") { // install sthe selection initializer - opts.initSelection = function (element,callback) { + opts.initSelection = function (element, callback) { var data = []; + element.find(":selected").each2(function (i, elm) { - data.push({id: elm.attr("value"), text: elm.text(), element: elm}); + data.push({id: elm.attr("value"), text: elm.text(), element: elm[0]}); }); - - if ($.isFunction(callback)) - callback(data); + callback(data); }; } else if ("data" in opts) { // install default initSelection when applied to hidden input and data is local @@ -1929,6 +2053,13 @@ the specific language governing permissions and limitations under the Apache Lic this.searchContainer = this.container.find(".select2-search-field"); this.selection = selection = this.container.find(selector); + this.search.bind("input paste", this.bind(function() { + if (!this.enabled) return; + if (!this.opened()) { + this.open(); + } + })); + this.search.bind("keydown", this.bind(function (e) { if (!this.enabled) return; @@ -1976,8 +2107,12 @@ the specific language governing permissions and limitations under the Apache Lic return; } - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - return; + if (e.which === KEY.ENTER) { + if (this.opts.openOnEnter === false) { + return; + } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { + return; + } } this.open(); @@ -1993,7 +2128,7 @@ the specific language governing permissions and limitations under the Apache Lic this.search.bind("blur", this.bind(function(e) { this.container.removeClass("select2-container-active"); this.search.removeClass("select2-focused"); - this.clearSearch(); + if (!this.opened()) this.clearSearch(); e.stopImmediatePropagation(); })); @@ -2016,6 +2151,8 @@ the specific language governing permissions and limitations under the Apache Lic this.clearPlaceholder(); })); + this.initContainerWidth(); + // set the placeholder if necessary this.clearSearch(); }, @@ -2069,9 +2206,7 @@ the specific language governing permissions and limitations under the Apache Lic // stretch the search box to full width of the container so as much of the placeholder is visible as possible this.resizeSearch(); } else { - // we set this to " " instead of "" and later clear it on focus() because there is a firefox bug - // that does not properly render the caret when the field starts out blank - this.search.val(" ").width(10); + this.search.val("").width(10); } }, @@ -2079,9 +2214,6 @@ the specific language governing permissions and limitations under the Apache Lic clearPlaceholder: function () { if (this.search.hasClass("select2-default")) { this.search.val("").removeClass("select2-default"); - } else { - // work around for the space character we set to avoid firefox caret bug - if (this.search.val() === " ") this.search.val(""); } }, @@ -2092,6 +2224,8 @@ the specific language governing permissions and limitations under the Apache Lic this.clearPlaceholder(); this.resizeSearch(); this.focusSearch(); + + this.opts.element.trigger($.Event("open")); }, // multi @@ -2104,6 +2238,7 @@ the specific language governing permissions and limitations under the Apache Lic focus: function () { this.close(); this.search.focus(); + this.opts.element.triggerHandler("focus"); }, // multi @@ -2146,6 +2281,9 @@ the specific language governing permissions and limitations under the Apache Lic // multi onSelect: function (data, options) { this.addSelectedChoice(data); + + this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); + if (this.select || !this.opts.closeOnSelect) this.postprocessResults(); if (this.opts.closeOnSelect) { @@ -2155,10 +2293,16 @@ the specific language governing permissions and limitations under the Apache Lic if (this.countSelectableResults()>0) { this.search.width(10); this.resizeSearch(); + if (this.val().length >= this.getMaximumSelectionSize()) { + // if we reached max selection size repaint the results so choices + // are replaced with the max selection reached message + this.updateResults(true); + } this.positionDropdown(); } else { // if nothing left to select close this.close(); + this.search.width(10); } } @@ -2252,6 +2396,8 @@ the specific language governing permissions and limitations under the Apache Lic if (this.select) this.postprocessResults(); } selected.remove(); + + this.opts.element.trigger({ type: "removed", val: this.id(data), choice: data }); this.triggerChange({ removed: data }); }, @@ -2287,7 +2433,6 @@ the specific language governing permissions and limitations under the Apache Lic // multi resizeSearch: function () { - var minimumWidth, left, maxWidth, containerLeft, searchWidth, sideBorderPadding = getSideBorderPadding(this.search); @@ -2299,6 +2444,7 @@ the specific language governing permissions and limitations under the Apache Lic containerLeft = this.selection.offset().left; searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; + if (searchWidth < minimumWidth) { searchWidth = maxWidth - sideBorderPadding; } @@ -2308,7 +2454,7 @@ the specific language governing permissions and limitations under the Apache Lic } if (searchWidth <= 0) { - searchWidth = minimumWidth + searchWidth = minimumWidth; } this.search.width(searchWidth); @@ -2370,16 +2516,13 @@ the specific language governing permissions and limitations under the Apache Lic this.setVal(val); if (this.select) { - this.select.find(":selected").each(function () { - data.push({id: $(this).attr("value"), text: $(this).text()}); - }); - this.updateSelection(data); + this.opts.initSelection(this.select, this.bind(this.updateSelection)); if (triggerChange) { this.triggerChange(); } } else { if (this.opts.initSelection === undefined) { - throw new Error("val() cannot be called if initSelection() is not defined") + throw new Error("val() cannot be called if initSelection() is not defined"); } this.opts.initSelection(this.opts.element, function(data){ @@ -2438,7 +2581,7 @@ the specific language governing permissions and limitations under the Apache Lic .get(); } else { if (!values) { values = []; } - ids = $.map(values, function(e) { return self.opts.id(e)}); + ids = $.map(values, function(e) { return self.opts.id(e); }); this.setVal(ids); this.updateSelection(values); this.clearSearch(); @@ -2499,9 +2642,9 @@ the specific language governing permissions and limitations under the Apache Lic dropdownCss: {}, containerCssClass: "", dropdownCssClass: "", - formatResult: function(result, container, query) { + formatResult: function(result, container, query, escapeMarkup) { var markup=[]; - markMatch(result.text, query.term, markup, this.escapeMarkup); + markMatch(result.text, query.term, markup, escapeMarkup); return markup.join(""); }, formatSelection: function (data, container) { @@ -2544,7 +2687,9 @@ the specific language governing permissions and limitations under the Apache Lic }); }, blurOnChange: false, - selectOnBlur: false + selectOnBlur: false, + adaptContainerCssClass: function(c) { return c; }, + adaptDropdownCssClass: function(c) { return null; } }; // exports diff --git a/module/web/static/js/views/filterView.js b/module/web/static/js/views/filterView.js index 792edfee2..ea0aff0d5 100644 --- a/module/web/static/js/views/filterView.js +++ b/module/web/static/js/views/filterView.js @@ -1,6 +1,16 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], function($, Backbone, _, App, Api) { + // Modified version of type ahead show, nearly the same without absolute positioning + function show() { + this.$menu + .insertAfter(this.$element) + .show(); + + this.shown = true; + return this; + } + // Renders the actionbar for the dashboard, handles everything related to filtering displayed files return Backbone.View.extend({ el: 'ul.actionbar', @@ -14,6 +24,9 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], stateMenu: null, initialize: function() { + + // use our modified method + $.fn.typeahead.Constructor.prototype.show = show; this.$('.search-query').typeahead({ minLength: 2, source: this.getAutocompletion @@ -24,7 +37,6 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], // Apply the filter before the content is shown App.vent.on('dashboard:contentReady', _.bind(this.apply_filter, this)); - }, render: function() { @@ -33,7 +45,8 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], getAutocompletion: function() { return ["static", "autocompletion", "demo", "with", "some", "keywords", - "a very long proposal for autocompletion"]; + "a very long proposal for autocompletion", "autobot", + "a very long proposal for autocompletion second one"]; }, switch_filter: function(e) { |