Upgrade to ExtJS 3.2.0 - Released 03/30/2010
[extjs.git] / examples / ux / ItemSelector.js
1 /*!
2  * Ext JS Library 3.2.0
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /*
8  * Note that this control will most likely remain as an example, and not as a core Ext form
9  * control.  However, the API will be changing in a future release and so should not yet be
10  * treated as a final, stable API at this time.
11  */
12
13 /**
14  * @class Ext.ux.form.ItemSelector
15  * @extends Ext.form.Field
16  * A control that allows selection of between two Ext.ux.form.MultiSelect controls.
17  *
18  *  @history
19  *    2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)
20  *
21  * @constructor
22  * Create a new ItemSelector
23  * @param {Object} config Configuration options
24  * @xtype itemselector 
25  */
26 Ext.ux.form.ItemSelector = Ext.extend(Ext.form.Field,  {
27     hideNavIcons:false,
28     imagePath:"",
29     iconUp:"up2.gif",
30     iconDown:"down2.gif",
31     iconLeft:"left2.gif",
32     iconRight:"right2.gif",
33     iconTop:"top2.gif",
34     iconBottom:"bottom2.gif",
35     drawUpIcon:true,
36     drawDownIcon:true,
37     drawLeftIcon:true,
38     drawRightIcon:true,
39     drawTopIcon:true,
40     drawBotIcon:true,
41     delimiter:',',
42     bodyStyle:null,
43     border:false,
44     defaultAutoCreate:{tag: "div"},
45     /**
46      * @cfg {Array} multiselects An array of {@link Ext.ux.form.MultiSelect} config objects, with at least all required parameters (e.g., store)
47      */
48     multiselects:null,
49
50     initComponent: function(){
51         Ext.ux.form.ItemSelector.superclass.initComponent.call(this);
52         this.addEvents({
53             'rowdblclick' : true,
54             'change' : true
55         });
56     },
57
58     onRender: function(ct, position){
59         Ext.ux.form.ItemSelector.superclass.onRender.call(this, ct, position);
60
61         // Internal default configuration for both multiselects
62         var msConfig = [{
63             legend: 'Available',
64             draggable: true,
65             droppable: true,
66             width: 100,
67             height: 100
68         },{
69             legend: 'Selected',
70             droppable: true,
71             draggable: true,
72             width: 100,
73             height: 100
74         }];
75
76         this.fromMultiselect = new Ext.ux.form.MultiSelect(Ext.applyIf(this.multiselects[0], msConfig[0]));
77         this.fromMultiselect.on('dblclick', this.onRowDblClick, this);
78
79         this.toMultiselect = new Ext.ux.form.MultiSelect(Ext.applyIf(this.multiselects[1], msConfig[1]));
80         this.toMultiselect.on('dblclick', this.onRowDblClick, this);
81
82         var p = new Ext.Panel({
83             bodyStyle:this.bodyStyle,
84             border:this.border,
85             layout:"table",
86             layoutConfig:{columns:3}
87         });
88
89         p.add(this.fromMultiselect);
90         var icons = new Ext.Panel({header:false});
91         p.add(icons);
92         p.add(this.toMultiselect);
93         p.render(this.el);
94         icons.el.down('.'+icons.bwrapCls).remove();
95
96         // ICON HELL!!!
97         if (this.imagePath!="" && this.imagePath.charAt(this.imagePath.length-1)!="/")
98             this.imagePath+="/";
99         this.iconUp = this.imagePath + (this.iconUp || 'up2.gif');
100         this.iconDown = this.imagePath + (this.iconDown || 'down2.gif');
101         this.iconLeft = this.imagePath + (this.iconLeft || 'left2.gif');
102         this.iconRight = this.imagePath + (this.iconRight || 'right2.gif');
103         this.iconTop = this.imagePath + (this.iconTop || 'top2.gif');
104         this.iconBottom = this.imagePath + (this.iconBottom || 'bottom2.gif');
105         var el=icons.getEl();
106         this.toTopIcon = el.createChild({tag:'img', src:this.iconTop, style:{cursor:'pointer', margin:'2px'}});
107         el.createChild({tag: 'br'});
108         this.upIcon = el.createChild({tag:'img', src:this.iconUp, style:{cursor:'pointer', margin:'2px'}});
109         el.createChild({tag: 'br'});
110         this.addIcon = el.createChild({tag:'img', src:this.iconRight, style:{cursor:'pointer', margin:'2px'}});
111         el.createChild({tag: 'br'});
112         this.removeIcon = el.createChild({tag:'img', src:this.iconLeft, style:{cursor:'pointer', margin:'2px'}});
113         el.createChild({tag: 'br'});
114         this.downIcon = el.createChild({tag:'img', src:this.iconDown, style:{cursor:'pointer', margin:'2px'}});
115         el.createChild({tag: 'br'});
116         this.toBottomIcon = el.createChild({tag:'img', src:this.iconBottom, style:{cursor:'pointer', margin:'2px'}});
117         this.toTopIcon.on('click', this.toTop, this);
118         this.upIcon.on('click', this.up, this);
119         this.downIcon.on('click', this.down, this);
120         this.toBottomIcon.on('click', this.toBottom, this);
121         this.addIcon.on('click', this.fromTo, this);
122         this.removeIcon.on('click', this.toFrom, this);
123         if (!this.drawUpIcon || this.hideNavIcons) { this.upIcon.dom.style.display='none'; }
124         if (!this.drawDownIcon || this.hideNavIcons) { this.downIcon.dom.style.display='none'; }
125         if (!this.drawLeftIcon || this.hideNavIcons) { this.addIcon.dom.style.display='none'; }
126         if (!this.drawRightIcon || this.hideNavIcons) { this.removeIcon.dom.style.display='none'; }
127         if (!this.drawTopIcon || this.hideNavIcons) { this.toTopIcon.dom.style.display='none'; }
128         if (!this.drawBotIcon || this.hideNavIcons) { this.toBottomIcon.dom.style.display='none'; }
129
130         var tb = p.body.first();
131         this.el.setWidth(p.body.first().getWidth());
132         p.body.removeClass();
133
134         this.hiddenName = this.name;
135         var hiddenTag = {tag: "input", type: "hidden", value: "", name: this.name};
136         this.hiddenField = this.el.createChild(hiddenTag);
137     },
138     
139     doLayout: function(){
140         if(this.rendered){
141             this.fromMultiselect.fs.doLayout();
142             this.toMultiselect.fs.doLayout();
143         }
144     },
145
146     afterRender: function(){
147         Ext.ux.form.ItemSelector.superclass.afterRender.call(this);
148
149         this.toStore = this.toMultiselect.store;
150         this.toStore.on('add', this.valueChanged, this);
151         this.toStore.on('remove', this.valueChanged, this);
152         this.toStore.on('load', this.valueChanged, this);
153         this.valueChanged(this.toStore);
154     },
155
156     toTop : function() {
157         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
158         var records = [];
159         if (selectionsArray.length > 0) {
160             selectionsArray.sort();
161             for (var i=0; i<selectionsArray.length; i++) {
162                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
163                 records.push(record);
164             }
165             selectionsArray = [];
166             for (var i=records.length-1; i>-1; i--) {
167                 record = records[i];
168                 this.toMultiselect.view.store.remove(record);
169                 this.toMultiselect.view.store.insert(0, record);
170                 selectionsArray.push(((records.length - 1) - i));
171             }
172         }
173         this.toMultiselect.view.refresh();
174         this.toMultiselect.view.select(selectionsArray);
175     },
176
177     toBottom : function() {
178         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
179         var records = [];
180         if (selectionsArray.length > 0) {
181             selectionsArray.sort();
182             for (var i=0; i<selectionsArray.length; i++) {
183                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
184                 records.push(record);
185             }
186             selectionsArray = [];
187             for (var i=0; i<records.length; i++) {
188                 record = records[i];
189                 this.toMultiselect.view.store.remove(record);
190                 this.toMultiselect.view.store.add(record);
191                 selectionsArray.push((this.toMultiselect.view.store.getCount()) - (records.length - i));
192             }
193         }
194         this.toMultiselect.view.refresh();
195         this.toMultiselect.view.select(selectionsArray);
196     },
197
198     up : function() {
199         var record = null;
200         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
201         selectionsArray.sort();
202         var newSelectionsArray = [];
203         if (selectionsArray.length > 0) {
204             for (var i=0; i<selectionsArray.length; i++) {
205                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
206                 if ((selectionsArray[i] - 1) >= 0) {
207                     this.toMultiselect.view.store.remove(record);
208                     this.toMultiselect.view.store.insert(selectionsArray[i] - 1, record);
209                     newSelectionsArray.push(selectionsArray[i] - 1);
210                 }
211             }
212             this.toMultiselect.view.refresh();
213             this.toMultiselect.view.select(newSelectionsArray);
214         }
215     },
216
217     down : function() {
218         var record = null;
219         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
220         selectionsArray.sort();
221         selectionsArray.reverse();
222         var newSelectionsArray = [];
223         if (selectionsArray.length > 0) {
224             for (var i=0; i<selectionsArray.length; i++) {
225                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
226                 if ((selectionsArray[i] + 1) < this.toMultiselect.view.store.getCount()) {
227                     this.toMultiselect.view.store.remove(record);
228                     this.toMultiselect.view.store.insert(selectionsArray[i] + 1, record);
229                     newSelectionsArray.push(selectionsArray[i] + 1);
230                 }
231             }
232             this.toMultiselect.view.refresh();
233             this.toMultiselect.view.select(newSelectionsArray);
234         }
235     },
236
237     fromTo : function() {
238         var selectionsArray = this.fromMultiselect.view.getSelectedIndexes();
239         var records = [];
240         if (selectionsArray.length > 0) {
241             for (var i=0; i<selectionsArray.length; i++) {
242                 record = this.fromMultiselect.view.store.getAt(selectionsArray[i]);
243                 records.push(record);
244             }
245             if(!this.allowDup)selectionsArray = [];
246             for (var i=0; i<records.length; i++) {
247                 record = records[i];
248                 if(this.allowDup){
249                     var x=new Ext.data.Record();
250                     record.id=x.id;
251                     delete x;
252                     this.toMultiselect.view.store.add(record);
253                 }else{
254                     this.fromMultiselect.view.store.remove(record);
255                     this.toMultiselect.view.store.add(record);
256                     selectionsArray.push((this.toMultiselect.view.store.getCount() - 1));
257                 }
258             }
259         }
260         this.toMultiselect.view.refresh();
261         this.fromMultiselect.view.refresh();
262         var si = this.toMultiselect.store.sortInfo;
263         if(si){
264             this.toMultiselect.store.sort(si.field, si.direction);
265         }
266         this.toMultiselect.view.select(selectionsArray);
267     },
268
269     toFrom : function() {
270         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
271         var records = [];
272         if (selectionsArray.length > 0) {
273             for (var i=0; i<selectionsArray.length; i++) {
274                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
275                 records.push(record);
276             }
277             selectionsArray = [];
278             for (var i=0; i<records.length; i++) {
279                 record = records[i];
280                 this.toMultiselect.view.store.remove(record);
281                 if(!this.allowDup){
282                     this.fromMultiselect.view.store.add(record);
283                     selectionsArray.push((this.fromMultiselect.view.store.getCount() - 1));
284                 }
285             }
286         }
287         this.fromMultiselect.view.refresh();
288         this.toMultiselect.view.refresh();
289         var si = this.fromMultiselect.store.sortInfo;
290         if (si){
291             this.fromMultiselect.store.sort(si.field, si.direction);
292         }
293         this.fromMultiselect.view.select(selectionsArray);
294     },
295
296     valueChanged: function(store) {
297         var record = null;
298         var values = [];
299         for (var i=0; i<store.getCount(); i++) {
300             record = store.getAt(i);
301             values.push(record.get(this.toMultiselect.valueField));
302         }
303         this.hiddenField.dom.value = values.join(this.delimiter);
304         this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
305     },
306
307     getValue : function() {
308         return this.hiddenField.dom.value;
309     },
310
311     onRowDblClick : function(vw, index, node, e) {
312         if (vw == this.toMultiselect.view){
313             this.toFrom();
314         } else if (vw == this.fromMultiselect.view) {
315             this.fromTo();
316         }
317         return this.fireEvent('rowdblclick', vw, index, node, e);
318     },
319
320     reset: function(){
321         range = this.toMultiselect.store.getRange();
322         this.toMultiselect.store.removeAll();
323         this.fromMultiselect.store.add(range);
324         var si = this.fromMultiselect.store.sortInfo;
325         if (si){
326             this.fromMultiselect.store.sort(si.field, si.direction);
327         }
328         this.valueChanged(this.toMultiselect.store);
329     }
330 });
331
332 Ext.reg('itemselector', Ext.ux.form.ItemSelector);
333
334 //backwards compat
335 Ext.ux.ItemSelector = Ext.ux.form.ItemSelector;