View | Details | Raw Unified | Return to bug 9043
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/en/css/ui.dropdownchecklist.themeroller.css (+29 lines)
Line 0 Link Here
1
/** Simple modifications needed for DropDownCheckList to take advantage of ThemeRoller settings */
2
.ui-dropdownchecklist .ui-widget-content
3
, .ui-dropdownchecklist .ui-widget-header {
4
	border: none;
5
}
6
.ui-dropdownchecklist-indent {
7
	padding-left: 7px;
8
}
9
/* Font size of 0 on the -selector and an explicit medium on -text required to eliminate 
10
   descender problems within the containers and still have a valid size for the text */
11
.ui-dropdownchecklist-selector-wrapper
12
, .ui-widget.ui-dropdownchecklist-selector-wrapper {
13
	vertical-align: middle;
14
	font-size: 0px;
15
}
16
.ui-dropdownchecklist-selector {
17
	padding: 1px 2px 2px 2px;
18
	font-size: 0px;
19
}
20
.ui-dropdownchecklist-text {
21
	font-size: medium;
22
}
23
.ui-dropdownchecklist-item
24
, .ui-dropdownchecklist-item input {
25
    vertical-align: middle;
26
}
27
.ui-dropdownchecklist-group {
28
	padding: 1px 2px 2px 2px;
29
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/ui.dropdownchecklist.js (+917 lines)
Line 0 Link Here
1
;(function($) {
2
/*
3
    * ui.dropdownchecklist
4
    *
5
    * Copyright (c) 2008-2010 Adrian Tosca, Copyright (c) 2010-2011 Ittrium LLC
6
    * Dual licensed under the MIT (MIT-LICENSE.txt) OR GPL (GPL-LICENSE.txt) licenses.
7
    *
8
*/
9
    // The dropdown check list jQuery plugin transforms a regular select html element into a dropdown check list.
10
    $.widget("ui.dropdownchecklist", {
11
    	// Some globlals
12
    	// $.ui.dropdownchecklist.gLastOpened - keeps track of last opened dropdowncheck list so we can close it
13
    	// $.ui.dropdownchecklist.gIDCounter - simple counter to provide a unique ID as needed
14
        version: function() {
15
            alert('DropDownCheckList v1.4');
16
        },    	
17
        // Creates the drop container that keeps the items and appends it to the document
18
        _appendDropContainer: function( controlItem ) {
19
            var wrapper = $("<div/>");
20
            // the container is wrapped in a div
21
            wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-dropcontainer-wrapper");
22
            wrapper.addClass("ui-widget");
23
            // assign an id
24
            wrapper.attr("id",controlItem.attr("id") + '-ddw');
25
            // initially positioned way off screen to prevent it from displaying
26
            // NOTE absolute position to enable width/height calculation
27
            wrapper.css({ position: 'absolute', left: "-33000px", top: "-33000px"  });
28
            
29
            var container = $("<div/>"); // the actual container
30
            container.addClass("ui-dropdownchecklist-dropcontainer ui-widget-content");
31
            container.css("overflow-y", "auto");
32
            wrapper.append(container);
33
            
34
            // insert the dropdown after the master control to try to keep the tab order intact
35
            // if you just add it to the end, tabbing out of the drop down takes focus off the page
36
            // @todo 22Sept2010 - check if size calculation is thrown off if the parent of the
37
            //		selector is hidden.  We may need to add it to the end of the document here, 
38
            //		calculate the size, and then move it back into proper position???
39
			//$(document.body).append(wrapper);
40
            wrapper.insertAfter(controlItem);
41
42
            // flag that tells if the drop container is shown or not
43
            wrapper.isOpen = false;
44
            return wrapper;
45
        },
46
        // Look for browser standard 'open' on a closed selector
47
		_isDropDownKeyShortcut: function(e,keycode) {
48
			return e.altKey && ($.ui.keyCode.DOWN == keycode);// Alt + Down Arrow
49
		},
50
		// Look for key that will tell us to close the open dropdown
51
		_isDropDownCloseKey: function(e,keycode) {
52
			return ($.ui.keyCode.ESCAPE == keycode) || ($.ui.keyCode.ENTER == keycode);
53
		},
54
		// Handler to change the active focus based on a keystroke, moving some count of
55
		// items from the element that has the current focus
56
		_keyFocusChange: function(target,delta,limitToItems) {
57
			// Find item with current focus
58
			var focusables = $(":focusable");
59
			var index = focusables.index(target);
60
			if ( index >= 0 ) {
61
				index += delta;
62
				if ( limitToItems ) {
63
					// Bound change to list of input elements
64
	            	var allCheckboxes = this.dropWrapper.find("input:not([disabled])");
65
	            	var firstIndex = focusables.index(allCheckboxes.get(0));
66
	            	var lastIndex = focusables.index(allCheckboxes.get(allCheckboxes.length-1));
67
	            	if ( index < firstIndex ) {
68
	            		index = lastIndex;
69
	            	} else if ( index > lastIndex ) {
70
	            		index = firstIndex;
71
	            	}
72
	            }
73
				focusables.get(index).focus();
74
			}
75
		},
76
		// Look for navigation, open, close (wired to keyup)
77
		_handleKeyboard: function(e) {
78
			var self = this;
79
			var keyCode = (e.keyCode || e.which);
80
			if (!self.dropWrapper.isOpen && self._isDropDownKeyShortcut(e, keyCode)) {
81
				// Key command to open the dropdown
82
				e.stopImmediatePropagation();
83
				self._toggleDropContainer(true);
84
			} else if (self.dropWrapper.isOpen && self._isDropDownCloseKey(e, keyCode)) {
85
				// Key command to close the dropdown (but we retain focus in the control)
86
				e.stopImmediatePropagation();
87
				self._toggleDropContainer(false);
88
				self.controlSelector.focus();
89
			} else if (self.dropWrapper.isOpen 
90
					&& (e.target.type == 'checkbox')
91
					&& ((keyCode == $.ui.keyCode.DOWN) || (keyCode == $.ui.keyCode.UP)) ) {
92
				// Up/Down to cycle throught the open items
93
				e.stopImmediatePropagation();
94
				self._keyFocusChange(e.target, (keyCode == $.ui.keyCode.DOWN) ? 1 : -1, true);
95
			} else if (self.dropWrapper.isOpen && (keyCode == $.ui.keyCode.TAB) ) {
96
				// I wanted to adjust normal 'tab' processing here, but research indicates
97
				// that TAB key processing is NOT a cancelable event. You have to use a timer
98
				// hack to pull the focus back to where you want it after browser tab
99
				// processing completes.  Not going to work for us.
100
				//e.stopImmediatePropagation();
101
				//self._keyFocusChange(e.target, (e.shiftKey) ? -1 : 1, true);
102
           }
103
		},
104
		// Look for change of focus
105
		_handleFocus: function(e,focusIn,forDropdown) {
106
			var self = this;
107
			if (forDropdown && !self.dropWrapper.isOpen) {
108
				// if the focus changes when the control is NOT open, mark it to show where the focus is/is not
109
				e.stopImmediatePropagation();
110
				if (focusIn) {
111
					self.controlSelector.addClass("ui-state-hover");
112
					if ($.ui.dropdownchecklist.gLastOpened != null) {
113
						$.ui.dropdownchecklist.gLastOpened._toggleDropContainer( false );
114
					}
115
				} else {
116
					self.controlSelector.removeClass("ui-state-hover");
117
				}
118
           	} else if (!forDropdown && !focusIn) {
119
           		// The dropdown is open, and an item (NOT the dropdown) has just lost the focus.
120
           		// we really need a reliable method to see who has the focus as we process the blur,
121
           		// but that mechanism does not seem to exist.  Instead we rely on a delay before
122
           		// posting the blur, with a focus event cancelling it before the delay expires.
123
				if ( e != null ) { e.stopImmediatePropagation(); }
124
				self.controlSelector.removeClass("ui-state-hover");
125
				self._toggleDropContainer( false );	        	
126
           	}
127
		},
128
		// Clear the pending change of focus, which keeps us 'in' the control
129
		_cancelBlur: function(e) {
130
			var self = this;
131
			if (self.blurringItem != null) {
132
				clearTimeout(self.blurringItem);
133
				self.blurringItem = null;
134
			} 
135
		},
136
        // Creates the control that will replace the source select and appends it to the document
137
        // The control resembles a regular select with single selection
138
        _appendControl: function() {
139
            var self = this, sourceSelect = this.sourceSelect, options = this.options;
140
141
            // the control is wrapped in a basic container
142
            // inline-block at this level seems to give us better size control
143
            var wrapper = $("<span/>");
144
            wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-selector-wrapper ui-widget");
145
            wrapper.css( { display: "inline-block", cursor: "default", overflow: "hidden" } );
146
            
147
            // assign an ID 
148
            var baseID = sourceSelect.attr("id");
149
            if ((baseID == null) || (baseID == "")) {
150
            	baseID = "ddcl-" + $.ui.dropdownchecklist.gIDCounter++;
151
            } else {
152
            	baseID = "ddcl-" + baseID;
153
			}
154
			wrapper.attr("id",baseID);
155
			
156
            // the actual control which you can style
157
            // inline-block needed to enable 'width' but has interesting problems cross browser
158
            var control = $("<span/>");
159
            control.addClass("ui-dropdownchecklist-selector ui-state-default");
160
            control.css( { display: "inline-block", overflow: "hidden", 'white-space': 'nowrap'} );
161
            // Setting a tab index means we are interested in the tab sequence
162
            var tabIndex = sourceSelect.attr("tabIndex");
163
            if ( tabIndex == null ) {
164
            	tabIndex = 0;
165
            } else {
166
            	tabIndex = parseInt(tabIndex);
167
            	if ( tabIndex < 0 ) {
168
            		tabIndex = 0;
169
            	}
170
            }
171
			control.attr("tabIndex", tabIndex);
172
			control.keyup(function(e) {self._handleKeyboard(e);});
173
			control.focus(function(e) {self._handleFocus(e,true,true);});
174
			control.blur(function(e) {self._handleFocus(e,false,true);});
175
            wrapper.append(control);
176
177
			// the optional icon (which is inherently a block) which we can float
178
			if (options.icon != null) {
179
				var iconPlacement = (options.icon.placement == null) ? "left" : options.icon.placement;
180
	            var anIcon = $("<div/>");
181
	            anIcon.addClass("ui-icon");
182
	            anIcon.addClass( (options.icon.toOpen != null) ? options.icon.toOpen : "ui-icon-triangle-1-e");
183
	            anIcon.css({ 'float': iconPlacement });
184
	            control.append(anIcon);
185
			}
186
            // the text container keeps the control text that is built from the selected (checked) items
187
            // inline-block needed to prevent long text from wrapping to next line when icon is active
188
            var textContainer = $("<span/>");
189
            textContainer.addClass("ui-dropdownchecklist-text");
190
            textContainer.css( {  display: "inline-block", 'white-space': "nowrap", overflow: "hidden" } );
191
            control.append(textContainer);
192
193
            // add the hover styles to the control
194
            wrapper.hover(
195
	            function() {
196
	                if (!self.disabled) {
197
	                    control.addClass("ui-state-hover");
198
	                }
199
	            }
200
	        , 	function() {
201
	                if (!self.disabled) {
202
	                    control.removeClass("ui-state-hover");
203
	                }
204
	            }
205
	        );
206
            // clicking on the control toggles the drop container
207
            wrapper.click(function(event) {
208
                if (!self.disabled) {
209
                    event.stopImmediatePropagation();
210
                    self._toggleDropContainer( !self.dropWrapper.isOpen );
211
                }
212
            });
213
            wrapper.insertAfter(sourceSelect);
214
215
			// Watch for a window resize and adjust the control if open
216
            $(window).resize(function() {
217
                if (!self.disabled && self.dropWrapper.isOpen) {
218
                	// Reopen yourself to get the position right
219
                    self._toggleDropContainer(true);
220
                }
221
            });       
222
            return wrapper;
223
        },
224
        // Creates a drop item that coresponds to an option element in the source select
225
        _createDropItem: function(index, tabIndex, value, text, optCss, checked, disabled, indent) {
226
            var self = this, options = this.options, sourceSelect = this.sourceSelect, controlWrapper = this.controlWrapper;
227
            // the item contains a div that contains a checkbox input and a lable for the text
228
            // the div
229
            var item = $("<div/>");
230
            item.addClass("ui-dropdownchecklist-item");
231
            item.css({'white-space': "nowrap"});
232
            var checkedString = checked ? ' checked="checked"' : '';
233
			var classString = disabled ? ' class="inactive"' : ' class="active"';
234
			
235
			// generated id must be a bit unique to keep from colliding
236
			var idBase = controlWrapper.attr("id");
237
			var id = idBase + '-i' + index;
238
            var checkBox;
239
            
240
            // all items start out disabled to keep them out of the tab order
241
            if (self.isMultiple) { // the checkbox
242
                checkBox = $('<input disabled type="checkbox" id="' + id + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />');
243
            } else { // the radiobutton
244
                checkBox = $('<input disabled type="radio" id="' + id + '" name="' + idBase + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />');
245
            }
246
            checkBox = checkBox.attr("index", index).val(value);
247
            item.append(checkBox);
248
            
249
            // the text
250
            var label = $("<label for=" + id + "/>");
251
            label.addClass("ui-dropdownchecklist-text");
252
            if ( optCss != null ) label.attr('style',optCss);
253
            label.css({ cursor: "default" });
254
            label.html(text);
255
			if (indent) {
256
				item.addClass("ui-dropdownchecklist-indent");
257
			}
258
			item.addClass("ui-state-default");
259
			if (disabled) {
260
				item.addClass("ui-state-disabled");
261
			}
262
	        label.click(function(e) {e.stopImmediatePropagation();});
263
            item.append(label);
264
            
265
           	// active items display themselves with hover
266
            item.hover(
267
            	function(e) {
268
            		var anItem = $(this);
269
                	if (!anItem.hasClass("ui-state-disabled")) { anItem.addClass("ui-state-hover"); }
270
            	}
271
            , 	function(e) {
272
            		var anItem = $(this);
273
                	anItem.removeClass("ui-state-hover");
274
            	}
275
            );
276
            // clicking on the checkbox synchronizes the source select
277
	        checkBox.click(function(e) {
278
	        	var aCheckBox = $(this);
279
				e.stopImmediatePropagation();
280
				if (aCheckBox.hasClass("active") ) {
281
					// Active checkboxes take active action
282
	                var callback = self.options.onItemClick;
283
	                if ($.isFunction(callback)) try {
284
                        callback.call(self,aCheckBox,sourceSelect.get(0));
285
                    } catch (ex) {
286
                        // reject the change on any error
287
                        aCheckBox.prop("checked",!aCheckBox.prop("checked"));
288
	                	self._syncSelected(aCheckBox);
289
                        return;
290
                    } 
291
	                self._syncSelected(aCheckBox);
292
	                self.sourceSelect.trigger("change", 'ddcl_internal');
293
	                if (!self.isMultiple && options.closeRadioOnClick) {
294
	                	self._toggleDropContainer(false);
295
	                }
296
				}
297
	        });
298
	        // we are interested in the focus leaving the check box
299
	        // but we need to detect the focus leaving one check box but
300
	        // entering another. There is no reliable way to detect who
301
	        // received the focus on a blur, so post the blur in the future,
302
	        // knowing we will cancel it if we capture the focus in a timely manner
303
	        // 23Sept2010 - unfortunately, IE 7+ and Chrome like to post a blur
304
	        // 				event to the current item with focus when the user
305
	        //				clicks in the scroll bar. So if you have a scrollable
306
	        //				dropdown with focus on an item, clicking in the scroll
307
	        //				will close the drop down.
308
	        //				I have no solution for blur processing at this time.
309
/*********
310
			var timerFunction = function(){ 
311
				// I had a hell of a time getting setTimeout to fire this, do not try to
312
				// define it within the blur function
313
				try { self._handleFocus(null,false,false); } catch(ex){ alert('timer failed: '+ex);}
314
			};
315
			checkBox.blur(function(e) { 
316
				self.blurringItem = setTimeout( timerFunction, 200 ); 
317
			});
318
			checkBox.focus(function(e) {self._cancelBlur();});
319
**********/	
320
	        // check/uncheck the item on clicks on the entire item div
321
	        item.click(function(e) {
322
	        	var anItem = $(this);
323
                e.stopImmediatePropagation();
324
				if (!anItem.hasClass("ui-state-disabled") ) {
325
					// check/uncheck the underlying control
326
					var aCheckBox = anItem.find("input");
327
	                var checked = aCheckBox.prop("checked");
328
	                aCheckBox.prop("checked", !checked);
329
	                
330
	                var callback = self.options.onItemClick;
331
	                if ($.isFunction(callback)) try {
332
                        callback.call(self,aCheckBox,sourceSelect.get(0));
333
                    } catch (ex) {
334
                        // reject the change on any error
335
                        aCheckBox.prop("checked",checked);
336
	                	self._syncSelected(aCheckBox);
337
                        return;
338
                    } 
339
	                self._syncSelected(aCheckBox);
340
	                self.sourceSelect.trigger("change", 'ddcl_internal');
341
	                if (!checked && !self.isMultiple && options.closeRadioOnClick) {
342
	                	self._toggleDropContainer(false);
343
	                }
344
				} else {
345
					// retain the focus even if disabled
346
					anItem.focus();
347
					self._cancelBlur();
348
				}
349
	        });
350
	        // do not let the focus wander around
351
			item.focus(function(e) { 
352
	        	var anItem = $(this);
353
                e.stopImmediatePropagation();
354
            });
355
			item.keyup(function(e) {self._handleKeyboard(e);});
356
            return item;
357
        },
358
		_createGroupItem: function(text,disabled) {
359
			var self = this;
360
			var group = $("<div />");
361
			group.addClass("ui-dropdownchecklist-group ui-widget-header");
362
			if (disabled) {
363
				group.addClass("ui-state-disabled");
364
			}
365
			group.css({'white-space': "nowrap"});
366
			
367
            var label = $("<span/>");
368
            label.addClass("ui-dropdownchecklist-text");
369
            label.css( { cursor: "default" });
370
            label.text(text);
371
			group.append(label);
372
			
373
			// anything interesting when you click the group???
374
	        group.click(function(e) {
375
	        	var aGroup= $(this);
376
                e.stopImmediatePropagation();
377
                // retain the focus even if no action is taken
378
                aGroup.focus();
379
                self._cancelBlur();
380
            });
381
	        // do not let the focus wander around
382
			group.focus(function(e) { 
383
	        	var aGroup = $(this);
384
                e.stopImmediatePropagation();
385
            });
386
			return group;
387
		},
388
		_createCloseItem: function(text) {
389
			var self = this;
390
			var closeItem = $("<div />");
391
			closeItem.addClass("ui-state-default ui-dropdownchecklist-close ui-dropdownchecklist-item");
392
			closeItem.css({'white-space': 'nowrap', 'text-align': 'right'});
393
			
394
            var label = $("<span/>");
395
            label.addClass("ui-dropdownchecklist-text");
396
            label.css( { cursor: "default" });
397
            label.html(text);
398
			closeItem.append(label);
399
			
400
			// close the control on click
401
	        closeItem.click(function(e) {
402
	        	var aGroup= $(this);
403
                e.stopImmediatePropagation();
404
                // retain the focus even if no action is taken
405
                aGroup.focus();
406
                self._toggleDropContainer( false );
407
            });
408
            closeItem.hover(
409
            	function(e) { $(this).addClass("ui-state-hover"); }
410
            , 	function(e) { $(this).removeClass("ui-state-hover"); }
411
            );
412
	        // do not let the focus wander around
413
			closeItem.focus(function(e) { 
414
	        	var aGroup = $(this);
415
                e.stopImmediatePropagation();
416
            });
417
			return closeItem;
418
		},
419
        // Creates the drop items and appends them to the drop container
420
        // Also calculates the size needed by the drop container and returns it
421
        _appendItems: function() {
422
            var self = this, config = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;
423
            var dropContainerDiv = dropWrapper.find(".ui-dropdownchecklist-dropcontainer");
424
			sourceSelect.children().each(function(index) { // when the select has groups
425
				var opt = $(this);
426
                if (opt.is("option")) {
427
                    self._appendOption(opt, dropContainerDiv, index, false, false);
428
                } else if (opt.is("optgroup")) {
429
					var disabled = opt.prop("disabled");
430
                    var text = opt.attr("label");
431
                    if (text != "") {
432
	                    var group = self._createGroupItem(text,disabled);
433
	                    dropContainerDiv.append(group);
434
	                }
435
                    self._appendOptions(opt, dropContainerDiv, index, true, disabled);
436
                }
437
			});
438
			if ( config.explicitClose != null ) {
439
				var closeItem = self._createCloseItem(config.explicitClose);
440
				dropContainerDiv.append(closeItem);
441
			}
442
            var divWidth = dropContainerDiv.outerWidth();
443
            var divHeight = dropContainerDiv.outerHeight();
444
            return { width: divWidth, height: divHeight };
445
        },
446
		_appendOptions: function(parent, container, parentIndex, indent, forceDisabled) {
447
			var self = this;
448
			parent.children("option").each(function(index) {
449
                var option = $(this);
450
                var childIndex = (parentIndex + "." + index);
451
                self._appendOption(option, container, childIndex, indent, forceDisabled);
452
            });
453
		},
454
        _appendOption: function(option, container, index, indent, forceDisabled) {
455
            var self = this;
456
            // Note that the browsers destroy any html structure within the OPTION
457
            var text = option.html();
458
            if ( (text != null) && (text != '') ) {
459
            	var value = option.val();
460
            	var optCss = option.attr('style');
461
            	var selected = option.prop("selected");
462
				var disabled = (forceDisabled || option.prop("disabled"));
463
				// Use the same tab index as the selector replacement
464
				var tabIndex = self.controlSelector.attr("tabindex");
465
            	var item = self._createDropItem(index, tabIndex, value, text, optCss, selected, disabled, indent);
466
            	container.append(item);
467
            }
468
        },
469
        // Synchronizes the items checked and the source select
470
        // When firstItemChecksAll option is active also synchronizes the checked items
471
        // senderCheckbox parameters is the checkbox input that generated the synchronization
472
        _syncSelected: function(senderCheckbox) {
473
            var self = this, options = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;
474
            var selectOptions = sourceSelect.get(0).options;
475
            var allCheckboxes = dropWrapper.find("input.active");
476
            if (options.firstItemChecksAll == 'exclusive') {
477
            	if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) {
478
            		// Initialization call with first item active
479
                    allCheckboxes.prop("checked", false);
480
                    $(allCheckboxes[0]).prop("checked", true);
481
                } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) {
482
                	// Action on the first, so all other checkboxes NOT active
483
                	var firstIsActive = senderCheckbox.prop("checked");
484
                    allCheckboxes.prop("checked", false);
485
                    $(allCheckboxes[0]).prop("checked", firstIsActive);
486
                } else  {
487
                    // check the first checkbox if all the other checkboxes are checked
488
                    var allChecked = true;
489
                    var firstCheckbox = null;
490
                    allCheckboxes.each(function(index) {
491
                        if (index > 0) {
492
                            var checked = $(this).prop("checked");
493
                            if (!checked) { allChecked = false; }
494
                        } else {
495
                        	firstCheckbox = $(this);
496
                        }
497
                    });
498
                    if ( firstCheckbox != null ) {
499
                    	if ( allChecked ) {
500
                    		// when all are checked, only the first left checked
501
                    		allCheckboxes.prop("checked", false);
502
                    	}
503
                    	firstCheckbox.prop("checked", allChecked );
504
                    }
505
                }
506
            } else if (options.firstItemChecksAll) {
507
            	if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) {
508
            		// Initialization call with first item active so force all to be active
509
                    allCheckboxes.prop("checked", true);
510
                } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) {
511
                	// Check all checkboxes if the first one is checked
512
                    allCheckboxes.prop("checked", senderCheckbox.prop("checked"));
513
                } else  {
514
                    // check the first checkbox if all the other checkboxes are checked
515
                    var allChecked = true;
516
                    var firstCheckbox = null;
517
                    allCheckboxes.each(function(index) {
518
                        if (index > 0) {
519
                            var checked = $(this).prop("checked");
520
                            if (!checked) { allChecked = false; }
521
                        } else {
522
                        	firstCheckbox = $(this);
523
                        }
524
                    });
525
                    if ( firstCheckbox != null ) {
526
                    	firstCheckbox.prop("checked", allChecked );
527
                    }
528
                }
529
            }
530
            // do the actual synch with the source select
531
            var empties = 0;
532
            allCheckboxes = dropWrapper.find("input");
533
            allCheckboxes.each(function(index) {
534
            	var anOption = $(selectOptions[index + empties]);
535
            	var optionText = anOption.html();
536
            	if ( (optionText == null) || (optionText == '') ) {
537
                    empties += 1;
538
                    anOption = $(selectOptions[index + empties]);
539
            	}
540
                anOption.prop("selected", $(this).prop("checked"));
541
            });
542
            // update the text shown in the control
543
            self._updateControlText();
544
        	
545
        	// Ensure the focus stays pointing where the user is working
546
        	if ( senderCheckbox != null) { senderCheckbox.focus(); }
547
        },
548
        _sourceSelectChangeHandler: function(event) {
549
            var self = this, dropWrapper = this.dropWrapper;
550
            dropWrapper.find("input").val(self.sourceSelect.val());
551
552
        	// update the text shown in the control
553
        	self._updateControlText();
554
        },
555
        // Updates the text shown in the control depending on the checked (selected) items
556
        _updateControlText: function() {
557
            var self = this, sourceSelect = this.sourceSelect, options = this.options, controlWrapper = this.controlWrapper;
558
            var firstOption = sourceSelect.find("option:first");
559
            var selectOptions = sourceSelect.find("option");
560
            var text = self._formatText(selectOptions, options.firstItemChecksAll, firstOption);
561
            var controlLabel = controlWrapper.find(".ui-dropdownchecklist-text");
562
            controlLabel.html(text);
563
            // the attribute needs naked text, not html
564
            controlLabel.attr("title", controlLabel.text());
565
        },
566
        // Formats the text that is shown in the control
567
        _formatText: function(selectOptions, firstItemChecksAll, firstOption) {
568
            var text;
569
            if ( $.isFunction(this.options.textFormatFunction) ) {
570
            	// let the callback do the formatting, but do not allow it to fail
571
            	try {
572
                	text = this.options.textFormatFunction(selectOptions);
573
                } catch(ex) {
574
                	alert( 'textFormatFunction failed: ' + ex );
575
                }
576
            } else if (firstItemChecksAll && (firstOption != null) && firstOption.prop("selected")) {
577
                // just set the text from the first item
578
                text = firstOption.html();
579
            } else {
580
                // concatenate the text from the checked items
581
                text = "";
582
                selectOptions.each(function() {
583
                    if ($(this).prop("selected")) {
584
                        if ( text != "" ) { text += ", "; }
585
                        /* NOTE use of .html versus .text, which can screw up ampersands for IE */
586
                        var optCss = $(this).attr('style');
587
                        var tempspan = $('<span/>');
588
                        tempspan.html( $(this).html() );
589
                        if ( optCss == null ) {
590
                        	text += tempspan.html();
591
                        } else {
592
                        	tempspan.attr('style',optCss);
593
                        	text += $("<span/>").append(tempspan).html();
594
                        }
595
                    }
596
                });
597
                if ( text == "" ) {
598
                    text = (this.options.emptyText != null) ? this.options.emptyText : "&nbsp;";
599
                }
600
            }
601
            return text;
602
        },
603
        // Shows and hides the drop container
604
        _toggleDropContainer: function( makeOpen ) {
605
            var self = this;
606
            // hides the last shown drop container
607
            var hide = function(instance) {
608
                if ((instance != null) && instance.dropWrapper.isOpen ){
609
                    instance.dropWrapper.isOpen = false;
610
                    $.ui.dropdownchecklist.gLastOpened = null;
611
612
	            	var config = instance.options;
613
                    instance.dropWrapper.css({
614
                        top: "-33000px",
615
                        left: "-33000px"
616
                    });
617
                    var aControl = instance.controlSelector;
618
	                aControl.removeClass("ui-state-active");
619
	                aControl.removeClass("ui-state-hover");
620
621
                    var anIcon = instance.controlWrapper.find(".ui-icon");
622
                    if ( anIcon.length > 0 ) {
623
                    	anIcon.removeClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s");
624
                    	anIcon.addClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e");
625
                    }
626
                    $(document).unbind("click", hide);
627
                    
628
                    // keep the items out of the tab order by disabling them
629
                    instance.dropWrapper.find("input.active").prop("disabled",true);
630
                    
631
                    // the following blur just does not fire???  because it is hidden???  because it does not have focus???
632
			  		//instance.sourceSelect.trigger("blur");
633
			  		//instance.sourceSelect.triggerHandler("blur");
634
			  		if($.isFunction(config.onComplete)) { try {
635
			     		config.onComplete.call(instance,instance.sourceSelect.get(0));
636
                    } catch(ex) {
637
                    	alert( 'callback failed: ' + ex );
638
                    }}
639
                }
640
            };
641
            // shows the given drop container instance
642
            var show = function(instance) {
643
            	if ( !instance.dropWrapper.isOpen ) {
644
	                instance.dropWrapper.isOpen = true;
645
	                $.ui.dropdownchecklist.gLastOpened = instance;
646
647
	            	var config = instance.options;
648
/**** Issue127 (and the like) to correct positioning when parent element is relative
649
 ****	This positioning only worked with simple, non-relative parent position
650
	                instance.dropWrapper.css({
651
	                    top: instance.controlWrapper.offset().top + instance.controlWrapper.outerHeight() + "px",
652
	                    left: instance.controlWrapper.offset().left + "px"
653
	                });
654
****/
655
             		if ((config.positionHow == null) || (config.positionHow == 'absolute')) {
656
             			/** Floats above subsequent content, but does NOT scroll */
657
		                instance.dropWrapper.css({
658
		                    position: 'absolute'
659
		                ,   top: instance.controlWrapper.position().top + instance.controlWrapper.outerHeight() + "px"
660
		                ,   left: instance.controlWrapper.position().left + "px"
661
		                });
662
		            } else if (config.positionHow == 'relative') {
663
		            	/** Scrolls with the parent but does NOT float above subsequent content */
664
		                instance.dropWrapper.css({
665
		                    position: 'relative'
666
		                ,   top: "0px"
667
		                ,   left: "0px"
668
		                });
669
					}
670
					var zIndex = 0;
671
					if (config.zIndex == null) {
672
						var ancestorsZIndexes = instance.controlWrapper.parents().map(
673
							function() {
674
								var zIndex = $(this).css("z-index");
675
								return isNaN(zIndex) ? 0 : zIndex; }
676
							).get();
677
						var parentZIndex = Math.max.apply(Math, ancestorsZIndexes);
678
						if ( parentZIndex >= 0) zIndex = parentZIndex+1;
679
					} else {
680
						/* Explicit set from the optins */
681
						zIndex = parseInt(config.zIndex);
682
					}
683
					if (zIndex > 0) {
684
						instance.dropWrapper.css( { 'z-index': zIndex } );
685
					}
686
687
	                var aControl = instance.controlSelector;
688
	                aControl.addClass("ui-state-active");
689
	                aControl.removeClass("ui-state-hover");
690
	                
691
	                var anIcon = instance.controlWrapper.find(".ui-icon");
692
	                if ( anIcon.length > 0 ) {
693
	                	anIcon.removeClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e");
694
	                	anIcon.addClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s");
695
	                }
696
	                $(document).bind("click", function(e) {hide(instance);} );
697
	                
698
                    // insert the items back into the tab order by enabling all active ones
699
                    var activeItems = instance.dropWrapper.find("input.active");
700
                    activeItems.prop("disabled",false);
701
                    
702
                    // we want the focus on the first active input item
703
                    var firstActiveItem = activeItems.get(0);
704
                    if ( firstActiveItem != null ) {
705
                    	firstActiveItem.focus();
706
                    }
707
			    }
708
            };
709
            if ( makeOpen ) {
710
            	hide($.ui.dropdownchecklist.gLastOpened);
711
            	show(self);
712
            } else {
713
            	hide(self);
714
            }
715
        },
716
        // Set the size of the control and of the drop container
717
        _setSize: function(dropCalculatedSize) {
718
            var options = this.options, dropWrapper = this.dropWrapper, controlWrapper = this.controlWrapper;
719
720
            // use the width from config options if set, otherwise set the same width as the drop container
721
            var controlWidth = dropCalculatedSize.width;
722
            if (options.width != null) {
723
                controlWidth = parseInt(options.width);
724
            } else if (options.minWidth != null) {
725
                var minWidth = parseInt(options.minWidth);
726
                // if the width is too small (usually when there are no items) set a minimum width
727
                if (controlWidth < minWidth) {
728
                    controlWidth = minWidth;
729
                }
730
            }
731
            var control = this.controlSelector;
732
            control.css({ width: controlWidth + "px" });
733
            
734
            // if we size the text, then Firefox places icons to the right properly
735
            // and we do not wrap on long lines
736
            var controlText = control.find(".ui-dropdownchecklist-text");
737
            var controlIcon = control.find(".ui-icon");
738
            if ( controlIcon != null ) {
739
            	// Must be an inner/outer/border problem, but IE6 needs an extra bit of space,
740
            	// otherwise you can get text pushed down into a second line when icons are active
741
            	controlWidth -= (controlIcon.outerWidth() + 4);
742
            	controlText.css( { width: controlWidth + "px" } );
743
            }
744
            // Account for padding, borders, etc
745
            controlWidth = controlWrapper.outerWidth();
746
            
747
            // the drop container height can be set from options
748
            var maxDropHeight = (options.maxDropHeight != null)
749
            					? parseInt(options.maxDropHeight)
750
            					: -1;
751
            var dropHeight = ((maxDropHeight > 0) && (dropCalculatedSize.height > maxDropHeight))
752
            					? maxDropHeight 
753
            					: dropCalculatedSize.height;
754
            // ensure the drop container is not less than the control width (would be ugly)
755
            var dropWidth = dropCalculatedSize.width < controlWidth ? controlWidth : dropCalculatedSize.width;
756
757
            $(dropWrapper).css({
758
                height: dropHeight + "px",
759
                width: dropWidth + "px"
760
            });
761
            dropWrapper.find(".ui-dropdownchecklist-dropcontainer").css({
762
                height: dropHeight + "px"
763
            });
764
        },
765
        // Initializes the plugin
766
        _init: function() {
767
            var self = this, options = this.options;
768
			if ( $.ui.dropdownchecklist.gIDCounter == null) {
769
				$.ui.dropdownchecklist.gIDCounter = 1;
770
			}
771
            // item blurring relies on a cancelable timer
772
            self.blurringItem = null;
773
774
            // sourceSelect is the select on which the plugin is applied
775
            var sourceSelect = self.element;
776
            self.initialDisplay = sourceSelect.css("display");
777
            sourceSelect.css("display", "none");
778
            self.initialMultiple = sourceSelect.prop("multiple");
779
            self.isMultiple = self.initialMultiple;
780
            if (options.forceMultiple != null) { self.isMultiple = options.forceMultiple; }
781
            sourceSelect.prop("multiple", true);
782
            self.sourceSelect = sourceSelect;
783
784
            // append the control that resembles a single selection select
785
            var controlWrapper = self._appendControl();
786
            self.controlWrapper = controlWrapper;
787
            self.controlSelector = controlWrapper.find(".ui-dropdownchecklist-selector");
788
789
            // create the drop container where the items are shown
790
            var dropWrapper = self._appendDropContainer(controlWrapper);
791
            self.dropWrapper = dropWrapper;
792
793
            // append the items from the source select element
794
            var dropCalculatedSize = self._appendItems();
795
796
            // updates the text shown in the control
797
            self._updateControlText(controlWrapper, dropWrapper, sourceSelect);
798
799
            // set the sizes of control and drop container
800
            self._setSize(dropCalculatedSize);
801
            
802
            // look for possible auto-check needed on first item
803
			if ( options.firstItemChecksAll ) {
804
				self._syncSelected(null);
805
			}
806
            // BGIFrame for IE6
807
			if (options.bgiframe && typeof self.dropWrapper.bgiframe == "function") {
808
				self.dropWrapper.bgiframe();
809
			}
810
          	// listen for change events on the source select element
811
          	// ensure we avoid processing internally triggered changes
812
          	self.sourceSelect.change(function(event, eventName) {
813
	            if (eventName != 'ddcl_internal') {
814
	                self._sourceSelectChangeHandler(event);
815
	            }
816
	        });
817
        },
818
        // Refresh the disable and check state from the underlying control
819
        _refreshOption: function(item,disabled,selected) {
820
			var aParent = item.parent();
821
			// account for enabled/disabled
822
            if ( disabled ) {
823
            	item.prop("disabled",true);
824
            	item.removeClass("active");
825
            	item.addClass("inactive");
826
            	aParent.addClass("ui-state-disabled");
827
            } else {
828
            	item.prop("disabled",false);
829
            	item.removeClass("inactive");
830
            	item.addClass("active");
831
            	aParent.removeClass("ui-state-disabled");
832
            }
833
            // adjust the checkbox state
834
            item.prop("checked",selected);
835
        },
836
        _refreshGroup: function(group,disabled) {
837
            if ( disabled ) {
838
            	group.addClass("ui-state-disabled");
839
            } else {
840
            	group.removeClass("ui-state-disabled");
841
            }
842
        },
843
        // External command to explicitly close the dropdown
844
        close: function() {
845
			this._toggleDropContainer(false);
846
        },
847
        // External command to refresh the ddcl from the underlying selector
848
        refresh: function() {
849
            var self = this, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;
850
            
851
            var allCheckBoxes = dropWrapper.find("input");
852
            var allGroups = dropWrapper.find(".ui-dropdownchecklist-group");
853
            
854
            var groupCount = 0;
855
            var optionCount = 0;
856
			sourceSelect.children().each(function(index) {
857
				var opt = $(this);
858
				var disabled = opt.prop("disabled");
859
                if (opt.is("option")) {
860
                	var selected = opt.prop("selected");
861
                	var anItem = $(allCheckBoxes[optionCount]);
862
                    self._refreshOption(anItem, disabled, selected);
863
                    optionCount += 1;
864
                } else if (opt.is("optgroup")) {
865
                    var text = opt.attr("label");
866
                    if (text != "") {
867
                    	var aGroup = $(allGroups[groupCount]);
868
                    	self._refreshGroup(aGroup, disabled);
869
                    	groupCount += 1;
870
	                }
871
					opt.children("option").each(function() {
872
		                var subopt = $(this);
873
						var subdisabled = (disabled || subopt.prop("disabled"));
874
                		var selected = subopt.prop("selected");
875
                		var subItem = $(allCheckBoxes[optionCount]);
876
		                self._refreshOption(subItem, subdisabled, selected );
877
		                optionCount += 1;
878
		            });
879
                }
880
			});
881
			// sync will handle firstItemChecksAll and updateControlText
882
			self._syncSelected(null);
883
        },
884
        // External command to enable the ddcl control
885
        enable: function() {
886
            this.controlSelector.removeClass("ui-state-disabled");
887
            this.disabled = false;
888
        },
889
        // External command to disable the ddcl control
890
        disable: function() {
891
            this.controlSelector.addClass("ui-state-disabled");
892
            this.disabled = true;
893
        },
894
        // External command to destroy all traces of the ddcl control
895
        destroy: function() {
896
            $.Widget.prototype.destroy.apply(this, arguments);
897
            this.sourceSelect.css("display", this.initialDisplay);
898
            this.sourceSelect.prop("multiple", this.initialMultiple);
899
            this.controlWrapper.unbind().remove();
900
            this.dropWrapper.remove();
901
        }
902
    });
903
904
    $.extend($.ui.dropdownchecklist, {
905
        defaults: {
906
            width: null
907
        ,   maxDropHeight: null
908
        ,   firstItemChecksAll: false
909
        ,   closeRadioOnClick: false
910
        ,   minWidth: 50
911
        ,   positionHow: 'absolute'
912
        ,   bgiframe: false
913
        ,	explicitClose: null
914
        }
915
    });
916
917
})(jQuery);
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt (-10 / +7 lines)
Lines 10-20 Link Here
10
   <link rel="stylesheet" type="text/css" href="[% themelang %]/css/right-to-left.css" />
