You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
549 lines
15 KiB
549 lines
15 KiB
define([ |
|
"dojo/_base/declare", |
|
"dojo/_base/lang", |
|
"dojo/_base/array", |
|
"dojo/_base/event", |
|
"dojo/dom-geometry", |
|
"dojo/dom-class", |
|
"dojo/dom-construct", |
|
"dojo/i18n", |
|
"dijit/_WidgetBase", |
|
"dijit/_TemplatedMixin", |
|
"dijit/_WidgetsInTemplateMixin", |
|
"dijit/registry", |
|
"dijit/Menu", |
|
"dijit/MenuItem", |
|
"dijit/Tooltip", |
|
"dijit/form/_FormSelectWidget", |
|
"dijit/form/ComboButton", |
|
"dojo/text!dojox/form/resources/_CheckedMultiSelectMenuItem.html", |
|
"dojo/text!dojox/form/resources/_CheckedMultiSelectItem.html", |
|
"dojo/text!dojox/form/resources/CheckedMultiSelect.html", |
|
"dojo/i18n!dojox/form/nls/CheckedMultiSelect", |
|
"dijit/form/CheckBox" // template |
|
], function(declare, lang, array, event, domGeometry, domClass, domConstruct, i18n, Widget, TemplatedMixin, WidgetsInTemplateMixin, registry, Menu, MenuItem, Tooltip, FormSelectWidget, ComboButton, CheckedMultiSelectMenuItem, CheckedMultiSelectItem, CheckedMultiSelect, nlsCheckedMultiSelect){ |
|
|
|
// module: |
|
// dojox/form/CheckedMultiSelect |
|
// summary: |
|
// Extends the core dojox.form.CheckedMultiSelect to provide a "checkbox" selector |
|
|
|
|
|
var formCheckedMultiSelectItem = declare("dojox.form._CheckedMultiSelectItem", [Widget, TemplatedMixin, WidgetsInTemplateMixin], { |
|
// summary: |
|
// The individual items for a CheckedMultiSelect |
|
|
|
templateString: CheckedMultiSelectItem, |
|
|
|
baseClass: "dojoxMultiSelectItem", |
|
|
|
// option: dojox.form.__SelectOption |
|
// The option that is associated with this item |
|
option: null, |
|
parent: null, |
|
|
|
// disabled: boolean |
|
// Whether or not this widget is disabled |
|
disabled: false, |
|
|
|
// readOnly: boolean |
|
// Whether or not this widget is readOnly |
|
readOnly: false, |
|
|
|
postMixInProperties: function(){ |
|
// summary: |
|
// Set the appropriate _subClass value - based on if we are multi- |
|
// or single-select |
|
this._type = this.parent.multiple ? |
|
{type: "checkbox", baseClass: "dijitCheckBox"} : |
|
{type: "radio", baseClass: "dijitRadio"}; |
|
// use global disabled/readOnly if set to true, otherwise use per-option setting |
|
if(!this.disabled){ |
|
this.disabled = this.option.disabled = this.option.disabled||false; |
|
} |
|
if(!this.readOnly){ |
|
this.readOnly = this.option.readOnly = this.option.readOnly||false; |
|
} |
|
this.inherited(arguments); |
|
}, |
|
|
|
postCreate: function(){ |
|
// summary: |
|
// Set innerHTML here - since the template gets messed up sometimes |
|
// with rich text |
|
this.inherited(arguments); |
|
this.labelNode.innerHTML = this.option.label; |
|
}, |
|
|
|
_changeBox: function(){ |
|
// summary: |
|
// Called to force the select to match the state of the check box |
|
// (only on click of the checkbox) Radio-based calls _setValueAttr |
|
// instead. |
|
if(this.get("disabled") || this.get("readOnly")){ return; } |
|
if(this.parent.multiple){ |
|
this.option.selected = this.checkBox.get('value') && true; |
|
}else{ |
|
this.parent.set('value', this.option.value); |
|
} |
|
// fire the parent's change |
|
this.parent._updateSelection(); |
|
|
|
// refocus the parent |
|
this.parent.focus(); |
|
}, |
|
|
|
_onClick: function(e){ |
|
// summary: |
|
// Sets the click state (passes through to the check box) |
|
if(this.get("disabled") || this.get("readOnly")){ |
|
event.stop(e); |
|
}else{ |
|
this.checkBox._onClick(e); |
|
} |
|
}, |
|
|
|
_updateBox: function(){ |
|
// summary: |
|
// Called to force the box to match the state of the select |
|
this.checkBox.set('value', this.option.selected); |
|
}, |
|
|
|
_setDisabledAttr: function(value){ |
|
// summary: |
|
// Disables (or enables) all the children as well |
|
this.disabled = value||this.option.disabled; |
|
this.checkBox.set("disabled", this.disabled); |
|
domClass.toggle(this.domNode, "dojoxMultiSelectDisabled", this.disabled); |
|
}, |
|
|
|
_setReadOnlyAttr: function(value){ |
|
// summary: |
|
// Sets read only (or unsets) all the children as well |
|
this.checkBox.set("readOnly", value); |
|
this.readOnly = value; |
|
} |
|
}); |
|
|
|
var formCheckedMultiSelectMenu = declare("dojox.form._CheckedMultiSelectMenu", Menu, { |
|
// summary: |
|
// An internally-used menu for dropdown that allows us a vertical scrollbar |
|
|
|
multiple: false, |
|
|
|
buildRendering: function(){ |
|
// summary: |
|
// Stub in our own changes, so that our domNode is not a table |
|
// otherwise, we won't respond correctly to heights/overflows |
|
this.inherited(arguments); |
|
var o = (this.menuTableNode = this.domNode), |
|
n = (this.domNode = domConstruct.create("div", {style: {overflowX: "hidden", overflowY: "scroll"}})); |
|
if(o.parentNode){ |
|
o.parentNode.replaceChild(n, o); |
|
} |
|
domClass.remove(o, "dijitMenuTable"); |
|
n.className = o.className + " dojoxCheckedMultiSelectMenu"; |
|
o.className = "dijitReset dijitMenuTable"; |
|
o.setAttribute("role", "listbox"); |
|
n.setAttribute("role", "presentation"); |
|
n.appendChild(o); |
|
}, |
|
|
|
resize: function(/*Object*/ mb){ |
|
// summary: |
|
// Overridden so that we are able to handle resizing our |
|
// internal widget. Note that this is not a "full" resize |
|
// implementation - it only works correctly if you pass it a |
|
// marginBox. |
|
// |
|
// mb: Object |
|
// The margin box to set this dropdown to. |
|
if(mb){ |
|
domGeometry.setMarginBox(this.domNode, mb); |
|
if("w" in mb){ |
|
// We've explicitly set the wrapper <div>'s width, so set <table> width to match. |
|
// 100% is safer than a pixel value because there may be a scroll bar with |
|
// browser/OS specific width. |
|
this.menuTableNode.style.width = "100%"; |
|
} |
|
} |
|
}, |
|
|
|
onClose: function(){ |
|
this.inherited(arguments); |
|
if(this.menuTableNode){ |
|
// Erase possible width: 100% setting from _SelectMenu.resize(). |
|
// Leaving it would interfere with the next openDropDown() call, which |
|
// queries the natural size of the drop down. |
|
this.menuTableNode.style.width = ""; |
|
} |
|
}, |
|
|
|
onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){ |
|
// summary: |
|
// Handle clicks on an item. |
|
// tags: |
|
// private |
|
|
|
// this can't be done in _onFocus since the _onFocus events occurs asynchronously |
|
if(typeof this.isShowingNow == 'undefined'){ // non-popup menu |
|
this._markActive(); |
|
} |
|
|
|
this.focusChild(item); |
|
|
|
if(item.disabled || item.readOnly){ return false; } |
|
|
|
if(!this.multiple){ |
|
// before calling user defined handler, close hierarchy of menus |
|
// and restore focus to place it was when menu was opened |
|
this.onExecute(); |
|
} |
|
// user defined handler for click |
|
item.onClick(evt); |
|
} |
|
}); |
|
|
|
var formCheckedMultiSelectMenuItem = declare("dojox.form._CheckedMultiSelectMenuItem", MenuItem, { |
|
// summary: |
|
// A checkbox-like menu item for toggling on and off |
|
|
|
templateString: CheckedMultiSelectMenuItem, |
|
|
|
// option: dojox.form.__SelectOption |
|
// The option that is associated with this item |
|
option: null, |
|
|
|
// reference of dojox.form._CheckedMultiSelectMenu |
|
parent: null, |
|
|
|
// icon of the checkbox/radio button |
|
iconClass: "", |
|
|
|
postMixInProperties: function(){ |
|
// summary: |
|
// Set the appropriate _subClass value - based on if we are multi- |
|
// or single-select |
|
if(this.parent.multiple){ |
|
this._iconClass = "dojoxCheckedMultiSelectMenuCheckBoxItemIcon"; |
|
this._type = {type: "checkbox"}; |
|
}else{ |
|
this._iconClass = ""; |
|
this._type = {type: "hidden"}; |
|
} |
|
this.disabled = this.option.disabled; |
|
this.checked = this.option.selected; |
|
this.label = this.option.label; |
|
this.readOnly = this.option.readOnly; |
|
this.inherited(arguments); |
|
}, |
|
|
|
onChange: function(/*Boolean*/ checked){ |
|
// summary: |
|
// User defined function to handle check/uncheck events |
|
// tags: |
|
// callback |
|
}, |
|
|
|
_updateBox: function(){ |
|
// summary: |
|
// Called to force the box to match the state of the select |
|
domClass.toggle(this.domNode, "dojoxCheckedMultiSelectMenuItemChecked", !!this.option.selected); |
|
this.domNode.setAttribute("aria-checked", this.option.selected); |
|
this.inputNode.checked = this.option.selected; |
|
if(!this.parent.multiple){ |
|
domClass.toggle(this.domNode, "dijitSelectSelectedOption", !!this.option.selected); |
|
} |
|
}, |
|
|
|
_onClick: function(/*Event*/ e){ |
|
// summary: |
|
// Clicking this item just toggles its state |
|
// tags: |
|
// private |
|
if(!this.disabled && !this.readOnly){ |
|
if(this.parent.multiple){ |
|
this.option.selected = !this.option.selected; |
|
this.parent.onChange(); |
|
this.onChange(this.option.selected); |
|
}else{ |
|
if(!this.option.selected){ |
|
array.forEach(this.parent.getChildren(), function(item){ |
|
item.option.selected = false; |
|
}); |
|
this.option.selected = true; |
|
this.parent.onChange(); |
|
this.onChange(this.option.selected); |
|
} |
|
} |
|
} |
|
this.inherited(arguments); |
|
} |
|
}); |
|
|
|
var formCheckedMultiSelect = declare("dojox.form.CheckedMultiSelect", FormSelectWidget, { |
|
// summary: |
|
// Extends the core dijit MultiSelect to provide a "checkbox" selector |
|
|
|
templateString: CheckedMultiSelect, |
|
|
|
baseClass: "dojoxCheckedMultiSelect", |
|
|
|
// required: Boolean |
|
// User is required to check at least one item. |
|
required: false, |
|
|
|
// invalidMessage: String |
|
// The message to display if value is invalid. |
|
invalidMessage: "$_unset_$", |
|
|
|
// _message: String |
|
// Currently displayed message |
|
_message: "", |
|
|
|
// dropDown: Boolean |
|
// Drop down version or not |
|
dropDown: false, |
|
|
|
// labelText: String |
|
// Label of the drop down button |
|
labelText: "", |
|
|
|
// tooltipPosition: String[] |
|
// See description of `Tooltip.defaultPosition` for details on this parameter. |
|
tooltipPosition: [], |
|
|
|
postMixInProperties: function(){ |
|
this.inherited(arguments); |
|
this._nlsResources = i18n.getLocalization("dojox.form", "CheckedMultiSelect", this.lang); |
|
if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this._nlsResources.invalidMessage; } |
|
}, |
|
|
|
_fillContent: function(){ |
|
// summary: |
|
// Set the value to be the first, or the selected index |
|
this.inherited(arguments); |
|
|
|
// set value from selected option |
|
if(this.options.length && !this.value && this.srcNodeRef){ |
|
var si = this.srcNodeRef.selectedIndex || 0; // || 0 needed for when srcNodeRef is not a SELECT |
|
this.value = this.options[si >= 0 ? si : 0].value; |
|
} |
|
if(this.dropDown){ |
|
domClass.toggle(this.selectNode, "dojoxCheckedMultiSelectHidden"); |
|
this.dropDownMenu = new formCheckedMultiSelectMenu({ |
|
id: this.id + "_menu", |
|
style: "display: none;", |
|
multiple: this.multiple, |
|
onChange: lang.hitch(this, "_updateSelection") |
|
}); |
|
} |
|
}, |
|
|
|
startup: function(){ |
|
// summary: |
|
// Set the value to be the first, or the selected index |
|
if(this.dropDown){ |
|
this.dropDownButton = new ComboButton({ |
|
label: this.labelText, |
|
dropDown: this.dropDownMenu, |
|
baseClass: "dojoxCheckedMultiSelectButton", |
|
maxHeight: this.maxHeight |
|
}, this.comboButtonNode); |
|
} |
|
this.inherited(arguments); |
|
}, |
|
|
|
_onMouseDown: function(e){ |
|
// summary: |
|
// Cancels the mousedown event to prevent others from stealing |
|
// focus |
|
e.preventDefault(); |
|
}, |
|
|
|
validator: function(){ |
|
// summary: |
|
// Overridable function used to validate that an item is selected if required = |
|
// true. |
|
// tags: |
|
// protected |
|
if(!this.required){ return true; } |
|
return array.some(this.getOptions(), function(opt){ |
|
return opt.selected && opt.value != null && opt.value.toString().length != 0; |
|
}); |
|
}, |
|
|
|
validate: function(isFocused){ |
|
Tooltip.hide(this.domNode); |
|
var isValid = this.isValid(isFocused); |
|
if(!isValid){ this.displayMessage(this.invalidMessage); } |
|
return isValid; |
|
}, |
|
|
|
isValid: function(/*Boolean*/ isFocused){ |
|
// summary: |
|
// Tests if the required items are selected. |
|
// Can override with your own routine in a subclass. |
|
// tags: |
|
// protected |
|
return this.validator(); |
|
}, |
|
|
|
getErrorMessage: function(/*Boolean*/ isFocused){ |
|
// summary: |
|
// Return an error message to show if appropriate |
|
// tags: |
|
// protected |
|
return this.invalidMessage; |
|
}, |
|
|
|
displayMessage: function(/*String*/ message){ |
|
// summary: |
|
// Overridable method to display validation errors/hints. |
|
// By default uses a tooltip. |
|
// tags: |
|
// extension |
|
Tooltip.hide(this.domNode); |
|
if(message){ |
|
Tooltip.show(message, this.domNode, this.tooltipPosition); |
|
} |
|
}, |
|
|
|
onAfterAddOptionItem: function(item, option){ |
|
// summary: |
|
// a function that can be connected to in order to receive a |
|
// notification that an item as been added to this dijit. |
|
}, |
|
|
|
_addOptionItem: function(/*dojox.form.__SelectOption*/ option){ |
|
var item; |
|
if(this.dropDown){ |
|
item = new formCheckedMultiSelectMenuItem({ |
|
option: option, |
|
parent: this.dropDownMenu |
|
}); |
|
this.dropDownMenu.addChild(item); |
|
}else{ |
|
item = new formCheckedMultiSelectItem({ |
|
option: option, |
|
parent: this, |
|
disabled: this.disabled, |
|
readOnly: this.readOnly |
|
}); |
|
this.wrapperDiv.appendChild(item.domNode); |
|
} |
|
this.onAfterAddOptionItem(item, option); |
|
}, |
|
|
|
_refreshState: function(){ |
|
// summary: |
|
// Validate if selection changes. |
|
this.validate(this.focused); |
|
}, |
|
|
|
onChange: function(newValue){ |
|
// summary: |
|
// Validate if selection changes. |
|
this._refreshState(); |
|
}, |
|
|
|
reset: function(){ |
|
// Overridden so that the state will be cleared. |
|
this.inherited(arguments); |
|
Tooltip.hide(this.domNode); |
|
}, |
|
|
|
_updateSelection: function(){ |
|
this.inherited(arguments); |
|
this._handleOnChange(this.value); |
|
array.forEach(this._getChildren(), function(item){ |
|
item._updateBox(); |
|
}); |
|
domConstruct.empty(this.containerNode); |
|
var self = this; |
|
array.forEach(this.value, function(item){ |
|
var opt = domConstruct.create("option", { |
|
"value": item, |
|
"label": item, |
|
"selected": "selected" |
|
}); |
|
domConstruct.place(opt, self.containerNode); |
|
}); |
|
if(this.dropDown && this.dropDownButton){ |
|
var i = 0, label = ""; |
|
array.forEach(this.options, function(option){ |
|
if(option.selected){ |
|
i++; |
|
label = option.label; |
|
} |
|
}); |
|
this.dropDownButton.set("label", this.multiple ? |
|
lang.replace(this._nlsResources.multiSelectLabelText, {num: i}) : |
|
label); |
|
} |
|
}, |
|
|
|
_getChildren: function(){ |
|
if(this.dropDown){ |
|
return this.dropDownMenu.getChildren(); |
|
}else{ |
|
return array.map(this.wrapperDiv.childNodes, function(n){ |
|
return registry.byNode(n); |
|
}); |
|
} |
|
}, |
|
|
|
invertSelection: function(onChange){ |
|
// summary: |
|
// Invert the selection |
|
// onChange: Boolean |
|
// If null, onChange is not fired. |
|
if(this.multiple){ |
|
array.forEach(this.options, function(i){ |
|
i.selected = !i.selected; |
|
}); |
|
this._updateSelection(); |
|
} |
|
}, |
|
|
|
_setDisabledAttr: function(value){ |
|
// summary: |
|
// Disable (or enable) all the children as well |
|
this.inherited(arguments); |
|
if(this.dropDown){ |
|
this.dropDownButton.set("disabled", value); |
|
} |
|
array.forEach(this._getChildren(), function(node){ |
|
if(node && node.set){ |
|
node.set("disabled", value); |
|
} |
|
}); |
|
}, |
|
|
|
_setReadOnlyAttr: function(value){ |
|
// summary: |
|
// Sets read only (or unsets) all the children as well |
|
this.inherited(arguments); |
|
if("readOnly" in this.attributeMap){ |
|
this[this.attributeMap.readOnly].setAttribute("readonly", value); |
|
} |
|
this.readOnly = value; |
|
array.forEach(this._getChildren(), function(node){ |
|
if(node && node.set){ |
|
node.set("readOnly", value); |
|
} |
|
}); |
|
}, |
|
|
|
uninitialize: function(){ |
|
Tooltip.hide(this.domNode); |
|
// Make sure these children are destroyed |
|
array.forEach(this._getChildren(), function(child){ |
|
child.destroyRecursive(); |
|
}); |
|
this.inherited(arguments); |
|
} |
|
}); |
|
|
|
return formCheckedMultiSelect; |
|
});
|
|
|