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