10
   <link rel="stylesheet" type="text/css" href="[% themelang %]/css/right-to-left.css" />
11
[% END %]
11
[% END %]
12
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.fixFloat.js"></script>
12
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.fixFloat.js"></script>
13
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/ui.dropdownchecklist.js"></script>
14
   <link rel="stylesheet" type="text/css" href="[% themelang %]/css/ui.dropdownchecklist.themeroller.css" />
13
<script type="text/javascript">
15
<script type="text/javascript">
14
//<![CDATA[
16
//<![CDATA[
15
    [% UNLESS ( searchfield ) %]$(document).ready(function(){
17
    [% UNLESS ( searchfield ) %]$(document).ready(function(){
16
            $('#toolbar').fixFloat();
18
            $('#toolbar').fixFloat();
17
        });[% END %]
19
        });[% END %]
20
21
    $(document).ready(function(){
22
        $("select[multiple='multiple']").dropdownchecklist( { emptyText: _("Please select ..."), width: 150 } );
23
    });
18
    // This is here because of its dependence on template variables, everything else should go in js/pages/preferences.js - jpw
24
    // This is here because of its dependence on template variables, everything else should go in js/pages/preferences.js - jpw
19
    var to_highlight = "[% searchfield |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]";
25
    var to_highlight = "[% searchfield |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]";
