source: Dev/trunk/src/client/dojo/dnd/Selector.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.0 KB
Line 
1define([
2        "../_base/array", "../_base/declare", "../_base/kernel", "../_base/lang",
3        "../dom", "../dom-construct", "../mouse", "../_base/NodeList", "../on", "../touch", "./common", "./Container"
4], function(array, declare, kernel, lang, dom, domConstruct, mouse, NodeList, on, touch, dnd, Container){
5
6// module:
7//              dojo/dnd/Selector
8
9/*
10        Container item states:
11                ""                      - an item is not selected
12                "Selected"      - an item is selected
13                "Anchor"        - an item is selected, and is an anchor for a "shift" selection
14*/
15
16/*=====
17var __SelectorArgs = declare([Container.__ContainerArgs], {
18        // singular: Boolean
19        //              allows selection of only one element, if true
20        singular: false,
21
22        // autoSync: Boolean
23        //              autosynchronizes the source with its list of DnD nodes,
24        autoSync: false
25});
26=====*/
27
28var Selector = declare("dojo.dnd.Selector", Container, {
29        // summary:
30        //              a Selector object, which knows how to select its children
31
32        /*=====
33        // selection: Set<String>
34        //              The set of id's that are currently selected, such that this.selection[id] == 1
35        //              if the node w/that id is selected.  Can iterate over selected node's id's like:
36        //      |               for(var id in this.selection)
37        selection: {},
38        =====*/
39
40        constructor: function(node, params){
41                // summary:
42                //              constructor of the Selector
43                // node: Node||String
44                //              node or node's id to build the selector on
45                // params: __SelectorArgs?
46                //              a dictionary of parameters
47                if(!params){ params = {}; }
48                this.singular = params.singular;
49                this.autoSync = params.autoSync;
50                // class-specific variables
51                this.selection = {};
52                this.anchor = null;
53                this.simpleSelection = false;
54                // set up events
55                this.events.push(
56                        on(this.node, touch.press, lang.hitch(this, "onMouseDown")),
57                        on(this.node, touch.release, lang.hitch(this, "onMouseUp"))
58                );
59        },
60
61        // object attributes (for markup)
62        singular: false,        // is singular property
63
64        // methods
65        getSelectedNodes: function(){
66                // summary:
67                //              returns a list (an array) of selected nodes
68                var t = new NodeList();
69                var e = dnd._empty;
70                for(var i in this.selection){
71                        if(i in e){ continue; }
72                        t.push(dom.byId(i));
73                }
74                return t;       // NodeList
75        },
76        selectNone: function(){
77                // summary:
78                //              unselects all items
79                return this._removeSelection()._removeAnchor(); // self
80        },
81        selectAll: function(){
82                // summary:
83                //              selects all items
84                this.forInItems(function(data, id){
85                        this._addItemClass(dom.byId(id), "Selected");
86                        this.selection[id] = 1;
87                }, this);
88                return this._removeAnchor();    // self
89        },
90        deleteSelectedNodes: function(){
91                // summary:
92                //              deletes all selected items
93                var e = dnd._empty;
94                for(var i in this.selection){
95                        if(i in e){ continue; }
96                        var n = dom.byId(i);
97                        this.delItem(i);
98                        domConstruct.destroy(n);
99                }
100                this.anchor = null;
101                this.selection = {};
102                return this;    // self
103        },
104        forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
105                // summary:
106                //              iterates over selected items;
107                //              see `dojo/dnd/Container.forInItems()` for details
108                o = o || kernel.global;
109                var s = this.selection, e = dnd._empty;
110                for(var i in s){
111                        if(i in e){ continue; }
112                        f.call(o, this.getItem(i), i, this);
113                }
114        },
115        sync: function(){
116                // summary:
117                //              sync up the node list with the data map
118
119                Selector.superclass.sync.call(this);
120
121                // fix the anchor
122                if(this.anchor){
123                        if(!this.getItem(this.anchor.id)){
124                                this.anchor = null;
125                        }
126                }
127
128                // fix the selection
129                var t = [], e = dnd._empty;
130                for(var i in this.selection){
131                        if(i in e){ continue; }
132                        if(!this.getItem(i)){
133                                t.push(i);
134                        }
135                }
136                array.forEach(t, function(i){
137                        delete this.selection[i];
138                }, this);
139
140                return this;    // self
141        },
142        insertNodes: function(addSelected, data, before, anchor){
143                // summary:
144                //              inserts new data items (see `dojo/dnd/Container.insertNodes()` method for details)
145                // addSelected: Boolean
146                //              all new nodes will be added to selected items, if true, no selection change otherwise
147                // data: Array
148                //              a list of data items, which should be processed by the creator function
149                // before: Boolean
150                //              insert before the anchor, if true, and after the anchor otherwise
151                // anchor: Node
152                //              the anchor node to be used as a point of insertion
153                var oldCreator = this._normalizedCreator;
154                this._normalizedCreator = function(item, hint){
155                        var t = oldCreator.call(this, item, hint);
156                        if(addSelected){
157                                if(!this.anchor){
158                                        this.anchor = t.node;
159                                        this._removeItemClass(t.node, "Selected");
160                                        this._addItemClass(this.anchor, "Anchor");
161                                }else if(this.anchor != t.node){
162                                        this._removeItemClass(t.node, "Anchor");
163                                        this._addItemClass(t.node, "Selected");
164                                }
165                                this.selection[t.node.id] = 1;
166                        }else{
167                                this._removeItemClass(t.node, "Selected");
168                                this._removeItemClass(t.node, "Anchor");
169                        }
170                        return t;
171                };
172                Selector.superclass.insertNodes.call(this, data, before, anchor);
173                this._normalizedCreator = oldCreator;
174                return this;    // self
175        },
176        destroy: function(){
177                // summary:
178                //              prepares the object to be garbage-collected
179                Selector.superclass.destroy.call(this);
180                this.selection = this.anchor = null;
181        },
182
183        // mouse events
184        onMouseDown: function(e){
185                // summary:
186                //              event processor for onmousedown
187                // e: Event
188                //              mouse event
189                if(this.autoSync){ this.sync(); }
190                if(!this.current){ return; }
191                if(!this.singular && !dnd.getCopyKeyState(e) && !e.shiftKey && (this.current.id in this.selection)){
192                        this.simpleSelection = true;
193                        if(mouse.isLeft(e)){
194                                // Accept the left button and stop the event.   Stopping the event prevents text selection while
195                                // dragging.   However, don't stop the event on mobile because that prevents a click event,
196                                // and also prevents scroll (see #15838).
197                                // For IE we don't stop event when multiple buttons are pressed.
198                                e.stopPropagation();
199                                e.preventDefault();
200                        }
201                        return;
202                }
203                if(!this.singular && e.shiftKey){
204                        if(!dnd.getCopyKeyState(e)){
205                                this._removeSelection();
206                        }
207                        var c = this.getAllNodes();
208                        if(c.length){
209                                if(!this.anchor){
210                                        this.anchor = c[0];
211                                        this._addItemClass(this.anchor, "Anchor");
212                                }
213                                this.selection[this.anchor.id] = 1;
214                                if(this.anchor != this.current){
215                                        var i = 0, node;
216                                        for(; i < c.length; ++i){
217                                                node = c[i];
218                                                if(node == this.anchor || node == this.current){ break; }
219                                        }
220                                        for(++i; i < c.length; ++i){
221                                                node = c[i];
222                                                if(node == this.anchor || node == this.current){ break; }
223                                                this._addItemClass(node, "Selected");
224                                                this.selection[node.id] = 1;
225                                        }
226                                        this._addItemClass(this.current, "Selected");
227                                        this.selection[this.current.id] = 1;
228                                }
229                        }
230                }else{
231                        if(this.singular){
232                                if(this.anchor == this.current){
233                                        if(dnd.getCopyKeyState(e)){
234                                                this.selectNone();
235                                        }
236                                }else{
237                                        this.selectNone();
238                                        this.anchor = this.current;
239                                        this._addItemClass(this.anchor, "Anchor");
240                                        this.selection[this.current.id] = 1;
241                                }
242                        }else{
243                                if(dnd.getCopyKeyState(e)){
244                                        if(this.anchor == this.current){
245                                                delete this.selection[this.anchor.id];
246                                                this._removeAnchor();
247                                        }else{
248                                                if(this.current.id in this.selection){
249                                                        this._removeItemClass(this.current, "Selected");
250                                                        delete this.selection[this.current.id];
251                                                }else{
252                                                        if(this.anchor){
253                                                                this._removeItemClass(this.anchor, "Anchor");
254                                                                this._addItemClass(this.anchor, "Selected");
255                                                        }
256                                                        this.anchor = this.current;
257                                                        this._addItemClass(this.current, "Anchor");
258                                                        this.selection[this.current.id] = 1;
259                                                }
260                                        }
261                                }else{
262                                        if(!(this.current.id in this.selection)){
263                                                this.selectNone();
264                                                this.anchor = this.current;
265                                                this._addItemClass(this.current, "Anchor");
266                                                this.selection[this.current.id] = 1;
267                                        }
268                                }
269                        }
270                }
271                e.stopPropagation();
272                e.preventDefault();
273        },
274        onMouseUp: function(/*===== e =====*/){
275                // summary:
276                //              event processor for onmouseup
277                // e: Event
278                //              mouse event
279                if(!this.simpleSelection){ return; }
280                this.simpleSelection = false;
281                this.selectNone();
282                if(this.current){
283                        this.anchor = this.current;
284                        this._addItemClass(this.anchor, "Anchor");
285                        this.selection[this.current.id] = 1;
286                }
287        },
288        onMouseMove: function(/*===== e =====*/){
289                // summary:
290                //              event processor for onmousemove
291                // e: Event
292                //              mouse event
293                this.simpleSelection = false;
294        },
295
296        // utilities
297        onOverEvent: function(){
298                // summary:
299                //              this function is called once, when mouse is over our container
300                this.onmousemoveEvent = on(this.node, touch.move, lang.hitch(this, "onMouseMove"));
301        },
302        onOutEvent: function(){
303                // summary:
304                //              this function is called once, when mouse is out of our container
305                if(this.onmousemoveEvent){
306                        this.onmousemoveEvent.remove();
307                        delete this.onmousemoveEvent;
308                }
309        },
310        _removeSelection: function(){
311                // summary:
312                //              unselects all items
313                var e = dnd._empty;
314                for(var i in this.selection){
315                        if(i in e){ continue; }
316                        var node = dom.byId(i);
317                        if(node){ this._removeItemClass(node, "Selected"); }
318                }
319                this.selection = {};
320                return this;    // self
321        },
322        _removeAnchor: function(){
323                if(this.anchor){
324                        this._removeItemClass(this.anchor, "Anchor");
325                        this.anchor = null;
326                }
327                return this;    // self
328        }
329});
330
331return Selector;
332
333});
Note: See TracBrowser for help on using the repository browser.