Bugzilla – Attachment 20718 Details for
Bug 9043
Adding system preferences to control the visibility of the content on the Advanced Search page
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
[ALT 3/3] Bug 9043: Add the dropdown check list jquery plugin
Bug-9043-Add-the-dropdown-check-list-jquery-plugin.patch (text/plain), 47.08 KB, created by
Jonathan Druart
on 2013-08-29 07:50:07 UTC
(
hide
)
Description:
[ALT 3/3] Bug 9043: Add the dropdown check list jquery plugin
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2013-08-29 07:50:07 UTC
Size:
47.08 KB
patch
obsolete
>From 995c8df72a78bd3fd3c0a55e496fda4f97e6eccb Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@biblibre.com> >Date: Tue, 13 Aug 2013 16:58:06 +0200 >Subject: [PATCH] Bug 9043: Add the dropdown check list jquery plugin > >--- > .../en/css/ui.dropdownchecklist.themeroller.css | 29 + > .../en/lib/jquery/plugins/ui.dropdownchecklist.js | 917 ++++++++++++++++++++ > .../prog/en/modules/admin/preferences.tt | 16 +- > 3 files changed, 953 insertions(+), 9 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/css/ui.dropdownchecklist.themeroller.css > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/ui.dropdownchecklist.js > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/ui.dropdownchecklist.themeroller.css b/koha-tmpl/intranet-tmpl/prog/en/css/ui.dropdownchecklist.themeroller.css >new file mode 100644 >index 0000000..2bdfce9 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/css/ui.dropdownchecklist.themeroller.css >@@ -0,0 +1,29 @@ >+/** Simple modifications needed for DropDownCheckList to take advantage of ThemeRoller settings */ >+.ui-dropdownchecklist .ui-widget-content >+, .ui-dropdownchecklist .ui-widget-header { >+ border: none; >+} >+.ui-dropdownchecklist-indent { >+ padding-left: 7px; >+} >+/* Font size of 0 on the -selector and an explicit medium on -text required to eliminate >+ descender problems within the containers and still have a valid size for the text */ >+.ui-dropdownchecklist-selector-wrapper >+, .ui-widget.ui-dropdownchecklist-selector-wrapper { >+ vertical-align: middle; >+ font-size: 0px; >+} >+.ui-dropdownchecklist-selector { >+ padding: 1px 2px 2px 2px; >+ font-size: 0px; >+} >+.ui-dropdownchecklist-text { >+ font-size: medium; >+} >+.ui-dropdownchecklist-item >+, .ui-dropdownchecklist-item input { >+ vertical-align: middle; >+} >+.ui-dropdownchecklist-group { >+ padding: 1px 2px 2px 2px; >+} >diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/ui.dropdownchecklist.js b/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/ui.dropdownchecklist.js >new file mode 100644 >index 0000000..94a30b8 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/ui.dropdownchecklist.js >@@ -0,0 +1,917 @@ >+;(function($) { >+/* >+ * ui.dropdownchecklist >+ * >+ * Copyright (c) 2008-2010 Adrian Tosca, Copyright (c) 2010-2011 Ittrium LLC >+ * Dual licensed under the MIT (MIT-LICENSE.txt) OR GPL (GPL-LICENSE.txt) licenses. >+ * >+*/ >+ // The dropdown check list jQuery plugin transforms a regular select html element into a dropdown check list. >+ $.widget("ui.dropdownchecklist", { >+ // Some globlals >+ // $.ui.dropdownchecklist.gLastOpened - keeps track of last opened dropdowncheck list so we can close it >+ // $.ui.dropdownchecklist.gIDCounter - simple counter to provide a unique ID as needed >+ version: function() { >+ alert('DropDownCheckList v1.4'); >+ }, >+ // Creates the drop container that keeps the items and appends it to the document >+ _appendDropContainer: function( controlItem ) { >+ var wrapper = $("<div/>"); >+ // the container is wrapped in a div >+ wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-dropcontainer-wrapper"); >+ wrapper.addClass("ui-widget"); >+ // assign an id >+ wrapper.attr("id",controlItem.attr("id") + '-ddw'); >+ // initially positioned way off screen to prevent it from displaying >+ // NOTE absolute position to enable width/height calculation >+ wrapper.css({ position: 'absolute', left: "-33000px", top: "-33000px" }); >+ >+ var container = $("<div/>"); // the actual container >+ container.addClass("ui-dropdownchecklist-dropcontainer ui-widget-content"); >+ container.css("overflow-y", "auto"); >+ wrapper.append(container); >+ >+ // insert the dropdown after the master control to try to keep the tab order intact >+ // if you just add it to the end, tabbing out of the drop down takes focus off the page >+ // @todo 22Sept2010 - check if size calculation is thrown off if the parent of the >+ // selector is hidden. We may need to add it to the end of the document here, >+ // calculate the size, and then move it back into proper position??? >+ //$(document.body).append(wrapper); >+ wrapper.insertAfter(controlItem); >+ >+ // flag that tells if the drop container is shown or not >+ wrapper.isOpen = false; >+ return wrapper; >+ }, >+ // Look for browser standard 'open' on a closed selector >+ _isDropDownKeyShortcut: function(e,keycode) { >+ return e.altKey && ($.ui.keyCode.DOWN == keycode);// Alt + Down Arrow >+ }, >+ // Look for key that will tell us to close the open dropdown >+ _isDropDownCloseKey: function(e,keycode) { >+ return ($.ui.keyCode.ESCAPE == keycode) || ($.ui.keyCode.ENTER == keycode); >+ }, >+ // Handler to change the active focus based on a keystroke, moving some count of >+ // items from the element that has the current focus >+ _keyFocusChange: function(target,delta,limitToItems) { >+ // Find item with current focus >+ var focusables = $(":focusable"); >+ var index = focusables.index(target); >+ if ( index >= 0 ) { >+ index += delta; >+ if ( limitToItems ) { >+ // Bound change to list of input elements >+ var allCheckboxes = this.dropWrapper.find("input:not([disabled])"); >+ var firstIndex = focusables.index(allCheckboxes.get(0)); >+ var lastIndex = focusables.index(allCheckboxes.get(allCheckboxes.length-1)); >+ if ( index < firstIndex ) { >+ index = lastIndex; >+ } else if ( index > lastIndex ) { >+ index = firstIndex; >+ } >+ } >+ focusables.get(index).focus(); >+ } >+ }, >+ // Look for navigation, open, close (wired to keyup) >+ _handleKeyboard: function(e) { >+ var self = this; >+ var keyCode = (e.keyCode || e.which); >+ if (!self.dropWrapper.isOpen && self._isDropDownKeyShortcut(e, keyCode)) { >+ // Key command to open the dropdown >+ e.stopImmediatePropagation(); >+ self._toggleDropContainer(true); >+ } else if (self.dropWrapper.isOpen && self._isDropDownCloseKey(e, keyCode)) { >+ // Key command to close the dropdown (but we retain focus in the control) >+ e.stopImmediatePropagation(); >+ self._toggleDropContainer(false); >+ self.controlSelector.focus(); >+ } else if (self.dropWrapper.isOpen >+ && (e.target.type == 'checkbox') >+ && ((keyCode == $.ui.keyCode.DOWN) || (keyCode == $.ui.keyCode.UP)) ) { >+ // Up/Down to cycle throught the open items >+ e.stopImmediatePropagation(); >+ self._keyFocusChange(e.target, (keyCode == $.ui.keyCode.DOWN) ? 1 : -1, true); >+ } else if (self.dropWrapper.isOpen && (keyCode == $.ui.keyCode.TAB) ) { >+ // I wanted to adjust normal 'tab' processing here, but research indicates >+ // that TAB key processing is NOT a cancelable event. You have to use a timer >+ // hack to pull the focus back to where you want it after browser tab >+ // processing completes. Not going to work for us. >+ //e.stopImmediatePropagation(); >+ //self._keyFocusChange(e.target, (e.shiftKey) ? -1 : 1, true); >+ } >+ }, >+ // Look for change of focus >+ _handleFocus: function(e,focusIn,forDropdown) { >+ var self = this; >+ if (forDropdown && !self.dropWrapper.isOpen) { >+ // if the focus changes when the control is NOT open, mark it to show where the focus is/is not >+ e.stopImmediatePropagation(); >+ if (focusIn) { >+ self.controlSelector.addClass("ui-state-hover"); >+ if ($.ui.dropdownchecklist.gLastOpened != null) { >+ $.ui.dropdownchecklist.gLastOpened._toggleDropContainer( false ); >+ } >+ } else { >+ self.controlSelector.removeClass("ui-state-hover"); >+ } >+ } else if (!forDropdown && !focusIn) { >+ // The dropdown is open, and an item (NOT the dropdown) has just lost the focus. >+ // we really need a reliable method to see who has the focus as we process the blur, >+ // but that mechanism does not seem to exist. Instead we rely on a delay before >+ // posting the blur, with a focus event cancelling it before the delay expires. >+ if ( e != null ) { e.stopImmediatePropagation(); } >+ self.controlSelector.removeClass("ui-state-hover"); >+ self._toggleDropContainer( false ); >+ } >+ }, >+ // Clear the pending change of focus, which keeps us 'in' the control >+ _cancelBlur: function(e) { >+ var self = this; >+ if (self.blurringItem != null) { >+ clearTimeout(self.blurringItem); >+ self.blurringItem = null; >+ } >+ }, >+ // Creates the control that will replace the source select and appends it to the document >+ // The control resembles a regular select with single selection >+ _appendControl: function() { >+ var self = this, sourceSelect = this.sourceSelect, options = this.options; >+ >+ // the control is wrapped in a basic container >+ // inline-block at this level seems to give us better size control >+ var wrapper = $("<span/>"); >+ wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-selector-wrapper ui-widget"); >+ wrapper.css( { display: "inline-block", cursor: "default", overflow: "hidden" } ); >+ >+ // assign an ID >+ var baseID = sourceSelect.attr("id"); >+ if ((baseID == null) || (baseID == "")) { >+ baseID = "ddcl-" + $.ui.dropdownchecklist.gIDCounter++; >+ } else { >+ baseID = "ddcl-" + baseID; >+ } >+ wrapper.attr("id",baseID); >+ >+ // the actual control which you can style >+ // inline-block needed to enable 'width' but has interesting problems cross browser >+ var control = $("<span/>"); >+ control.addClass("ui-dropdownchecklist-selector ui-state-default"); >+ control.css( { display: "inline-block", overflow: "hidden", 'white-space': 'nowrap'} ); >+ // Setting a tab index means we are interested in the tab sequence >+ var tabIndex = sourceSelect.attr("tabIndex"); >+ if ( tabIndex == null ) { >+ tabIndex = 0; >+ } else { >+ tabIndex = parseInt(tabIndex); >+ if ( tabIndex < 0 ) { >+ tabIndex = 0; >+ } >+ } >+ control.attr("tabIndex", tabIndex); >+ control.keyup(function(e) {self._handleKeyboard(e);}); >+ control.focus(function(e) {self._handleFocus(e,true,true);}); >+ control.blur(function(e) {self._handleFocus(e,false,true);}); >+ wrapper.append(control); >+ >+ // the optional icon (which is inherently a block) which we can float >+ if (options.icon != null) { >+ var iconPlacement = (options.icon.placement == null) ? "left" : options.icon.placement; >+ var anIcon = $("<div/>"); >+ anIcon.addClass("ui-icon"); >+ anIcon.addClass( (options.icon.toOpen != null) ? options.icon.toOpen : "ui-icon-triangle-1-e"); >+ anIcon.css({ 'float': iconPlacement }); >+ control.append(anIcon); >+ } >+ // the text container keeps the control text that is built from the selected (checked) items >+ // inline-block needed to prevent long text from wrapping to next line when icon is active >+ var textContainer = $("<span/>"); >+ textContainer.addClass("ui-dropdownchecklist-text"); >+ textContainer.css( { display: "inline-block", 'white-space': "nowrap", overflow: "hidden" } ); >+ control.append(textContainer); >+ >+ // add the hover styles to the control >+ wrapper.hover( >+ function() { >+ if (!self.disabled) { >+ control.addClass("ui-state-hover"); >+ } >+ } >+ , function() { >+ if (!self.disabled) { >+ control.removeClass("ui-state-hover"); >+ } >+ } >+ ); >+ // clicking on the control toggles the drop container >+ wrapper.click(function(event) { >+ if (!self.disabled) { >+ event.stopImmediatePropagation(); >+ self._toggleDropContainer( !self.dropWrapper.isOpen ); >+ } >+ }); >+ wrapper.insertAfter(sourceSelect); >+ >+ // Watch for a window resize and adjust the control if open >+ $(window).resize(function() { >+ if (!self.disabled && self.dropWrapper.isOpen) { >+ // Reopen yourself to get the position right >+ self._toggleDropContainer(true); >+ } >+ }); >+ return wrapper; >+ }, >+ // Creates a drop item that coresponds to an option element in the source select >+ _createDropItem: function(index, tabIndex, value, text, optCss, checked, disabled, indent) { >+ var self = this, options = this.options, sourceSelect = this.sourceSelect, controlWrapper = this.controlWrapper; >+ // the item contains a div that contains a checkbox input and a lable for the text >+ // the div >+ var item = $("<div/>"); >+ item.addClass("ui-dropdownchecklist-item"); >+ item.css({'white-space': "nowrap"}); >+ var checkedString = checked ? ' checked="checked"' : ''; >+ var classString = disabled ? ' class="inactive"' : ' class="active"'; >+ >+ // generated id must be a bit unique to keep from colliding >+ var idBase = controlWrapper.attr("id"); >+ var id = idBase + '-i' + index; >+ var checkBox; >+ >+ // all items start out disabled to keep them out of the tab order >+ if (self.isMultiple) { // the checkbox >+ checkBox = $('<input disabled type="checkbox" id="' + id + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />'); >+ } else { // the radiobutton >+ checkBox = $('<input disabled type="radio" id="' + id + '" name="' + idBase + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />'); >+ } >+ checkBox = checkBox.attr("index", index).val(value); >+ item.append(checkBox); >+ >+ // the text >+ var label = $("<label for=" + id + "/>"); >+ label.addClass("ui-dropdownchecklist-text"); >+ if ( optCss != null ) label.attr('style',optCss); >+ label.css({ cursor: "default" }); >+ label.html(text); >+ if (indent) { >+ item.addClass("ui-dropdownchecklist-indent"); >+ } >+ item.addClass("ui-state-default"); >+ if (disabled) { >+ item.addClass("ui-state-disabled"); >+ } >+ label.click(function(e) {e.stopImmediatePropagation();}); >+ item.append(label); >+ >+ // active items display themselves with hover >+ item.hover( >+ function(e) { >+ var anItem = $(this); >+ if (!anItem.hasClass("ui-state-disabled")) { anItem.addClass("ui-state-hover"); } >+ } >+ , function(e) { >+ var anItem = $(this); >+ anItem.removeClass("ui-state-hover"); >+ } >+ ); >+ // clicking on the checkbox synchronizes the source select >+ checkBox.click(function(e) { >+ var aCheckBox = $(this); >+ e.stopImmediatePropagation(); >+ if (aCheckBox.hasClass("active") ) { >+ // Active checkboxes take active action >+ var callback = self.options.onItemClick; >+ if ($.isFunction(callback)) try { >+ callback.call(self,aCheckBox,sourceSelect.get(0)); >+ } catch (ex) { >+ // reject the change on any error >+ aCheckBox.prop("checked",!aCheckBox.prop("checked")); >+ self._syncSelected(aCheckBox); >+ return; >+ } >+ self._syncSelected(aCheckBox); >+ self.sourceSelect.trigger("change", 'ddcl_internal'); >+ if (!self.isMultiple && options.closeRadioOnClick) { >+ self._toggleDropContainer(false); >+ } >+ } >+ }); >+ // we are interested in the focus leaving the check box >+ // but we need to detect the focus leaving one check box but >+ // entering another. There is no reliable way to detect who >+ // received the focus on a blur, so post the blur in the future, >+ // knowing we will cancel it if we capture the focus in a timely manner >+ // 23Sept2010 - unfortunately, IE 7+ and Chrome like to post a blur >+ // event to the current item with focus when the user >+ // clicks in the scroll bar. So if you have a scrollable >+ // dropdown with focus on an item, clicking in the scroll >+ // will close the drop down. >+ // I have no solution for blur processing at this time. >+/********* >+ var timerFunction = function(){ >+ // I had a hell of a time getting setTimeout to fire this, do not try to >+ // define it within the blur function >+ try { self._handleFocus(null,false,false); } catch(ex){ alert('timer failed: '+ex);} >+ }; >+ checkBox.blur(function(e) { >+ self.blurringItem = setTimeout( timerFunction, 200 ); >+ }); >+ checkBox.focus(function(e) {self._cancelBlur();}); >+**********/ >+ // check/uncheck the item on clicks on the entire item div >+ item.click(function(e) { >+ var anItem = $(this); >+ e.stopImmediatePropagation(); >+ if (!anItem.hasClass("ui-state-disabled") ) { >+ // check/uncheck the underlying control >+ var aCheckBox = anItem.find("input"); >+ var checked = aCheckBox.prop("checked"); >+ aCheckBox.prop("checked", !checked); >+ >+ var callback = self.options.onItemClick; >+ if ($.isFunction(callback)) try { >+ callback.call(self,aCheckBox,sourceSelect.get(0)); >+ } catch (ex) { >+ // reject the change on any error >+ aCheckBox.prop("checked",checked); >+ self._syncSelected(aCheckBox); >+ return; >+ } >+ self._syncSelected(aCheckBox); >+ self.sourceSelect.trigger("change", 'ddcl_internal'); >+ if (!checked && !self.isMultiple && options.closeRadioOnClick) { >+ self._toggleDropContainer(false); >+ } >+ } else { >+ // retain the focus even if disabled >+ anItem.focus(); >+ self._cancelBlur(); >+ } >+ }); >+ // do not let the focus wander around >+ item.focus(function(e) { >+ var anItem = $(this); >+ e.stopImmediatePropagation(); >+ }); >+ item.keyup(function(e) {self._handleKeyboard(e);}); >+ return item; >+ }, >+ _createGroupItem: function(text,disabled) { >+ var self = this; >+ var group = $("<div />"); >+ group.addClass("ui-dropdownchecklist-group ui-widget-header"); >+ if (disabled) { >+ group.addClass("ui-state-disabled"); >+ } >+ group.css({'white-space': "nowrap"}); >+ >+ var label = $("<span/>"); >+ label.addClass("ui-dropdownchecklist-text"); >+ label.css( { cursor: "default" }); >+ label.text(text); >+ group.append(label); >+ >+ // anything interesting when you click the group??? >+ group.click(function(e) { >+ var aGroup= $(this); >+ e.stopImmediatePropagation(); >+ // retain the focus even if no action is taken >+ aGroup.focus(); >+ self._cancelBlur(); >+ }); >+ // do not let the focus wander around >+ group.focus(function(e) { >+ var aGroup = $(this); >+ e.stopImmediatePropagation(); >+ }); >+ return group; >+ }, >+ _createCloseItem: function(text) { >+ var self = this; >+ var closeItem = $("<div />"); >+ closeItem.addClass("ui-state-default ui-dropdownchecklist-close ui-dropdownchecklist-item"); >+ closeItem.css({'white-space': 'nowrap', 'text-align': 'right'}); >+ >+ var label = $("<span/>"); >+ label.addClass("ui-dropdownchecklist-text"); >+ label.css( { cursor: "default" }); >+ label.html(text); >+ closeItem.append(label); >+ >+ // close the control on click >+ closeItem.click(function(e) { >+ var aGroup= $(this); >+ e.stopImmediatePropagation(); >+ // retain the focus even if no action is taken >+ aGroup.focus(); >+ self._toggleDropContainer( false ); >+ }); >+ closeItem.hover( >+ function(e) { $(this).addClass("ui-state-hover"); } >+ , function(e) { $(this).removeClass("ui-state-hover"); } >+ ); >+ // do not let the focus wander around >+ closeItem.focus(function(e) { >+ var aGroup = $(this); >+ e.stopImmediatePropagation(); >+ }); >+ return closeItem; >+ }, >+ // Creates the drop items and appends them to the drop container >+ // Also calculates the size needed by the drop container and returns it >+ _appendItems: function() { >+ var self = this, config = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper; >+ var dropContainerDiv = dropWrapper.find(".ui-dropdownchecklist-dropcontainer"); >+ sourceSelect.children().each(function(index) { // when the select has groups >+ var opt = $(this); >+ if (opt.is("option")) { >+ self._appendOption(opt, dropContainerDiv, index, false, false); >+ } else if (opt.is("optgroup")) { >+ var disabled = opt.prop("disabled"); >+ var text = opt.attr("label"); >+ if (text != "") { >+ var group = self._createGroupItem(text,disabled); >+ dropContainerDiv.append(group); >+ } >+ self._appendOptions(opt, dropContainerDiv, index, true, disabled); >+ } >+ }); >+ if ( config.explicitClose != null ) { >+ var closeItem = self._createCloseItem(config.explicitClose); >+ dropContainerDiv.append(closeItem); >+ } >+ var divWidth = dropContainerDiv.outerWidth(); >+ var divHeight = dropContainerDiv.outerHeight(); >+ return { width: divWidth, height: divHeight }; >+ }, >+ _appendOptions: function(parent, container, parentIndex, indent, forceDisabled) { >+ var self = this; >+ parent.children("option").each(function(index) { >+ var option = $(this); >+ var childIndex = (parentIndex + "." + index); >+ self._appendOption(option, container, childIndex, indent, forceDisabled); >+ }); >+ }, >+ _appendOption: function(option, container, index, indent, forceDisabled) { >+ var self = this; >+ // Note that the browsers destroy any html structure within the OPTION >+ var text = option.html(); >+ if ( (text != null) && (text != '') ) { >+ var value = option.val(); >+ var optCss = option.attr('style'); >+ var selected = option.prop("selected"); >+ var disabled = (forceDisabled || option.prop("disabled")); >+ // Use the same tab index as the selector replacement >+ var tabIndex = self.controlSelector.attr("tabindex"); >+ var item = self._createDropItem(index, tabIndex, value, text, optCss, selected, disabled, indent); >+ container.append(item); >+ } >+ }, >+ // Synchronizes the items checked and the source select >+ // When firstItemChecksAll option is active also synchronizes the checked items >+ // senderCheckbox parameters is the checkbox input that generated the synchronization >+ _syncSelected: function(senderCheckbox) { >+ var self = this, options = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper; >+ var selectOptions = sourceSelect.get(0).options; >+ var allCheckboxes = dropWrapper.find("input.active"); >+ if (options.firstItemChecksAll == 'exclusive') { >+ if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) { >+ // Initialization call with first item active >+ allCheckboxes.prop("checked", false); >+ $(allCheckboxes[0]).prop("checked", true); >+ } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) { >+ // Action on the first, so all other checkboxes NOT active >+ var firstIsActive = senderCheckbox.prop("checked"); >+ allCheckboxes.prop("checked", false); >+ $(allCheckboxes[0]).prop("checked", firstIsActive); >+ } else { >+ // check the first checkbox if all the other checkboxes are checked >+ var allChecked = true; >+ var firstCheckbox = null; >+ allCheckboxes.each(function(index) { >+ if (index > 0) { >+ var checked = $(this).prop("checked"); >+ if (!checked) { allChecked = false; } >+ } else { >+ firstCheckbox = $(this); >+ } >+ }); >+ if ( firstCheckbox != null ) { >+ if ( allChecked ) { >+ // when all are checked, only the first left checked >+ allCheckboxes.prop("checked", false); >+ } >+ firstCheckbox.prop("checked", allChecked ); >+ } >+ } >+ } else if (options.firstItemChecksAll) { >+ if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) { >+ // Initialization call with first item active so force all to be active >+ allCheckboxes.prop("checked", true); >+ } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) { >+ // Check all checkboxes if the first one is checked >+ allCheckboxes.prop("checked", senderCheckbox.prop("checked")); >+ } else { >+ // check the first checkbox if all the other checkboxes are checked >+ var allChecked = true; >+ var firstCheckbox = null; >+ allCheckboxes.each(function(index) { >+ if (index > 0) { >+ var checked = $(this).prop("checked"); >+ if (!checked) { allChecked = false; } >+ } else { >+ firstCheckbox = $(this); >+ } >+ }); >+ if ( firstCheckbox != null ) { >+ firstCheckbox.prop("checked", allChecked ); >+ } >+ } >+ } >+ // do the actual synch with the source select >+ var empties = 0; >+ allCheckboxes = dropWrapper.find("input"); >+ allCheckboxes.each(function(index) { >+ var anOption = $(selectOptions[index + empties]); >+ var optionText = anOption.html(); >+ if ( (optionText == null) || (optionText == '') ) { >+ empties += 1; >+ anOption = $(selectOptions[index + empties]); >+ } >+ anOption.prop("selected", $(this).prop("checked")); >+ }); >+ // update the text shown in the control >+ self._updateControlText(); >+ >+ // Ensure the focus stays pointing where the user is working >+ if ( senderCheckbox != null) { senderCheckbox.focus(); } >+ }, >+ _sourceSelectChangeHandler: function(event) { >+ var self = this, dropWrapper = this.dropWrapper; >+ dropWrapper.find("input").val(self.sourceSelect.val()); >+ >+ // update the text shown in the control >+ self._updateControlText(); >+ }, >+ // Updates the text shown in the control depending on the checked (selected) items >+ _updateControlText: function() { >+ var self = this, sourceSelect = this.sourceSelect, options = this.options, controlWrapper = this.controlWrapper; >+ var firstOption = sourceSelect.find("option:first"); >+ var selectOptions = sourceSelect.find("option"); >+ var text = self._formatText(selectOptions, options.firstItemChecksAll, firstOption); >+ var controlLabel = controlWrapper.find(".ui-dropdownchecklist-text"); >+ controlLabel.html(text); >+ // the attribute needs naked text, not html >+ controlLabel.attr("title", controlLabel.text()); >+ }, >+ // Formats the text that is shown in the control >+ _formatText: function(selectOptions, firstItemChecksAll, firstOption) { >+ var text; >+ if ( $.isFunction(this.options.textFormatFunction) ) { >+ // let the callback do the formatting, but do not allow it to fail >+ try { >+ text = this.options.textFormatFunction(selectOptions); >+ } catch(ex) { >+ alert( 'textFormatFunction failed: ' + ex ); >+ } >+ } else if (firstItemChecksAll && (firstOption != null) && firstOption.prop("selected")) { >+ // just set the text from the first item >+ text = firstOption.html(); >+ } else { >+ // concatenate the text from the checked items >+ text = ""; >+ selectOptions.each(function() { >+ if ($(this).prop("selected")) { >+ if ( text != "" ) { text += ", "; } >+ /* NOTE use of .html versus .text, which can screw up ampersands for IE */ >+ var optCss = $(this).attr('style'); >+ var tempspan = $('<span/>'); >+ tempspan.html( $(this).html() ); >+ if ( optCss == null ) { >+ text += tempspan.html(); >+ } else { >+ tempspan.attr('style',optCss); >+ text += $("<span/>").append(tempspan).html(); >+ } >+ } >+ }); >+ if ( text == "" ) { >+ text = (this.options.emptyText != null) ? this.options.emptyText : " "; >+ } >+ } >+ return text; >+ }, >+ // Shows and hides the drop container >+ _toggleDropContainer: function( makeOpen ) { >+ var self = this; >+ // hides the last shown drop container >+ var hide = function(instance) { >+ if ((instance != null) && instance.dropWrapper.isOpen ){ >+ instance.dropWrapper.isOpen = false; >+ $.ui.dropdownchecklist.gLastOpened = null; >+ >+ var config = instance.options; >+ instance.dropWrapper.css({ >+ top: "-33000px", >+ left: "-33000px" >+ }); >+ var aControl = instance.controlSelector; >+ aControl.removeClass("ui-state-active"); >+ aControl.removeClass("ui-state-hover"); >+ >+ var anIcon = instance.controlWrapper.find(".ui-icon"); >+ if ( anIcon.length > 0 ) { >+ anIcon.removeClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s"); >+ anIcon.addClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e"); >+ } >+ $(document).unbind("click", hide); >+ >+ // keep the items out of the tab order by disabling them >+ instance.dropWrapper.find("input.active").prop("disabled",true); >+ >+ // the following blur just does not fire??? because it is hidden??? because it does not have focus??? >+ //instance.sourceSelect.trigger("blur"); >+ //instance.sourceSelect.triggerHandler("blur"); >+ if($.isFunction(config.onComplete)) { try { >+ config.onComplete.call(instance,instance.sourceSelect.get(0)); >+ } catch(ex) { >+ alert( 'callback failed: ' + ex ); >+ }} >+ } >+ }; >+ // shows the given drop container instance >+ var show = function(instance) { >+ if ( !instance.dropWrapper.isOpen ) { >+ instance.dropWrapper.isOpen = true; >+ $.ui.dropdownchecklist.gLastOpened = instance; >+ >+ var config = instance.options; >+/**** Issue127 (and the like) to correct positioning when parent element is relative >+ **** This positioning only worked with simple, non-relative parent position >+ instance.dropWrapper.css({ >+ top: instance.controlWrapper.offset().top + instance.controlWrapper.outerHeight() + "px", >+ left: instance.controlWrapper.offset().left + "px" >+ }); >+****/ >+ if ((config.positionHow == null) || (config.positionHow == 'absolute')) { >+ /** Floats above subsequent content, but does NOT scroll */ >+ instance.dropWrapper.css({ >+ position: 'absolute' >+ , top: instance.controlWrapper.position().top + instance.controlWrapper.outerHeight() + "px" >+ , left: instance.controlWrapper.position().left + "px" >+ }); >+ } else if (config.positionHow == 'relative') { >+ /** Scrolls with the parent but does NOT float above subsequent content */ >+ instance.dropWrapper.css({ >+ position: 'relative' >+ , top: "0px" >+ , left: "0px" >+ }); >+ } >+ var zIndex = 0; >+ if (config.zIndex == null) { >+ var ancestorsZIndexes = instance.controlWrapper.parents().map( >+ function() { >+ var zIndex = $(this).css("z-index"); >+ return isNaN(zIndex) ? 0 : zIndex; } >+ ).get(); >+ var parentZIndex = Math.max.apply(Math, ancestorsZIndexes); >+ if ( parentZIndex >= 0) zIndex = parentZIndex+1; >+ } else { >+ /* Explicit set from the optins */ >+ zIndex = parseInt(config.zIndex); >+ } >+ if (zIndex > 0) { >+ instance.dropWrapper.css( { 'z-index': zIndex } ); >+ } >+ >+ var aControl = instance.controlSelector; >+ aControl.addClass("ui-state-active"); >+ aControl.removeClass("ui-state-hover"); >+ >+ var anIcon = instance.controlWrapper.find(".ui-icon"); >+ if ( anIcon.length > 0 ) { >+ anIcon.removeClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e"); >+ anIcon.addClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s"); >+ } >+ $(document).bind("click", function(e) {hide(instance);} ); >+ >+ // insert the items back into the tab order by enabling all active ones >+ var activeItems = instance.dropWrapper.find("input.active"); >+ activeItems.prop("disabled",false); >+ >+ // we want the focus on the first active input item >+ var firstActiveItem = activeItems.get(0); >+ if ( firstActiveItem != null ) { >+ firstActiveItem.focus(); >+ } >+ } >+ }; >+ if ( makeOpen ) { >+ hide($.ui.dropdownchecklist.gLastOpened); >+ show(self); >+ } else { >+ hide(self); >+ } >+ }, >+ // Set the size of the control and of the drop container >+ _setSize: function(dropCalculatedSize) { >+ var options = this.options, dropWrapper = this.dropWrapper, controlWrapper = this.controlWrapper; >+ >+ // use the width from config options if set, otherwise set the same width as the drop container >+ var controlWidth = dropCalculatedSize.width; >+ if (options.width != null) { >+ controlWidth = parseInt(options.width); >+ } else if (options.minWidth != null) { >+ var minWidth = parseInt(options.minWidth); >+ // if the width is too small (usually when there are no items) set a minimum width >+ if (controlWidth < minWidth) { >+ controlWidth = minWidth; >+ } >+ } >+ var control = this.controlSelector; >+ control.css({ width: controlWidth + "px" }); >+ >+ // if we size the text, then Firefox places icons to the right properly >+ // and we do not wrap on long lines >+ var controlText = control.find(".ui-dropdownchecklist-text"); >+ var controlIcon = control.find(".ui-icon"); >+ if ( controlIcon != null ) { >+ // Must be an inner/outer/border problem, but IE6 needs an extra bit of space, >+ // otherwise you can get text pushed down into a second line when icons are active >+ controlWidth -= (controlIcon.outerWidth() + 4); >+ controlText.css( { width: controlWidth + "px" } ); >+ } >+ // Account for padding, borders, etc >+ controlWidth = controlWrapper.outerWidth(); >+ >+ // the drop container height can be set from options >+ var maxDropHeight = (options.maxDropHeight != null) >+ ? parseInt(options.maxDropHeight) >+ : -1; >+ var dropHeight = ((maxDropHeight > 0) && (dropCalculatedSize.height > maxDropHeight)) >+ ? maxDropHeight >+ : dropCalculatedSize.height; >+ // ensure the drop container is not less than the control width (would be ugly) >+ var dropWidth = dropCalculatedSize.width < controlWidth ? controlWidth : dropCalculatedSize.width; >+ >+ $(dropWrapper).css({ >+ height: dropHeight + "px", >+ width: dropWidth + "px" >+ }); >+ dropWrapper.find(".ui-dropdownchecklist-dropcontainer").css({ >+ height: dropHeight + "px" >+ }); >+ }, >+ // Initializes the plugin >+ _init: function() { >+ var self = this, options = this.options; >+ if ( $.ui.dropdownchecklist.gIDCounter == null) { >+ $.ui.dropdownchecklist.gIDCounter = 1; >+ } >+ // item blurring relies on a cancelable timer >+ self.blurringItem = null; >+ >+ // sourceSelect is the select on which the plugin is applied >+ var sourceSelect = self.element; >+ self.initialDisplay = sourceSelect.css("display"); >+ sourceSelect.css("display", "none"); >+ self.initialMultiple = sourceSelect.prop("multiple"); >+ self.isMultiple = self.initialMultiple; >+ if (options.forceMultiple != null) { self.isMultiple = options.forceMultiple; } >+ sourceSelect.prop("multiple", true); >+ self.sourceSelect = sourceSelect; >+ >+ // append the control that resembles a single selection select >+ var controlWrapper = self._appendControl(); >+ self.controlWrapper = controlWrapper; >+ self.controlSelector = controlWrapper.find(".ui-dropdownchecklist-selector"); >+ >+ // create the drop container where the items are shown >+ var dropWrapper = self._appendDropContainer(controlWrapper); >+ self.dropWrapper = dropWrapper; >+ >+ // append the items from the source select element >+ var dropCalculatedSize = self._appendItems(); >+ >+ // updates the text shown in the control >+ self._updateControlText(controlWrapper, dropWrapper, sourceSelect); >+ >+ // set the sizes of control and drop container >+ self._setSize(dropCalculatedSize); >+ >+ // look for possible auto-check needed on first item >+ if ( options.firstItemChecksAll ) { >+ self._syncSelected(null); >+ } >+ // BGIFrame for IE6 >+ if (options.bgiframe && typeof self.dropWrapper.bgiframe == "function") { >+ self.dropWrapper.bgiframe(); >+ } >+ // listen for change events on the source select element >+ // ensure we avoid processing internally triggered changes >+ self.sourceSelect.change(function(event, eventName) { >+ if (eventName != 'ddcl_internal') { >+ self._sourceSelectChangeHandler(event); >+ } >+ }); >+ }, >+ // Refresh the disable and check state from the underlying control >+ _refreshOption: function(item,disabled,selected) { >+ var aParent = item.parent(); >+ // account for enabled/disabled >+ if ( disabled ) { >+ item.prop("disabled",true); >+ item.removeClass("active"); >+ item.addClass("inactive"); >+ aParent.addClass("ui-state-disabled"); >+ } else { >+ item.prop("disabled",false); >+ item.removeClass("inactive"); >+ item.addClass("active"); >+ aParent.removeClass("ui-state-disabled"); >+ } >+ // adjust the checkbox state >+ item.prop("checked",selected); >+ }, >+ _refreshGroup: function(group,disabled) { >+ if ( disabled ) { >+ group.addClass("ui-state-disabled"); >+ } else { >+ group.removeClass("ui-state-disabled"); >+ } >+ }, >+ // External command to explicitly close the dropdown >+ close: function() { >+ this._toggleDropContainer(false); >+ }, >+ // External command to refresh the ddcl from the underlying selector >+ refresh: function() { >+ var self = this, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper; >+ >+ var allCheckBoxes = dropWrapper.find("input"); >+ var allGroups = dropWrapper.find(".ui-dropdownchecklist-group"); >+ >+ var groupCount = 0; >+ var optionCount = 0; >+ sourceSelect.children().each(function(index) { >+ var opt = $(this); >+ var disabled = opt.prop("disabled"); >+ if (opt.is("option")) { >+ var selected = opt.prop("selected"); >+ var anItem = $(allCheckBoxes[optionCount]); >+ self._refreshOption(anItem, disabled, selected); >+ optionCount += 1; >+ } else if (opt.is("optgroup")) { >+ var text = opt.attr("label"); >+ if (text != "") { >+ var aGroup = $(allGroups[groupCount]); >+ self._refreshGroup(aGroup, disabled); >+ groupCount += 1; >+ } >+ opt.children("option").each(function() { >+ var subopt = $(this); >+ var subdisabled = (disabled || subopt.prop("disabled")); >+ var selected = subopt.prop("selected"); >+ var subItem = $(allCheckBoxes[optionCount]); >+ self._refreshOption(subItem, subdisabled, selected ); >+ optionCount += 1; >+ }); >+ } >+ }); >+ // sync will handle firstItemChecksAll and updateControlText >+ self._syncSelected(null); >+ }, >+ // External command to enable the ddcl control >+ enable: function() { >+ this.controlSelector.removeClass("ui-state-disabled"); >+ this.disabled = false; >+ }, >+ // External command to disable the ddcl control >+ disable: function() { >+ this.controlSelector.addClass("ui-state-disabled"); >+ this.disabled = true; >+ }, >+ // External command to destroy all traces of the ddcl control >+ destroy: function() { >+ $.Widget.prototype.destroy.apply(this, arguments); >+ this.sourceSelect.css("display", this.initialDisplay); >+ this.sourceSelect.prop("multiple", this.initialMultiple); >+ this.controlWrapper.unbind().remove(); >+ this.dropWrapper.remove(); >+ } >+ }); >+ >+ $.extend($.ui.dropdownchecklist, { >+ defaults: { >+ width: null >+ , maxDropHeight: null >+ , firstItemChecksAll: false >+ , closeRadioOnClick: false >+ , minWidth: 50 >+ , positionHow: 'absolute' >+ , bgiframe: false >+ , explicitClose: null >+ } >+ }); >+ >+})(jQuery); >\ No newline at end of file >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt >index 98d985e..aa6b4b9 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt >@@ -10,11 +10,17 @@ > <link rel="stylesheet" type="text/css" href="[% themelang %]/css/right-to-left.css" /> > [% END %] > <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.fixFloat.js"></script> >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/ui.dropdownchecklist.js"></script> >+ <link rel="stylesheet" type="text/css" href="[% themelang %]/css/ui.dropdownchecklist.themeroller.css" /> > <script type="text/javascript"> > //<![CDATA[ > [% UNLESS ( searchfield ) %]$(document).ready(function(){ > $('#toolbar').fixFloat(); > });[% END %] >+ >+ $(document).ready(function(){ >+ $("select[multiple='multiple']").dropdownchecklist( { emptyText: _("Please select ..."), width: 150 } ); >+ }); > // This is here because of its dependence on template variables, everything else should go in js/pages/preferences.js - jpw > var to_highlight = "[% searchfield |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]"; > var search_jumped = [% IF ( search_jumped ) %]true[% ELSE %]false[% END %]; >@@ -114,15 +120,7 @@ > </select> > [% ELSIF ( CHUNK.type_multiple ) %] > <select name="pref_[% CHUNK.name %]" id="pref_[% CHUNK.name %]" class="preference preference-[% CHUNK.class or "choice" %]" multiple="multiple"> >- [% FOREACH CHOICE IN CHUNK.CHOICES %] >- [% IF ( CHOICE.selected ) %] >- <option value="[% CHOICE.value %]" selected="selected"> >- [% ELSE %] >- <option value="[% CHOICE.value %]"> >- [% END %] >- [% CHOICE.text %] >- </option> >- [% END %] >+ [% FOREACH CHOICE IN CHUNK.CHOICES %][% IF ( CHOICE.selected ) %]<option value="[% CHOICE.value %]" selected="selected">[% ELSE %]<option value="[% CHOICE.value %]">[% END %][% CHOICE.text %]</option>[% END %] > </select> > [% ELSIF ( CHUNK.type_textarea ) %] > <a class="expand-textarea" style="display: none" href="#">Click to Edit</a> >-- >1.7.10.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 9043
:
13385
|
13858
|
15312
|
15328
|
15329
|
15546
|
15547
|
15792
|
19150
|
19151
|
20316
|
20317
|
20318
|
20717
|
20718
|
21643
|
21644
|
21645
|
27524
|
27525
|
27526
|
29005
|
29006
|
29007
|
29914
|
29915
|
29916
|
29945
|
29946
|
30183
|
30184
|
30185
|
30186
|
30967
|
30968
|
30969
|
31170
|
31557
|
31558
|
31559
|
31560
|
31561
|
33428
|
33429
|
33430
|
33431
|
33432
|
33617
|
33620
|
33947