20
    var search_jumped = [% IF ( search_jumped ) %]true[% ELSE %]false[% END %];
26
    var search_jumped = [% IF ( search_jumped ) %]true[% ELSE %]false[% END %];
Lines 114-128 Link Here
114
                    </select>
120
                    </select>
115
                    [% ELSIF ( CHUNK.type_multiple ) %]
121
                    [% ELSIF ( CHUNK.type_multiple ) %]
116
                    <select name="pref_[% CHUNK.name %]" id="pref_[% CHUNK.name %]" class="preference preference-[% CHUNK.class or "choice" %]" multiple="multiple">
122
                    <select name="pref_[% CHUNK.name %]" id="pref_[% CHUNK.name %]" class="preference preference-[% CHUNK.class or "choice" %]" multiple="multiple">
117
                        [% FOREACH CHOICE IN CHUNK.CHOICES %]
123
                        [% FOREACH CHOICE IN CHUNK.CHOICES %][% IF ( CHOICE.selected ) %]<option value="[% CHOICE.value %]" selected="selected">[% ELSE %]<option value="[% CHOICE.value %]">[% END %][% CHOICE.text %]</option>[% END %]
118
                        [% IF ( CHOICE.selected ) %]
119
                        <option value="[% CHOICE.value %]" selected="selected">
120
                        [% ELSE %]
121
                        <option value="[% CHOICE.value %]">
122
                        [% END %]
123
                            [% CHOICE.text %]
124
                        </option>
125
                        [% END %]
126
                    </select>
124
                    </select>
127
                    [% ELSIF ( CHUNK.type_textarea ) %]
125
                    [% ELSIF ( CHUNK.type_textarea ) %]
128
					<a class="expand-textarea" style="display: none" href="#">Click to Edit</a>
126
					<a class="expand-textarea" style="display: none" href="#">Click to Edit</a>
129
- 

Return to bug 9043