├── .gitignore ├── .travis.yml ├── demos ├── img │ ├── icons-18-black.png │ ├── icons-18-white.png │ ├── icons-36-black.png │ ├── icons-36-white.png │ ├── glyphicons-halflings.png │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_2e83ff_256x240.png │ ├── ui-icons_454545_256x240.png │ ├── ui-icons_888888_256x240.png │ ├── ui-icons_cd0a0a_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ ├── ui-icons_ffffff_256x240.png │ ├── glyphicons-halflings-white.png │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_flat_75_ffffff_40x100.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_glass_75_dadada_1x400.png │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ ├── ui-bg_glass_95_fef1ec_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ └── ui-bg_highlight-soft_100_eeeeee_1x100.png ├── default.html ├── css │ └── bootstrap.css └── bootstrap-buttons.html ├── libs └── jasmine │ ├── jasmine_favicon.png │ ├── MIT.LICENSE │ ├── jasmine.css │ ├── jasmine-jquery-1.3.1.js │ └── jasmine-html.js ├── src ├── javascripts │ ├── jquery.selectBoxIt.selectOption.min.js │ ├── jquery.selectBoxIt.wait.min.js │ ├── jquery.selectBoxIt.setOption.min.js │ ├── jquery.selectBoxIt.setOptions.min.js │ ├── jquery.selectBoxIt.enable.min.js │ ├── jquery.selectBoxIt.dynamicPositioning.min.js │ ├── jquery.selectBoxIt.ariaAccessibility.min.js │ ├── jquery.selectBoxIt.disable.min.js │ ├── jquery.selectBoxIt.keyboardNavigation.min.js │ ├── jquery.selectBoxIt.keyboardSearch.min.js │ ├── jquery.selectBoxIt.selectOption.js │ ├── jquery.selectBoxIt.wait.js │ ├── jquery.selectBoxIt.setOptions.js │ ├── jquery.selectBoxIt.setOption.js │ ├── jquery.selectBoxIt.enable.js │ ├── jquery.selectBoxIt.dynamicPositioning.js │ ├── jquery.selectBoxIt.disable.js │ ├── jquery.selectBoxIt.keyboardNavigation.js │ ├── jquery.selectBoxIt.ariaAccessibility.js │ ├── jquery.selectBoxIt.keyboardSearch.js │ ├── jquery.selectBoxIt.core.min.js │ └── jquery.selectBoxIt.min.js └── stylesheets │ └── SelectBoxIt │ ├── jquery.selectBoxIt-bootstrapbutton.css │ └── jquery.selectBoxIt.css ├── LICENSE-MIT ├── package.json ├── selectBoxIt.jquery.json ├── test ├── SpecRunner.html └── spec │ └── selectBoxItSpec.js ├── grunt.js └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - 0.9 -------------------------------------------------------------------------------- /demos/img/icons-18-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/icons-18-black.png -------------------------------------------------------------------------------- /demos/img/icons-18-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/icons-18-white.png -------------------------------------------------------------------------------- /demos/img/icons-36-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/icons-36-black.png -------------------------------------------------------------------------------- /demos/img/icons-36-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/icons-36-white.png -------------------------------------------------------------------------------- /libs/jasmine/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/libs/jasmine/jasmine_favicon.png -------------------------------------------------------------------------------- /demos/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /demos/img/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /demos/img/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /demos/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /demos/img/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /demos/img/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /demos/img/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /demos/img/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /demos/img/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/who/jquery.selectBoxIt.js/master/demos/img/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.selectOption.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.selectOption=function(e,t){var n=this;return typeof e=="number"?n.selectBox.val(n.selectBox.find("option").eq(e).val()).change():typeof e=="string"&&n.selectBox.val(e).change(),n._callbackSupport(t),n}}); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.wait.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.wait=function(e,t){var n=this,r=this.returnTimeout(e);return r.then(function(){n._callbackSupport(t)}),n},e.selectBox.selectBoxIt.prototype.returnTimeout=function(t){return e.Deferred(function(e){setTimeout(e.resolve,t)})}}); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.setOption.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.setOption=function(t,n,r){var i=this;return t==="showFirstOption"&&!n?i.listItems.eq(0).hide():t==="showFirstOption"&&n?i.listItems.eq(0).show():t==="defaultIcon"&&n?i.dropdownImage.attr("class",n+" selectboxit-arrow"):t==="downArrowIcon"&&n?i.downArrow.attr("class",n+" selectboxit-arrow"):t==="defaultText"&&i.dropdownText.text(n),e.Widget.prototype._setOption.apply(i,arguments),i._callbackSupport(r),i}}); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.setOptions.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.setOptions=function(t,n){var r=this;return e.Widget.prototype._setOptions.apply(r,arguments),r.options.showFirstOption?r.listItems.eq(0).show():r.listItems.eq(0).hide(),r.options.defaultIcon&&r.dropdownImage.attr("class",r.options.defaultIcon+" selectboxit-arrow"),r.options.downArrowIcon&&r.downArrow.attr("class",r.options.downArrowIcon+" selectboxit-arrow"),r.options.defaultText&&r.dropdownText.text(r.options.defaultText),r._callbackSupport(n),r}}); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.enable.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.enable=function(t){var n=this;return n.options.disabled&&(n.triggerEvent("enable"),n.selectBox.removeAttr("disabled"),n.dropdown.attr("tabindex",0).removeClass(n.disabledClasses),e.Widget.prototype.enable.call(n),n._callbackSupport(t)),n},e.selectBox.selectBoxIt.prototype.enableOption=function(e,t){var n=this,r,i=0,s,o;return typeof e=="number"&&(r=n.selectBox.find("option").eq(e),n.triggerEvent("enable-option"),r.removeAttr("disabled"),n.listItems.eq(e).attr("data-disabled","false").removeClass(n.disabledClasses)),n._callbackSupport(t),n}}); -------------------------------------------------------------------------------- /src/stylesheets/SelectBoxIt/jquery.selectBoxIt-bootstrapbutton.css: -------------------------------------------------------------------------------- 1 | .selectboxit-container, 2 | .selectboxit, 3 | .selectboxit-default-icon, 4 | .selectboxit-text, 5 | .selectboxit-arrow { 6 | display: inline-block; 7 | -webkit-touch-callout: none; 8 | -webkit-user-select: none; 9 | -khtml-user-select: none; 10 | -moz-user-select: -moz-none; 11 | ms-user-select: none; 12 | -o-user-select: none; 13 | user-select: none; 14 | } 15 | 16 | .selectboxit { 17 | cursor:pointer; 18 | } 19 | 20 | .selectboxit.selectboxit-disabled { 21 | cursor: default; 22 | } 23 | 24 | .selectboxit-optgroup-header[data-disabled='true']:hover { 25 | cursor: default; 26 | } 27 | 28 | /* play nice with bootstrap */ 29 | .dropdown-menu.selectboxit-options { 30 | top: auto; 31 | left: auto; 32 | } 33 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.dynamicPositioning.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype._dynamicPositioning=function(){var n=this,r=n.dropdown.offset().top,i=n.list.data("max-height")||n.list.outerHeight(),s=n.dropdown.outerHeight(),o=e(t).height(),u=e(t).scrollTop(),a=r+s+i<=o+u,f=!a;n.list.data("max-height")||n.list.data("max-height",n.list.outerHeight()),n.selectBox.css("display","none");if(!f)n.list.css("max-height",n.list.data("max-height")),n.list.css("top","auto");else if(n.dropdown.offset().top-u>=i)n.list.css("max-height",n.list.data("max-height")),n.list.css("top",n.dropdown.position().top-n.list.outerHeight());else{var l=Math.abs(r+s+i-(o+u)),c=Math.abs(n.dropdown.offset().top-u-i);l=1.6.1" 20 | }, 21 | "licenses": [ 22 | { 23 | "type": "MIT", 24 | "url": "https://github.com/gfranko/jquery.selectBoxIt.js/blob/master/LICENSE-MIT" 25 | } 26 | ], 27 | "bugs": "https://github.com/gfranko/jquery.selectBoxIt.js/issues", 28 | "docs": "http://gregfranko.com/jquery.selectBoxIt.js", 29 | "download": "http://gregfranko.com/jquery.selectBoxIt.js/js/jquery.selectBoxIt.min.js" 30 | } -------------------------------------------------------------------------------- /test/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | jQuery.selectBoxIt.js Jasmine Unit Tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.selectOption.js: -------------------------------------------------------------------------------- 1 | // Select Option Module 2 | // ==================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | // Select Option 24 | // ------------- 25 | // Programatically selects a drop down option by either index or value 26 | 27 | $.selectBox.selectBoxIt.prototype.selectOption = function(val, callback) { 28 | 29 | // Stores the plugin context inside of the self variable 30 | var self = this; 31 | 32 | // Makes sure the passed in position is a number 33 | if(typeof val === "number") { 34 | 35 | // Set's the original select box value and triggers the change event (which SelectBoxIt listens for) 36 | self.selectBox.val(self.selectBox.find("option").eq(val).val()).change(); 37 | 38 | } 39 | 40 | else if(typeof val === "string") { 41 | 42 | // Set's the original select box value and triggers the change event (which SelectBoxIt listens for) 43 | self.selectBox.val(val).change(); 44 | 45 | } 46 | 47 | // Calls the callback function 48 | self._callbackSupport(callback); 49 | 50 | // Maintains chainability 51 | return self; 52 | 53 | }; 54 | 55 | })); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.wait.js: -------------------------------------------------------------------------------- 1 | // Wait Module 2 | // =========== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | // Wait 24 | // ---- 25 | // Delays execution by the amount of time 26 | // specified by the parameter 27 | 28 | $.selectBox.selectBoxIt.prototype.wait = function(time, callback) { 29 | 30 | var self = this, 31 | 32 | // The timeout variable stores a Deferred Object, which will be resolved after the time specified in the parameter 33 | timeout = this.returnTimeout(time); 34 | 35 | // Once the Deferred object is resolved, call the callback function 36 | timeout.then(function() { 37 | 38 | // Provide callback function support 39 | self._callbackSupport(callback); 40 | 41 | }); 42 | 43 | // Maintains chainability 44 | return self; 45 | 46 | }; 47 | 48 | //Return timeout 49 | // ------------- 50 | // Returns a Deferred Object after the time 51 | // specified by the parameter 52 | 53 | $.selectBox.selectBoxIt.prototype.returnTimeout = function(time) { 54 | 55 | //Returns a Deferred Object 56 | return $.Deferred(function(dfd) { 57 | 58 | //Call the JavaScript `setTimeout function and resolve the Deferred Object 59 | setTimeout(dfd.resolve, time); 60 | 61 | }); 62 | 63 | }; 64 | 65 | })); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.setOptions.js: -------------------------------------------------------------------------------- 1 | // Set Options Module 2 | // ================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //Set Options 24 | // ---------- 25 | // Accepts an object to replace plugin options 26 | // properties of the plugin options object 27 | 28 | $.selectBox.selectBoxIt.prototype.setOptions = function(newOptions, callback) { 29 | 30 | var self = this; 31 | 32 | $.Widget.prototype._setOptions.apply(self, arguments); 33 | 34 | // If the `showFirstOption` option is true 35 | if (self.options["showFirstOption"]) { 36 | 37 | // Shows the first option in the dropdown list 38 | self.listItems.eq(0).show(); 39 | 40 | } 41 | 42 | // If the `showFirstOption` option is false 43 | else { 44 | 45 | // Hides the first option in the dropdown list 46 | self.listItems.eq(0).hide(); 47 | 48 | } 49 | 50 | if(self.options["defaultIcon"]) { 51 | 52 | self.dropdownImage.attr("class", self.options["defaultIcon"] + " selectboxit-arrow"); 53 | 54 | } 55 | 56 | if(self.options["downArrowIcon"]) { 57 | 58 | self.downArrow.attr("class", self.options["downArrowIcon"] + " selectboxit-arrow"); 59 | 60 | } 61 | 62 | // If the defaultText option is set, make sure the dropdown list default text reflects this value 63 | if (self.options["defaultText"]) { 64 | 65 | self.dropdownText.text(self.options["defaultText"]); 66 | 67 | } 68 | 69 | // Provide callback function support 70 | self._callbackSupport(callback); 71 | 72 | // Maintains chainability 73 | return self; 74 | 75 | }; 76 | 77 | })); -------------------------------------------------------------------------------- /demos/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 | 32 | 33 | 48 | 49 | 64 | 65 |
66 | 67 | 68 | 69 | 70 | 81 | 82 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.setOption.js: -------------------------------------------------------------------------------- 1 | // Set Option Module 2 | // ================= 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //Set Option 24 | // ---------- 25 | // Accepts an string key, a value, and a callback function to replace a single 26 | // property of the plugin options object 27 | 28 | $.selectBox.selectBoxIt.prototype.setOption = function(key, value, callback) { 29 | 30 | var self = this; 31 | 32 | // If a user sets the `showFirstOption` to false 33 | if (key === "showFirstOption" && !value) { 34 | 35 | //Hides the first option in the dropdown list 36 | self.listItems.eq(0).hide(); 37 | 38 | } 39 | 40 | // If a user sets the `showFirstOption` to true 41 | else if (key === "showFirstOption" && value) { 42 | 43 | //Shows the first option in the dropdown list 44 | self.listItems.eq(0).show(); 45 | 46 | } 47 | 48 | else if(key === "defaultIcon" && value) { 49 | 50 | self.dropdownImage.attr("class", value + " selectboxit-arrow"); 51 | 52 | } 53 | 54 | else if(key === "downArrowIcon" && value) { 55 | 56 | self.downArrow.attr("class", value + " selectboxit-arrow"); 57 | 58 | } 59 | 60 | // If a user sets the defaultText option 61 | else if (key === "defaultText") { 62 | 63 | // Sets the new dropdown list default text 64 | self.dropdownText.text(value); 65 | 66 | } 67 | 68 | $.Widget.prototype._setOption.apply(self, arguments); 69 | 70 | // Provides callback function support 71 | self._callbackSupport(callback); 72 | 73 | // Maintains chainability 74 | return self; 75 | 76 | }; 77 | 78 | })); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.enable.js: -------------------------------------------------------------------------------- 1 | // Enable Module 2 | // ============= 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //Enable 24 | // ----- 25 | // Enables the new dropdown list 26 | 27 | $.selectBox.selectBoxIt.prototype.enable = function(callback) { 28 | 29 | var self = this; 30 | 31 | if(self.options["disabled"]) { 32 | 33 | // Triggers a `enable` custom event on the original select box 34 | self.triggerEvent("enable"); 35 | 36 | // Removes the `disabled` attribute from the original dropdown list 37 | self.selectBox.removeAttr("disabled"); 38 | 39 | // Make the dropdown list focusable 40 | self.dropdown.attr("tabindex", 0) 41 | 42 | // Disable styling for disabled state 43 | .removeClass(self.disabledClasses); 44 | 45 | $.Widget.prototype.enable.call(self); 46 | 47 | // Provide callback function support 48 | self._callbackSupport(callback); 49 | 50 | } 51 | 52 | //Maintains chainability 53 | return self; 54 | 55 | }; 56 | 57 | // Enable Option 58 | // ------------- 59 | // Disables a single drop down option 60 | 61 | $.selectBox.selectBoxIt.prototype.enableOption = function(index, callback) { 62 | 63 | var self = this, currentSelectBoxOption, currentIndex = 0, hasNextEnabled, hasPreviousEnabled; 64 | 65 | // If an index is passed to target an indropdownidual drop down option 66 | if(typeof index === "number") { 67 | 68 | // The select box option being targeted 69 | currentSelectBoxOption = self.selectBox.find("option").eq(index); 70 | 71 | // Triggers a `enable-option` custom event on the original select box and passes the enabled option 72 | self.triggerEvent("enable-option"); 73 | 74 | // Disables the targeted select box option 75 | currentSelectBoxOption.removeAttr("disabled"); 76 | 77 | // Disables the drop down option 78 | self.listItems.eq(index).attr("data-disabled", "false"). 79 | 80 | // Applies disabled styling for the drop down option 81 | removeClass(self.disabledClasses); 82 | 83 | } 84 | 85 | // Provides callback function support 86 | self._callbackSupport(callback); 87 | 88 | // Maintains chainability 89 | return self; 90 | 91 | }; 92 | 93 | })); -------------------------------------------------------------------------------- /grunt.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 4 | var min = {}; 5 | [ 6 | 'ariaAccessibility', 7 | 'core', 8 | 'disable', 9 | 'dynamicPositioning', 10 | 'enable', 11 | 'keyboardNavigation', 12 | 'keyboardSearch', 13 | 'selectOption', 14 | 'setOption', 15 | 'setOptions', 16 | 'wait' 17 | ].forEach(function(name) { 18 | min[name] = { 19 | src: 'src/javascripts/jquery.selectBoxIt.' + name + '.js', 20 | dest: 'src/javascripts/jquery.selectBoxIt.' + name + '.min.js' 21 | }; 22 | }); 23 | 24 | // Project configuration. 25 | grunt.initConfig({ 26 | pkg: '', 27 | meta: { 28 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + 29 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 30 | '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' + 31 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 32 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */' 33 | }, 34 | concat: { 35 | minified: { 36 | src: ['src/javascripts/jquery.selectBoxIt.core.min.js', 'src/javascripts/jquery.selectBoxIt.ariaAccessibility.min.js', 'src/javascripts/jquery.selectBoxIt.disable.min.js', 'src/javascripts/jquery.selectBoxIt.dynamicPositioning.min.js', 'src/javascripts/jquery.selectBoxIt.enable.min.js', 'src/javascripts/jquery.selectBoxIt.keyboardNavigation.min.js', 'src/javascripts/jquery.selectBoxIt.keyboardSearch.min.js', 'src/javascripts/jquery.selectBoxIt.selectOption.min.js', 'src/javascripts/jquery.selectBoxIt.setOption.min.js', 'src/javascripts/jquery.selectBoxIt.setOptions.min.js', 'src/javascripts/jquery.selectBoxIt.wait.min.js'], 37 | dest: 'src/javascripts/jquery.selectBoxIt.min.js' 38 | }, 39 | unminified: { 40 | src: ['src/javascripts/jquery.selectBoxIt.core.js', 'src/javascripts/jquery.selectBoxIt.ariaAccessibility.js', 'src/javascripts/jquery.selectBoxIt.disable.js', 'src/javascripts/jquery.selectBoxIt.dynamicPositioning.js', 'src/javascripts/jquery.selectBoxIt.enable.js', 'src/javascripts/jquery.selectBoxIt.keyboardNavigation.js', 'src/javascripts/jquery.selectBoxIt.keyboardSearch.js', 'src/javascripts/jquery.selectBoxIt.selectOption.js', 'src/javascripts/jquery.selectBoxIt.setOption.js', 'src/javascripts/jquery.selectBoxIt.setOptions.js', 'src/javascripts/jquery.selectBoxIt.wait.js'], 41 | dest: 'src/javascripts/jquery.selectBoxIt.js' 42 | } 43 | }, 44 | 45 | min: min, 46 | 47 | jasmine: { 48 | all: { 49 | src:['test/SpecRunner.html'], 50 | timeout: 150000 //in milliseconds 51 | } 52 | }, 53 | lint: { 54 | files: ['grunt.js','src/javascripts/jquery.selectBoxIt.ariaAccessibility.js', 'src/javascripts/jquery.selectBoxIt.core.js', 'src/javascripts/jquery.selectBoxIt.disable.js', 'src/javascripts/jquery.selectBoxIt.dynamicPositioning.js', 'src/javascripts/jquery.selectBoxIt.enable.js', 'src/javascripts/jquery.selectBoxIt.keyboardNavigation.js', 'src/javascripts/jquery.selectBoxIt.keyboardSearch.js', 'src/javascripts/jquery.selectBoxIt.selectOption.js', 'src/javascripts/jquery.selectBoxIt.setOption.js', 'src/javascripts/jquery.selectBoxIt.setOptions.js', 'src/javascripts/jquery.selectBoxIt.wait.js'] 55 | }, 56 | watch: { 57 | files: '', 58 | tasks: 'lint jasmine' 59 | }, 60 | jshint: { 61 | options: { 62 | curly: true, 63 | eqeqeq: true, 64 | immed: true, 65 | latedef: true, 66 | newcap: true, 67 | noarg: true, 68 | sub: true, 69 | undef: true, 70 | boss: true, 71 | eqnull: true, 72 | browser: true, 73 | jquery: true 74 | }, 75 | globals: { 76 | jQuery: true 77 | } 78 | }, 79 | uglify: {} 80 | }); 81 | 82 | grunt.loadNpmTasks('grunt-jasmine-task'); 83 | 84 | // Default task. 85 | grunt.registerTask('default', 'lint jasmine min concat'); 86 | 87 | // Travis CI task. 88 | grunt.registerTask('travis', 'lint jasmine'); 89 | 90 | }; -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.dynamicPositioning.js: -------------------------------------------------------------------------------- 1 | // Dynamic Positioning Module 2 | // ========================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //_Dynamic positioning 24 | // ------------------ 25 | // Dynamically positions the dropdown list options list 26 | 27 | $.selectBox.selectBoxIt.prototype._dynamicPositioning = function() { 28 | 29 | var self = this, 30 | 31 | // Returns the x and y coordinates of the dropdown list options list relative to the document 32 | listOffsetTop = self.dropdown.offset().top, 33 | 34 | // The height of the dropdown list options list 35 | listHeight = self.list.data("max-height") || self.list.outerHeight(), 36 | 37 | // The height of the dropdown list DOM element 38 | selectBoxHeight = self.dropdown.outerHeight(), 39 | 40 | viewportNode = self.options["viewport"]; 41 | 42 | viewport = $.isEmptyObject(viewportNode) ? $(window) : $(viewportNode); 43 | 44 | viewPortHeight = viewport.height(), 45 | 46 | viewportScrollTop = $.isWindow(viewport.get(0)) ? viewport.scrollTop() : viewport.offset().top, 47 | 48 | topToBottom = (listOffsetTop + selectBoxHeight + listHeight <= viewPortHeight + viewportScrollTop), 49 | 50 | bottomReached = !topToBottom; 51 | 52 | if(!self.list.data("max-height")) { 53 | 54 | self.list.data("max-height", self.list.outerHeight()); 55 | 56 | } 57 | 58 | // Makes sure the original select box is hidden 59 | self.selectBox.css("display", "none"); 60 | 61 | // If there is room on the bottom of the viewport to display the drop down options 62 | if (!bottomReached) { 63 | 64 | self.list.css("max-height", self.list.data("max-height")); 65 | 66 | // Sets custom CSS properties to place the dropdown list options directly below the dropdown list 67 | self.list.css("top", "auto"); 68 | 69 | } 70 | 71 | // If there is room on the top of the viewport 72 | else if((self.dropdown.offset().top - viewportScrollTop) >= listHeight) { 73 | 74 | self.list.css("max-height", self.list.data("max-height")); 75 | 76 | // Sets custom CSS properties to place the dropdown list options directly above the dropdown list 77 | self.list.css("top", (self.dropdown.position().top - self.list.outerHeight())); 78 | 79 | } 80 | 81 | // If there is not enough room on the top or the bottom 82 | else { 83 | 84 | var outsideBottomViewport = Math.abs((listOffsetTop + selectBoxHeight + listHeight) - (viewPortHeight + viewportScrollTop)), 85 | 86 | outsideTopViewport = Math.abs((self.dropdown.offset().top - viewportScrollTop) - listHeight); 87 | 88 | // If there is more room on the bottom 89 | if(outsideBottomViewport < outsideTopViewport) { 90 | 91 | self.list.css("max-height", self.list.data("max-height") - outsideBottomViewport - (selectBoxHeight/2)); 92 | 93 | self.list.css("top", "auto"); 94 | 95 | } 96 | 97 | // If there is more room on the top 98 | else { 99 | 100 | self.list.css("max-height", self.list.data("max-height") - outsideTopViewport - (selectBoxHeight/2)); 101 | 102 | // Sets custom CSS properties to place the dropdown list options directly above the dropdown list 103 | self.list.css("top", (self.dropdown.position().top - self.list.outerHeight())); 104 | 105 | } 106 | 107 | } 108 | 109 | // Maintains chainability 110 | return self; 111 | 112 | }; 113 | 114 | })); -------------------------------------------------------------------------------- /src/stylesheets/SelectBoxIt/jquery.selectBoxIt.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jquery.selectBoxIt.css 2.9.9 3 | * Author: @gregfranko 4 | */ 5 | 6 | /* Div container holding the dropdown list */ 7 | .selectboxit-container { 8 | position: relative; 9 | display: inline-block; 10 | /* Prevents text selection */ 11 | -webkit-touch-callout: none; 12 | -webkit-user-select: none; 13 | -khtml-user-select: none; 14 | -moz-user-select: -moz-none; 15 | ms-user-select: none; 16 | -o-user-select: none; 17 | user-select: none; 18 | } 19 | 20 | /* Dropdown List Box */ 21 | .selectboxit-container .selectboxit { 22 | width: 220px; /* Width of the dropdown list box */ 23 | height: 30px; /* Height of the select box */ 24 | cursor: pointer; 25 | padding: 0; 26 | display: block; 27 | border-radius: 6px; 28 | margin: 0; 29 | } 30 | 31 | .selectboxit-container .selectboxit:focus { 32 | outline: 0; 33 | } 34 | 35 | .selectboxit-container .selectboxit.selectboxit-disabled { 36 | cursor: default; 37 | } 38 | 39 | /* Dropdown list Default Icon Positioning */ 40 | .selectboxit-default-icon { 41 | float: left; 42 | } 43 | 44 | /* Dropdown List Box Text */ 45 | .selectboxit-text { 46 | font: 14px Helvetica, Arial; 47 | text-indent: 5px; 48 | height: 30px; 49 | line-height: 30px; 50 | overflow: hidden; 51 | float: left; 52 | white-space: nowrap; 53 | } 54 | 55 | /* Dropdown List Options List*/ 56 | .selectboxit-container .selectboxit-options { 57 | min-width: 220px; /* Minimum Width of the dropdown list box options */ 58 | /* IE7 hack */ 59 | *width: 220px; 60 | font: 14px Helvetica, Arial; 61 | margin: 0; 62 | padding: 0; 63 | list-style: none; 64 | position: absolute; 65 | overflow: auto; 66 | cursor: pointer; 67 | display: none; 68 | z-index: 9999999999999; 69 | outline: none; 70 | top: auto; 71 | bottom: auto; 72 | left: auto; 73 | right: auto; 74 | -moz-box-shadow: none; /* Firefox */ 75 | -webkit-box-shadow: none; /* Safari, Chrome */ 76 | box-shadow: none; /* CSS3 */ 77 | border-radius: 6px; 78 | text-align: left; 79 | } 80 | 81 | /* Overrides Bootstrap drop down option style */ 82 | .selectboxit-options .selectboxit-option.active .selectboxit-option-anchor { 83 | color: #fff; 84 | } 85 | 86 | .selectboxit-option .selectboxit-option-anchor { 87 | padding: 0px 3px; 88 | line-height: 30px; 89 | height: 30px; 90 | } 91 | 92 | .selectboxit-option .selectboxit-option-anchor:hover { 93 | text-decoration: none; 94 | } 95 | 96 | /* Dropdown List Individual Options */ 97 | .selectboxit-option, .selectboxit-optgroup-header { 98 | line-height: 30px; /* Height of Individual Select Box Options */ 99 | height: 30px; 100 | text-indent: 5px; /* Horizontal Positioning of the select box option text */ 101 | overflow: hidden; 102 | white-space: nowrap; 103 | list-style: none; 104 | margin: 0; 105 | display: block; 106 | } 107 | 108 | /* The first drop down option */ 109 | .selectboxit-option-first { 110 | border-top-right-radius: 6px; 111 | border-top-left-radius: 6px; 112 | } 113 | 114 | /* The first drop down option */ 115 | .selectboxit-optgroup-header + .selectboxit-option-first { 116 | border-top-right-radius: 0px; 117 | border-top-left-radius: 0px; 118 | } 119 | 120 | /* The last drop down option */ 121 | .selectboxit-option-last { 122 | border-bottom-right-radius: 6px; 123 | border-bottom-left-radius: 6px; 124 | } 125 | 126 | /* Dropdown List Optgroup Headers */ 127 | .selectboxit-optgroup-header { 128 | font-weight: bold; 129 | padding: 5px; 130 | } 131 | 132 | /* Dropdown List Optgroup Options */ 133 | .selectboxit-optgroup-option { 134 | text-indent: 20px; 135 | } 136 | 137 | /* Dropdown List Optgroup Header hover psuedo class */ 138 | .selectboxit-optgroup-header:hover { 139 | cursor: default; 140 | } 141 | 142 | /* Dropdown List Down Arrow Container (if an image is not used) */ 143 | .selectboxit-arrow-container { 144 | /* Positions the down arrow */ 145 | width: 30px; 146 | float: right; 147 | position: relative; 148 | } 149 | 150 | /* Dropdown List Down Arrow */ 151 | .selectboxit .selectboxit-arrow-container .selectboxit-arrow { 152 | /* Horizontally centers the down arrow */ 153 | margin: 0 auto; 154 | display: block; 155 | position: absolute; 156 | top: 50%; 157 | right: 40%; 158 | } 159 | 160 | .jqueryui .selectboxit .selectboxit-arrow-container .selectboxit-arrow { 161 | right: 25%; 162 | } 163 | 164 | /* Dropdown List Down Arrow For jQueryUI and jQuery Mobile */ 165 | .selectboxit .selectboxit-arrow-container .selectboxit-arrow.ui-icon { 166 | top: 30%; 167 | } 168 | 169 | /* Dropdown List Individual Option Icon Positioning */ 170 | .selectboxit-option-icon { 171 | float: left; 172 | } 173 | 174 | /* Dropdown List Individual Option Image Positioning */ 175 | .selectboxit-option-icon-url { 176 | width: 18px; 177 | height: 18px; 178 | background-size: 18px 18px; 179 | background-repeat: no-repeat; 180 | } 181 | 182 | .selectboxit-default-icon.selectboxit-option-icon-url { 183 | margin-left: 5px; 184 | } 185 | 186 | /* jQueryUI and jQuery Mobile compatability fix - Feel free to remove this style if you are not using jQuery Mobile */ 187 | .jqueryui .ui-icon { 188 | background-color: inherit; 189 | } 190 | 191 | /* Another jQueryUI and jQuery Mobile compatability fix - Feel free to remove this style if you are not using jQuery Mobile */ 192 | .jqueryui .ui-icon-triangle-1-s { 193 | background-position: -64px -16px; 194 | } -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.disable.js: -------------------------------------------------------------------------------- 1 | // Disable Module 2 | // ============== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | // Disable 24 | // ------- 25 | // Disables the new dropdown list 26 | 27 | $.selectBox.selectBoxIt.prototype.disable = function(callback) { 28 | 29 | var self = this; 30 | 31 | if(!self.options["disabled"]) { 32 | 33 | // Makes sure the dropdown list is closed 34 | self.close(); 35 | 36 | // Triggers a `disable` custom event on the original select box 37 | self.triggerEvent("disable"); 38 | 39 | // Sets the `disabled` attribute on the original select box 40 | self.selectBox.attr("disabled", "disabled"); 41 | 42 | // Makes the dropdown list not focusable by removing the `tabindex` attribute 43 | self.dropdown.removeAttr("tabindex") 44 | 45 | // Enabled styling for disabled state 46 | .addClass("selectboxit-disabled"); 47 | 48 | // Calls the jQueryUI Widget Factory disable method to make sure all options are correctly synced 49 | $.Widget.prototype.disable.call(self); 50 | 51 | } 52 | 53 | // Provides callback function support 54 | self._callbackSupport(callback); 55 | 56 | // Maintains chainability 57 | return self; 58 | 59 | }; 60 | 61 | // Disable Option 62 | // -------------- 63 | // Disables a single drop down option 64 | 65 | $.selectBox.selectBoxIt.prototype.disableOption = function(index, callback) { 66 | 67 | var self = this, currentSelectBoxOption, hasNextEnabled, hasPreviousEnabled; 68 | 69 | // If an index is passed to target an indropdownidual drop down option 70 | if(typeof index === "number") { 71 | 72 | // Makes sure the dropdown list is closed 73 | self.close(); 74 | 75 | // The select box option being targeted 76 | currentSelectBoxOption = self.selectBox.find("option").eq(index); 77 | 78 | // Triggers a `disable-option` custom event on the original select box and passes the disabled option 79 | self.triggerEvent("disable-option"); 80 | 81 | // Disables the targeted select box option 82 | currentSelectBoxOption.attr("disabled", "disabled"); 83 | 84 | // Disables the drop down option 85 | self.listItems.eq(index).attr("data-disabled", "true"). 86 | 87 | // Applies disabled styling for the drop down option 88 | addClass(self.disabledClasses); 89 | 90 | // If the currently selected drop down option is the item being disabled 91 | if(self.currentFocus === index) { 92 | 93 | hasNextEnabled = self.listItems.eq(self.currentFocus).nextAll("li").not("[data-disabled='true']").first().length; 94 | 95 | hasPreviousEnabled = self.listItems.eq(self.currentFocus).prevAll("li").not("[data-disabled='true']").first().length; 96 | 97 | // If there is a currently enabled option beneath the currently selected option 98 | if(hasNextEnabled) { 99 | 100 | // Selects the option beneath the currently selected option 101 | self.moveDown(); 102 | 103 | } 104 | 105 | // If there is a currently enabled option above the currently selected option 106 | else if(hasPreviousEnabled) { 107 | 108 | // Selects the option above the currently selected option 109 | self.moveUp(); 110 | 111 | } 112 | 113 | // If there is not a currently enabled option 114 | else { 115 | 116 | // Disables the entire drop down list 117 | self.disable(); 118 | 119 | } 120 | 121 | } 122 | 123 | } 124 | 125 | // Provides callback function support 126 | self._callbackSupport(callback); 127 | 128 | // Maintains chainability 129 | return self; 130 | 131 | }; 132 | 133 | //_Is Disabled 134 | // ----------- 135 | // Checks the original select box for the 136 | // disabled attribute 137 | 138 | $.selectBox.selectBoxIt.prototype._isDisabled = function(callback) { 139 | 140 | var self = this; 141 | 142 | //If the original select box is disabled 143 | if (self.originalElem.disabled) { 144 | 145 | //Disables the dropdown list 146 | self.disable(); 147 | } 148 | 149 | //Maintains chainability 150 | return self; 151 | 152 | }; 153 | 154 | })); -------------------------------------------------------------------------------- /libs/jasmine/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | #HTMLReporter a { text-decoration: none; } 5 | #HTMLReporter a:hover { text-decoration: underline; } 6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } 7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } 8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; } 9 | #HTMLReporter .version { color: #aaaaaa; } 10 | #HTMLReporter .banner { margin-top: 14px; } 11 | #HTMLReporter .duration { color: #aaaaaa; float: right; } 12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } 13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } 14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; } 15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } 16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; } 17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; } 19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } 20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; } 21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } 22 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 23 | #HTMLReporter .runningAlert { background-color: #666666; } 24 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; } 25 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; } 26 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } 27 | #HTMLReporter .passingAlert { background-color: #a6b779; } 28 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } 29 | #HTMLReporter .failingAlert { background-color: #cf867e; } 30 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; } 31 | #HTMLReporter .results { margin-top: 14px; } 32 | #HTMLReporter #details { display: none; } 33 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } 34 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 35 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 36 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 37 | #HTMLReporter.showDetails .summary { display: none; } 38 | #HTMLReporter.showDetails #details { display: block; } 39 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 40 | #HTMLReporter .summary { margin-top: 14px; } 41 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } 42 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } 43 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; } 44 | #HTMLReporter .description + .suite { margin-top: 0; } 45 | #HTMLReporter .suite { margin-top: 14px; } 46 | #HTMLReporter .suite a { color: #333333; } 47 | #HTMLReporter #details .specDetail { margin-bottom: 28px; } 48 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } 49 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } 50 | #HTMLReporter .resultMessage span.result { display: block; } 51 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 52 | 53 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } 54 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; } 55 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } 56 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } 57 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } 58 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } 59 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } 60 | #TrivialReporter .runner.running { background-color: yellow; } 61 | #TrivialReporter .options { text-align: right; font-size: .8em; } 62 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } 63 | #TrivialReporter .suite .suite { margin: 5px; } 64 | #TrivialReporter .suite.passed { background-color: #dfd; } 65 | #TrivialReporter .suite.failed { background-color: #fdd; } 66 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } 67 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } 68 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } 69 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } 70 | #TrivialReporter .spec.skipped { background-color: #bbb; } 71 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } 72 | #TrivialReporter .passed { background-color: #cfc; display: none; } 73 | #TrivialReporter .failed { background-color: #fbb; } 74 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } 75 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } 76 | #TrivialReporter .resultMessage .mismatch { color: black; } 77 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } 78 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } 79 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } 80 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; } 81 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } 82 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.keyboardNavigation.js: -------------------------------------------------------------------------------- 1 | // Keyboard Navigation Module 2 | // ========================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //Move Down 24 | // -------- 25 | // Handles the down keyboard navigation logic 26 | 27 | $.selectBox.selectBoxIt.prototype.moveDown = function(callback) { 28 | 29 | var self = this; 30 | 31 | // Increments `currentFocus`, which represents the currently focused list item `id` attribute. 32 | self.currentFocus += 1; 33 | 34 | // Determines whether the dropdown option the user is trying to go to is currently disabled 35 | var disabled = self.listItems.eq(self.currentFocus).attr("data-disabled") === "true" ? true: false, 36 | 37 | hasNextEnabled = self.listItems.eq(self.currentFocus).nextAll("li").not("[data-disabled='true']").first().length; 38 | 39 | // If the user has reached the top of the list 40 | if (self.currentFocus === self.listItems.length) { 41 | 42 | // Does not allow the user to continue to go up the list 43 | self.currentFocus -= 1; 44 | 45 | } 46 | 47 | // If the option the user is trying to go to is disabled, but there is another enabled option 48 | else if (disabled && hasNextEnabled) { 49 | 50 | // Blur the previously selected option 51 | self.listItems.eq(self.currentFocus - 1).blur(); 52 | 53 | // Call the `moveDown` method again 54 | self.moveDown(); 55 | 56 | // Exit the method 57 | return; 58 | 59 | } 60 | 61 | // If the option the user is trying to go to is disabled, but there is not another enabled option 62 | else if (disabled && !hasNextEnabled) { 63 | 64 | self.currentFocus -= 1; 65 | 66 | } 67 | 68 | // If the user has not reached the bottom of the unordered list 69 | else { 70 | 71 | // Blurs the previously focused list item 72 | // The jQuery `end()` method allows you to continue chaining while also using a different selector 73 | self.listItems.eq(self.currentFocus - 1).blur().end(). 74 | 75 | // Focuses the currently focused list item 76 | eq(self.currentFocus).focusin(); 77 | 78 | // Calls `scrollToView` to make sure the `scrollTop` is correctly updated. The `down` user action 79 | self._scrollToView("down"); 80 | 81 | // Triggers the custom `moveDown` event on the original select box 82 | self.triggerEvent("moveDown"); 83 | 84 | } 85 | 86 | // Provide callback function support 87 | self._callbackSupport(callback); 88 | 89 | // Maintains chainability 90 | return self; 91 | 92 | }; 93 | 94 | //Move Up 95 | // ------ 96 | // Handles the up keyboard navigation logic 97 | $.selectBox.selectBoxIt.prototype.moveUp = function(callback) { 98 | 99 | var self = this; 100 | 101 | // Increments `currentFocus`, which represents the currently focused list item `id` attribute. 102 | self.currentFocus -= 1; 103 | 104 | // Determines whether the dropdown option the user is trying to go to is currently disabled 105 | var disabled = self.listItems.eq(self.currentFocus).attr("data-disabled") === "true" ? true: false, 106 | 107 | hasPreviousEnabled = self.listItems.eq(self.currentFocus).prevAll("li").not("[data-disabled='true']").first().length; 108 | 109 | // If the user has reached the top of the list 110 | if (self.currentFocus === -1) { 111 | 112 | // Does not allow the user to continue to go up the list 113 | self.currentFocus += 1; 114 | } 115 | 116 | // If the option the user is trying to go to is disabled and the user is not trying to go up after the user has reached the top of the list 117 | else if (disabled && hasPreviousEnabled) { 118 | 119 | // Blur the previously selected option 120 | self.listItems.eq(self.currentFocus + 1).blur(); 121 | 122 | // Call the `moveUp` method again 123 | self.moveUp(); 124 | 125 | // Exits the method 126 | return; 127 | } 128 | 129 | else if (disabled && !hasPreviousEnabled) { 130 | 131 | self.currentFocus += 1; 132 | 133 | } 134 | 135 | // If the user has not reached the top of the unordered list 136 | else { 137 | 138 | // Blurs the previously focused list item 139 | // The jQuery `end()` method allows you to continue chaining while also using a different selector 140 | self.listItems.eq(this.currentFocus + 1).blur().end(). 141 | 142 | // Focuses the currently focused list item 143 | eq(self.currentFocus).focusin(); 144 | 145 | // Calls `scrollToView` to make sure the `scrollTop` is correctly updated. The `down` user action 146 | self._scrollToView("up"); 147 | 148 | // Triggers the custom `moveDown` event on the original select box 149 | self.triggerEvent("moveUp"); 150 | 151 | } 152 | 153 | // Provide callback function support 154 | self._callbackSupport(callback); 155 | 156 | // Maintains chainability 157 | return self; 158 | 159 | }; 160 | 161 | })); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.ariaAccessibility.js: -------------------------------------------------------------------------------- 1 | // Accessibility Module 2 | // ==================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | //_ARIA Accessibility 24 | // ------------------ 25 | // Adds ARIA (Accessible Rich Internet Applications) 26 | // Accessibility Tags to the Select Box 27 | 28 | $.selectBox.selectBoxIt.prototype._ariaAccessibility = function() { 29 | 30 | var self = this; 31 | 32 | //Adds `ARIA attributes` to the dropdown list 33 | self.dropdown.attr({ 34 | 35 | //W3C `combobox` description: A presentation of a select; usually similar to a textbox where users can type ahead to select an option. 36 | "role": "combobox", 37 | 38 | //W3C `aria-autocomplete` description: Indicates whether user input completion suggestions are provided. 39 | "aria-autocomplete": "list", 40 | 41 | //W3C `aria-expanded` description: Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. 42 | "aria-expanded": "false", 43 | 44 | //W3C `aria-owns` description: The value of the aria-owns attribute is a space-separated list of IDREFS that reference one or more elements in the document by ID. The reason for adding aria-owns is to expose a parent/child contextual relationship to assistive technologies that is otherwise impossible to infer from the DOM. 45 | "aria-owns": self.list.attr("id"), 46 | 47 | //W3C `aria-activedescendant` description: This is used when a composite widget is responsible for managing its current active child to reduce the overhead of having all children be focusable. Examples include: multi-level lists, trees, and grids. 48 | "aria-activedescendant": self.listItems.eq(self.currentFocus).attr("id"), 49 | 50 | //W3C `aria-label` description: It provides the user with a recognizable name of the object. 51 | "aria-label": $("label[for='" + self.originalElem.id + "']").text() || "", 52 | 53 | //W3C `aria-live` description: Indicates that an element will be updated. 54 | //Use the assertive value when the update needs to be communicated to the user more urgently. 55 | "aria-live": "assertive" 56 | }). 57 | 58 | //Dynamically adds `ARIA attributes` if the new dropdown list is enabled or disabled 59 | bind({ 60 | 61 | //Select box custom `disable` event with the `selectBoxIt` namespace 62 | "disable.selectBoxIt" : function() { 63 | 64 | //W3C `aria-disabled` description: Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. 65 | self.dropdown.attr("aria-disabled", "true"); 66 | 67 | }, 68 | 69 | //Select box custom `enable` event with the `selectBoxIt` namespace 70 | "enable.selectBoxIt" : function() { 71 | 72 | //W3C `aria-disabled` description: Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. 73 | self.dropdown.attr("aria-disabled", "false"); 74 | 75 | } 76 | 77 | }); 78 | 79 | //Adds ARIA attributes to the dropdown list options list 80 | self.list.attr({ 81 | 82 | //W3C `listbox` description: A widget that allows the user to select one or more items from a list of choices. 83 | "role": "listbox", 84 | 85 | //Indicates that the dropdown list options list is currently hidden 86 | "aria-hidden": "true" 87 | }); 88 | 89 | //Adds `ARIA attributes` to the dropdown list options 90 | self.listItems.attr({ 91 | 92 | //This must be set for each element when the container element role is set to `listbox` 93 | "role": "option" 94 | }); 95 | 96 | //Dynamically updates the new dropdown list `aria-label` attribute after the original dropdown list value changes 97 | self.selectBox.bind({ 98 | 99 | //Custom `change` event with the `selectBoxIt` namespace 100 | "change.selectBoxIt": function() { 101 | 102 | //Provides the user with a recognizable name of the object. 103 | self.dropdownText.attr("aria-label", self.originalElem.value); 104 | 105 | }, 106 | 107 | //Custom `open` event with the `selectBoxIt` namespace 108 | "open.selectBoxIt": function() { 109 | 110 | //Indicates that the dropdown list options list is currently visible 111 | self.list.attr("aria-hidden", "false"); 112 | 113 | //Indicates that the dropdown list is currently expanded 114 | self.dropdown.attr("aria-expanded", "true"); 115 | 116 | }, 117 | 118 | //Custom `close` event with the `selectBoxIt` namespace 119 | "close.selectBoxIt": function() { 120 | 121 | //Indicates that the dropdown list options list is currently hidden 122 | self.list.attr("aria-hidden", "true"); 123 | 124 | //Indicates that the dropdown list is currently collapsed 125 | self.dropdown.attr("aria-expanded", "false"); 126 | 127 | } 128 | 129 | }); 130 | 131 | //Maintains chainability 132 | return self; 133 | 134 | }; 135 | 136 | })); -------------------------------------------------------------------------------- /demos/css/bootstrap.css: -------------------------------------------------------------------------------- 1 | /*! (Modified by Shane Fire from Boostrap) 2 | 3 | * Bootstrap v2.1.1 4 | * 5 | * Copyright 2012 Twitter, Inc 6 | * Licensed under the Apache License v2.0 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 10 | */ 11 | 12 | 13 | .dropup, 14 | .dropdown { 15 | position: relative; 16 | } 17 | 18 | .caret { 19 | display: inline-block; 20 | width: 0; 21 | height: 0; 22 | vertical-align: top; 23 | border-top: 4px solid #000000; 24 | border-right: 4px solid transparent; 25 | border-left: 4px solid transparent; 26 | content: ""; 27 | } 28 | 29 | .dropdown .caret { 30 | margin-top: 8px; 31 | margin-left: 2px; 32 | } 33 | 34 | .dropdown-menu { 35 | position: absolute; 36 | top: 100%; 37 | left: 0; 38 | z-index: 1000; 39 | display: none; 40 | float: left; 41 | min-width: 160px; 42 | padding: 5px 0; 43 | margin: 2px 0 0; 44 | list-style: none; 45 | background-color: #ffffff; 46 | border: 1px solid #ccc; 47 | border: 1px solid rgba(0, 0, 0, 0.2); 48 | *border-right-width: 2px; 49 | *border-bottom-width: 2px; 50 | -webkit-border-radius: 6px; 51 | -moz-border-radius: 6px; 52 | border-radius: 6px; 53 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 54 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 55 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 56 | -webkit-background-clip: padding-box; 57 | -moz-background-clip: padding; 58 | background-clip: padding-box; 59 | } 60 | 61 | .dropdown-menu a { 62 | display: block; 63 | padding: 3px 20px; 64 | clear: both; 65 | font-weight: normal; 66 | line-height: 20px; 67 | color: #333333; 68 | white-space: nowrap; 69 | } 70 | 71 | .dropdown-menu li > a:hover, 72 | .dropdown-menu li > a:focus, 73 | .dropdown-submenu:hover > a { 74 | color: #ffffff; 75 | text-decoration: none; 76 | background-color: #0088cc; 77 | background-color: #0081c2; 78 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 79 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 80 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 81 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 82 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 83 | background-repeat: repeat-x; 84 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); 85 | } 86 | 87 | .dropdown-menu .active > a, 88 | .dropdown-menu .active > a:hover { 89 | color: #ffffff; 90 | text-decoration: none; 91 | background-color: #0088cc; 92 | background-color: #0081c2; 93 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 94 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 95 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 96 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 97 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 98 | background-repeat: repeat-x; 99 | outline: 0; 100 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); 101 | } 102 | 103 | .dropdown-menu .disabled > a, 104 | .dropdown-menu .disabled > a:hover { 105 | color: #999999; 106 | } 107 | 108 | .dropdown-menu .disabled > a:hover { 109 | text-decoration: none; 110 | cursor: default; 111 | background-color: transparent; 112 | } 113 | 114 | 115 | .dropup .caret, 116 | .navbar-fixed-bottom .dropdown .caret { 117 | border-top: 0; 118 | border-bottom: 4px solid #000000; 119 | content: ""; 120 | } 121 | 122 | .dropup .dropdown-menu, 123 | .navbar-fixed-bottom .dropdown .dropdown-menu { 124 | top: auto; 125 | bottom: 100%; 126 | margin-bottom: 1px; 127 | } 128 | 129 | .btn { 130 | display: inline-block; 131 | *display: inline; 132 | padding: 4px 14px; 133 | margin-bottom: 0; 134 | *margin-left: .3em; 135 | font-size: 14px; 136 | line-height: 20px; 137 | *line-height: 20px; 138 | color: #333333; 139 | text-align: center; 140 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 141 | vertical-align: middle; 142 | cursor: pointer; 143 | background-color: #f5f5f5; 144 | *background-color: #e6e6e6; 145 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); 146 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); 147 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); 148 | background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); 149 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); 150 | background-repeat: repeat-x; 151 | border: 1px solid #bbbbbb; 152 | *border: 0; 153 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 154 | border-color: #e6e6e6 #e6e6e6 #bfbfbf; 155 | border-bottom-color: #a2a2a2; 156 | -webkit-border-radius: 4px; 157 | -moz-border-radius: 4px; 158 | border-radius: 4px; 159 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); 160 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 161 | *zoom: 1; 162 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 163 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 164 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 165 | } 166 | 167 | .btn:hover, 168 | .btn:active, 169 | .btn.active, 170 | .btn.disabled, 171 | .btn[disabled] { 172 | color: #333333; 173 | background-color: #e6e6e6; 174 | *background-color: #d9d9d9; 175 | } 176 | 177 | .btn:active, 178 | .btn.active { 179 | background-color: #cccccc \9; 180 | } 181 | 182 | .btn:first-child { 183 | *margin-left: 0; 184 | } 185 | 186 | .btn:hover { 187 | color: #333333; 188 | text-decoration: none; 189 | background-color: #e6e6e6; 190 | *background-color: #d9d9d9; 191 | /* Buttons in IE7 don't get borders, so darken on hover */ 192 | 193 | background-position: 0 -15px; 194 | -webkit-transition: background-position 0.1s linear; 195 | -moz-transition: background-position 0.1s linear; 196 | -o-transition: background-position 0.1s linear; 197 | transition: background-position 0.1s linear; 198 | } 199 | 200 | .btn:focus { 201 | outline: thin dotted #333; 202 | outline: 5px auto -webkit-focus-ring-color; 203 | outline-offset: -2px; 204 | } 205 | 206 | .btn.active, 207 | .btn:active { 208 | background-color: #e6e6e6; 209 | background-color: #d9d9d9 \9; 210 | background-image: none; 211 | outline: 0; 212 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 213 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 214 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.keyboardSearch.js: -------------------------------------------------------------------------------- 1 | // Keyboard Search Module 2 | // ====================== 3 | 4 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 5 | 6 | (function (selectBoxIt) { 7 | 8 | //ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 9 | "use strict"; 10 | 11 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 12 | selectBoxIt(window.jQuery, window, document); 13 | 14 | } 15 | 16 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 17 | 18 | (function ($, window, document, undefined) { 19 | 20 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 21 | "use strict"; 22 | 23 | // _Set Current Search Option 24 | // ------------------------- 25 | // Sets the currently selected dropdown list search option 26 | 27 | $.selectBox.selectBoxIt.prototype._setCurrentSearchOption = function(currentOption) { 28 | 29 | var self = this; 30 | 31 | // Does not change the current option if `showFirstOption` is false and the matched search item is the hidden first option. 32 | // Otherwise, the current option value is updated 33 | if ((self.options["aggressiveChange"] || self.options["selectWhenHidden"] || self.listItems.eq(currentOption).is(":visible")) && self.listItems.eq(currentOption).data("disabled") !== true) { 34 | 35 | // Calls the `blur` event of the currently selected dropdown list option 36 | self.listItems.eq(self.currentFocus).blur(); 37 | 38 | // Sets `currentIndex` to the currently selected dropdown list option 39 | self.currentIndex = currentOption; 40 | 41 | // Sets `currentFocus` to the currently selected dropdown list option 42 | self.currentFocus = currentOption; 43 | 44 | // Focuses the currently selected dropdown list option 45 | self.listItems.eq(self.currentFocus).focusin(); 46 | 47 | // Updates the scrollTop so that the currently selected dropdown list option is visible to the user 48 | self._scrollToView("search"); 49 | 50 | // Triggers the custom `search` event on the original select box 51 | self.triggerEvent("search"); 52 | 53 | } 54 | 55 | //Maintains chainability 56 | return self; 57 | 58 | }; 59 | 60 | // _Search Algorithm 61 | // ----------------- 62 | // Uses regular expressions to find text matches 63 | $.selectBox.selectBoxIt.prototype._searchAlgorithm = function(currentIndex, alphaNumeric) { 64 | 65 | var self = this, 66 | 67 | // Boolean to determine if a pattern match exists 68 | matchExists = false, 69 | 70 | // Iteration variable used in the outermost for loop 71 | x, 72 | 73 | // Iteration variable used in the nested for loop 74 | y, 75 | 76 | // Variable used to cache the length of the text array (Small enhancement to speed up traversing) 77 | arrayLength; 78 | 79 | // Loops through the text array to find a pattern match 80 | for (x = currentIndex, arrayLength = self.textArray.length; x < arrayLength; x += 1) { 81 | 82 | // Nested for loop to help search for a pattern match with the currently traversed array item 83 | for (y = 0; y < arrayLength; y += 1) { 84 | 85 | // Searches for a match 86 | if (self.textArray[y].search(alphaNumeric) !== -1) { 87 | 88 | // `matchExists` is set to true if there is a match 89 | matchExists = true; 90 | 91 | // Exits the nested for loop 92 | y = arrayLength; 93 | 94 | } 95 | 96 | } // End nested for loop 97 | 98 | //If a match does not exist 99 | if (!matchExists) { 100 | 101 | // Sets the current text to the last entered character 102 | self.currentText = self.currentText.charAt(self.currentText.length - 1). 103 | 104 | // Escapes the regular expression to make sure special characters are seen as literal characters instead of special commands 105 | replace(/[|()\[{.+*?$\\]/g, "\\$0"); 106 | 107 | // Resets the regular expression with the new value of `self.currentText` 108 | alphaNumeric = new RegExp(self.currentText, "gi"); 109 | 110 | } 111 | 112 | // Searches based on the first letter of the dropdown list options text if the currentText < 2 characters 113 | if (self.currentText.length < 3) { 114 | 115 | alphaNumeric = new RegExp(self.currentText.charAt(0), "gi"); 116 | 117 | //If there is a match based on the first character 118 | if ((self.textArray[x].charAt(0).search(alphaNumeric) !== -1)) { 119 | 120 | //Sets properties of that dropdown list option to make it the currently selected option 121 | self._setCurrentSearchOption(x); 122 | 123 | //Increments the current index by one 124 | self.currentIndex += 1; 125 | 126 | //Exits the search 127 | return false; 128 | 129 | } 130 | } 131 | 132 | // If `self.currentText` > 1 character 133 | else { 134 | 135 | // If there is a match based on the entire string 136 | if ((self.textArray[x].search(alphaNumeric) !== -1)) { 137 | 138 | // Sets properties of that dropdown list option to make it the currently selected option 139 | self._setCurrentSearchOption(x); 140 | 141 | // Exits the search 142 | return false; 143 | } 144 | } 145 | 146 | // If the current text search is an exact match 147 | if (self.textArray[x].toLowerCase() === self.currentText.toLowerCase()) { 148 | 149 | // Sets properties of that dropdown list option to make it the currently selected option 150 | self._setCurrentSearchOption(x); 151 | 152 | // Resets the current text search to a blank string to start fresh again 153 | self.currentText = ""; 154 | 155 | // Exits the search 156 | return false; 157 | 158 | } 159 | } 160 | 161 | //Returns true if there is not a match at all 162 | return true; 163 | }; 164 | 165 | // Search 166 | // ------ 167 | // Calls searchAlgorithm() 168 | $.selectBox.selectBoxIt.prototype.search = function(alphaNumericKey, rememberPreviousSearch, callback) { 169 | 170 | var self = this; 171 | 172 | if(self.currentText === undefined) { 173 | 174 | self.currentText = ""; 175 | 176 | } 177 | 178 | // If the search method is being called internally by the plugin, and not externally as a method by a user 179 | if (rememberPreviousSearch) { 180 | 181 | // Continued search with history from past searches. Properly escapes the regular expression 182 | self.currentText += alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0"); 183 | 184 | } 185 | 186 | else { 187 | 188 | // Brand new search. Properly escapes the regular expression 189 | self.currentText = alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0"); 190 | 191 | } 192 | 193 | // Searches globally 194 | var notFound = self._searchAlgorithm(self.currentIndex, self.currentText); 195 | 196 | // Searches the list again if a match is not found. This is needed, because the first search started at the array indece of the currently selected dropdown list option, and does not search the options before the current array indece. 197 | // If there are many similar dropdown list options, starting the search at the indece of the currently selected dropdown list option is needed to properly traverse the text array. 198 | if (notFound) { 199 | 200 | // Searches the dropdown list values starting from the beginning of the text array 201 | self._searchAlgorithm(0, self.currentText); 202 | 203 | } 204 | 205 | // Provide callback function support 206 | self._callbackSupport(callback); 207 | 208 | // Maintains chainability 209 | return self; 210 | 211 | }; 212 | 213 | })); -------------------------------------------------------------------------------- /libs/jasmine/jasmine-jquery-1.3.1.js: -------------------------------------------------------------------------------- 1 | var readFixtures = function() { 2 | return jasmine.getFixtures().proxyCallTo_('read', arguments); 3 | }; 4 | 5 | var preloadFixtures = function() { 6 | jasmine.getFixtures().proxyCallTo_('preload', arguments); 7 | }; 8 | 9 | var loadFixtures = function() { 10 | jasmine.getFixtures().proxyCallTo_('load', arguments); 11 | }; 12 | 13 | var setFixtures = function(html) { 14 | jasmine.getFixtures().set(html); 15 | }; 16 | 17 | var sandbox = function(attributes) { 18 | return jasmine.getFixtures().sandbox(attributes); 19 | }; 20 | 21 | var spyOnEvent = function(selector, eventName) { 22 | jasmine.JQuery.events.spyOn(selector, eventName); 23 | }; 24 | 25 | jasmine.getFixtures = function() { 26 | return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures(); 27 | }; 28 | 29 | jasmine.Fixtures = function() { 30 | this.containerId = 'jasmine-fixtures'; 31 | this.fixturesCache_ = {}; 32 | this.fixturesPath = 'spec/javascripts/fixtures'; 33 | }; 34 | 35 | jasmine.Fixtures.prototype.set = function(html) { 36 | this.cleanUp(); 37 | this.createContainer_(html); 38 | }; 39 | 40 | jasmine.Fixtures.prototype.preload = function() { 41 | this.read.apply(this, arguments); 42 | }; 43 | 44 | jasmine.Fixtures.prototype.load = function() { 45 | this.cleanUp(); 46 | this.createContainer_(this.read.apply(this, arguments)); 47 | }; 48 | 49 | jasmine.Fixtures.prototype.read = function() { 50 | var htmlChunks = []; 51 | 52 | var fixtureUrls = arguments; 53 | for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) { 54 | htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex])); 55 | } 56 | 57 | return htmlChunks.join(''); 58 | }; 59 | 60 | jasmine.Fixtures.prototype.clearCache = function() { 61 | this.fixturesCache_ = {}; 62 | }; 63 | 64 | jasmine.Fixtures.prototype.cleanUp = function() { 65 | jQuery('#' + this.containerId).remove(); 66 | }; 67 | 68 | jasmine.Fixtures.prototype.sandbox = function(attributes) { 69 | var attributesToSet = attributes || {}; 70 | return jQuery('
').attr(attributesToSet); 71 | }; 72 | 73 | jasmine.Fixtures.prototype.createContainer_ = function(html) { 74 | var container; 75 | if(html instanceof jQuery) { 76 | container = jQuery('
'); 77 | container.html(html); 78 | } else { 79 | container = '
' + html + '
' 80 | } 81 | jQuery('body').append(container); 82 | }; 83 | 84 | jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) { 85 | if (typeof this.fixturesCache_[url] == 'undefined') { 86 | this.loadFixtureIntoCache_(url); 87 | } 88 | return this.fixturesCache_[url]; 89 | }; 90 | 91 | jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) { 92 | var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl; 93 | var request = new XMLHttpRequest(); 94 | request.open("GET", url + "?" + new Date().getTime(), false); 95 | request.send(null); 96 | this.fixturesCache_[relativeUrl] = request.responseText; 97 | }; 98 | 99 | jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) { 100 | return this[methodName].apply(this, passedArguments); 101 | }; 102 | 103 | 104 | jasmine.JQuery = function() {}; 105 | 106 | jasmine.JQuery.browserTagCaseIndependentHtml = function(html) { 107 | return jQuery('
').append(html).html(); 108 | }; 109 | 110 | jasmine.JQuery.elementToString = function(element) { 111 | return jQuery('
').append($(element).clone()).html(); 112 | }; 113 | 114 | jasmine.JQuery.matchersClass = {}; 115 | 116 | (function(namespace) { 117 | var data = { 118 | spiedEvents: {}, 119 | handlers: [] 120 | }; 121 | 122 | namespace.events = { 123 | spyOn: function(selector, eventName) { 124 | var handler = function(e) { 125 | data.spiedEvents[[selector, eventName]] = e; 126 | }; 127 | jQuery(selector).bind(eventName, handler); 128 | data.handlers.push(handler); 129 | }, 130 | 131 | wasTriggered: function(selector, eventName) { 132 | return !!(data.spiedEvents[[selector, eventName]]); 133 | }, 134 | 135 | wasPrevented: function(selector, eventName) { 136 | return data.spiedEvents[[selector, eventName]].isDefaultPrevented(); 137 | }, 138 | 139 | cleanUp: function() { 140 | data.spiedEvents = {}; 141 | data.handlers = []; 142 | } 143 | } 144 | })(jasmine.JQuery); 145 | 146 | (function(){ 147 | var jQueryMatchers = { 148 | toHaveClass: function(className) { 149 | return this.actual.hasClass(className); 150 | }, 151 | 152 | toBeVisible: function() { 153 | return this.actual.is(':visible'); 154 | }, 155 | 156 | toBeHidden: function() { 157 | return this.actual.is(':hidden'); 158 | }, 159 | 160 | toBeSelected: function() { 161 | return this.actual.is(':selected'); 162 | }, 163 | 164 | toBeChecked: function() { 165 | return this.actual.is(':checked'); 166 | }, 167 | 168 | toBeEmpty: function() { 169 | return this.actual.is(':empty'); 170 | }, 171 | 172 | toExist: function() { 173 | return this.actual.length; 174 | }, 175 | 176 | toHaveAttr: function(attributeName, expectedAttributeValue) { 177 | return hasProperty(this.actual.attr(attributeName), expectedAttributeValue); 178 | }, 179 | 180 | toHaveProp: function(propertyName, expectedPropertyValue) { 181 | return hasProperty(this.actual.prop(propertyName), expectedPropertyValue); 182 | }, 183 | 184 | toHaveId: function(id) { 185 | return this.actual.attr('id') == id; 186 | }, 187 | 188 | toHaveHtml: function(html) { 189 | return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html); 190 | }, 191 | 192 | toHaveText: function(text) { 193 | var trimmedText = $.trim(this.actual.text()); 194 | if (text && jQuery.isFunction(text.test)) { 195 | return text.test(trimmedText); 196 | } else { 197 | return trimmedText == text; 198 | } 199 | }, 200 | 201 | toHaveValue: function(value) { 202 | return this.actual.val() == value; 203 | }, 204 | 205 | toHaveData: function(key, expectedValue) { 206 | return hasProperty(this.actual.data(key), expectedValue); 207 | }, 208 | 209 | toBe: function(selector) { 210 | return this.actual.is(selector); 211 | }, 212 | 213 | toContain: function(selector) { 214 | return this.actual.find(selector).length; 215 | }, 216 | 217 | toBeDisabled: function(selector){ 218 | return this.actual.is(':disabled'); 219 | }, 220 | 221 | toBeFocused: function(selector) { 222 | return this.actual.is(':focus'); 223 | }, 224 | 225 | // tests the existence of a specific event binding 226 | toHandle: function(eventName) { 227 | var events = this.actual.data("events"); 228 | return events && events[eventName].length > 0; 229 | }, 230 | 231 | // tests the existence of a specific event binding + handler 232 | toHandleWith: function(eventName, eventHandler) { 233 | var stack = this.actual.data("events")[eventName]; 234 | var i; 235 | for (i = 0; i < stack.length; i++) { 236 | if (stack[i].handler == eventHandler) { 237 | return true; 238 | } 239 | } 240 | return false; 241 | } 242 | }; 243 | 244 | var hasProperty = function(actualValue, expectedValue) { 245 | if (expectedValue === undefined) { 246 | return actualValue !== undefined; 247 | } 248 | return actualValue == expectedValue; 249 | }; 250 | 251 | var bindMatcher = function(methodName) { 252 | var builtInMatcher = jasmine.Matchers.prototype[methodName]; 253 | 254 | jasmine.JQuery.matchersClass[methodName] = function() { 255 | if (this.actual 256 | && (this.actual instanceof jQuery 257 | || jasmine.isDomNode(this.actual))) { 258 | this.actual = $(this.actual); 259 | var result = jQueryMatchers[methodName].apply(this, arguments); 260 | this.actual = jasmine.JQuery.elementToString(this.actual); 261 | return result; 262 | } 263 | 264 | if (builtInMatcher) { 265 | return builtInMatcher.apply(this, arguments); 266 | } 267 | 268 | return false; 269 | }; 270 | }; 271 | 272 | for(var methodName in jQueryMatchers) { 273 | bindMatcher(methodName); 274 | } 275 | })(); 276 | 277 | beforeEach(function() { 278 | this.addMatchers(jasmine.JQuery.matchersClass); 279 | this.addMatchers({ 280 | toHaveBeenTriggeredOn: function(selector) { 281 | this.message = function() { 282 | return [ 283 | "Expected event " + this.actual + " to have been triggered on " + selector, 284 | "Expected event " + this.actual + " not to have been triggered on " + selector 285 | ]; 286 | }; 287 | return jasmine.JQuery.events.wasTriggered($(selector), this.actual); 288 | } 289 | }); 290 | this.addMatchers({ 291 | toHaveBeenPreventedOn: function(selector) { 292 | this.message = function() { 293 | return [ 294 | "Expected event " + this.actual + " to have been prevented on " + selector, 295 | "Expected event " + this.actual + " not to have been prevented on " + selector 296 | ]; 297 | }; 298 | return jasmine.JQuery.events.wasPrevented(selector, this.actual); 299 | } 300 | }); 301 | }); 302 | 303 | afterEach(function() { 304 | jasmine.getFixtures().cleanUp(); 305 | jasmine.JQuery.events.cleanUp(); 306 | }); -------------------------------------------------------------------------------- /demos/bootstrap-buttons.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |

11 | 26 | 27 | 42 | 43 | 58 | 73 | 88 | 103 |

104 |
105 | 106 |
107 |

108 | 123 | 124 | 139 | 140 | 155 | 170 | 185 | 200 |

201 |
202 | 203 |
204 | 205 | 206 | 207 | 208 | 215 | 216 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.core.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.widget("selectBox.selectBoxIt",{VERSION:"2.9.9",options:{showEffect:"none",showEffectOptions:{},showEffectSpeed:"medium",hideEffect:"none",hideEffectOptions:{},hideEffectSpeed:"medium",showFirstOption:!0,defaultText:"",defaultIcon:"",downArrowIcon:"",theme:"bootstrap",keydownOpen:!0,isMobile:function(){var e=navigator.userAgent||navigator.vendor||t.opera;return/iPhone|iPod|iPad|Android|BlackBerry|Opera Mini|IEMobile/.test(e)},nostyle:!1,"native":!1,aggressiveChange:!1,selectWhenHidden:!0},_create:function(){var t=this;if(!t.element.is("select"))return;return t.originalElem=t.element[0],t.selectBox=t.element,t.selectItems=t.element.find("option"),t.firstSelectItem=t.element.find("option").slice(0,1),t.currentFocus=0,t.blur=!0,t.documentHeight=e(n).height(),t.textArray=[],t.currentIndex=0,t.flipped=!1,t.disabledClasses=function(){return t.options.theme==="bootstrap"?"disabled":t.options.theme==="jqueryui"?"ui-state-disabled":t.options.theme==="jquerymobile"?"ui-disabled":"selectboxit-disabled"}(),t._createdropdown()._createUnorderedList()._addSelectBoxAttributes()._replaceSelectBox()._eventHandlers(),t.originalElem.disabled&&t.disable&&t.disable(),t._ariaAccessibility&&t._ariaAccessibility(),t.options.theme==="bootstrap"?t._twitterbootstrap():this.options.theme==="jqueryui"?t._jqueryui():this.options.theme==="jquerymobile"?t._jquerymobile():t._addClasses(),t._mobile(),t.options["native"]&&this._applyNativeSelect(),t.triggerEvent("create"),t},_createdropdown:function(){var t=this;return t.dropdownText=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItText","class":"selectboxit-text",unselectable:"on",text:t.firstSelectItem.text()}).attr("data-val",t.originalElem.value),t.dropdownImage=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItDefaultIcon","class":"selectboxit-default-icon",unselectable:"on"}),t.dropdown=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxIt","class":"selectboxit "+(t.selectBox.attr("class")||""),name:t.originalElem.name,tabindex:t.selectBox.attr("tabindex")||"0",unselectable:"on"}).append(t.dropdownImage).append(t.dropdownText),t.dropdownContainer=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItContainer","class":"selectboxit-container"}).append(t.dropdown),t},_createUnorderedList:function(){var t=this,n,r,i,s,o,u,a,f="",l=e("
    ",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItOptions","class":"selectboxit-options",tabindex:-1});t.options.showFirstOption||(t.selectItems=t.selectBox.find("option").slice(1)),t.selectItems.each(function(l){r="",i="",n=e(this).prop("disabled"),s=e(this).data("icon")||"",o=e(this).data("iconurl")||"",u=o?"selectboxit-option-icon-url":"",a=o?"style=\"background-image:url('"+o+"');\"":"",e(this).parent().is("optgroup")&&(r="selectboxit-optgroup-option",e(this).index()===0&&(i=''+e(this).parent().first().attr("label")+"")),f+=i+'
  • "+t.htmlEscape(e(this).text())+"
  • ",t.textArray[l]=n?"":e(this).text(),this.selected&&(t.dropdownText.text(e(this).text()),t.currentFocus=l)});if((t.options.defaultText||t.selectBox.data("text"))&&!t.selectBox.find("option[selected]").length){var c=t.options.defaultText||t.selectBox.data("text");t.dropdownText.text(c),t.options.defaultText=c}return l.append(f),t.list=l,t.dropdownContainer.append(t.list),t.listItems=t.list.find("li"),t.listItems.first().addClass("selectboxit-option-first"),t.listItems.last().addClass("selectboxit-option-last"),t.list.find("li[data-disabled='true']").not(".optgroupHeader").addClass(t.disabledClasses),t.currentFocus===0&&!t.options.showFirstOption&&t.listItems.eq(0).hasClass(t.disabledClasses)&&(t.currentFocus=+t.listItems.not(".ui-state-disabled").first().attr("id")),t.dropdownImage.addClass(t.selectBox.data("icon")||t.options.defaultIcon||t.listItems.eq(t.currentFocus).find("i").attr("class")),t.dropdownImage.attr("style",t.listItems.eq(t.currentFocus).find("i").attr("style")),t},_replaceSelectBox:function(){var t=this;t.selectBox.css("display","none").after(t.dropdownContainer);var n=t.dropdown.height();return t.downArrow=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItArrow","class":"selectboxit-arrow",unselectable:"on"}),t.downArrowContainer=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItArrowContainer","class":"selectboxit-arrow-container",unselectable:"on"}).append(t.downArrow),t.dropdown.append(this.options.nostyle?t.downArrow:t.downArrowContainer),t.options.nostyle||(t.downArrowContainer.css({height:n+"px"}),t.dropdownText.css({"line-height":t.dropdown.css("height"),"max-width":t.dropdown.outerWidth()-(t.downArrowContainer.outerWidth()+t.dropdownImage.outerWidth())}),t.dropdownImage.css({"margin-top":n/4}),t.listItems.removeClass("selectboxit-selected").eq(t.currentFocus).addClass("selectboxit-selected")),t},_scrollToView:function(e){var t=this,n=t.list.scrollTop(),r=t.listItems.eq(t.currentFocus).height(),i=t.listItems.eq(t.currentFocus).position().top,s=t.list.height();return e==="search"?s-i/g,">")},triggerEvent:function(e){var t=this,n=t.options.showFirstOption?t.currentFocus:t.currentFocus-1>=0?t.currentFocus:0;return t.selectBox.trigger(e,{elem:t.selectBox.eq(n),"dropdown-elem":t.listItems.eq(t.currentFocus)}),t},_addSelectBoxAttributes:function(t){var n=this;return n._addAttributes(n.selectBox.prop("attributes"),n.dropdown),n.selectItems.each(function(t){n._addAttributes(e(this).prop("attributes"),n.listItems.eq(t))}),n},_addAttributes:function(t,n){var r=this,i=["title","rel"];return t.length&&e.each(t,function(t,r){var s=r.name.toLowerCase(),o=r.value;o!=="null"&&(e.inArray(s,i)!==-1||s.indexOf("data")!==-1)&&n.attr(s,o)}),r}})}); -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | jquery.selectBoxIt.js - jQuery Select Box Plugin 2 | ------------------------------------------------ 3 | 4 | [![Build Status](https://travis-ci.org/gfranko/jquery.selectBoxIt.js.png?branch=master)](https://travis-ci.org/gfranko/jquery.selectBoxIt.js) 5 | 6 | A jQuery plugin that progressively enhances an HTML Select Box into a single option dropdown list. The dropdown list can be optionally styled with **Twitter Bootstrap**, **jQueryUI ThemeRoller**, or **jQuery Mobile**, optionally animated with **jQueryUI show/hide effects**, and works on Desktop, Tablet, and Mobile browsers. 7 | 8 | [Homepage](http://gregfranko.com/jquery.selectBoxIt.js/) 9 | 10 | [Annotated Source Code](http://www.gregfranko.com/jquery.selectBoxIt.js/docs/jQuery.selectBoxIt.html) 11 | 12 | **Notable Features** 13 | 14 | - Styleable with Twitter Bootstrap, jQueryUI Themeroller, and jQuery Mobile 15 | 16 | - Supports Desktop, Tablet, and Mobile browsers 17 | 18 | - Supports all jQuery and jQueryUI show/hide effects (optional) 19 | 20 | - Supports all Twitter Bootstrap (Glyphicons) and jQueryUI/custom icons 21 | 22 | - Includes ARIA (Accessible Rich Internet Applications) support 23 | 24 | - Full keyboard search and navigation support 25 | 26 | - An event API triggered on the original select box element that calls the plugin 27 | 28 | - A method API providing methods to interact with the dropdown list (i.e. Search, Open, Disable, Set Options). 29 | 30 | - Passes jsHint with no errors 31 | 32 | - Selected, Disabled, and Optgroup Support 33 | 34 | - Easily extendable to allow developers to create new widgets 35 | 36 | ##Requirements 37 | jQuery 1.6.1+ (It is always recommended to use the latest version of jQuery) 38 | 39 | jQueryUI Widget Factory 1.8.19+ (It is always recommended to use the latest version of the jQueryUI Widget Factory) 40 | 41 | ##Desktop Browser Support 42 | IE8+, Firefox 4+, Chrome, Safari 4+, Opera 11+ (Other browsers may work, but I did not test on them) 43 | 44 | **Note:** The CSS3 `background-size` property is used for the icon images, which is only supported in IE9+ 45 | 46 | ##Mobile/Tablet Browser Support 47 | iOs 3+, Android 2.1+ (Other browsers may work, but I did not test on them) 48 | 49 | 50 | ##Unit Tests 51 | All unit tests are written using the Jasmine Framework 52 | 53 | ##Contributing 54 | Take care to maintain the existing coding style. Add Jasmine unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt). 55 | 56 | If you plan to contribute to `SelectBoxIt` in the future, keep in mind that you should make sure your code passes the Grunt checks. 57 | 58 | To set up the SelectBoxIt grunt/node.js dependencies, first make sure you have [PhantomJS](http://phantomjs.org/) installed, which is a headless browser. Unfortunately PhantomJS cannot be installed automatically. 59 | 60 | Next, navigate to within the **jquery.selectBoxIt.js** folder and type `npm install' (this should install grunt and a few other node.js libraries). 61 | 62 | **Note:** If you are on Windows, remember you need to run the grunt command using `grunt.cmd`. Also, if you have trouble getting the Jasmine Unit Tests to work with PhantomJS 1.5 (the current release), install PhantomJS 1.3. 63 | 64 | After you have verified your code, send a pull request to the `SelectBoxIt` dev branch. After you send a pull request, you will hear back from me shortly after I review your code. 65 | 66 | You'll find source code in the "src" subdirectory! 67 | 68 | ##Forking 69 | If you find that you need a feature that SelectBoxIt does not currently support, either let me know via the SelectBoxIt issue tracker, or fork SelectBoxIt on Github and easily extend SelectBoxIt to create your own widget! 70 | 71 | ##Change Log 72 | 73 | `2.9.9` - January 20, 2013 74 | 75 | - Fixed [#98](https://github.com/gfranko/jquery.selectBoxIt.js/issues/98) 76 | - Fixed keyboard search with disabled options bug and keyboard search accuracy 77 | - Refactored attribute copy logic 78 | - Added the **selectWhenHidden** option to allow drop down options to be selected with the keyboard when the drop down is hidden 79 | - Added back **IE 7 support** in this release after numerous requests 80 | - Fixed [#102](https://github.com/gfranko/jquery.selectBoxIt.js/issues/102) 81 | - Fixed optgroup mouse cursor 82 | - Upgrade CSS styles to support select boxes with options without text 83 | 84 | `2.9.0` - January 15, 2013 85 | 86 | - Removed outline from appearing around the drop down 87 | - Fixed non select box bug [#94](https://github.com/gfranko/jquery.selectBoxIt.js/issues/94) 88 | - Fixed IE 8 bug from copying over all select box attributes to the new drop down [#95](https://github.com/gfranko/jquery.selectBoxIt.js/issues/95) 89 | 90 | `2.8.0` - January 12, 2013 91 | 92 | _IMPORTANT_: **Dropped IE7 support** - This does not mean new features will not work in IE7, but instead that they will not be tested in IE7. 93 | 94 | - All attributes on the original select box and select box options are now being copied over to the new drop down. 95 | 96 | `2.7.0` - January 11, 2013 97 | 98 | - Refactored internal drop down DOM element property names. 99 | 100 | `2.6.0` - January 8, 2013 101 | 102 | - Added support for styling the currently `selected` drop down option via the **selectboxit-selected** CSS class [#86](https://github.com/gfranko/jquery.selectBoxIt.js/issues/86) 103 | 104 | - Fixed `refresh()` method mobile bug [#68](https://github.com/gfranko/jquery.selectBoxIt.js/issues/68) 105 | 106 | - Refactored and fixed bugs for SelectBoxIt internal event triggering: All custom events now return an object containing both the currently selected select box and drop down options 107 | 108 | `2.5.0` - January 6, 2013 109 | 110 | **Default Behavior Change** 111 | 112 | - SelectBoxIt will no longer select a drop down option (and trigger the change event on the original select box) when a user navigates to an option using the up and down arrow keys via the keyboard, or searches for an option using the keyboard. An option will only be `selected` when a user clicks an option or presses the `enter` key when an option is actively "focused". [#85](https://github.com/gfranko/jquery.selectBoxIt.js/issues/85) 113 | 114 | - Added a new option, **aggressiveChange**, which _will_ select a drop down option (and trigger the change event on the original select box) when a user navigates to an option using the up and down arrow keys via the keyboard, or searchs for an option using the keyboard. 115 | 116 | - There is now always an "active" class when drop down options are moused over. [#84](https://github.com/gfranko/jquery.selectBoxIt.js/issues/84) 117 | 118 | `2.4.0` - January 2, 2013 119 | 120 | - Added the **data-iconurl** HTML5 data attribute to support relative and absolute image url's 121 | 122 | `2.3.0` - December 18, 2012 123 | 124 | - Added the `disableOption()` and `enableOption()` methods 125 | 126 | - Fixed disabled state CSS class bug. Now allows all supported themes (Twitter Bootstrap, jQueryUI, and jQuery Mobile) CSS class's are able to take effect 127 | 128 | - Improved custom event handling. The **moveDown**, **moveUp**, **search**, **option-click**, **disable-option**, and **enable-option** custom events now pass an object back in the second argument of the callback function event handler. Within the _object.elem_ property, is the single select box option that was interacted with. 129 | 130 | - Added Travis CI testing support 131 | 132 | **Note:** If you are using Twitter Bootstrap as your theme, then it is recommended to upgrade to Twitter Bootstrap v2.2.0 or greater () 133 | 134 | `2.2.0` - December 15, 2012 135 | 136 | - Added jQuery Mobile `data-theme` supporting 137 | 138 | `2.2.0 RC1` - December 13, 2012 139 | 140 | - Added jQuery Mobile CSS Theming Support 141 | 142 | - Added the **selectOption()** method 143 | 144 | `2.1.0` - December 3, 2012 145 | 146 | - Multiple bug fixes: [#53](https://github.com/gfranko/jquery.selectBoxIt.js/issues/53), [#54](https://github.com/gfranko/jquery.selectBoxIt.js/issues/54), [#55](https://github.com/gfranko/jquery.selectBoxIt.js/issues/55), and [#56](https://github.com/gfranko/jquery.selectBoxIt.js/issues/56). 147 | 148 | - Added the **native** option: Allows you to trigger the native select box element when a user is interacting with the drop down 149 | 150 | `2.0.0` - November 9th, 2012 151 | 152 | - Greatly improved dynamic positioning. SelectBoxIt now makes sure that the drop down list never runs off of the page (no matter how small the viewport is) 153 | 154 | - Improved support for enclosing a drop down arrow inside of a box (by setting a border) 155 | 156 | - Simplified mobile device checking for iOs, Android, Blackberry, Opera Mini, and Windows mobile devices (Removed the long regex supplied by [detectmobilebrowsers.com](http://www.detectmobilebrowsers.com)) 157 | 158 | 159 | `1.9.0` - October 31, 2012 160 | 161 | - Added **nostyle** option 162 | 163 | - Updated the CSS to remove tag names, remove IE7 hack, and improve CSS specificity 164 | 165 | - Thanks to @gavacho for the contributions 166 | 167 | `1.8.0` - October 27, 2012 168 | 169 | **Multiple Bug Fixes and Features Added: 170 | 171 | - Fixed IE7 focus bug 172 | 173 | - Removed all CSS attributes from the JS (to allow for maximum flexibility when changing styles) #34 174 | 175 | - SelectBoxIt now copies over all classes and inline styles from the original select box to the new drop down #34 176 | 177 | - Refresh method bug fix #32 178 | 179 | `1.7.0` - October 12, 2012 180 | 181 | **Multiple Bug Fixes** 182 | 183 | - Allow users to programmatically change the value of the select element [#28](https://github.com/gfranko/jquery.selectBoxIt.js/issues/28) 184 | 185 | - Removed unique id attributes from select boxes that do not originally include an id attribute [#27](https://github.com/gfranko/jquery.selectBoxIt.js/issues/27) 186 | 187 | - Applied HTML attribute encoding for quotes inside of option values [#8](https://github.com/gfranko/jquery.selectBoxIt.js/issues/8) 188 | 189 | - Fixed jQuery 1.8.2 keyboard compatibility bug [#26](https://github.com/gfranko/jquery.selectBoxIt.js/issues/26) 190 | 191 | `1.6.0` - September 28, 2012 192 | 193 | - Improved the CSS flexibility (can now more easily use auto widths) 194 | 195 | `1.5.0` - September 26, 2012 196 | 197 | - Improved the search algorithm 198 | 199 | `1.4.0` - September 23, 2012 200 | 201 | - **BIG NEWS:** Added Mobile and Tablet Support 202 | 203 | - Added the **isMobile** option 204 | 205 | `1.3.0` - September 9, 2012 206 | 207 | - Added the **changed** custom event 208 | 209 | `1.2.0` - September 6, 2012 210 | 211 | - Fixed IE8 keyboard navigation and search bug 212 | 213 | - Added a **keydownOpen** option to allow the dropdown list to be visible if the user presses the up or down arrow key 214 | 215 | `1.1.0` - September 5, 2012 216 | 217 | - Added Twitter Bootstrap Theming Support 218 | 219 | - Added a **refresh** public method 220 | 221 | - Added the _destroy_ method into the SelectBoxIt core 222 | 223 | `1.0.0` - August 8, 2012 *Stable 1.0 release* 224 | 225 | - Upgraded Homepage/Documentation 226 | 227 | - The plugin was split into modules (multiple files) and a custom build process was created 228 | 229 | - Big fixes/code clean up 230 | 231 | `0.9.0` - May 21, 2012 *Approaching a stable 1.0 release* 232 | 233 | - IE7 and IE8 bug fix: A special thanks to [lhwparis](https://github.com/lhwparis) 234 | 235 | `0.8.0` - May 15, 2012 *Approaching a stable 1.0 release* 236 | 237 | - Bug fixes for the `disabled` use cases 238 | 239 | `0.7.0` - May 10, 2012 [Documentation](http://gregfranko.com/blog/introducing-the-jquery-plugin-selectboxit/#optgroup-support) 240 | 241 | - Added optgroup support to allow dropdown list options to be put in subgroups. 242 | 243 | - Bug fixes to the `change` and `focus` Event API handlers 244 | 245 | `0.6.0` - May 3, 2012 [Documentation](http://gregfranko.com/blog/introducing-the-jquery-plugin-selectboxit/#using-icons) 246 | 247 | - Added jQueryUI and custom icon support to allow icons to be used for the dropdown list and also alongside individual dropdown options. You can specify the class names that you want to use to show the appropriate icon (set the background-image property inside of your CSS). There are two ways to do this (HTML5 data attributes or SelectBoxIt options) 248 | 249 | * Added support for three new HTML5 data attributes to be used with the original select box element. Use cases for each are described below. 250 | * data-icon - Specifies the custom or jQueryUI CSS classes you want to use to show icon images for the dropdown list and/or dropdown list individual options 251 | * data-downarrow - Specifies the custom or jQueryUI CSS classes you want to use to replace the default down arrow icon image 252 | * data-text - Specifies the custom text that you want to use for the dropdown list 253 | 254 | * Added support for two new options. Use cases for each are described below. 255 | * defaultIcon - An alternative to the `data-icon` HTML5 data attribute 256 | * downArrowIcon - An alternative to the `data-downarrow` HTML5 data attribute 257 | 258 | `0.5.0` - April 29, 2012 **MAJOR REWRITE** 259 | 260 | - `SelectBoxIt` has been rewritten using the `jQueryUI Widget Factory`! This means that `SelectBoxIt` depends on both jQuery and the jQueryUI Widget Factory. This also means that there are a few API changes that are not backwards compatible... 261 | * `getOption()`, `getOptions()`, and `create()` were all removed from the Method API 262 | * To use the custom pseudo selector, you must now use `$(":selectBox-selectBoxIt")` 263 | 264 | - `Grunt` Integration. `SelectBoxIt` now uses [grunt](https://github.com/cowboy/grunt) to run jsHint for code quality checking, Jasmine for unit testing, and UglifyJS for minification. 265 | 266 | - Removed `AMD` Support 267 | 268 | 269 | `0.4.0` - April 28, 2012 270 | 271 | - `AMD Support`. If `AMD` support is found, SelectBoxIt is wrapped in a define `module`. 272 | [UMD Patterns](https://github.com/umdjs/umd/blob/master/jqueryPlugin.js) 273 | - Bug fixes for supporting the `disabled` HTML property for individual select box options 274 | 275 | 276 | `0.3.0` - April 25, 2012 277 | 278 | - A new option, `defaultText`, was added to allow users to specify the default text of the dropdown list that is not linked to a specific select box option 279 | 280 | - The `disabled` HTML property is now supported for individual select box options 281 | 282 | - When a user presses the `esc` keyboard key, the dropdown options list will now close (become hidden) 283 | 284 | 285 | `0.2.0` - April 24, 2012 286 | 287 | - This release requires you to use jQuery 1.6.1+. 288 | 289 | - You are no longer required to have select box option values be the same as the select box option text. 290 | 291 | - IE bug fix to prevent default dropdown text from being selectable 292 | 293 | 294 | `0.1.0` - April 14, 2012 295 | 296 | - Initial SelectBoxIt release. Added annotated source code, unit tests, and documentation 297 | 298 | **Contributors** 299 | 300 | Greg Franko - [@gfranko](https://github.com/gfranko) 301 | 302 | Thomas von Deyen - [@tvdeyen](https://github.com/tvdeyen) 303 | 304 | ## License 305 | Copyright (c) 2012 Greg Franko 306 | Licensed under the MIT license. 307 | -------------------------------------------------------------------------------- /test/spec/selectBoxItSpec.js: -------------------------------------------------------------------------------- 1 | describe('selectBoxIt jQuery Plugin', function () { 2 | var selectBoxIt; 3 | 4 | beforeEach(function() { 5 | 6 | setFixtures(''); 7 | 8 | spyOnEvent($("select#test"), "create"); 9 | 10 | selectBoxIt = $("select#test").selectBoxIt().data("selectBoxIt"); 11 | 12 | }); 13 | 14 | describe("create()", function() { 15 | 16 | describe("Creating the new select box HTML", function () { 17 | 18 | it("should hide the original select box", function() { 19 | 20 | expect(selectBoxIt.originalElem).toBeHidden(); 21 | 22 | }); 23 | 24 | it("should create a new dropdown element to replace the original select box", function() { 25 | 26 | expect(selectBoxIt.dropdown).toExist(); 27 | 28 | expect(selectBoxIt.dropdown).toBe("span"); 29 | 30 | expect(selectBoxIt.dropdown).toBeVisible(); 31 | 32 | }); 33 | 34 | it("should add a css class to the new dropdown container element", function() { 35 | 36 | expect(selectBoxIt.dropdownContainer).toHaveClass("selectboxit-container"); 37 | 38 | }); 39 | 40 | it("should add a css class to the new dropdown text element", function() { 41 | 42 | expect(selectBoxIt.dropdownText).toHaveClass("selectboxit-text"); 43 | 44 | }); 45 | 46 | it("should add a css class to the new dropdown icon element", function() { 47 | 48 | expect(selectBoxIt.dropdownImage).toHaveClass("selectboxit-default-icon"); 49 | 50 | }); 51 | 52 | it("should add a css class to the new dropdown arrow element", function() { 53 | 54 | expect(selectBoxIt.downArrowContainer).toHaveClass("selectboxit-arrow-container"); 55 | 56 | }); 57 | 58 | it("should add a css class to the new dropdown arrow container element", function() { 59 | 60 | expect(selectBoxIt.downArrow).toHaveClass("selectboxit-arrow"); 61 | 62 | }); 63 | 64 | it("should add a css class to the new dropdown element", function() { 65 | 66 | expect(selectBoxIt.dropdown).toHaveClass("selectboxit"); 67 | 68 | }); 69 | 70 | it("should add Twitter Bootstrap CSS classes by default", function() { 71 | 72 | expect(selectBoxIt.dropdown).toHaveClass("btn"); 73 | 74 | expect(selectBoxIt.list).toHaveClass("dropdown-menu"); 75 | 76 | }); 77 | 78 | it("should create a new dropdown element to nest inside of the top level dropdown element", function() { 79 | 80 | expect(selectBoxIt.dropdownText).toExist(); 81 | 82 | expect(selectBoxIt.dropdownText).toBe("span"); 83 | 84 | expect(selectBoxIt.dropdown).toContain(selectBoxIt.dropdownText); 85 | 86 | }); 87 | 88 | it("should set the new select box text to the original select box value if the default text option is not set", function() { 89 | 90 | if(!selectBoxIt.defaultText && !selectBoxIt.selectBox.data("text")) { 91 | 92 | expect(selectBoxIt.dropdownText).toHaveText(selectBoxIt.selectBox.val()); 93 | 94 | } 95 | 96 | else { 97 | 98 | expect(selectBoxIt.dropdownText).toHaveText(selectBoxIt.options.defaultText); 99 | 100 | } 101 | 102 | }); 103 | 104 | it("should create a hidden unordered list that contains list items", function() { 105 | 106 | expect(selectBoxIt.list).toExist(); 107 | 108 | expect(selectBoxIt.list).toBe("ul"); 109 | 110 | expect(selectBoxIt.list).toContain(selectBoxIt.listItems); 111 | 112 | }); 113 | 114 | it("should create list items containing select box option values from the original select box", function() { 115 | 116 | expect(selectBoxIt.listItems).toExist(); 117 | 118 | expect(selectBoxIt.listItems).toBe("li"); 119 | 120 | expect(selectBoxIt.list.text()).toEqual(selectBoxIt.selectItems.text()); 121 | 122 | }); 123 | 124 | it("should create a down arrow dropdown container that holds the actual down arrow dropdown element", function() { 125 | 126 | expect(selectBoxIt.downArrowContainer).toExist(); 127 | 128 | expect(selectBoxIt.downArrowContainer).toBe("span"); 129 | 130 | expect(selectBoxIt.downArrowContainer).toContain(selectBoxIt.downArrow); 131 | 132 | }); 133 | 134 | it("should create a down arrow dropdown that holds the down arrow image", function() { 135 | 136 | if(selectBoxIt.options.jqueryUI) { 137 | 138 | expect(selectBoxIt.downArrow).toExist(); 139 | 140 | expect(selectBoxIt.downArrow).toBe("i"); 141 | 142 | } 143 | 144 | }); 145 | 146 | it("should trigger the custom 'create' event", function() { 147 | 148 | expect("create").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 149 | 150 | }); 151 | 152 | it("should not allow a disabled option to be set as the currentFocus", function() { 153 | 154 | expect(selectBoxIt.currentFocus).not.toHaveClass("ui-widget-disabled"); 155 | 156 | }); 157 | }); 158 | 159 | describe('Setting the correct CSS and HTML attributes for the new select box', function () { 160 | 161 | it("should set the dropdown element 'tabindex' attribute to '0'", function() { 162 | 163 | expect(selectBoxIt.dropdown).toHaveAttr("tabindex", 0); 164 | 165 | }); 166 | 167 | it("should set the UL element tabindex attribute to -1", function() { 168 | 169 | expect(selectBoxIt.list).toHaveAttr("tabindex", -1); 170 | 171 | }); 172 | 173 | }); 174 | 175 | }); 176 | 177 | describe("open()", function() { 178 | 179 | beforeEach(function() { 180 | 181 | spyOnEvent(selectBoxIt.selectBox, "open"); 182 | 183 | selectBoxIt.open(); 184 | 185 | }); 186 | 187 | it("should make the select box options list visible", function() { 188 | 189 | expect(selectBoxIt.list).toBeVisible(); 190 | 191 | }); 192 | 193 | }); 194 | 195 | describe("close()", function() { 196 | 197 | beforeEach(function() { 198 | 199 | spyOnEvent(selectBoxIt.selectBox, "close"); 200 | 201 | selectBoxIt.open().close(); 202 | 203 | }); 204 | 205 | it("should trigger a custom 'close' event on the original select box", function() { 206 | 207 | expect("close").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 208 | 209 | }); 210 | 211 | it("should hide the select box options list", function() { 212 | 213 | expect(selectBoxIt.list).toBeHidden(); 214 | 215 | }); 216 | 217 | }); 218 | 219 | describe("moveDown()", function() { 220 | 221 | beforeEach(function() { 222 | 223 | spyOnEvent($("select#test"), "moveDown"); 224 | 225 | }); 226 | 227 | it("should trigger focus and blur events, and update the select box current value", function() { 228 | 229 | selectBoxIt.selectItems.each(function(index) { 230 | 231 | //Cache the previous and next list elements 232 | var previous = selectBoxIt.listItems.eq(selectBoxIt.currentFocus), 233 | 234 | next = selectBoxIt.listItems.eq(selectBoxIt.currentFocus + 1); 235 | 236 | //Spy on the blur event for the previous list item element to be focused 237 | spyOnEvent(previous, "blur"); 238 | 239 | //Spy on the focus event for the next list item element to be focused 240 | spyOnEvent(next, "focusin"); 241 | 242 | //Call the moveUp() method 243 | selectBoxIt.moveDown(); 244 | 245 | //Check to make sure the blur and focus events were properly triggered on the correct elements 246 | 247 | expect("blur").toHaveBeenTriggeredOn(previous); 248 | 249 | expect("focusin").toHaveBeenTriggeredOn(next); 250 | 251 | expect("moveDown").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 252 | 253 | }); 254 | 255 | }); 256 | 257 | }); 258 | 259 | describe("moveUp()", function() { 260 | 261 | beforeEach(function() { 262 | 263 | spyOnEvent($("select#test"), "moveUp"); 264 | 265 | }); 266 | 267 | it("should trigger focus and blur events, and update the select box current value", function() { 268 | 269 | //Sets the select box value to the last select box option 270 | selectBoxIt.currentFocus = +selectBoxIt.listItems.last().attr("id"); 271 | 272 | selectBoxIt.selectItems.each(function(index) { 273 | 274 | //Cache the previous and next list elements 275 | var previous = selectBoxIt.listItems.eq(selectBoxIt.currentFocus), 276 | 277 | next = selectBoxIt.listItems.eq(selectBoxIt.currentFocus - 1); 278 | 279 | //Spy on the blur event for the previous list item element to be focused 280 | spyOnEvent(previous, "blur"); 281 | 282 | //Spy on the focus event for the next list item element to be focused 283 | spyOnEvent(next, "focusin"); 284 | 285 | //Call the moveUp() method 286 | selectBoxIt.moveUp(); 287 | 288 | //Check to make sure the blur and focus events were properly triggered on the correct elements 289 | expect("blur").toHaveBeenTriggeredOn(previous); 290 | 291 | expect("focusin").toHaveBeenTriggeredOn(next); 292 | 293 | expect("moveUp").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 294 | 295 | }); 296 | 297 | }); 298 | 299 | }); 300 | 301 | describe("getOption()", function() { 302 | 303 | it("should return the proper plugin option for each key", function() { 304 | 305 | for(var x in selectBoxIt.options) { 306 | 307 | var key = x, 308 | 309 | value = selectBoxIt.options[x]; 310 | 311 | expect(value).toEqual(selectBoxIt.option(key)); 312 | 313 | } 314 | 315 | }); 316 | 317 | }); 318 | 319 | describe("getOptions()", function() { 320 | 321 | it("should return an object containing all of the plugin options", function() { 322 | 323 | var options = selectBoxIt.options; 324 | 325 | for(var x in selectBoxIt.options) { 326 | 327 | expect(selectBoxIt.options[x]).toEqual(options[x]); 328 | 329 | } 330 | 331 | }); 332 | 333 | }); 334 | 335 | describe("setOption()", function() { 336 | 337 | it("should update an existing plugin option", function() { 338 | 339 | var key = "showEffect", value="slide"; 340 | 341 | selectBoxIt.setOption(key, value); 342 | 343 | expect(selectBoxIt.option(key)).toEqual(value); 344 | 345 | }); 346 | 347 | }); 348 | 349 | describe("setOptions()", function() { 350 | 351 | it("should update multiple plugin options", function() { 352 | 353 | var newOptions = { showEffect: "fadeIn", showEffectSpeed: "medium" }; 354 | 355 | selectBoxIt.setOptions(newOptions); 356 | 357 | expect(selectBoxIt.option("showEffect")).toEqual("fadeIn"); 358 | 359 | expect(selectBoxIt.option("showEffectSpeed")).toEqual("medium"); 360 | 361 | }); 362 | 363 | }); 364 | 365 | describe("disable()", function() { 366 | 367 | beforeEach(function() { 368 | 369 | spyOnEvent(selectBoxIt.selectBox, "disable"); 370 | 371 | selectBoxIt.disable(); 372 | 373 | }); 374 | 375 | it("should trigger a custom 'disable' event", function() { 376 | 377 | expect("disable").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 378 | 379 | }); 380 | 381 | it("should disable the original select box", function() { 382 | 383 | expect(selectBoxIt.selectBox).toBeDisabled(); 384 | 385 | }); 386 | 387 | it("should remove the 'tabindex' html attribute from the select box", function() { 388 | 389 | expect(selectBoxIt.dropdown).not.toHaveAttr("tabindex"); 390 | 391 | }); 392 | 393 | }); 394 | 395 | describe("enable()", function() { 396 | 397 | beforeEach(function() { 398 | 399 | selectBoxIt.disable(); 400 | 401 | spyOnEvent(selectBoxIt.selectBox, "enable"); 402 | 403 | selectBoxIt.enable(); 404 | 405 | }); 406 | 407 | it("should trigger a custom 'enable' event on the original select box", function() { 408 | 409 | expect("enable").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 410 | 411 | }); 412 | 413 | it("should disable the original select box", function() { 414 | 415 | expect(selectBoxIt.selectBox).not.toBeDisabled(); 416 | 417 | }); 418 | 419 | it("should set the 'tabindex' html attribute for the select box to 0", function() { 420 | 421 | expect(selectBoxIt.dropdown).toHaveAttr("tabindex", 0); 422 | 423 | }); 424 | 425 | }); 426 | 427 | describe("destroy()", function() { 428 | 429 | beforeEach(function() { 430 | 431 | spyOn($.fn, "unbind").andCallThrough(); 432 | 433 | spyOn($.fn, "undelegate").andCallThrough(); 434 | 435 | spyOn($.fn, "remove").andCallThrough(); 436 | 437 | spyOnEvent(selectBoxIt.dropdown, "destroy"); 438 | 439 | spyOnEvent(selectBoxIt.selectBox, "destroy"); 440 | 441 | selectBoxIt.destroy(); 442 | 443 | }); 444 | 445 | it("should unbind all of the event handlers associated with the selectBoxIt plugin", function() { 446 | 447 | expect($.fn.unbind).toHaveBeenCalledWith(".selectBoxIt"); 448 | 449 | }); 450 | 451 | it("should undelegate all of the event handlers attached via event delegation with the selectBoxIt plugin", function() { 452 | 453 | expect($.fn.undelegate).toHaveBeenCalledWith(".selectBoxIt"); 454 | 455 | }); 456 | 457 | it("should trigger a custom 'destroy' event on the select box", function() { 458 | 459 | expect("destroy").toHaveBeenTriggeredOn(selectBoxIt.dropdown); 460 | 461 | }); 462 | 463 | it("should trigger a custom 'destroy' event on the original select box", function() { 464 | 465 | expect("destroy").toHaveBeenTriggeredOn(selectBoxIt.selectBox); 466 | 467 | }); 468 | 469 | it("should remove all of the DOM elements created by the selectBoxIt plugin", function() { 470 | 471 | expect($.fn.remove).toHaveBeenCalled(); 472 | 473 | }); 474 | 475 | it("should make the original select box visible", function() { 476 | 477 | expect(selectBoxIt.selectBox).toBeVisible(); 478 | 479 | }); 480 | 481 | }); 482 | 483 | describe("Custom pseudo selector", function() { 484 | 485 | it("should create a custom pseudo selector that returns every select box DOM element that has called the plugin", function() { 486 | 487 | expect($(":selectBox-selectBoxIt")).toBe("select"); 488 | 489 | expect($(":selectBox-selectBoxIt")).toHaveId("test"); 490 | 491 | }); 492 | 493 | }); 494 | 495 | describe("Custom Icons", function() { 496 | 497 | it("should set the default icon if the HTML5 data-icon is specified", function() { 498 | 499 | expect(selectBoxIt.dropdownImage).toHaveClass("ui-icon ui-icon-power"); 500 | 501 | }); 502 | 503 | it("should set the default icon if the defaultIcon option is set using setOption()", function() { 504 | 505 | selectBoxIt.setOption("defaultIcon", "ui-icon ui-icon-info"); 506 | 507 | expect(selectBoxIt.dropdownImage).toHaveClass("ui-icon ui-icon-info"); 508 | 509 | }); 510 | 511 | it("should set the default icon if the defaultIcon option is set using setOptions()", function() { 512 | 513 | selectBoxIt.setOptions({ defaultIcon: "ui-icon ui-icon-info" }); 514 | 515 | expect(selectBoxIt.dropdownImage).toHaveClass("ui-icon ui-icon-info"); 516 | 517 | }); 518 | 519 | it("should set the correct icon for each dropdown option", function() { 520 | 521 | selectBoxIt.selectItems.each(function(index) { 522 | 523 | if($(this).data("icon")) { 524 | 525 | expect(selectBoxIt.listItems.eq(index).find("i")).toHaveClass($(this).data("icon")); 526 | 527 | } 528 | 529 | }); 530 | 531 | }); 532 | 533 | }); 534 | 535 | describe("Setting custom text", function() { 536 | 537 | it("should set the default text if the select box has the HTML5 data-text attribute", function() { 538 | 539 | if(selectBoxIt.selectBox.data("text")) { 540 | 541 | expect(selectBoxIt.dropdownText.text()).toEqual(selectBoxIt.selectBox.data("text")); 542 | 543 | } 544 | 545 | }); 546 | 547 | it("should set the default text if the setOption() method sets the defaultText", function() { 548 | 549 | selectBoxIt.setOption("defaultText", "Testing"); 550 | 551 | expect(selectBoxIt.dropdownText.text()).toEqual("Testing"); 552 | 553 | }); 554 | 555 | it("should set the default text if the setOptions() method sets the defaultText", function() { 556 | 557 | selectBoxIt.setOptions({ defaultText: "Testing" }); 558 | 559 | expect(selectBoxIt.dropdownText.text()).toEqual("Testing"); 560 | 561 | }); 562 | 563 | }); 564 | 565 | describe("selectOption()", function() { 566 | 567 | it("should set the correct dropdown value if an indece is passed", function() { 568 | 569 | selectBoxIt.selectOption(3); 570 | 571 | expect(selectBoxIt.dropdownText.attr("data-val")).toEqual(selectBoxIt.selectBox.val()); 572 | 573 | }); 574 | 575 | it("should set the correct dropdown text if an indece is passed", function() { 576 | 577 | selectBoxIt.selectOption(3); 578 | 579 | expect(selectBoxIt.dropdownText.text()).toEqual(selectBoxIt.selectBox.find("option:selected").text()); 580 | 581 | }); 582 | 583 | it("should set the correct dropdown value if a value is passed", function() { 584 | 585 | selectBoxIt.selectOption("March"); 586 | 587 | expect(selectBoxIt.dropdownText.attr("data-val")).toEqual(selectBoxIt.selectBox.val()); 588 | 589 | }); 590 | 591 | it("should set the correct dropdown text if a value is passed", function() { 592 | 593 | selectBoxIt.selectOption("March"); 594 | 595 | expect(selectBoxIt.dropdownText.text()).toEqual(selectBoxIt.selectBox.find("option:selected").text()); 596 | 597 | }); 598 | 599 | }); 600 | 601 | describe("refresh()", function() { 602 | 603 | it("should dynamically add a drop down option", function() { 604 | 605 | var length = selectBoxIt.selectBox.find("option").length; 606 | 607 | selectBoxIt.selectBox.append(""); 608 | 609 | expect(selectBoxIt.selectBox.find("option").length).toEqual(length + 1); 610 | 611 | }); 612 | 613 | it("should update any drop down option text that changes", function() { 614 | 615 | var elem = selectBoxIt.selectBox.find("option").eq(2); 616 | 617 | elem.text("New Text"); 618 | 619 | selectBoxIt.refresh(); 620 | 621 | expect(selectBoxIt.listItems.eq(2).text()).toEqual(elem.text()); 622 | 623 | }); 624 | 625 | }); 626 | 627 | }); -------------------------------------------------------------------------------- /libs/jasmine/jasmine-html.js: -------------------------------------------------------------------------------- 1 | jasmine.HtmlReporterHelpers = {}; 2 | 3 | jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { 4 | var el = document.createElement(type); 5 | 6 | for (var i = 2; i < arguments.length; i++) { 7 | var child = arguments[i]; 8 | 9 | if (typeof child === 'string') { 10 | el.appendChild(document.createTextNode(child)); 11 | } else { 12 | if (child) { 13 | el.appendChild(child); 14 | } 15 | } 16 | } 17 | 18 | for (var attr in attrs) { 19 | if (attr == "className") { 20 | el[attr] = attrs[attr]; 21 | } else { 22 | el.setAttribute(attr, attrs[attr]); 23 | } 24 | } 25 | 26 | return el; 27 | }; 28 | 29 | jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { 30 | var results = child.results(); 31 | var status = results.passed() ? 'passed' : 'failed'; 32 | if (results.skipped) { 33 | status = 'skipped'; 34 | } 35 | 36 | return status; 37 | }; 38 | 39 | jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { 40 | var parentDiv = this.dom.summary; 41 | var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; 42 | var parent = child[parentSuite]; 43 | 44 | if (parent) { 45 | if (typeof this.views.suites[parent.id] == 'undefined') { 46 | this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); 47 | } 48 | parentDiv = this.views.suites[parent.id].element; 49 | } 50 | 51 | parentDiv.appendChild(childElement); 52 | }; 53 | 54 | 55 | jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { 56 | for(var fn in jasmine.HtmlReporterHelpers) { 57 | ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; 58 | } 59 | }; 60 | 61 | jasmine.HtmlReporter = function(_doc) { 62 | var self = this; 63 | var doc = _doc || window.document; 64 | 65 | var reporterView; 66 | 67 | var dom = {}; 68 | 69 | // Jasmine Reporter Public Interface 70 | self.logRunningSpecs = false; 71 | 72 | self.reportRunnerStarting = function(runner) { 73 | var specs = runner.specs() || []; 74 | 75 | if (specs.length == 0) { 76 | return; 77 | } 78 | 79 | createReporterDom(runner.env.versionString()); 80 | doc.body.appendChild(dom.reporter); 81 | 82 | reporterView = new jasmine.HtmlReporter.ReporterView(dom); 83 | reporterView.addSpecs(specs, self.specFilter); 84 | }; 85 | 86 | self.reportRunnerResults = function(runner) { 87 | reporterView && reporterView.complete(); 88 | }; 89 | 90 | self.reportSuiteResults = function(suite) { 91 | reporterView.suiteComplete(suite); 92 | }; 93 | 94 | self.reportSpecStarting = function(spec) { 95 | if (self.logRunningSpecs) { 96 | self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 97 | } 98 | }; 99 | 100 | self.reportSpecResults = function(spec) { 101 | reporterView.specComplete(spec); 102 | }; 103 | 104 | self.log = function() { 105 | var console = jasmine.getGlobal().console; 106 | if (console && console.log) { 107 | if (console.log.apply) { 108 | console.log.apply(console, arguments); 109 | } else { 110 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 111 | } 112 | } 113 | }; 114 | 115 | self.specFilter = function(spec) { 116 | if (!focusedSpecName()) { 117 | return true; 118 | } 119 | 120 | return spec.getFullName().indexOf(focusedSpecName()) === 0; 121 | }; 122 | 123 | return self; 124 | 125 | function focusedSpecName() { 126 | var specName; 127 | 128 | (function memoizeFocusedSpec() { 129 | if (specName) { 130 | return; 131 | } 132 | 133 | var paramMap = []; 134 | var params = doc.location.search.substring(1).split('&'); 135 | 136 | for (var i = 0; i < params.length; i++) { 137 | var p = params[i].split('='); 138 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 139 | } 140 | 141 | specName = paramMap.spec; 142 | })(); 143 | 144 | return specName; 145 | } 146 | 147 | function createReporterDom(version) { 148 | dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, 149 | dom.banner = self.createDom('div', { className: 'banner' }, 150 | self.createDom('span', { className: 'title' }, "Jasmine "), 151 | self.createDom('span', { className: 'version' }, version)), 152 | 153 | dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), 154 | dom.alert = self.createDom('div', {className: 'alert'}), 155 | dom.results = self.createDom('div', {className: 'results'}, 156 | dom.summary = self.createDom('div', { className: 'summary' }), 157 | dom.details = self.createDom('div', { id: 'details' })) 158 | ); 159 | } 160 | }; 161 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) { 162 | this.startedAt = new Date(); 163 | this.runningSpecCount = 0; 164 | this.completeSpecCount = 0; 165 | this.passedCount = 0; 166 | this.failedCount = 0; 167 | this.skippedCount = 0; 168 | 169 | this.createResultsMenu = function() { 170 | this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, 171 | this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), 172 | ' | ', 173 | this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); 174 | 175 | this.summaryMenuItem.onclick = function() { 176 | dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); 177 | }; 178 | 179 | this.detailsMenuItem.onclick = function() { 180 | showDetails(); 181 | }; 182 | }; 183 | 184 | this.addSpecs = function(specs, specFilter) { 185 | this.totalSpecCount = specs.length; 186 | 187 | this.views = { 188 | specs: {}, 189 | suites: {} 190 | }; 191 | 192 | for (var i = 0; i < specs.length; i++) { 193 | var spec = specs[i]; 194 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); 195 | if (specFilter(spec)) { 196 | this.runningSpecCount++; 197 | } 198 | } 199 | }; 200 | 201 | this.specComplete = function(spec) { 202 | this.completeSpecCount++; 203 | 204 | if (isUndefined(this.views.specs[spec.id])) { 205 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); 206 | } 207 | 208 | var specView = this.views.specs[spec.id]; 209 | 210 | switch (specView.status()) { 211 | case 'passed': 212 | this.passedCount++; 213 | break; 214 | 215 | case 'failed': 216 | this.failedCount++; 217 | break; 218 | 219 | case 'skipped': 220 | this.skippedCount++; 221 | break; 222 | } 223 | 224 | specView.refresh(); 225 | this.refresh(); 226 | }; 227 | 228 | this.suiteComplete = function(suite) { 229 | var suiteView = this.views.suites[suite.id]; 230 | if (isUndefined(suiteView)) { 231 | return; 232 | } 233 | suiteView.refresh(); 234 | }; 235 | 236 | this.refresh = function() { 237 | 238 | if (isUndefined(this.resultsMenu)) { 239 | this.createResultsMenu(); 240 | } 241 | 242 | // currently running UI 243 | if (isUndefined(this.runningAlert)) { 244 | this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"}); 245 | dom.alert.appendChild(this.runningAlert); 246 | } 247 | this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); 248 | 249 | // skipped specs UI 250 | if (isUndefined(this.skippedAlert)) { 251 | this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"}); 252 | } 253 | 254 | this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 255 | 256 | if (this.skippedCount === 1 && isDefined(dom.alert)) { 257 | dom.alert.appendChild(this.skippedAlert); 258 | } 259 | 260 | // passing specs UI 261 | if (isUndefined(this.passedAlert)) { 262 | this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"}); 263 | } 264 | this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); 265 | 266 | // failing specs UI 267 | if (isUndefined(this.failedAlert)) { 268 | this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); 269 | } 270 | this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); 271 | 272 | if (this.failedCount === 1 && isDefined(dom.alert)) { 273 | dom.alert.appendChild(this.failedAlert); 274 | dom.alert.appendChild(this.resultsMenu); 275 | } 276 | 277 | // summary info 278 | this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); 279 | this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; 280 | }; 281 | 282 | this.complete = function() { 283 | dom.alert.removeChild(this.runningAlert); 284 | 285 | this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 286 | 287 | if (this.failedCount === 0) { 288 | dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); 289 | } else { 290 | showDetails(); 291 | } 292 | 293 | dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); 294 | }; 295 | 296 | return this; 297 | 298 | function showDetails() { 299 | if (dom.reporter.className.search(/showDetails/) === -1) { 300 | dom.reporter.className += " showDetails"; 301 | } 302 | } 303 | 304 | function isUndefined(obj) { 305 | return typeof obj === 'undefined'; 306 | } 307 | 308 | function isDefined(obj) { 309 | return !isUndefined(obj); 310 | } 311 | 312 | function specPluralizedFor(count) { 313 | var str = count + " spec"; 314 | if (count > 1) { 315 | str += "s" 316 | } 317 | return str; 318 | } 319 | 320 | }; 321 | 322 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); 323 | 324 | 325 | jasmine.HtmlReporter.SpecView = function(spec, dom, views) { 326 | this.spec = spec; 327 | this.dom = dom; 328 | this.views = views; 329 | 330 | this.symbol = this.createDom('li', { className: 'pending' }); 331 | this.dom.symbolSummary.appendChild(this.symbol); 332 | 333 | this.summary = this.createDom('div', { className: 'specSummary' }, 334 | this.createDom('a', { 335 | className: 'description', 336 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), 337 | title: this.spec.getFullName() 338 | }, this.spec.description) 339 | ); 340 | 341 | this.detail = this.createDom('div', { className: 'specDetail' }, 342 | this.createDom('a', { 343 | className: 'description', 344 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), 345 | title: this.spec.getFullName() 346 | }, this.spec.getFullName()) 347 | ); 348 | }; 349 | 350 | jasmine.HtmlReporter.SpecView.prototype.status = function() { 351 | return this.getSpecStatus(this.spec); 352 | }; 353 | 354 | jasmine.HtmlReporter.SpecView.prototype.refresh = function() { 355 | this.symbol.className = this.status(); 356 | 357 | switch (this.status()) { 358 | case 'skipped': 359 | break; 360 | 361 | case 'passed': 362 | this.appendSummaryToSuiteDiv(); 363 | break; 364 | 365 | case 'failed': 366 | this.appendSummaryToSuiteDiv(); 367 | this.appendFailureDetail(); 368 | break; 369 | } 370 | }; 371 | 372 | jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { 373 | this.summary.className += ' ' + this.status(); 374 | this.appendToSummary(this.spec, this.summary); 375 | }; 376 | 377 | jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { 378 | this.detail.className += ' ' + this.status(); 379 | 380 | var resultItems = this.spec.results().getItems(); 381 | var messagesDiv = this.createDom('div', { className: 'messages' }); 382 | 383 | for (var i = 0; i < resultItems.length; i++) { 384 | var result = resultItems[i]; 385 | 386 | if (result.type == 'log') { 387 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 388 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 389 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 390 | 391 | if (result.trace.stack) { 392 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 393 | } 394 | } 395 | } 396 | 397 | if (messagesDiv.childNodes.length > 0) { 398 | this.detail.appendChild(messagesDiv); 399 | this.dom.details.appendChild(this.detail); 400 | } 401 | }; 402 | 403 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { 404 | this.suite = suite; 405 | this.dom = dom; 406 | this.views = views; 407 | 408 | this.element = this.createDom('div', { className: 'suite' }, 409 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description) 410 | ); 411 | 412 | this.appendToSummary(this.suite, this.element); 413 | }; 414 | 415 | jasmine.HtmlReporter.SuiteView.prototype.status = function() { 416 | return this.getSpecStatus(this.suite); 417 | }; 418 | 419 | jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { 420 | this.element.className += " " + this.status(); 421 | }; 422 | 423 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); 424 | 425 | /* @deprecated Use jasmine.HtmlReporter instead 426 | */ 427 | jasmine.TrivialReporter = function(doc) { 428 | this.document = doc || document; 429 | this.suiteDivs = {}; 430 | this.logRunningSpecs = false; 431 | }; 432 | 433 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 434 | var el = document.createElement(type); 435 | 436 | for (var i = 2; i < arguments.length; i++) { 437 | var child = arguments[i]; 438 | 439 | if (typeof child === 'string') { 440 | el.appendChild(document.createTextNode(child)); 441 | } else { 442 | if (child) { el.appendChild(child); } 443 | } 444 | } 445 | 446 | for (var attr in attrs) { 447 | if (attr == "className") { 448 | el[attr] = attrs[attr]; 449 | } else { 450 | el.setAttribute(attr, attrs[attr]); 451 | } 452 | } 453 | 454 | return el; 455 | }; 456 | 457 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 458 | var showPassed, showSkipped; 459 | 460 | this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, 461 | this.createDom('div', { className: 'banner' }, 462 | this.createDom('div', { className: 'logo' }, 463 | this.createDom('span', { className: 'title' }, "Jasmine"), 464 | this.createDom('span', { className: 'version' }, runner.env.versionString())), 465 | this.createDom('div', { className: 'options' }, 466 | "Show ", 467 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 468 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 469 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 470 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 471 | ) 472 | ), 473 | 474 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 475 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 476 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 477 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 478 | ); 479 | 480 | this.document.body.appendChild(this.outerDiv); 481 | 482 | var suites = runner.suites(); 483 | for (var i = 0; i < suites.length; i++) { 484 | var suite = suites[i]; 485 | var suiteDiv = this.createDom('div', { className: 'suite' }, 486 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 487 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 488 | this.suiteDivs[suite.id] = suiteDiv; 489 | var parentDiv = this.outerDiv; 490 | if (suite.parentSuite) { 491 | parentDiv = this.suiteDivs[suite.parentSuite.id]; 492 | } 493 | parentDiv.appendChild(suiteDiv); 494 | } 495 | 496 | this.startedAt = new Date(); 497 | 498 | var self = this; 499 | showPassed.onclick = function(evt) { 500 | if (showPassed.checked) { 501 | self.outerDiv.className += ' show-passed'; 502 | } else { 503 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 504 | } 505 | }; 506 | 507 | showSkipped.onclick = function(evt) { 508 | if (showSkipped.checked) { 509 | self.outerDiv.className += ' show-skipped'; 510 | } else { 511 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 512 | } 513 | }; 514 | }; 515 | 516 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 517 | var results = runner.results(); 518 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 519 | this.runnerDiv.setAttribute("class", className); 520 | //do it twice for IE 521 | this.runnerDiv.setAttribute("className", className); 522 | var specs = runner.specs(); 523 | var specCount = 0; 524 | for (var i = 0; i < specs.length; i++) { 525 | if (this.specFilter(specs[i])) { 526 | specCount++; 527 | } 528 | } 529 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 530 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 531 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 532 | 533 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 534 | }; 535 | 536 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 537 | var results = suite.results(); 538 | var status = results.passed() ? 'passed' : 'failed'; 539 | if (results.totalCount === 0) { // todo: change this to check results.skipped 540 | status = 'skipped'; 541 | } 542 | this.suiteDivs[suite.id].className += " " + status; 543 | }; 544 | 545 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 546 | if (this.logRunningSpecs) { 547 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 548 | } 549 | }; 550 | 551 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 552 | var results = spec.results(); 553 | var status = results.passed() ? 'passed' : 'failed'; 554 | if (results.skipped) { 555 | status = 'skipped'; 556 | } 557 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 558 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 559 | this.createDom('a', { 560 | className: 'description', 561 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 562 | title: spec.getFullName() 563 | }, spec.description)); 564 | 565 | 566 | var resultItems = results.getItems(); 567 | var messagesDiv = this.createDom('div', { className: 'messages' }); 568 | for (var i = 0; i < resultItems.length; i++) { 569 | var result = resultItems[i]; 570 | 571 | if (result.type == 'log') { 572 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 573 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 574 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 575 | 576 | if (result.trace.stack) { 577 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 578 | } 579 | } 580 | } 581 | 582 | if (messagesDiv.childNodes.length > 0) { 583 | specDiv.appendChild(messagesDiv); 584 | } 585 | 586 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 587 | }; 588 | 589 | jasmine.TrivialReporter.prototype.log = function() { 590 | var console = jasmine.getGlobal().console; 591 | if (console && console.log) { 592 | if (console.log.apply) { 593 | console.log.apply(console, arguments); 594 | } else { 595 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 596 | } 597 | } 598 | }; 599 | 600 | jasmine.TrivialReporter.prototype.getLocation = function() { 601 | return this.document.location; 602 | }; 603 | 604 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 605 | var paramMap = {}; 606 | var params = this.getLocation().search.substring(1).split('&'); 607 | for (var i = 0; i < params.length; i++) { 608 | var p = params[i].split('='); 609 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 610 | } 611 | 612 | if (!paramMap.spec) { 613 | return true; 614 | } 615 | return spec.getFullName().indexOf(paramMap.spec) === 0; 616 | }; 617 | -------------------------------------------------------------------------------- /src/javascripts/jquery.selectBoxIt.min.js: -------------------------------------------------------------------------------- 1 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.widget("selectBox.selectBoxIt",{VERSION:"2.9.9",options:{showEffect:"none",showEffectOptions:{},showEffectSpeed:"medium",hideEffect:"none",hideEffectOptions:{},hideEffectSpeed:"medium",showFirstOption:!0,defaultText:"",defaultIcon:"",downArrowIcon:"",theme:"bootstrap",keydownOpen:!0,isMobile:function(){var e=navigator.userAgent||navigator.vendor||t.opera;return/iPhone|iPod|iPad|Android|BlackBerry|Opera Mini|IEMobile/.test(e)},nostyle:!1,"native":!1,aggressiveChange:!1,selectWhenHidden:!0},_create:function(){var t=this;if(!t.element.is("select"))return;return t.originalElem=t.element[0],t.selectBox=t.element,t.selectItems=t.element.find("option"),t.firstSelectItem=t.element.find("option").slice(0,1),t.currentFocus=0,t.blur=!0,t.documentHeight=e(n).height(),t.textArray=[],t.currentIndex=0,t.flipped=!1,t.disabledClasses=function(){return t.options.theme==="bootstrap"?"disabled":t.options.theme==="jqueryui"?"ui-state-disabled":t.options.theme==="jquerymobile"?"ui-disabled":"selectboxit-disabled"}(),t._createdropdown()._createUnorderedList()._addSelectBoxAttributes()._replaceSelectBox()._eventHandlers(),t.originalElem.disabled&&t.disable&&t.disable(),t._ariaAccessibility&&t._ariaAccessibility(),t.options.theme==="bootstrap"?t._twitterbootstrap():this.options.theme==="jqueryui"?t._jqueryui():this.options.theme==="jquerymobile"?t._jquerymobile():t._addClasses(),t._mobile(),t.options["native"]&&this._applyNativeSelect(),t.triggerEvent("create"),t},_createdropdown:function(){var t=this;return t.dropdownText=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItText","class":"selectboxit-text",unselectable:"on",text:t.firstSelectItem.text()}).attr("data-val",t.originalElem.value),t.dropdownImage=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItDefaultIcon","class":"selectboxit-default-icon",unselectable:"on"}),t.dropdown=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxIt","class":"selectboxit "+(t.selectBox.attr("class")||""),name:t.originalElem.name,tabindex:t.selectBox.attr("tabindex")||"0",unselectable:"on"}).append(t.dropdownImage).append(t.dropdownText),t.dropdownContainer=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItContainer","class":"selectboxit-container"}).append(t.dropdown),t},_createUnorderedList:function(){var t=this,n,r,i,s,o,u,a,f="",l=e("
      ",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItOptions","class":"selectboxit-options",tabindex:-1});t.options.showFirstOption||(t.selectItems=t.selectBox.find("option").slice(1)),t.selectItems.each(function(l){r="",i="",n=e(this).prop("disabled"),s=e(this).data("icon")||"",o=e(this).data("iconurl")||"",u=o?"selectboxit-option-icon-url":"",a=o?"style=\"background-image:url('"+o+"');\"":"",e(this).parent().is("optgroup")&&(r="selectboxit-optgroup-option",e(this).index()===0&&(i=''+e(this).parent().first().attr("label")+"")),f+=i+'
    • "+t.htmlEscape(e(this).text())+"
    • ",t.textArray[l]=n?"":e(this).text(),this.selected&&(t.dropdownText.text(e(this).text()),t.currentFocus=l)});if((t.options.defaultText||t.selectBox.data("text"))&&!t.selectBox.find("option[selected]").length){var c=t.options.defaultText||t.selectBox.data("text");t.dropdownText.text(c),t.options.defaultText=c}return l.append(f),t.list=l,t.dropdownContainer.append(t.list),t.listItems=t.list.find("li"),t.listItems.first().addClass("selectboxit-option-first"),t.listItems.last().addClass("selectboxit-option-last"),t.list.find("li[data-disabled='true']").not(".optgroupHeader").addClass(t.disabledClasses),t.currentFocus===0&&!t.options.showFirstOption&&t.listItems.eq(0).hasClass(t.disabledClasses)&&(t.currentFocus=+t.listItems.not(".ui-state-disabled").first().attr("id")),t.dropdownImage.addClass(t.selectBox.data("icon")||t.options.defaultIcon||t.listItems.eq(t.currentFocus).find("i").attr("class")),t.dropdownImage.attr("style",t.listItems.eq(t.currentFocus).find("i").attr("style")),t},_replaceSelectBox:function(){var t=this;t.selectBox.css("display","none").after(t.dropdownContainer);var n=t.dropdown.height();return t.downArrow=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItArrow","class":"selectboxit-arrow",unselectable:"on"}),t.downArrowContainer=e("",{id:(t.originalElem.id||"")&&t.originalElem.id+"SelectBoxItArrowContainer","class":"selectboxit-arrow-container",unselectable:"on"}).append(t.downArrow),t.dropdown.append(this.options.nostyle?t.downArrow:t.downArrowContainer),t.options.nostyle||(t.downArrowContainer.css({height:n+"px"}),t.dropdownText.css({"line-height":t.dropdown.css("height"),"max-width":t.dropdown.outerWidth()-(t.downArrowContainer.outerWidth()+t.dropdownImage.outerWidth())}),t.dropdownImage.css({"margin-top":n/4}),t.listItems.removeClass("selectboxit-selected").eq(t.currentFocus).addClass("selectboxit-selected")),t},_scrollToView:function(e){var t=this,n=t.list.scrollTop(),r=t.listItems.eq(t.currentFocus).height(),i=t.listItems.eq(t.currentFocus).position().top,s=t.list.height();return e==="search"?s-i/g,">")},triggerEvent:function(e){var t=this,n=t.options.showFirstOption?t.currentFocus:t.currentFocus-1>=0?t.currentFocus:0;return t.selectBox.trigger(e,{elem:t.selectBox.eq(n),"dropdown-elem":t.listItems.eq(t.currentFocus)}),t},_addSelectBoxAttributes:function(t){var n=this;return n._addAttributes(n.selectBox.prop("attributes"),n.dropdown),n.selectItems.each(function(t){n._addAttributes(e(this).prop("attributes"),n.listItems.eq(t))}),n},_addAttributes:function(t,n){var r=this,i=["title","rel"];return t.length&&e.each(t,function(t,r){var s=r.name.toLowerCase(),o=r.value;o!=="null"&&(e.inArray(s,i)!==-1||s.indexOf("data")!==-1)&&n.attr(s,o)}),r}})}); 2 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype._ariaAccessibility=function(){var t=this;return t.dropdown.attr({role:"combobox","aria-autocomplete":"list","aria-expanded":"false","aria-owns":t.list.attr("id"),"aria-activedescendant":t.listItems.eq(t.currentFocus).attr("id"),"aria-label":e("label[for='"+t.originalElem.id+"']").text()||"","aria-live":"assertive"}).bind({"disable.selectBoxIt":function(){t.dropdown.attr("aria-disabled","true")},"enable.selectBoxIt":function(){t.dropdown.attr("aria-disabled","false")}}),t.list.attr({role:"listbox","aria-hidden":"true"}),t.listItems.attr({role:"option"}),t.selectBox.bind({"change.selectBoxIt":function(){t.dropdownText.attr("aria-label",t.originalElem.value)},"open.selectBoxIt":function(){t.list.attr("aria-hidden","false"),t.dropdown.attr("aria-expanded","true")},"close.selectBoxIt":function(){t.list.attr("aria-hidden","true"),t.dropdown.attr("aria-expanded","false")}}),t}}); 3 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype.disable=function(t){var n=this;return n.options.disabled||(n.close(),n.triggerEvent("disable"),n.selectBox.attr("disabled","disabled"),n.dropdown.removeAttr("tabindex").addClass("selectboxit-disabled"),e.Widget.prototype.disable.call(n)),n._callbackSupport(t),n},e.selectBox.selectBoxIt.prototype.disableOption=function(e,t){var n=this,r,i,s;return typeof e=="number"&&(n.close(),r=n.selectBox.find("option").eq(e),n.triggerEvent("disable-option"),r.attr("disabled","disabled"),n.listItems.eq(e).attr("data-disabled","true").addClass(n.disabledClasses),n.currentFocus===e&&(i=n.listItems.eq(n.currentFocus).nextAll("li").not("[data-disabled='true']").first().length,s=n.listItems.eq(n.currentFocus).prevAll("li").not("[data-disabled='true']").first().length,i?n.moveDown():s?n.moveUp():n.disable())),n._callbackSupport(t),n},e.selectBox.selectBoxIt.prototype._isDisabled=function(e){var t=this;return t.originalElem.disabled&&t.disable(),t}}); 4 | (function(e){"use strict";e(window.jQuery,window,document)})(function(e,t,n,r){"use strict";e.selectBox.selectBoxIt.prototype._dynamicPositioning=function(){var n=this,r=n.dropdown.offset().top,i=n.list.data("max-height")||n.list.outerHeight(),s=n.dropdown.outerHeight(),o=e(t).height(),u=e(t).scrollTop(),a=r+s+i<=o+u,f=!a;n.list.data("max-height")||n.list.data("max-height",n.list.outerHeight()),n.selectBox.css("display","none");if(!f)n.list.css("max-height",n.list.data("max-height")),n.list.css("top","auto");else if(n.dropdown.offset().top-u>=i)n.list.css("max-height",n.list.data("max-height")),n.list.css("top",n.dropdown.position().top-n.list.outerHeight());else{var l=Math.abs(r+s+i-(o+u)),c=Math.abs(n.dropdown.offset().top-u-i);l