PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/qooxdoo-2.1.1-sdk/framework/source/class/qx/ui/form/ComboBox.js

https://bitbucket.org/vegansk/test_qooxdoo
JavaScript | 491 lines | 238 code | 88 blank | 165 comment | 38 complexity | ee17b5e4f8d1cce74e797e2f38ae72d7 MD5 | raw file
  1. /* ************************************************************************
  2. qooxdoo - the new era of web development
  3. http://qooxdoo.org
  4. Copyright:
  5. 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
  6. License:
  7. LGPL: http://www.gnu.org/licenses/lgpl.html
  8. EPL: http://www.eclipse.org/org/documents/epl-v10.php
  9. See the LICENSE file in the project's top-level directory for details.
  10. Authors:
  11. * Martin Wittemann (martinwittemann)
  12. * Sebastian Werner (wpbasti)
  13. * Jonathan Weiß (jonathan_rass)
  14. ************************************************************************ */
  15. /**
  16. * Basically a text fields which allows a selection from a list of
  17. * preconfigured options. Allows custom user input. Public API is value
  18. * oriented.
  19. *
  20. * To work with selections without custom input the ideal candidates are
  21. * the {@link SelectBox} or the {@link RadioGroup}.
  22. *
  23. * @childControl textfield {qx.ui.form.TextField} textfield component of the combobox
  24. * @childControl button {qx.ui.form.Button} button to open the list popup
  25. * @childControl list {qx.ui.form.List} list inside the popup
  26. */
  27. qx.Class.define("qx.ui.form.ComboBox",
  28. {
  29. extend : qx.ui.form.AbstractSelectBox,
  30. implement : [qx.ui.form.IStringForm],
  31. /*
  32. *****************************************************************************
  33. CONSTRUCTOR
  34. *****************************************************************************
  35. */
  36. construct : function()
  37. {
  38. this.base(arguments);
  39. var textField = this._createChildControl("textfield");
  40. this._createChildControl("button");
  41. this.addListener("click", this._onClick);
  42. // forward the focusin and focusout events to the textfield. The textfield
  43. // is not focusable so the events need to be forwarded manually.
  44. this.addListener("focusin", function(e) {
  45. textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
  46. }, this);
  47. this.addListener("focusout", function(e) {
  48. textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
  49. }, this);
  50. },
  51. /*
  52. *****************************************************************************
  53. PROPERTIES
  54. *****************************************************************************
  55. */
  56. properties :
  57. {
  58. // overridden
  59. appearance :
  60. {
  61. refine : true,
  62. init : "combobox"
  63. },
  64. /**
  65. * String value which will be shown as a hint if the field is all of:
  66. * unset, unfocused and enabled. Set to null to not show a placeholder
  67. * text.
  68. */
  69. placeholder :
  70. {
  71. check : "String",
  72. nullable : true,
  73. apply : "_applyPlaceholder"
  74. }
  75. },
  76. /*
  77. *****************************************************************************
  78. EVENTS
  79. *****************************************************************************
  80. */
  81. events :
  82. {
  83. /** Whenever the value is changed this event is fired
  84. *
  85. * Event data: The new text value of the field.
  86. */
  87. "changeValue" : "qx.event.type.Data"
  88. },
  89. /*
  90. *****************************************************************************
  91. MEMBERS
  92. *****************************************************************************
  93. */
  94. members :
  95. {
  96. __preSelectedItem : null,
  97. __onInputId : null,
  98. // property apply
  99. _applyPlaceholder : function(value, old) {
  100. this.getChildControl("textfield").setPlaceholder(value);
  101. },
  102. /*
  103. ---------------------------------------------------------------------------
  104. WIDGET API
  105. ---------------------------------------------------------------------------
  106. */
  107. // overridden
  108. _createChildControlImpl : function(id, hash)
  109. {
  110. var control;
  111. switch(id)
  112. {
  113. case "textfield":
  114. control = new qx.ui.form.TextField();
  115. control.setFocusable(false);
  116. control.addState("inner");
  117. control.addListener("changeValue", this._onTextFieldChangeValue, this);
  118. control.addListener("blur", this.close, this);
  119. this._add(control, {flex: 1});
  120. break;
  121. case "button":
  122. control = new qx.ui.form.Button();
  123. control.setFocusable(false);
  124. control.setKeepActive(true);
  125. control.addState("inner");
  126. this._add(control);
  127. break;
  128. case "list":
  129. // Get the list from the AbstractSelectBox
  130. control = this.base(arguments, id)
  131. // Change selection mode
  132. control.setSelectionMode("single");
  133. break;
  134. }
  135. return control || this.base(arguments, id);
  136. },
  137. // overridden
  138. /**
  139. * @lint ignoreReferenceField(_forwardStates)
  140. */
  141. _forwardStates : {
  142. focused : true,
  143. invalid : true
  144. },
  145. // overridden
  146. tabFocus : function()
  147. {
  148. var field = this.getChildControl("textfield");
  149. field.getFocusElement().focus();
  150. field.selectAllText();
  151. },
  152. // overridden
  153. focus : function()
  154. {
  155. this.base(arguments);
  156. this.getChildControl("textfield").getFocusElement().focus();
  157. },
  158. // interface implementation
  159. setValue : function(value)
  160. {
  161. var textfield = this.getChildControl("textfield");
  162. if (textfield.getValue() == value) {
  163. return;
  164. }
  165. // Apply to text field
  166. textfield.setValue(value);
  167. },
  168. // interface implementation
  169. getValue : function() {
  170. return this.getChildControl("textfield").getValue();
  171. },
  172. // interface implementation
  173. resetValue : function() {
  174. this.getChildControl("textfield").setValue(null);
  175. },
  176. /*
  177. ---------------------------------------------------------------------------
  178. EVENT LISTENERS
  179. ---------------------------------------------------------------------------
  180. */
  181. // overridden
  182. _onKeyPress : function(e)
  183. {
  184. var popup = this.getChildControl("popup");
  185. var iden = e.getKeyIdentifier();
  186. if (iden == "Down" && e.isAltPressed())
  187. {
  188. this.getChildControl("button").addState("selected");
  189. this.toggle();
  190. e.stopPropagation();
  191. }
  192. else if (iden == "Enter")
  193. {
  194. if (popup.isVisible())
  195. {
  196. this._setPreselectedItem();
  197. this.resetAllTextSelection();
  198. this.close();
  199. e.stop();
  200. }
  201. }
  202. else if (popup.isVisible())
  203. {
  204. this.base(arguments, e);
  205. }
  206. },
  207. /**
  208. * Toggles the popup's visibility.
  209. *
  210. * @param e {qx.event.type.Mouse} Mouse click event
  211. */
  212. _onClick : function(e)
  213. {
  214. var target = e.getTarget();
  215. if (target == this.getChildControl("button")) {
  216. this.toggle();
  217. } else {
  218. this.close();
  219. }
  220. },
  221. // overridden
  222. _onListMouseDown : function(e)
  223. {
  224. this._setPreselectedItem();
  225. },
  226. /**
  227. * Apply pre-selected item
  228. */
  229. _setPreselectedItem: function() {
  230. if (this.__preSelectedItem)
  231. {
  232. var label = this.__preSelectedItem.getLabel();
  233. if (this.getFormat()!= null) {
  234. label = this.getFormat().call(this, this.__preSelectedItem);
  235. }
  236. // check for translation
  237. if (label && label.translate) {
  238. label = label.translate();
  239. }
  240. this.setValue(label);
  241. this.__preSelectedItem = null;
  242. }
  243. },
  244. // overridden
  245. _onListChangeSelection : function(e)
  246. {
  247. var current = e.getData();
  248. if (current.length > 0)
  249. {
  250. // Ignore quick context (e.g. mouseover)
  251. // and configure the new value when closing the popup afterwards
  252. var list = this.getChildControl("list");
  253. var ctx = list.getSelectionContext();
  254. if (ctx == "quick" || ctx == "key" )
  255. {
  256. this.__preSelectedItem = current[0];
  257. }
  258. else
  259. {
  260. var label = current[0].getLabel();
  261. if (this.getFormat()!= null) {
  262. label = this.getFormat().call(this, current[0]);
  263. }
  264. // check for translation
  265. if (label && label.translate) {
  266. label = label.translate();
  267. }
  268. this.setValue(label);
  269. this.__preSelectedItem = null;
  270. }
  271. }
  272. },
  273. // overridden
  274. _onPopupChangeVisibility : function(e)
  275. {
  276. this.base(arguments, e);
  277. // Synchronize the list with the current value on every
  278. // opening of the popup. This is useful because through
  279. // the quick selection mode, the list may keep an invalid
  280. // selection on close or the user may enter text while
  281. // the combobox is closed and reopen it afterwards.
  282. var popup = this.getChildControl("popup");
  283. if (popup.isVisible())
  284. {
  285. var list = this.getChildControl("list");
  286. var value = this.getValue();
  287. var item = null;
  288. if (value) {
  289. item = list.findItem(value);
  290. }
  291. if (item) {
  292. list.setSelection([item]);
  293. } else {
  294. list.resetSelection();
  295. }
  296. }
  297. else
  298. {
  299. // When closing the popup text should selected and field should
  300. // have the focus. Identical to when reaching the field using the TAB key.
  301. //
  302. // Only focus if popup was visible before. Fixes [BUG #4453].
  303. if (e.getOldData() == "visible") {
  304. this.tabFocus();
  305. }
  306. }
  307. // In all cases: Remove focused state from button
  308. this.getChildControl("button").removeState("selected");
  309. },
  310. /**
  311. * Reacts on value changes of the text field and syncs the
  312. * value to the combobox.
  313. *
  314. * @param e {qx.event.type.Data} Change event
  315. */
  316. _onTextFieldChangeValue : function(e)
  317. {
  318. var value = e.getData();
  319. var list = this.getChildControl("list");
  320. if (value != null) {
  321. // Select item when possible
  322. var item = list.findItem(value, false);
  323. if (item) {
  324. list.setSelection([item]);
  325. } else {
  326. list.resetSelection();
  327. }
  328. } else {
  329. list.resetSelection();
  330. }
  331. // Fire event
  332. this.fireDataEvent("changeValue", value, e.getOldData());
  333. },
  334. /*
  335. ---------------------------------------------------------------------------
  336. TEXTFIELD SELECTION API
  337. ---------------------------------------------------------------------------
  338. */
  339. /**
  340. * Returns the current selection.
  341. * This method only works if the widget is already created and
  342. * added to the document.
  343. *
  344. * @return {String|null}
  345. */
  346. getTextSelection : function() {
  347. return this.getChildControl("textfield").getTextSelection();
  348. },
  349. /**
  350. * Returns the current selection length.
  351. * This method only works if the widget is already created and
  352. * added to the document.
  353. *
  354. * @return {Integer|null}
  355. */
  356. getTextSelectionLength : function() {
  357. return this.getChildControl("textfield").getTextSelectionLength();
  358. },
  359. /**
  360. * Set the selection to the given start and end (zero-based).
  361. * If no end value is given the selection will extend to the
  362. * end of the textfield's content.
  363. * This method only works if the widget is already created and
  364. * added to the document.
  365. *
  366. * @param start {Integer} start of the selection (zero-based)
  367. * @param end {Integer} end of the selection
  368. */
  369. setTextSelection : function(start, end) {
  370. this.getChildControl("textfield").setTextSelection(start, end);
  371. },
  372. /**
  373. * Clears the current selection.
  374. * This method only works if the widget is already created and
  375. * added to the document.
  376. *
  377. */
  378. clearTextSelection : function() {
  379. this.getChildControl("textfield").clearTextSelection();
  380. },
  381. /**
  382. * Selects the whole content
  383. *
  384. */
  385. selectAllText : function() {
  386. this.getChildControl("textfield").selectAllText();
  387. },
  388. /**
  389. * Clear any text selection, then select all text
  390. *
  391. */
  392. resetAllTextSelection: function() {
  393. this.clearTextSelection();
  394. this.selectAllText();
  395. }
  396. }
  397. });