//>>built define("dojo/dnd/Selector", ["../main", "./common", "./Container"], function(dojo) { // module: // dojo/dnd/Selector // summary: // TODOC /* Container item states: "" - an item is not selected "Selected" - an item is selected "Anchor" - an item is selected, and is an anchor for a "shift" selection */ /*===== dojo.declare("dojo.dnd.__SelectorArgs", [dojo.dnd.__ContainerArgs], { // singular: Boolean // allows selection of only one element, if true singular: false, // autoSync: Boolean // autosynchronizes the source with its list of DnD nodes, autoSync: false }); =====*/ dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, { // summary: // a Selector object, which knows how to select its children /*===== // selection: Set // The set of id's that are currently selected, such that this.selection[id] == 1 // if the node w/that id is selected. Can iterate over selected node's id's like: // | for(var id in this.selection) selection: {}, =====*/ constructor: function(node, params){ // summary: // constructor of the Selector // node: Node||String // node or node's id to build the selector on // params: dojo.dnd.__SelectorArgs? // a dictionary of parameters if(!params){ params = {}; } this.singular = params.singular; this.autoSync = params.autoSync; // class-specific variables this.selection = {}; this.anchor = null; this.simpleSelection = false; // set up events this.events.push( dojo.connect(this.node, "onmousedown", this, "onMouseDown"), dojo.connect(this.node, "onmouseup", this, "onMouseUp")); }, // object attributes (for markup) singular: false, // is singular property // methods getSelectedNodes: function(){ // summary: // returns a list (an array) of selected nodes var t = new dojo.NodeList(); var e = dojo.dnd._empty; for(var i in this.selection){ if(i in e){ continue; } t.push(dojo.byId(i)); } return t; // NodeList }, selectNone: function(){ // summary: // unselects all items return this._removeSelection()._removeAnchor(); // self }, selectAll: function(){ // summary: // selects all items this.forInItems(function(data, id){ this._addItemClass(dojo.byId(id), "Selected"); this.selection[id] = 1; }, this); return this._removeAnchor(); // self }, deleteSelectedNodes: function(){ // summary: // deletes all selected items var e = dojo.dnd._empty; for(var i in this.selection){ if(i in e){ continue; } var n = dojo.byId(i); this.delItem(i); dojo.destroy(n); } this.anchor = null; this.selection = {}; return this; // self }, forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){ // summary: // iterates over selected items; // see `dojo.dnd.Container.forInItems()` for details o = o || dojo.global; var s = this.selection, e = dojo.dnd._empty; for(var i in s){ if(i in e){ continue; } f.call(o, this.getItem(i), i, this); } }, sync: function(){ // summary: // sync up the node list with the data map dojo.dnd.Selector.superclass.sync.call(this); // fix the anchor if(this.anchor){ if(!this.getItem(this.anchor.id)){ this.anchor = null; } } // fix the selection var t = [], e = dojo.dnd._empty; for(var i in this.selection){ if(i in e){ continue; } if(!this.getItem(i)){ t.push(i); } } dojo.forEach(t, function(i){ delete this.selection[i]; }, this); return this; // self }, insertNodes: function(addSelected, data, before, anchor){ // summary: // inserts new data items (see `dojo.dnd.Container.insertNodes()` method for details) // addSelected: Boolean // all new nodes will be added to selected items, if true, no selection change otherwise // data: Array // a list of data items, which should be processed by the creator function // before: Boolean // insert before the anchor, if true, and after the anchor otherwise // anchor: Node // the anchor node to be used as a point of insertion var oldCreator = this._normalizedCreator; this._normalizedCreator = function(item, hint){ var t = oldCreator.call(this, item, hint); if(addSelected){ if(!this.anchor){ this.anchor = t.node; this._removeItemClass(t.node, "Selected"); this._addItemClass(this.anchor, "Anchor"); }else if(this.anchor != t.node){ this._removeItemClass(t.node, "Anchor"); this._addItemClass(t.node, "Selected"); } this.selection[t.node.id] = 1; }else{ this._removeItemClass(t.node, "Selected"); this._removeItemClass(t.node, "Anchor"); } return t; }; dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor); this._normalizedCreator = oldCreator; return this; // self }, destroy: function(){ // summary: // prepares the object to be garbage-collected dojo.dnd.Selector.superclass.destroy.call(this); this.selection = this.anchor = null; }, // mouse events onMouseDown: function(e){ // summary: // event processor for onmousedown // e: Event // mouse event if(this.autoSync){ this.sync(); } if(!this.current){ return; } if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){ this.simpleSelection = true; if(e.button === dojo.mouseButtons.LEFT){ // accept the left button and stop the event // for IE we don't stop event when multiple buttons are pressed dojo.stopEvent(e); } return; } if(!this.singular && e.shiftKey){ if(!dojo.isCopyKey(e)){ this._removeSelection(); } var c = this.getAllNodes(); if(c.length){ if(!this.anchor){ this.anchor = c[0]; this._addItemClass(this.anchor, "Anchor"); } this.selection[this.anchor.id] = 1; if(this.anchor != this.current){ var i = 0; for(; i < c.length; ++i){ var node = c[i]; if(node == this.anchor || node == this.current){ break; } } for(++i; i < c.length; ++i){ var node = c[i]; if(node == this.anchor || node == this.current){ break; } this._addItemClass(node, "Selected"); this.selection[node.id] = 1; } this._addItemClass(this.current, "Selected"); this.selection[this.current.id] = 1; } } }else{ if(this.singular){ if(this.anchor == this.current){ if(dojo.isCopyKey(e)){ this.selectNone(); } }else{ this.selectNone(); this.anchor = this.current; this._addItemClass(this.anchor, "Anchor"); this.selection[this.current.id] = 1; } }else{ if(dojo.isCopyKey(e)){ if(this.anchor == this.current){ delete this.selection[this.anchor.id]; this._removeAnchor(); }else{ if(this.current.id in this.selection){ this._removeItemClass(this.current, "Selected"); delete this.selection[this.current.id]; }else{ if(this.anchor){ this._removeItemClass(this.anchor, "Anchor"); this._addItemClass(this.anchor, "Selected"); } this.anchor = this.current; this._addItemClass(this.current, "Anchor"); this.selection[this.current.id] = 1; } } }else{ if(!(this.current.id in this.selection)){ this.selectNone(); this.anchor = this.current; this._addItemClass(this.current, "Anchor"); this.selection[this.current.id] = 1; } } } } dojo.stopEvent(e); }, onMouseUp: function(e){ // summary: // event processor for onmouseup // e: Event // mouse event if(!this.simpleSelection){ return; } this.simpleSelection = false; this.selectNone(); if(this.current){ this.anchor = this.current; this._addItemClass(this.anchor, "Anchor"); this.selection[this.current.id] = 1; } }, onMouseMove: function(e){ // summary: // event processor for onmousemove // e: Event // mouse event this.simpleSelection = false; }, // utilities onOverEvent: function(){ // summary: // this function is called once, when mouse is over our container this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove"); }, onOutEvent: function(){ // summary: // this function is called once, when mouse is out of our container dojo.disconnect(this.onmousemoveEvent); delete this.onmousemoveEvent; }, _removeSelection: function(){ // summary: // unselects all items var e = dojo.dnd._empty; for(var i in this.selection){ if(i in e){ continue; } var node = dojo.byId(i); if(node){ this._removeItemClass(node, "Selected"); } } this.selection = {}; return this; // self }, _removeAnchor: function(){ if(this.anchor){ this._removeItemClass(this.anchor, "Anchor"); this.anchor = null; } return this; // self } }); return dojo.dnd.Selector; });