2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
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;
10 dojo.provide("dojo.dnd.Selector");
11 dojo.require("dojo.dnd.common");
12 dojo.require("dojo.dnd.Container");
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
23 dojo.declare("dojo.dnd.__SelectorArgs", [dojo.dnd.__ContainerArgs], {
25 // allows selection of only one element, if true
29 // autosynchronizes the source with its list of DnD nodes,
34 dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, {
36 // a Selector object, which knows how to select its children
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)
46 constructor: function(node, params){
48 // constructor of the Selector
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
59 this.simpleSelection = false;
62 dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
63 dojo.connect(this.node, "onmouseup", this, "onMouseUp"));
66 // object attributes (for markup)
67 singular: false, // is singular property
70 getSelectedNodes: function(){
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; }
81 selectNone: function(){
83 // unselects all items
84 return this._removeSelection()._removeAnchor(); // self
86 selectAll: function(){
89 this.forInItems(function(data, id){
90 this._addItemClass(dojo.byId(id), "Selected");
91 this.selection[id] = 1;
93 return this._removeAnchor(); // self
95 deleteSelectedNodes: function(){
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);
109 forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
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;
116 if(i in e){ continue; }
117 f.call(o, this.getItem(i), i, this);
122 // sync up the node list with the data map
124 dojo.dnd.Selector.superclass.sync.call(this);
128 if(!this.getItem(this.anchor.id)){
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)){
141 dojo.forEach(t, function(i){
142 delete this.selection[i];
147 insertNodes: function(addSelected, data, before, anchor){
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
153 // a list of data items, which should be processed by the creator function
155 // insert before the anchor, if true, and after the anchor otherwise
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);
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");
170 this.selection[t.node.id] = 1;
172 this._removeItemClass(t.node, "Selected");
173 this._removeItemClass(t.node, "Anchor");
177 dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
178 this._normalizedCreator = oldCreator;
183 // prepares the object to be garbage-collected
184 dojo.dnd.Selector.superclass.destroy.call(this);
185 this.selection = this.anchor = null;
189 markupFactory: function(params, node){
190 params._skipStartup = true;
191 return new dojo.dnd.Selector(node, params);
195 onMouseDown: function(e){
197 // event processor for onmousedown
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
211 if(!this.singular && e.shiftKey){
212 if(!dojo.isCopyKey(e)){
213 this._removeSelection();
215 var c = this.getAllNodes();
219 this._addItemClass(this.anchor, "Anchor");
221 this.selection[this.anchor.id] = 1;
222 if(this.anchor != this.current){
224 for(; i < c.length; ++i){
226 if(node == this.anchor || node == this.current){ break; }
228 for(++i; i < c.length; ++i){
230 if(node == this.anchor || node == this.current){ break; }
231 this._addItemClass(node, "Selected");
232 this.selection[node.id] = 1;
234 this._addItemClass(this.current, "Selected");
235 this.selection[this.current.id] = 1;
240 if(this.anchor == this.current){
241 if(dojo.isCopyKey(e)){
246 this.anchor = this.current;
247 this._addItemClass(this.anchor, "Anchor");
248 this.selection[this.current.id] = 1;
251 if(dojo.isCopyKey(e)){
252 if(this.anchor == this.current){
253 delete this.selection[this.anchor.id];
254 this._removeAnchor();
256 if(this.current.id in this.selection){
257 this._removeItemClass(this.current, "Selected");
258 delete this.selection[this.current.id];
261 this._removeItemClass(this.anchor, "Anchor");
262 this._addItemClass(this.anchor, "Selected");
264 this.anchor = this.current;
265 this._addItemClass(this.current, "Anchor");
266 this.selection[this.current.id] = 1;
270 if(!(this.current.id in this.selection)){
272 this.anchor = this.current;
273 this._addItemClass(this.current, "Anchor");
274 this.selection[this.current.id] = 1;
281 onMouseUp: function(e){
283 // event processor for onmouseup
286 if(!this.simpleSelection){ return; }
287 this.simpleSelection = false;
290 this.anchor = this.current;
291 this._addItemClass(this.anchor, "Anchor");
292 this.selection[this.current.id] = 1;
295 onMouseMove: function(e){
297 // event processor for onmousemove
300 this.simpleSelection = false;
304 onOverEvent: function(){
306 // this function is called once, when mouse is over our container
307 this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
309 onOutEvent: function(){
311 // this function is called once, when mouse is out of our container
312 dojo.disconnect(this.onmousemoveEvent);
313 delete this.onmousemoveEvent;
315 _removeSelection: function(){
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"); }
327 _removeAnchor: function(){
329 this._removeItemClass(this.anchor, "Anchor");