ItemSelector.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js">/*
  19. * Note that this control will most likely remain as an example, and not as a core Ext form
  20. * control. However, the API will be changing in a future release and so should not yet be
  21. * treated as a final, stable API at this time.
  22. */
  23. <span id='Ext-ux-form-ItemSelector'>/**
  24. </span> * A control that allows selection of between two Ext.ux.form.MultiSelect controls.
  25. */
  26. Ext.define('Ext.ux.form.ItemSelector', {
  27. extend: 'Ext.ux.form.MultiSelect',
  28. alias: ['widget.itemselectorfield', 'widget.itemselector'],
  29. alternateClassName: ['Ext.ux.ItemSelector'],
  30. requires: [
  31. 'Ext.button.Button',
  32. 'Ext.ux.form.MultiSelect'
  33. ],
  34. <span id='Ext-ux-form-ItemSelector-cfg-hideNavIcons'> /**
  35. </span> * @cfg {Boolean} [hideNavIcons=false] True to hide the navigation icons
  36. */
  37. hideNavIcons:false,
  38. <span id='Ext-ux-form-ItemSelector-cfg-buttons'> /**
  39. </span> * @cfg {Array} buttons Defines the set of buttons that should be displayed in between the ItemSelector
  40. * fields. Defaults to &lt;tt&gt;['top', 'up', 'add', 'remove', 'down', 'bottom']&lt;/tt&gt;. These names are used
  41. * to build the button CSS class names, and to look up the button text labels in {@link #buttonsText}.
  42. * This can be overridden with a custom Array to change which buttons are displayed or their order.
  43. */
  44. buttons: ['top', 'up', 'add', 'remove', 'down', 'bottom'],
  45. <span id='Ext-ux-form-ItemSelector-cfg-buttonsText'> /**
  46. </span> * @cfg {Object} buttonsText The tooltips for the {@link #buttons}.
  47. * Labels for buttons.
  48. */
  49. buttonsText: {
  50. top: &quot;Move to Top&quot;,
  51. up: &quot;Move Up&quot;,
  52. add: &quot;Add to Selected&quot;,
  53. remove: &quot;Remove from Selected&quot;,
  54. down: &quot;Move Down&quot;,
  55. bottom: &quot;Move to Bottom&quot;
  56. },
  57. initComponent: function() {
  58. var me = this;
  59. me.ddGroup = me.id + '-dd';
  60. me.callParent();
  61. // bindStore must be called after the fromField has been created because
  62. // it copies records from our configured Store into the fromField's Store
  63. me.bindStore(me.store);
  64. },
  65. createList: function(title){
  66. var me = this;
  67. return Ext.create('Ext.ux.form.MultiSelect', {
  68. submitValue: false,
  69. flex: 1,
  70. dragGroup: me.ddGroup,
  71. dropGroup: me.ddGroup,
  72. title: title,
  73. store: {
  74. model: me.store.model,
  75. data: []
  76. },
  77. displayField: me.displayField,
  78. disabled: me.disabled,
  79. listeners: {
  80. boundList: {
  81. scope: me,
  82. itemdblclick: me.onItemDblClick,
  83. drop: me.syncValue
  84. }
  85. }
  86. });
  87. },
  88. setupItems: function() {
  89. var me = this;
  90. me.fromField = me.createList(me.fromTitle);
  91. me.toField = me.createList(me.toTitle);
  92. return {
  93. border: false,
  94. layout: {
  95. type: 'hbox',
  96. align: 'stretch'
  97. },
  98. items: [
  99. me.fromField,
  100. {
  101. xtype: 'container',
  102. margins: '0 4',
  103. width: 22,
  104. layout: {
  105. type: 'vbox',
  106. pack: 'center'
  107. },
  108. items: me.createButtons()
  109. },
  110. me.toField
  111. ]
  112. };
  113. },
  114. createButtons: function(){
  115. var me = this,
  116. buttons = [];
  117. if (!me.hideNavIcons) {
  118. Ext.Array.forEach(me.buttons, function(name) {
  119. buttons.push({
  120. xtype: 'button',
  121. tooltip: me.buttonsText[name],
  122. handler: me['on' + Ext.String.capitalize(name) + 'BtnClick'],
  123. cls: Ext.baseCSSPrefix + 'form-itemselector-btn',
  124. iconCls: Ext.baseCSSPrefix + 'form-itemselector-' + name,
  125. navBtn: true,
  126. scope: me,
  127. margin: '4 0 0 0'
  128. });
  129. });
  130. }
  131. return buttons;
  132. },
  133. <span id='Ext-ux-form-ItemSelector-method-getSelections'> /**
  134. </span> * Get the selected records from the specified list.
  135. *
  136. * Records will be returned *in store order*, not in order of selection.
  137. * @param {Ext.view.BoundList} list The list to read selections from.
  138. * @return {Ext.data.Model[]} The selected records in store order.
  139. *
  140. */
  141. getSelections: function(list) {
  142. var store = list.getStore();
  143. return Ext.Array.sort(list.getSelectionModel().getSelection(), function(a, b) {
  144. a = store.indexOf(a);
  145. b = store.indexOf(b);
  146. if (a &lt; b) {
  147. return -1;
  148. } else if (a &gt; b) {
  149. return 1;
  150. }
  151. return 0;
  152. });
  153. },
  154. onTopBtnClick : function() {
  155. var list = this.toField.boundList,
  156. store = list.getStore(),
  157. selected = this.getSelections(list);
  158. store.suspendEvents();
  159. store.remove(selected, true);
  160. store.insert(0, selected);
  161. store.resumeEvents();
  162. list.refresh();
  163. this.syncValue();
  164. list.getSelectionModel().select(selected);
  165. },
  166. onBottomBtnClick : function() {
  167. var list = this.toField.boundList,
  168. store = list.getStore(),
  169. selected = this.getSelections(list);
  170. store.suspendEvents();
  171. store.remove(selected, true);
  172. store.add(selected);
  173. store.resumeEvents();
  174. list.refresh();
  175. this.syncValue();
  176. list.getSelectionModel().select(selected);
  177. },
  178. onUpBtnClick : function() {
  179. var list = this.toField.boundList,
  180. store = list.getStore(),
  181. selected = this.getSelections(list),
  182. rec,
  183. i = 0,
  184. len = selected.length,
  185. index = 0;
  186. // Move each selection up by one place if possible
  187. store.suspendEvents();
  188. for (; i &lt; len; ++i, index++) {
  189. rec = selected[i];
  190. index = Math.max(index, store.indexOf(rec) - 1);
  191. store.remove(rec, true);
  192. store.insert(index, rec);
  193. }
  194. store.resumeEvents();
  195. list.refresh();
  196. this.syncValue();
  197. list.getSelectionModel().select(selected);
  198. },
  199. onDownBtnClick : function() {
  200. var list = this.toField.boundList,
  201. store = list.getStore(),
  202. selected = this.getSelections(list),
  203. rec,
  204. i = selected.length - 1,
  205. index = store.getCount() - 1;
  206. // Move each selection down by one place if possible
  207. store.suspendEvents();
  208. for (; i &gt; -1; --i, index--) {
  209. rec = selected[i];
  210. index = Math.min(index, store.indexOf(rec) + 1);
  211. store.remove(rec, true);
  212. store.insert(index, rec);
  213. }
  214. store.resumeEvents();
  215. list.refresh();
  216. this.syncValue();
  217. list.getSelectionModel().select(selected);
  218. },
  219. onAddBtnClick : function() {
  220. var me = this,
  221. selected = me.getSelections(me.fromField.boundList);
  222. me.moveRec(true, selected);
  223. me.toField.boundList.getSelectionModel().select(selected);
  224. },
  225. onRemoveBtnClick : function() {
  226. var me = this,
  227. selected = me.getSelections(me.toField.boundList);
  228. me.moveRec(false, selected);
  229. me.fromField.boundList.getSelectionModel().select(selected);
  230. },
  231. moveRec: function(add, recs) {
  232. var me = this,
  233. fromField = me.fromField,
  234. toField = me.toField,
  235. fromStore = add ? fromField.store : toField.store,
  236. toStore = add ? toField.store : fromField.store;
  237. fromStore.suspendEvents();
  238. toStore.suspendEvents();
  239. fromStore.remove(recs);
  240. toStore.add(recs);
  241. fromStore.resumeEvents();
  242. toStore.resumeEvents();
  243. fromField.boundList.refresh();
  244. toField.boundList.refresh();
  245. me.syncValue();
  246. },
  247. // Synchronizes the submit value with the current state of the toStore
  248. syncValue: function() {
  249. var me = this;
  250. me.mixins.field.setValue.call(me, me.setupValue(me.toField.store.getRange()));
  251. },
  252. onItemDblClick: function(view, rec) {
  253. this.moveRec(view === this.fromField.boundList, rec);
  254. },
  255. setValue: function(value) {
  256. var me = this,
  257. fromField = me.fromField,
  258. toField = me.toField,
  259. fromStore = fromField.store,
  260. toStore = toField.store,
  261. selected;
  262. // Wait for from store to be loaded
  263. if (!me.fromStorePopulated) {
  264. me.fromField.store.on({
  265. load: Ext.Function.bind(me.setValue, me, [value]),
  266. single: true
  267. });
  268. return;
  269. }
  270. value = me.setupValue(value);
  271. me.mixins.field.setValue.call(me, value);
  272. selected = me.getRecordsForValue(value);
  273. // Clear both left and right Stores.
  274. // Both stores must not fire events during this process.
  275. fromStore.suspendEvents();
  276. toStore.suspendEvents();
  277. fromStore.removeAll();
  278. toStore.removeAll();
  279. // Reset fromStore
  280. me.populateFromStore(me.store);
  281. // Copy selection across to toStore
  282. Ext.Array.forEach(selected, function(rec){
  283. // In the from store, move it over
  284. if (fromStore.indexOf(rec) &gt; -1) {
  285. fromStore.remove(rec);
  286. }
  287. toStore.add(rec);
  288. });
  289. // Stores may now fire events
  290. fromStore.resumeEvents();
  291. toStore.resumeEvents();
  292. // Refresh both sides and then update the app layout
  293. Ext.suspendLayouts();
  294. fromField.boundList.refresh();
  295. toField.boundList.refresh();
  296. Ext.resumeLayouts(true);
  297. },
  298. onBindStore: function(store, initial) {
  299. var me = this;
  300. if (me.fromField) {
  301. me.fromField.store.removeAll()
  302. me.toField.store.removeAll();
  303. // Add everything to the from field as soon as the Store is loaded
  304. if (store.getCount()) {
  305. me.populateFromStore(store);
  306. } else {
  307. me.store.on('load', me.populateFromStore, me);
  308. }
  309. }
  310. },
  311. populateFromStore: function(store) {
  312. var fromStore = this.fromField.store;
  313. // Flag set when the fromStore has been loaded
  314. this.fromStorePopulated = true;
  315. fromStore.add(store.getRange());
  316. // setValue waits for the from Store to be loaded
  317. fromStore.fireEvent('load', fromStore);
  318. },
  319. onEnable: function(){
  320. var me = this;
  321. me.callParent();
  322. me.fromField.enable();
  323. me.toField.enable();
  324. Ext.Array.forEach(me.query('[navBtn]'), function(btn){
  325. btn.enable();
  326. });
  327. },
  328. onDisable: function(){
  329. var me = this;
  330. me.callParent();
  331. me.fromField.disable();
  332. me.toField.disable();
  333. Ext.Array.forEach(me.query('[navBtn]'), function(btn){
  334. btn.disable();
  335. });
  336. },
  337. onDestroy: function(){
  338. this.bindStore(null);
  339. this.callParent();
  340. }
  341. });
  342. </pre>
  343. </body>
  344. </html>