From cad5e703f8b148a40ad4bb19da6ca63d867c9584 Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Tue, 8 Sep 2015 14:06:00 +0000 Subject: [PATCH] Cosmetics: - Better use of the space in the search form: multi-select drop down list are now small when closed and larger when opened - Nicer feedback when hiding/showing sections in the "printable version" of a details page. SVN:trunk[3732] --- application/itopwebpage.class.inc.php | 7 +- application/portalwebpage.class.inc.php | 2 +- css/jquery.multiselect.css | 3 +- css/light-grey.css | 30 +- css/light-grey.scss | 23 +- images/eye-closed-555.png | Bin 0 -> 274 bytes images/eye-closed-fff.png | Bin 0 -> 237 bytes images/eye-open-555.png | Bin 0 -> 355 bytes images/eye-open-fff.png | Bin 0 -> 327 bytes js/jquery.multiselect.js | 745 ++++++++++++++++++++++++ js/jquery.multiselect.min.js | 20 - 11 files changed, 803 insertions(+), 27 deletions(-) create mode 100755 images/eye-closed-555.png create mode 100755 images/eye-closed-fff.png create mode 100755 images/eye-open-555.png create mode 100755 images/eye-open-fff.png create mode 100644 js/jquery.multiselect.js delete mode 100644 js/jquery.multiselect.min.js diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index 2d25b5a89..739cba9b5 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -73,7 +73,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage $this->add_linked_script('../js/g.pie.js'); $this->add_linked_script('../js/g.dot.js'); $this->add_linked_script('../js/charts.js'); - $this->add_linked_script('../js/jquery.multiselect.min.js'); + $this->add_linked_script('../js/jquery.multiselect.js'); $this->add_linked_script('../js/ajaxfileupload.js'); $this->add_linked_script('../js/jquery.mousewheel.js'); @@ -728,6 +728,11 @@ $('.hideable-chapter').click(function(){ $('#'+sChapterId).toggle(); $(this).toggleClass('strikethrough'); }); +$('fieldset').each(function() { + var jLegend = $(this).find('legend'); + jLegend.remove(); + $(this).wrapInner('').prepend(jLegend); +}); $('legend').css('cursor', 'pointer').click(function(){ $(this).parent('fieldset').toggleClass('not-printable strikethrough'); }); diff --git a/application/portalwebpage.class.inc.php b/application/portalwebpage.class.inc.php index 16e7d905d..93b86f180 100644 --- a/application/portalwebpage.class.inc.php +++ b/application/portalwebpage.class.inc.php @@ -88,7 +88,7 @@ class PortalWebPage extends NiceWebPage $this->add_linked_script("../js/forms-json-utils.js"); $this->add_linked_script("../js/swfobject.js"); $this->add_linked_script("../js/jquery.qtip-1.0.min.js"); - $this->add_linked_script('../js/jquery.multiselect.min.js'); + $this->add_linked_script('../js/jquery.multiselect.js'); $this->add_linked_script("../js/ajaxfileupload.js"); $this->add_linked_script("../js/ckeditor/ckeditor.js"); $this->add_linked_script("../js/ckeditor/adapters/jquery.js"); diff --git a/css/jquery.multiselect.css b/css/jquery.multiselect.css index 898786a61..65f64ae17 100644 --- a/css/jquery.multiselect.css +++ b/css/jquery.multiselect.css @@ -1,4 +1,5 @@ -.ui-multiselect { padding:2px 0 2px 4px; text-align:left } +.ui-multiselect { padding:2px 0 2px 4px; text-align:left; white-space:nowrap; overflow:hidden; } +button.ui-multiselect > span { overflow:hidden; } .ui-multiselect span.ui-icon { float:right } .ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; } .ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important } diff --git a/css/light-grey.css b/css/light-grey.css index 095d6944d..0a2cd2e45 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -2021,8 +2021,31 @@ div.explain-printable { } -.hideable-chapter.strikethrough span.ui-tabs-anchor { +#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter span { + padding-left: 20px; + background: url(../images/eye-open-555.png) 2px center no-repeat; +} + + +#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter.strikethrough span { text-decoration: line-through; + background: url(../images/eye-closed-555.png) 2px center no-repeat; +} + + +.printable-version legend { + padding-left: 26px; + background: #1c94c4 url(../images/eye-open-fff.png) 8px center no-repeat; +} + + +.printable-version .strikethrough legend { + background: #1c94c4 url(../images/eye-closed-fff.png) 8px center no-repeat; +} + + +.printable-version fieldset.strikethrough span { + display: none; } @@ -2031,3 +2054,8 @@ div.explain-printable { } +select.multiselect { + max-width: 150px; +} + + diff --git a/css/light-grey.scss b/css/light-grey.scss index 6e1126cc2..4f1ab67d1 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -1494,11 +1494,28 @@ div.explain-printable { .hideable-chapter { cursor: pointer; } - -.hideable-chapter.strikethrough span.ui-tabs-anchor { - text-decoration: line-through; +#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter span { + padding-left: 20px; + background: url(../images/eye-open-555.png) 2px center no-repeat; } +#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter.strikethrough span { + text-decoration: line-through; + background: url(../images/eye-closed-555.png) 2px center no-repeat; +} +.printable-version legend { + padding-left: 26px; + background: $complement-color url(../images/eye-open-fff.png) 8px center no-repeat; +} +.printable-version .strikethrough legend { + background: $complement-color url(../images/eye-closed-fff.png) 8px center no-repeat; +} +.printable-version fieldset.strikethrough span { + display: none; +} .strikethrough { text-decoration: line-through; } +select.multiselect { + max-width: 150px; +} \ No newline at end of file diff --git a/images/eye-closed-555.png b/images/eye-closed-555.png new file mode 100755 index 0000000000000000000000000000000000000000..6366701c3a8d33ccab6ee3a10b592327259d3754 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xws^WYhE&{2`t|?6J+tbJ&PFGLtOE%K4TdHrU+gEuF&ybs zd11`(=&!>c#wShO4s#feu)1W0F+BR|pu=#aRe@P%VcQqxk5x>wm>YiBTwzrZ&rfJ9 za;RVqIas}7I$zVAjwdPg3S|yL)eK4z3+gmmb}^+KU|dmtVec0Puj5P`xkBWXPcXQx zI8txYY}L3!=GD=^0qV^$ng01v;Lb3>*dwdlyBR UFZ;m733NY$r>mdKI;Vst02p{=6951J literal 0 HcmV?d00001 diff --git a/images/eye-closed-fff.png b/images/eye-closed-fff.png new file mode 100755 index 0000000000000000000000000000000000000000..765064b1add0e348c751fa4d5f9eb8469e7c2645 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X`aNA7Ln>}1{rdmko>_H9XQPur)`0}W2lfKz)dS}<3hZZp z^n1aPf`9fbA_6ljL?(P;X<%WQz;aFaf(*lv_Y1Rx9g=hco;Q48Q{Zc`%4HOgXL-c$ z;rER_iCtwQdxFr(pL`zc4zRs*&XiwKC6M4yCb!E`HsBUxXIpklV$Q!7$&|h&63)sz h#!bEp85me37@kk_o#(Li2p`aC44$rjF6*2UngBHOP^l$V#+*Vot7)b#iFPn|lotE=nFmoKHIr3ncMt5&VLa^*^BXz2g{|Jhj< zJAv&E@(TuXu>uB06Rzz*MV+25jv*DdQu=T69ai9R=3QFyomcA7pa0YK8ni-Z%PYyU zGq?Tas5ROAe8%OBW%_$xIk&SO_fDJsWOnq0>cS7jcdJ$}e0PVxFNW9p`muvc^qF^9 z_%3r~`E$c;;!(3sInQlp!W-m1#;nx*CFl5SX&84Z=PJ$MLw|Nn6YN|o7kel8=*m0s fw>R%&;$b*-UBs}?{n1aLqZmA0{an^LB{Ts5_CBSe literal 0 HcmV?d00001 diff --git a/images/eye-open-fff.png b/images/eye-open-fff.png new file mode 100755 index 0000000000000000000000000000000000000000..b118f2b3fa0e7459552edca302eb4f4b38e1bf96 GIT binary patch literal 327 zcmV-N0l5B&P)8KqK7++)-8o4rRl%pLljt?8hfW0H~C!H6b9nDN2lsGrKLN^&?jvY3;72+Q8 z$s2UEP?15MXoU|f1VIClH%N)Sd5&rZ{|Xt#JH|@lxXtoE+(HTW=FcnSV9)~hWH2x3 zvi$leEMOE|qBk*gQiEg-mh?Xc>tl3R2acGL)-~xL|qm>m2a)002ovPDHLkV1g2He)0eS literal 0 HcmV?d00001 diff --git a/js/jquery.multiselect.js b/js/jquery.multiselect.js new file mode 100644 index 000000000..0d59afcf2 --- /dev/null +++ b/js/jquery.multiselect.js @@ -0,0 +1,745 @@ +/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */ +/* + * jQuery MultiSelect UI Widget 1.14pre + * Copyright (c) 2012 Eric Hynds + * + * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/ + * + * Depends: + * - jQuery 1.4.2+ + * - jQuery UI 1.8 widget factory + * + * Optional: + * - jQuery UI effects + * - jQuery UI position utility + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Patched by Denis Flaven to add the minWidthButton option + * + */ +(function($, undefined) { + + var multiselectID = 0; + var $doc = $(document); + + $.widget("ech.multiselect", { + + // default options + options: { + header: true, + height: 175, + minWidthButton: 150, + minWidth: 250, + classes: '', + checkAllText: 'Check all', + uncheckAllText: 'Uncheck all', + noneSelectedText: 'Select options', + selectedText: '# selected', + selectedList: 0, + show: null, + hide: null, + autoOpen: false, + multiple: true, + position: {}, + appendTo: "body" + }, + + _create: function() { + var el = this.element.hide(); + var o = this.options; + + this.speed = $.fx.speeds._default; // default speed for effects + this._isOpen = false; // assume no + + // create a unique namespace for events that the widget + // factory cannot unbind automatically. Use eventNamespace if on + // jQuery UI 1.9+, and otherwise fallback to a custom string. + this._namespaceID = this.eventNamespace || ('multiselect' + multiselectID); + + var button = (this.button = $('')) + .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all') + .addClass(o.classes) + .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') }) + .insertAfter(el), + + buttonlabel = (this.buttonlabel = $('')) + .html(o.noneSelectedText) + .appendTo(button), + + menu = (this.menu = $('
')) + .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all') + .addClass(o.classes) + .appendTo($(o.appendTo)), + + header = (this.header = $('
')) + .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix') + .appendTo(menu), + + headerLinkContainer = (this.headerLinkContainer = $('
    ')) + .addClass('ui-helper-reset') + .html(function() { + if(o.header === true) { + return '
  • ' + o.checkAllText + '
  • ' + o.uncheckAllText + '
  • '; + } else if(typeof o.header === "string") { + return '
  • ' + o.header + '
  • '; + } else { + return ''; + } + }) + .append('
  • ') + .appendTo(header), + + checkboxContainer = (this.checkboxContainer = $('
      ')) + .addClass('ui-multiselect-checkboxes ui-helper-reset') + .appendTo(menu); + + // perform event bindings + this._bindEvents(); + + // build menu + this.refresh(true); + + // some addl. logic for single selects + if(!o.multiple) { + menu.addClass('ui-multiselect-single'); + } + + // bump unique ID + multiselectID++; + }, + + _init: function() { + if(this.options.header === false) { + this.header.hide(); + } + if(!this.options.multiple) { + this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide(); + } + if(this.options.autoOpen) { + this.open(); + } + if(this.element.is(':disabled')) { + this.disable(); + } + }, + + refresh: function(init) { + var el = this.element; + var o = this.options; + var menu = this.menu; + var checkboxContainer = this.checkboxContainer; + var optgroups = []; + var html = ""; + var id = el.attr('id') || multiselectID++; // unique ID for the label & option tags + + // build items + el.find('option').each(function(i) { + var $this = $(this); + var parent = this.parentNode; + var description = this.innerHTML; + var title = this.title; + var value = this.value; + var inputID = 'ui-multiselect-' + (this.id || id + '-option-' + i); + var isDisabled = this.disabled; + var isSelected = this.selected; + var labelClasses = [ 'ui-corner-all' ]; + var liClasses = (isDisabled ? 'ui-multiselect-disabled ' : ' ') + this.className; + var optLabel; + + // is this an optgroup? + if(parent.tagName === 'OPTGROUP') { + optLabel = parent.getAttribute('label'); + + // has this optgroup been added already? + if($.inArray(optLabel, optgroups) === -1) { + html += '
    • ' + optLabel + '
    • '; + optgroups.push(optLabel); + } + } + + if(isDisabled) { + labelClasses.push('ui-state-disabled'); + } + + // browsers automatically select the first option + // by default with single selects + if(isSelected && !o.multiple) { + labelClasses.push('ui-state-active'); + } + + html += '
    • '; + + // create the label + html += '
    • '; + }); + + // insert into the DOM + checkboxContainer.html(html); + + // cache some moar useful elements + this.labels = menu.find('label'); + this.inputs = this.labels.children('input'); + + // set widths + this._setButtonWidth(); + this._setMenuWidth(); + + // remember default value + this.button[0].defaultValue = this.update(); + + // broadcast refresh event; useful for widgets + if(!init) { + this._trigger('refresh'); + } + }, + + // updates the button text. call refresh() to rebuild + update: function() { + var o = this.options; + var $inputs = this.inputs; + var $checked = $inputs.filter(':checked'); + var numChecked = $checked.length; + var value; + + if(numChecked === 0) { + value = o.noneSelectedText; + } else { + if($.isFunction(o.selectedText)) { + value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get()); + } else if(/\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList) { + value = $checked.map(function() { return $(this).next().html(); }).get().join(', '); + } else { + value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length); + } + } + + this._setButtonValue(value); + + return value; + }, + + // this exists as a separate method so that the developer + // can easily override it. + _setButtonValue: function(value) { + this.buttonlabel.text(value); + }, + + // binds events + _bindEvents: function() { + var self = this; + var button = this.button; + + function clickHandler() { + self[ self._isOpen ? 'close' : 'open' ](); + return false; + } + + // webkit doesn't like it when you click on the span :( + button + .find('span') + .bind('click.multiselect', clickHandler); + + // button events + button.bind({ + click: clickHandler, + keypress: function(e) { + switch(e.which) { + case 27: // esc + case 38: // up + case 37: // left + self.close(); + break; + case 39: // right + case 40: // down + self.open(); + break; + } + }, + mouseenter: function() { + if(!button.hasClass('ui-state-disabled')) { + $(this).addClass('ui-state-hover'); + } + }, + mouseleave: function() { + $(this).removeClass('ui-state-hover'); + }, + focus: function() { + if(!button.hasClass('ui-state-disabled')) { + $(this).addClass('ui-state-focus'); + } + }, + blur: function() { + $(this).removeClass('ui-state-focus'); + } + }); + + // header links + this.header.delegate('a', 'click.multiselect', function(e) { + // close link + if($(this).hasClass('ui-multiselect-close')) { + self.close(); + + // check all / uncheck all + } else { + self[$(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll'](); + } + + e.preventDefault(); + }); + + // optgroup label toggle support + this.menu.delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function(e) { + e.preventDefault(); + + var $this = $(this); + var $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)'); + var nodes = $inputs.get(); + var label = $this.parent().text(); + + // trigger event and bail if the return is false + if(self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false) { + return; + } + + // toggle inputs + self._toggleChecked( + $inputs.filter(':checked').length !== $inputs.length, + $inputs + ); + + self._trigger('optgrouptoggle', e, { + inputs: nodes, + label: label, + checked: nodes[0].checked + }); + }) + .delegate('label', 'mouseenter.multiselect', function() { + if(!$(this).hasClass('ui-state-disabled')) { + self.labels.removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover').find('input').focus(); + } + }) + .delegate('label', 'keydown.multiselect', function(e) { + e.preventDefault(); + + switch(e.which) { + case 9: // tab + case 27: // esc + self.close(); + break; + case 38: // up + case 40: // down + case 37: // left + case 39: // right + self._traverse(e.which, this); + break; + case 13: // enter + $(this).find('input')[0].click(); + break; + } + }) + .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function(e) { + var $this = $(this); + var val = this.value; + var checked = this.checked; + var tags = self.element.find('option'); + + // bail if this input is disabled or the event is cancelled + if(this.disabled || self._trigger('click', e, { value: val, text: this.title, checked: checked }) === false) { + e.preventDefault(); + return; + } + + // make sure the input has focus. otherwise, the esc key + // won't close the menu after clicking an item. + $this.focus(); + + // toggle aria state + $this.attr('aria-selected', checked); + + // change state on the original option tags + tags.each(function() { + if(this.value === val) { + this.selected = checked; + } else if(!self.options.multiple) { + this.selected = false; + } + }); + + // some additional single select-specific logic + if(!self.options.multiple) { + self.labels.removeClass('ui-state-active'); + $this.closest('label').toggleClass('ui-state-active', checked); + + // close menu + self.close(); + } + + // fire change on the select box + self.element.trigger("change"); + + // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827 + // http://bugs.jquery.com/ticket/3827 + setTimeout($.proxy(self.update, self), 10); + }); + + // close each widget when clicking on any other element/anywhere else on the page + $doc.bind('mousedown.' + this._namespaceID, function(event) { + var target = event.target; + + if(self._isOpen + && target !== self.button[0] + && target !== self.menu[0] + && !$.contains(self.menu[0], target) + && !$.contains(self.button[0], target) + ) { + self.close(); + } + }); + + // deal with form resets. the problem here is that buttons aren't + // restored to their defaultValue prop on form reset, and the reset + // handler fires before the form is actually reset. delaying it a bit + // gives the form inputs time to clear. + $(this.element[0].form).bind('reset.multiselect', function() { + setTimeout($.proxy(self.refresh, self), 10); + }); + }, + + // set button width + _setButtonWidth: function() { + var width = this.element.outerWidth(); + var o = this.options; + + if(/\d/.test(o.minWidthButton) && width < o.minWidthButton) { + width = o.minWidthButton; + } + + // set widths + this.button.outerWidth(width); + }, + + // set menu width + _setMenuWidth: function() { + var o = this.options; + var m = this.menu; + if(/\d/.test(o.minWidth) && this.button.outerWidth() < o.minWidth) { + m.outerWidth(o.minWidth); + } + else + { + m.outerWidth(this.button.outerWidth()); + } + }, + + // move up or down within the menu + _traverse: function(which, start) { + var $start = $(start); + var moveToLast = which === 38 || which === 37; + + // select the first li that isn't an optgroup label / disabled + var $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)').first(); + + // if at the first/last element + if(!$next.length) { + var $container = this.menu.find('ul').last(); + + // move to the first/last + this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover'); + + // set scroll position + $container.scrollTop(moveToLast ? $container.height() : 0); + + } else { + $next.find('label').trigger('mouseover'); + } + }, + + // This is an internal function to toggle the checked property and + // other related attributes of a checkbox. + // + // The context of this function should be a checkbox; do not proxy it. + _toggleState: function(prop, flag) { + return function() { + if(!this.disabled) { + this[ prop ] = flag; + } + + if(flag) { + this.setAttribute('aria-selected', true); + } else { + this.removeAttribute('aria-selected'); + } + }; + }, + + _toggleChecked: function(flag, group) { + var $inputs = (group && group.length) ? group : this.inputs; + var self = this; + + // toggle state on inputs + $inputs.each(this._toggleState('checked', flag)); + + // give the first input focus + $inputs.eq(0).focus(); + + // update button text + this.update(); + + // gather an array of the values that actually changed + var values = $inputs.map(function() { + return this.value; + }).get(); + + // toggle state on original option tags + this.element + .find('option') + .each(function() { + if(!this.disabled && $.inArray(this.value, values) > -1) { + self._toggleState('selected', flag).call(this); + } + }); + + // trigger the change event on the select + if($inputs.length) { + this.element.trigger("change"); + } + }, + + _toggleDisabled: function(flag) { + this.button.attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled'); + + var inputs = this.menu.find('input'); + var key = "ech-multiselect-disabled"; + + if(flag) { + // remember which elements this widget disabled (not pre-disabled) + // elements, so that they can be restored if the widget is re-enabled. + inputs = inputs.filter(':enabled').data(key, true) + } else { + inputs = inputs.filter(function() { + return $.data(this, key) === true; + }).removeData(key); + } + + inputs + .attr({ 'disabled':flag, 'arial-disabled':flag }) + .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled'); + + this.element.attr({ + 'disabled':flag, + 'aria-disabled':flag + }); + }, + + // open the menu + open: function(e) { + var self = this; + var button = this.button; + var menu = this.menu; + var speed = this.speed; + var o = this.options; + var args = []; + + // bail if the multiselectopen event returns false, this widget is disabled, or is already open + if(this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen) { + return; + } + + var $container = menu.find('ul').last(); + var effect = o.show; + + // figure out opening effects/speeds + if($.isArray(o.show)) { + effect = o.show[0]; + speed = o.show[1] || self.speed; + } + + // if there's an effect, assume jQuery UI is in use + // build the arguments to pass to show() + if(effect) { + args = [ effect, speed ]; + } + + // set the scroll of the checkbox container + $container.scrollTop(0).height(o.height); + + // positon + this.position(); + + // show the menu, maybe with a speed/effect combo + $.fn.show.apply(menu, args); + + // select the first not disabled option + // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover + // will actually trigger mouseenter. the mouseenter trigger is there for when it's eventually fixed + this.labels.filter(':not(.ui-state-disabled)').eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus'); + + button.addClass('ui-state-active'); + this._isOpen = true; + this._trigger('open'); + }, + + // close the menu + close: function() { + if(this._trigger('beforeclose') === false) { + return; + } + + var o = this.options; + var effect = o.hide; + var speed = this.speed; + var args = []; + + // figure out opening effects/speeds + if($.isArray(o.hide)) { + effect = o.hide[0]; + speed = o.hide[1] || this.speed; + } + + if(effect) { + args = [ effect, speed ]; + } + + $.fn.hide.apply(this.menu, args); + this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave'); + this._isOpen = false; + this._trigger('close'); + }, + + enable: function() { + this._toggleDisabled(false); + }, + + disable: function() { + this._toggleDisabled(true); + }, + + checkAll: function(e) { + this._toggleChecked(true); + this._trigger('checkAll'); + }, + + uncheckAll: function() { + this._toggleChecked(false); + this._trigger('uncheckAll'); + }, + + getChecked: function() { + return this.menu.find('input').filter(':checked'); + }, + + destroy: function() { + // remove classes + data + $.Widget.prototype.destroy.call(this); + + // unbind events + $doc.unbind(this._namespaceID); + + this.button.remove(); + this.menu.remove(); + this.element.show(); + + return this; + }, + + isOpen: function() { + return this._isOpen; + }, + + widget: function() { + return this.menu; + }, + + getButton: function() { + return this.button; + }, + + position: function() { + var o = this.options; + + // use the position utility if it exists and options are specifified + if($.ui.position && !$.isEmptyObject(o.position)) { + o.position.of = o.position.of || this.button; + + this.menu + .show() + .position(o.position) + .hide(); + + // otherwise fallback to custom positioning + } else { + var pos = this.button.offset(); + + this.menu.css({ + top: pos.top + this.button.outerHeight(), + left: pos.left + }); + } + }, + + // react to option changes after initialization + _setOption: function(key, value) { + var menu = this.menu; + + switch(key) { + case 'header': + menu.find('div.ui-multiselect-header')[value ? 'show' : 'hide'](); + break; + case 'checkAllText': + menu.find('a.ui-multiselect-all span').eq(-1).text(value); + break; + case 'uncheckAllText': + menu.find('a.ui-multiselect-none span').eq(-1).text(value); + break; + case 'height': + menu.find('ul').last().height(parseInt(value, 10)); + break; + case 'minWidth': + this.options[key] = parseInt(value, 10); + this._setButtonWidth(); + this._setMenuWidth(); + break; + case 'selectedText': + case 'selectedList': + case 'noneSelectedText': + this.options[key] = value; // these all needs to update immediately for the update() call + this.update(); + break; + case 'classes': + menu.add(this.button).removeClass(this.options.classes).addClass(value); + break; + case 'multiple': + menu.toggleClass('ui-multiselect-single', !value); + this.options.multiple = value; + this.element[0].multiple = value; + this.refresh(); + break; + case 'position': + this.position(); + } + + $.Widget.prototype._setOption.apply(this, arguments); + } + }); + +})(jQuery); diff --git a/js/jquery.multiselect.min.js b/js/jquery.multiselect.min.js deleted file mode 100644 index e9243506c..000000000 --- a/js/jquery.multiselect.min.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * jQuery MultiSelect UI Widget 1.13 - * Copyright (c) 2012 Eric Hynds - * - * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/ - * - * Depends: - * - jQuery 1.4.2+ - * - jQuery UI 1.8 widget factory - * - * Optional: - * - jQuery UI effects - * - jQuery UI position utility - * - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - */ -(function(d){var k=0;d.widget("ech.multiselect",{options:{header:!0,height:175,minWidth:225,classes:"",checkAllText:"Check all",uncheckAllText:"Uncheck all",noneSelectedText:"Select options",selectedText:"# selected",selectedList:0,show:null,hide:null,autoOpen:!1,multiple:!0,position:{}},_create:function(){var a=this.element.hide(),b=this.options;this.speed=d.fx.speeds._default;this._isOpen=!1;a=(this.button=d('')).addClass("ui-multiselect ui-widget ui-state-default ui-corner-all").addClass(b.classes).attr({title:a.attr("title"),"aria-haspopup":!0,tabIndex:a.attr("tabIndex")}).insertAfter(a);(this.buttonlabel=d("")).html(b.noneSelectedText).appendTo(a);var a=(this.menu=d("
      ")).addClass("ui-multiselect-menu ui-widget ui-widget-content ui-corner-all").addClass(b.classes).appendTo(document.body),c=(this.header=d("
      ")).addClass("ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix").appendTo(a);(this.headerLinkContainer=d("
        ")).addClass("ui-helper-reset").html(function(){return!0===b.header?'
      • '+b.checkAllText+'
      • '+b.uncheckAllText+"
      • ":"string"===typeof b.header?"
      • "+b.header+"
      • ":""}).append('
      • ').appendTo(c);(this.checkboxContainer=d("
          ")).addClass("ui-multiselect-checkboxes ui-helper-reset").appendTo(a);this._bindEvents();this.refresh(!0);b.multiple||a.addClass("ui-multiselect-single")},_init:function(){!1===this.options.header&&this.header.hide();this.options.multiple||this.headerLinkContainer.find(".ui-multiselect-all, .ui-multiselect-none").hide();this.options.autoOpen&&this.open();this.element.is(":disabled")&&this.disable()},refresh:function(a){var b=this.element,c=this.options,f=this.menu,h=this.checkboxContainer,g=[],e="",i=b.attr("id")||k++;b.find("option").each(function(b){d(this);var a=this.parentNode,f=this.innerHTML,h=this.title,k=this.value,b="ui-multiselect-"+(this.id||i+"-option-"+b),l=this.disabled,n=this.selected,m=["ui-corner-all"],o=(l?"ui-multiselect-disabled ":" ")+this.className,j;"OPTGROUP"===a.tagName&&(j=a.getAttribute("label"),-1===d.inArray(j,g)&&(e+='
        • '+j+"
        • ",g.push(j)));l&&m.push("ui-state-disabled");n&&!c.multiple&&m.push("ui-state-active");e+='
        • ';e+='
        • "});h.html(e);this.labels=f.find("label");this.inputs=this.labels.children("input");this._setButtonWidth();this._setMenuWidth();this.button[0].defaultValue=this.update();a||this._trigger("refresh")},update:function(){var a=this.options,b=this.inputs,c=b.filter(":checked"),f=c.length,a=0===f?a.noneSelectedText:d.isFunction(a.selectedText)?a.selectedText.call(this,f,b.length,c.get()):/\d/.test(a.selectedList)&&0