7b03060671afc98a9ecb0cddc9ebad0b14e90201.svn-base 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. /*
  2. * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
  3. *
  4. * http://extjs.com/license
  5. */
  6. Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {
  7. defaultAutoCreate : {
  8. tag : "input",
  9. type : "text",
  10. size : "24",
  11. autocomplete : "off"
  12. },
  13. listClass : "",
  14. selectedClass : "x-combo-selected",
  15. triggerClass : "x-form-arrow-trigger",
  16. shadow : "sides",
  17. listAlign : "tl-bl?",
  18. maxHeight : 300,
  19. triggerAction : "query",
  20. minChars : 4,
  21. typeAhead : false,
  22. queryDelay : 500,
  23. pageSize : 0,
  24. selectOnFocus : false,
  25. queryParam : "query",
  26. loadingText : "Loading...",
  27. resizable : false,
  28. handleHeight : 8,
  29. editable : true,
  30. allQuery : "",
  31. mode : "remote",
  32. minListWidth : 70,
  33. forceSelection : false,
  34. typeAheadDelay : 250,
  35. lazyInit : true,
  36. initComponent : function() {
  37. Ext.form.ComboBox.superclass.initComponent.call(this);
  38. this.addEvents("expand", "collapse", "beforeselect", "select",
  39. "beforequery");
  40. if (this.transform) {
  41. this.allowDomMove = false;
  42. var C = Ext.getDom(this.transform);
  43. if (!this.hiddenName) {
  44. this.hiddenName = C.name
  45. }
  46. if (!this.store) {
  47. this.mode = "local";
  48. var G = [], D = C.options;
  49. for (var B = 0, A = D.length; B < A; B++) {
  50. var F = D[B];
  51. var E = (Ext.isIE
  52. ? F.getAttributeNode("value").specified
  53. : F.hasAttribute("value"))
  54. ? F.value
  55. : F.text;
  56. if (F.selected) {
  57. this.value = E
  58. }
  59. G.push([E, F.text])
  60. }
  61. this.store = new Ext.data.SimpleStore({
  62. "id" : 0,
  63. fields : ["value", "text"],
  64. data : G
  65. });
  66. this.valueField = "value";
  67. this.displayField = "text"
  68. }
  69. C.name = Ext.id();
  70. if (!this.lazyRender) {
  71. this.target = true;
  72. this.el = Ext.DomHelper.insertBefore(C, this.autoCreate
  73. || this.defaultAutoCreate);
  74. Ext.removeNode(C);
  75. this.render(this.el.parentNode)
  76. } else {
  77. Ext.removeNode(C)
  78. }
  79. }
  80. this.selectedIndex = -1;
  81. if (this.mode == "local") {
  82. if (this.initialConfig.queryDelay === undefined) {
  83. this.queryDelay = 10
  84. }
  85. if (this.initialConfig.minChars === undefined) {
  86. this.minChars = 0
  87. }
  88. }
  89. },
  90. onRender : function(B, A) {
  91. Ext.form.ComboBox.superclass.onRender.call(this, B, A);
  92. if (this.hiddenName) {
  93. this.hiddenField = this.el.insertSibling({
  94. tag : "input",
  95. type : "hidden",
  96. name : this.hiddenName,
  97. id : (this.hiddenId || this.hiddenName)
  98. }, "before", true);
  99. this.hiddenField.value = this.hiddenValue !== undefined
  100. ? this.hiddenValue
  101. : this.value !== undefined ? this.value : "";
  102. this.el.dom.removeAttribute("name")
  103. }
  104. if (Ext.isGecko) {
  105. this.el.dom.setAttribute("autocomplete", "off")
  106. }
  107. if (!this.lazyInit) {
  108. this.initList()
  109. } else {
  110. this.on("focus", this.initList, this, {
  111. single : true
  112. })
  113. }
  114. if (!this.editable) {
  115. this.editable = true;
  116. this.setEditable(false)
  117. }
  118. },
  119. initList : function() {
  120. if (!this.list) {
  121. var A = "x-combo-list";
  122. this.list = new Ext.Layer({
  123. shadow : this.shadow,
  124. cls : [A, this.listClass].join(" "),
  125. constrain : false
  126. });
  127. var B = this.listWidth
  128. || Math
  129. .max(this.wrap.getWidth(),
  130. this.minListWidth);
  131. this.list.setWidth(B);
  132. this.list.swallowEvent("mousewheel");
  133. this.assetHeight = 0;
  134. if (this.title) {
  135. this.header = this.list.createChild({
  136. cls : A + "-hd",
  137. html : this.title
  138. });
  139. this.assetHeight += this.header.getHeight()
  140. }
  141. this.innerList = this.list.createChild({
  142. cls : A + "-inner"
  143. });
  144. this.innerList.on("mouseover", this.onViewOver, this);
  145. this.innerList.on("mousemove", this.onViewMove, this);
  146. this.innerList.setWidth(B - this.list.getFrameWidth("lr"));
  147. if (this.pageSize) {
  148. this.footer = this.list.createChild({
  149. cls : A + "-ft"
  150. });
  151. this.pageTb = new Ext.PagingToolbar({
  152. store : this.store,
  153. pageSize : this.pageSize,
  154. renderTo : this.footer
  155. });
  156. this.assetHeight += this.footer.getHeight()
  157. }
  158. if (!this.tpl) {
  159. this.tpl = "<tpl for=\".\"><div class=\"" + A
  160. + "-item\">{" + this.displayField
  161. + "}</div></tpl>"
  162. }
  163. this.view = new Ext.DataView({
  164. applyTo : this.innerList,
  165. tpl : this.tpl,
  166. singleSelect : true,
  167. selectedClass : this.selectedClass,
  168. itemSelector : this.itemSelector || "." + A
  169. + "-item"
  170. });
  171. this.view.on("click", this.onViewClick, this);
  172. this.bindStore(this.store, true);
  173. if (this.resizable) {
  174. this.resizer = new Ext.Resizable(this.list, {
  175. pinned : true,
  176. handles : "se"
  177. });
  178. this.resizer.on("resize", function(E, C, D) {
  179. this.maxHeight = D - this.handleHeight
  180. - this.list.getFrameWidth("tb")
  181. - this.assetHeight;
  182. this.listWidth = C;
  183. this.innerList.setWidth(C
  184. - this.list.getFrameWidth("lr"));
  185. this.restrictHeight()
  186. }, this);
  187. this[this.pageSize ? "footer" : "innerList"].setStyle(
  188. "margin-bottom", this.handleHeight + "px")
  189. }
  190. }
  191. },
  192. bindStore : function(A, B) {
  193. if (this.store && !B) {
  194. this.store.un("beforeload", this.onBeforeLoad, this);
  195. this.store.un("load", this.onLoad, this);
  196. this.store.un("loadexception", this.collapse, this);
  197. if (!A) {
  198. this.store = null;
  199. if (this.view) {
  200. this.view.setStore(null)
  201. }
  202. }
  203. }
  204. if (A) {
  205. this.store = Ext.StoreMgr.lookup(A);
  206. this.store.on("beforeload", this.onBeforeLoad, this);
  207. this.store.on("load", this.onLoad, this);
  208. this.store.on("loadexception", this.collapse, this);
  209. if (this.view) {
  210. this.view.setStore(A)
  211. }
  212. }
  213. },
  214. initEvents : function() {
  215. Ext.form.ComboBox.superclass.initEvents.call(this);
  216. this.keyNav = new Ext.KeyNav(this.el, {
  217. "up" : function(A) {
  218. this.inKeyMode = true;
  219. this.selectPrev()
  220. },
  221. "down" : function(A) {
  222. if (!this.isExpanded()) {
  223. this.onTriggerClick()
  224. } else {
  225. this.inKeyMode = true;
  226. this.selectNext()
  227. }
  228. },
  229. "enter" : function(A) {
  230. this.onViewClick()
  231. },
  232. "esc" : function(A) {
  233. this.collapse()
  234. },
  235. "tab" : function(A) {
  236. this.onViewClick(false);
  237. return true
  238. },
  239. scope : this,
  240. doRelay : function(C, B, A) {
  241. if (A == "down" || this.scope.isExpanded()) {
  242. return Ext.KeyNav.prototype.doRelay.apply(
  243. this, arguments)
  244. }
  245. return true
  246. },
  247. forceKeyDown : true
  248. });
  249. this.queryDelay = Math.max(this.queryDelay || 10,
  250. this.mode == "local" ? 10 : 250);
  251. this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
  252. if (this.typeAhead) {
  253. this.taTask = new Ext.util.DelayedTask(this.onTypeAhead,
  254. this)
  255. }
  256. if (this.editable !== false) {
  257. this.el.on("keyup", this.onKeyUp, this)
  258. }
  259. if (this.forceSelection) {
  260. this.on("blur", this.doForce, this)
  261. }
  262. },
  263. onDestroy : function() {
  264. if (this.view) {
  265. this.view.el.removeAllListeners();
  266. this.view.el.remove();
  267. this.view.purgeListeners()
  268. }
  269. if (this.list) {
  270. this.list.destroy()
  271. }
  272. this.bindStore(null);
  273. Ext.form.ComboBox.superclass.onDestroy.call(this)
  274. },
  275. fireKey : function(A) {
  276. if (A.isNavKeyPress() && !this.list.isVisible()) {
  277. this.fireEvent("specialkey", this, A)
  278. }
  279. },
  280. onResize : function(A, B) {
  281. Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
  282. if (this.list && this.listWidth === undefined) {
  283. var C = Math.max(A, this.minListWidth);
  284. this.list.setWidth(C);
  285. this.innerList.setWidth(C - this.list.getFrameWidth("lr"))
  286. }
  287. },
  288. onDisable : function() {
  289. Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
  290. if (this.hiddenField) {
  291. this.hiddenField.disabled = this.disabled
  292. }
  293. },
  294. setEditable : function(A) {
  295. if (A == this.editable) {
  296. return
  297. }
  298. this.editable = A;
  299. if (!A) {
  300. this.el.dom.setAttribute("readOnly", true);
  301. this.el.on("mousedown", this.onTriggerClick, this);
  302. this.el.addClass("x-combo-noedit")
  303. } else {
  304. this.el.dom.setAttribute("readOnly", false);
  305. this.el.un("mousedown", this.onTriggerClick, this);
  306. this.el.removeClass("x-combo-noedit")
  307. }
  308. },
  309. onBeforeLoad : function() {
  310. if (!this.hasFocus) {
  311. return
  312. }
  313. this.innerList.update(this.loadingText
  314. ? "<div class=\"loading-indicator\">"
  315. + this.loadingText + "</div>"
  316. : "");
  317. this.restrictHeight();
  318. this.selectedIndex = -1
  319. },
  320. onLoad : function() {
  321. if (!this.hasFocus) {
  322. return
  323. }
  324. if (this.store.getCount() > 0) {
  325. this.expand();
  326. this.restrictHeight();
  327. if (this.lastQuery == this.allQuery) {
  328. if (this.editable) {
  329. this.el.dom.select()
  330. }
  331. if (!this.selectByValue(this.value, true)) {
  332. this.select(0, true)
  333. }
  334. } else {
  335. this.selectNext();
  336. if (this.typeAhead
  337. && this.lastKey != Ext.EventObject.BACKSPACE
  338. && this.lastKey != Ext.EventObject.DELETE) {
  339. this.taTask.delay(this.typeAheadDelay)
  340. }
  341. }
  342. } else {
  343. this.onEmptyResults()
  344. }
  345. },
  346. onTypeAhead : function() {
  347. if (this.store.getCount() > 0) {
  348. var B = this.store.getAt(0);
  349. var C = B.data[this.displayField];
  350. var A = C.length;
  351. var D = this.getRawValue().length;
  352. if (D != A) {
  353. this.setRawValue(C);
  354. this.selectText(D, C.length)
  355. }
  356. }
  357. },
  358. onSelect : function(A, B) {
  359. if (this.fireEvent("beforeselect", this, A, B) !== false) {
  360. this.setValue(A.data[this.valueField || this.displayField]);
  361. this.collapse();
  362. this.fireEvent("select", this, A, B)
  363. }
  364. },
  365. getValue : function() {
  366. if (this.valueField) {
  367. return typeof this.value != "undefined" ? this.value : ""
  368. } else {
  369. return Ext.form.ComboBox.superclass.getValue.call(this)
  370. }
  371. },
  372. clearValue : function() {
  373. if (this.hiddenField) {
  374. this.hiddenField.value = ""
  375. }
  376. this.setRawValue("");
  377. this.lastSelectionText = "";
  378. this.applyEmptyText()
  379. },
  380. setValue : function(A) {
  381. var C = A;
  382. if (this.valueField) {
  383. var B = this.findRecord(this.valueField, A);
  384. if (B) {
  385. C = B.data[this.displayField]
  386. } else {
  387. if (this.valueNotFoundText !== undefined) {
  388. C = this.valueNotFoundText
  389. }
  390. }
  391. }
  392. this.lastSelectionText = C;
  393. if (this.hiddenField) {
  394. this.hiddenField.value = A
  395. }
  396. Ext.form.ComboBox.superclass.setValue.call(this, C);
  397. this.value = A
  398. },
  399. findRecord : function(C, B) {
  400. var A;
  401. if (this.store.getCount() > 0) {
  402. this.store.each(function(D) {
  403. if (D.data[C] == B) {
  404. A = D;
  405. return false
  406. }
  407. })
  408. }
  409. return A
  410. },
  411. onViewMove : function(B, A) {
  412. this.inKeyMode = false
  413. },
  414. onViewOver : function(D, B) {
  415. if (this.inKeyMode) {
  416. return
  417. }
  418. var C = this.view.findItemFromChild(B);
  419. if (C) {
  420. var A = this.view.indexOf(C);
  421. this.select(A, false)
  422. }
  423. },
  424. onViewClick : function(B) {
  425. var A = this.view.getSelectedIndexes()[0];
  426. var C = this.store.getAt(A);
  427. if (C) {
  428. this.onSelect(C, A)
  429. }
  430. if (B !== false) {
  431. this.el.focus()
  432. }
  433. },
  434. restrictHeight : function() {
  435. this.innerList.dom.style.height = "";
  436. var A = this.innerList.dom;
  437. var C = this.list.getFrameWidth("tb");
  438. var B = Math
  439. .max(A.clientHeight, A.offsetHeight, A.scrollHeight);
  440. this.innerList.setHeight(B < this.maxHeight
  441. ? "auto"
  442. : this.maxHeight);
  443. this.list.beginUpdate();
  444. this.list.setHeight(this.innerList.getHeight() + C
  445. + (this.resizable ? this.handleHeight : 0)
  446. + this.assetHeight);
  447. this.list.alignTo(this.el, this.listAlign);
  448. this.list.endUpdate()
  449. },
  450. onEmptyResults : function() {
  451. this.collapse()
  452. },
  453. isExpanded : function() {
  454. return this.list && this.list.isVisible()
  455. },
  456. selectByValue : function(A, C) {
  457. if (A !== undefined && A !== null) {
  458. var B = this.findRecord(this.valueField
  459. || this.displayField, A);
  460. if (B) {
  461. this.select(this.store.indexOf(B), C);
  462. return true
  463. }
  464. }
  465. return false
  466. },
  467. select : function(A, C) {
  468. this.selectedIndex = A;
  469. this.view.select(A);
  470. if (C !== false) {
  471. var B = this.view.getNode(A);
  472. if (B) {
  473. this.innerList.scrollChildIntoView(B, false)
  474. }
  475. }
  476. },
  477. selectNext : function() {
  478. var A = this.store.getCount();
  479. if (A > 0) {
  480. if (this.selectedIndex == -1) {
  481. this.select(0)
  482. } else {
  483. if (this.selectedIndex < A - 1) {
  484. this.select(this.selectedIndex + 1)
  485. }
  486. }
  487. }
  488. },
  489. selectPrev : function() {
  490. var A = this.store.getCount();
  491. if (A > 0) {
  492. if (this.selectedIndex == -1) {
  493. this.select(0)
  494. } else {
  495. if (this.selectedIndex != 0) {
  496. this.select(this.selectedIndex - 1)
  497. }
  498. }
  499. }
  500. },
  501. onKeyUp : function(A) {
  502. if (this.editable !== false && !A.isSpecialKey()) {
  503. this.lastKey = A.getKey();
  504. this.dqTask.delay(this.queryDelay)
  505. }
  506. },
  507. validateBlur : function() {
  508. return !this.list || !this.list.isVisible()
  509. },
  510. initQuery : function() {
  511. this.doQuery(this.getRawValue())
  512. },
  513. doForce : function() {
  514. if (this.el.dom.value.length > 0) {
  515. this.el.dom.value = this.lastSelectionText === undefined
  516. ? ""
  517. : this.lastSelectionText;
  518. this.applyEmptyText()
  519. }
  520. },
  521. doQuery : function(C, B) {
  522. if (C === undefined || C === null) {
  523. C = ""
  524. }
  525. var A = {
  526. query : C,
  527. forceAll : B,
  528. combo : this,
  529. cancel : false
  530. };
  531. if (this.fireEvent("beforequery", A) === false || A.cancel) {
  532. return false
  533. }
  534. C = A.query;
  535. B = A.forceAll;
  536. if (B === true || (C.length >= this.minChars)) {
  537. if (this.lastQuery !== C) {
  538. this.lastQuery = C;
  539. if (this.mode == "local") {
  540. this.selectedIndex = -1;
  541. if (B) {
  542. this.store.clearFilter()
  543. } else {
  544. this.store.filter(this.displayField, C)
  545. }
  546. this.onLoad()
  547. } else {
  548. this.store.baseParams[this.queryParam] = C;
  549. this.store.load({
  550. params : this.getParams(C)
  551. });
  552. this.expand()
  553. }
  554. } else {
  555. this.selectedIndex = -1;
  556. this.onLoad()
  557. }
  558. }
  559. },
  560. getParams : function(A) {
  561. var B = {};
  562. if (this.pageSize) {
  563. B.start = 0;
  564. B.limit = this.pageSize
  565. }
  566. return B
  567. },
  568. collapse : function() {
  569. if (!this.isExpanded()) {
  570. return
  571. }
  572. this.list.hide();
  573. Ext.getDoc().un("mousewheel", this.collapseIf, this);
  574. Ext.getDoc().un("mousedown", this.collapseIf, this);
  575. this.fireEvent("collapse", this)
  576. },
  577. collapseIf : function(A) {
  578. if (!A.within(this.wrap) && !A.within(this.list)) {
  579. this.collapse()
  580. }
  581. },
  582. expand : function() {
  583. if (this.isExpanded() || !this.hasFocus) {
  584. return
  585. }
  586. this.list.alignTo(this.wrap, this.listAlign);
  587. this.list.show();
  588. Ext.getDoc().on("mousewheel", this.collapseIf, this);
  589. Ext.getDoc().on("mousedown", this.collapseIf, this);
  590. this.fireEvent("expand", this)
  591. },
  592. onTriggerClick : function() {
  593. if (this.disabled) {
  594. return
  595. }
  596. if (this.isExpanded()) {
  597. this.collapse();
  598. this.el.focus()
  599. } else {
  600. this.onFocus({});
  601. if (this.triggerAction == "all") {
  602. this.doQuery(this.allQuery, true)
  603. } else {
  604. this.doQuery(this.getRawValue())
  605. }
  606. this.el.focus()
  607. }
  608. }
  609. });
  610. Ext.reg("combo", Ext.form.ComboBox);