Select.js.uncompressed.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. require({cache:{
  2. 'url:dijit/form/templates/Select.html':"<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdata-dojo-attach-point=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\trole=\"listbox\" aria-haspopup=\"true\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents\" role=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitInputField dijitButtonText\" data-dojo-attach-point=\"containerNode,_popupStateNode\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitValidationContainer\"\n\t\t\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t/></div\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} data-dojo-attach-point=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\n\t\t/></td\n\t\t><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer\"\n\t\t\tdata-dojo-attach-point=\"titleNode\" role=\"presentation\"\n\t\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t\t${_buttonInputDisabled}\n\t\t/></td\n\t></tr></tbody\n></table>\n"}});
  3. define("dijit/form/Select", [
  4. "dojo/_base/array", // array.forEach
  5. "dojo/_base/declare", // declare
  6. "dojo/dom-attr", // domAttr.set
  7. "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
  8. "dojo/dom-geometry", // domGeometry.setMarginBox
  9. "dojo/_base/event", // event.stop
  10. "dojo/i18n", // i18n.getLocalization
  11. "dojo/_base/lang", // lang.hitch
  12. "dojo/sniff", // has("ie")
  13. "./_FormSelectWidget",
  14. "../_HasDropDown",
  15. "../Menu",
  16. "../MenuItem",
  17. "../MenuSeparator",
  18. "../Tooltip",
  19. "dojo/text!./templates/Select.html",
  20. "dojo/i18n!./nls/validate"
  21. ], function(array, declare, domAttr, domClass, domGeometry, event, i18n, lang, has,
  22. _FormSelectWidget, _HasDropDown, Menu, MenuItem, MenuSeparator, Tooltip, template){
  23. // module:
  24. // dijit/form/Select
  25. var _SelectMenu = declare("dijit.form._SelectMenu", Menu, {
  26. // summary:
  27. // An internally-used menu for dropdown that allows us a vertical scrollbar
  28. // Override Menu.autoFocus setting so that opening a Select highlights the current value.
  29. autoFocus: true,
  30. buildRendering: function(){
  31. // summary:
  32. // Stub in our own changes, so that our domNode is not a table
  33. // otherwise, we won't respond correctly to heights/overflows
  34. this.inherited(arguments);
  35. var o = (this.menuTableNode = this.domNode);
  36. var n = (this.domNode = this.ownerDocument.createElement("div"));
  37. n.style.cssText = "overflow-x: hidden; overflow-y: scroll";
  38. if(o.parentNode){
  39. o.parentNode.replaceChild(n, o);
  40. }
  41. domClass.remove(o, "dijitMenuTable");
  42. n.className = o.className + " dijitSelectMenu";
  43. o.className = "dijitReset dijitMenuTable";
  44. o.setAttribute("role", "listbox");
  45. n.setAttribute("role", "presentation");
  46. n.appendChild(o);
  47. },
  48. postCreate: function(){
  49. // summary:
  50. // stop mousemove from selecting text on IE to be consistent with other browsers
  51. this.inherited(arguments);
  52. this.connect(this.domNode, "onselectstart", event.stop);
  53. },
  54. focus: function(){
  55. // summary:
  56. // Overridden so that the previously selected value will be focused instead of only the first item
  57. var found = false,
  58. val = this.parentWidget.value;
  59. if(lang.isArray(val)){
  60. val = val[val.length-1];
  61. }
  62. if(val){ // if focus selected
  63. array.forEach(this.parentWidget._getChildren(), function(child){
  64. if(child.option && (val === child.option.value)){ // find menu item widget with this value
  65. found = true;
  66. this.focusChild(child, false); // focus previous selection
  67. }
  68. }, this);
  69. }
  70. if(!found){
  71. this.inherited(arguments); // focus first item by default
  72. }
  73. },
  74. resize: function(/*Object*/ mb){
  75. // summary:
  76. // Overridden so that we are able to handle resizing our
  77. // internal widget. Note that this is not a "full" resize
  78. // implementation - it only works correctly if you pass it a
  79. // marginBox.
  80. //
  81. // mb: Object
  82. // The margin box to set this dropdown to.
  83. if(mb){
  84. domGeometry.setMarginBox(this.domNode, mb);
  85. if("w" in mb){
  86. // We've explicitly set the wrapper <div>'s width, so set <table> width to match.
  87. // 100% is safer than a pixel value because there may be a scroll bar with
  88. // browser/OS specific width.
  89. this.menuTableNode.style.width = "100%";
  90. }
  91. }
  92. }
  93. });
  94. var Select = declare("dijit.form.Select", [_FormSelectWidget, _HasDropDown], {
  95. // summary:
  96. // This is a "styleable" select box - it is basically a DropDownButton which
  97. // can take a `<select>` as its input.
  98. baseClass: "dijitSelect dijitValidationTextBox",
  99. templateString: template,
  100. _buttonInputDisabled: has("ie") ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
  101. // required: Boolean
  102. // Can be true or false, default is false.
  103. required: false,
  104. // state: [readonly] String
  105. // "Incomplete" if this select is required but unset (i.e. blank value), "" otherwise
  106. state: "",
  107. // message: String
  108. // Currently displayed error/prompt message
  109. message: "",
  110. // tooltipPosition: String[]
  111. // See description of `dijit/Tooltip.defaultPosition` for details on this parameter.
  112. tooltipPosition: [],
  113. // emptyLabel: string
  114. // What to display in an "empty" dropdown
  115. emptyLabel: "&#160;", // &nbsp;
  116. // _isLoaded: Boolean
  117. // Whether or not we have been loaded
  118. _isLoaded: false,
  119. // _childrenLoaded: Boolean
  120. // Whether or not our children have been loaded
  121. _childrenLoaded: false,
  122. _fillContent: function(){
  123. // summary:
  124. // Set the value to be the first, or the selected index
  125. this.inherited(arguments);
  126. // set value from selected option
  127. if(this.options.length && !this.value && this.srcNodeRef){
  128. var si = this.srcNodeRef.selectedIndex || 0; // || 0 needed for when srcNodeRef is not a SELECT
  129. this.value = this.options[si >= 0 ? si : 0].value;
  130. }
  131. // Create the dropDown widget
  132. this.dropDown = new _SelectMenu({ id: this.id + "_menu", parentWidget: this });
  133. domClass.add(this.dropDown.domNode, this.baseClass.replace(/\s+|$/g, "Menu "));
  134. },
  135. _getMenuItemForOption: function(/*_FormSelectWidget.__SelectOption*/ option){
  136. // summary:
  137. // For the given option, return the menu item that should be
  138. // used to display it. This can be overridden as needed
  139. if(!option.value && !option.label){
  140. // We are a separator (no label set for it)
  141. return new MenuSeparator({ownerDocument: this.ownerDocument});
  142. }else{
  143. // Just a regular menu option
  144. var click = lang.hitch(this, "_setValueAttr", option);
  145. var item = new MenuItem({
  146. option: option,
  147. label: option.label || this.emptyLabel,
  148. onClick: click,
  149. ownerDocument: this.ownerDocument,
  150. dir: this.dir,
  151. disabled: option.disabled || false
  152. });
  153. item.focusNode.setAttribute("role", "option");
  154. return item;
  155. }
  156. },
  157. _addOptionItem: function(/*_FormSelectWidget.__SelectOption*/ option){
  158. // summary:
  159. // For the given option, add an option to our dropdown.
  160. // If the option doesn't have a value, then a separator is added
  161. // in that place.
  162. if(this.dropDown){
  163. this.dropDown.addChild(this._getMenuItemForOption(option));
  164. }
  165. },
  166. _getChildren: function(){
  167. if(!this.dropDown){
  168. return [];
  169. }
  170. return this.dropDown.getChildren();
  171. },
  172. _loadChildren: function(/*Boolean*/ loadMenuItems){
  173. // summary:
  174. // Resets the menu and the length attribute of the button - and
  175. // ensures that the label is appropriately set.
  176. // loadMenuItems: Boolean
  177. // actually loads the child menu items - we only do this when we are
  178. // populating for showing the dropdown.
  179. if(loadMenuItems === true){
  180. // this.inherited destroys this.dropDown's child widgets (MenuItems).
  181. // Avoid this.dropDown (Menu widget) having a pointer to a destroyed widget (which will cause
  182. // issues later in _setSelected). (see #10296)
  183. if(this.dropDown){
  184. delete this.dropDown.focusedChild;
  185. }
  186. if(this.options.length){
  187. this.inherited(arguments);
  188. }else{
  189. // Drop down menu is blank but add one blank entry just so something appears on the screen
  190. // to let users know that they are no choices (mimicing native select behavior)
  191. array.forEach(this._getChildren(), function(child){ child.destroyRecursive(); });
  192. var item = new MenuItem({
  193. ownerDocument: this.ownerDocument,
  194. label: this.emptyLabel
  195. });
  196. this.dropDown.addChild(item);
  197. }
  198. }else{
  199. this._updateSelection();
  200. }
  201. this._isLoaded = false;
  202. this._childrenLoaded = true;
  203. if(!this._loadingStore){
  204. // Don't call this if we are loading - since we will handle it later
  205. this._setValueAttr(this.value, false);
  206. }
  207. },
  208. _refreshState: function(){
  209. if(this._started){
  210. this.validate(this.focused);
  211. }
  212. },
  213. startup: function(){
  214. this.inherited(arguments);
  215. this._refreshState(); // after all _set* methods have run
  216. },
  217. _setValueAttr: function(value){
  218. this.inherited(arguments);
  219. domAttr.set(this.valueNode, "value", this.get("value"));
  220. this._refreshState(); // to update this.state
  221. },
  222. _setDisabledAttr: function(/*Boolean*/ value){
  223. this.inherited(arguments);
  224. this._refreshState(); // to update this.state
  225. },
  226. _setRequiredAttr: function(/*Boolean*/ value){
  227. this._set("required", value);
  228. this.focusNode.setAttribute("aria-required", value);
  229. this._refreshState(); // to update this.state
  230. },
  231. _setOptionsAttr: function(/*Array*/ options){
  232. this._isLoaded = false;
  233. this._set('options', options);
  234. },
  235. _setDisplay: function(/*String*/ newDisplay){
  236. // summary:
  237. // sets the display for the given value (or values)
  238. var lbl = newDisplay || this.emptyLabel;
  239. this.containerNode.innerHTML = '<span role="option" class="dijitReset dijitInline ' + this.baseClass.replace(/\s+|$/g, "Label ")+'">' + lbl + '</span>';
  240. },
  241. validate: function(/*Boolean*/ isFocused){
  242. // summary:
  243. // Called by oninit, onblur, and onkeypress, and whenever required/disabled state changes
  244. // description:
  245. // Show missing or invalid messages if appropriate, and highlight textbox field.
  246. // Used when a select is initially set to no value and the user is required to
  247. // set the value.
  248. var isValid = this.disabled || this.isValid(isFocused);
  249. this._set("state", isValid ? "" : (this._hasBeenBlurred ? "Error" : "Incomplete"));
  250. this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
  251. var message = isValid ? "" : this._missingMsg;
  252. if(message && this.focused && this._hasBeenBlurred){
  253. Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
  254. }else{
  255. Tooltip.hide(this.domNode);
  256. }
  257. this._set("message", message);
  258. return isValid;
  259. },
  260. isValid: function(/*Boolean*/ /*===== isFocused =====*/){
  261. // summary:
  262. // Whether or not this is a valid value. The only way a Select
  263. // can be invalid is when it's required but nothing is selected.
  264. return (!this.required || this.value === 0 || !(/^\s*$/.test(this.value || ""))); // handle value is null or undefined
  265. },
  266. reset: function(){
  267. // summary:
  268. // Overridden so that the state will be cleared.
  269. this.inherited(arguments);
  270. Tooltip.hide(this.domNode);
  271. this._refreshState(); // to update this.state
  272. },
  273. postMixInProperties: function(){
  274. // summary:
  275. // set the missing message
  276. this.inherited(arguments);
  277. this._missingMsg = i18n.getLocalization("dijit.form", "validate", this.lang).missingMessage;
  278. },
  279. postCreate: function(){
  280. // summary:
  281. // stop mousemove from selecting text on IE to be consistent with other browsers
  282. this.inherited(arguments);
  283. this.connect(this.domNode, "onselectstart", event.stop);
  284. this.domNode.setAttribute("aria-expanded", "false");
  285. if(has("ie") < 9){
  286. // IE INPUT tag fontFamily has to be set directly using STYLE
  287. // the defer gives IE a chance to render the TextBox and to deal with font inheritance
  288. this.defer(function(){
  289. try{
  290. var s = domStyle.getComputedStyle(this.domNode); // can throw an exception if widget is immediately destroyed
  291. if(s){
  292. var ff = s.fontFamily;
  293. if(ff){
  294. var inputs = this.domNode.getElementsByTagName("INPUT");
  295. if(inputs){
  296. for(var i=0; i < inputs.length; i++){
  297. inputs[i].style.fontFamily = ff;
  298. }
  299. }
  300. }
  301. }
  302. }catch(e){/*when used in a Dialog, and this is called before the dialog is
  303. shown, s.fontFamily would trigger "Invalid Argument" error.*/}
  304. });
  305. }
  306. },
  307. _setStyleAttr: function(/*String||Object*/ value){
  308. this.inherited(arguments);
  309. domClass.toggle(this.domNode, this.baseClass.replace(/\s+|$/g, "FixedWidth "), !!this.domNode.style.width);
  310. },
  311. isLoaded: function(){
  312. return this._isLoaded;
  313. },
  314. loadDropDown: function(/*Function*/ loadCallback){
  315. // summary:
  316. // populates the menu
  317. this._loadChildren(true);
  318. this._isLoaded = true;
  319. loadCallback();
  320. },
  321. closeDropDown: function(){
  322. // overriding _HasDropDown.closeDropDown()
  323. this.inherited(arguments);
  324. if(this.dropDown && this.dropDown.menuTableNode){
  325. // Erase possible width: 100% setting from _SelectMenu.resize().
  326. // Leaving it would interfere with the next openDropDown() call, which
  327. // queries the natural size of the drop down.
  328. this.dropDown.menuTableNode.style.width = "";
  329. }
  330. },
  331. destroy: function(preserveDom){
  332. if(this.dropDown && !this.dropDown._destroyed){
  333. this.dropDown.destroyRecursive(preserveDom);
  334. delete this.dropDown;
  335. }
  336. this.inherited(arguments);
  337. },
  338. _onFocus: function(){
  339. this.validate(true); // show tooltip if second focus of required tooltip, but no selection
  340. this.inherited(arguments);
  341. },
  342. _onBlur: function(){
  343. Tooltip.hide(this.domNode);
  344. this.inherited(arguments);
  345. this.validate(false);
  346. }
  347. });
  348. Select._Menu = _SelectMenu; // for monkey patching
  349. return Select;
  350. });