UNPKG

dojo

Version:

Dojo core is a powerful, lightweight library that makes common tasks quicker and easier. Animate elements, manipulate the DOM, and query with easy CSS syntax, all without sacrificing performance.

334 lines (316 loc) 9.2 kB
define([ "../_base/array", "../_base/declare", "../_base/kernel", "../_base/lang", "../dom", "../dom-construct", "../mouse", "../_base/NodeList", "../on", "../touch", "./common", "./Container" ], function(array, declare, kernel, lang, dom, domConstruct, mouse, NodeList, on, touch, dnd, Container){ // module: // dojo/dnd/Selector /* 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 */ /*===== var __SelectorArgs = declare([Container.__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 }); =====*/ var Selector = declare("dojo.dnd.Selector", Container, { // summary: // a Selector object, which knows how to select its children /*===== // selection: Set<String> // 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: __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( on(this.node, touch.press, lang.hitch(this, "onMouseDown")), on(this.node, touch.release, lang.hitch(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 NodeList(); var e = dnd._empty; for(var i in this.selection){ if(i in e){ continue; } t.push(dom.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(dom.byId(id), "Selected"); this.selection[id] = 1; }, this); return this._removeAnchor(); // self }, deleteSelectedNodes: function(){ // summary: // deletes all selected items var e = dnd._empty; for(var i in this.selection){ if(i in e){ continue; } var n = dom.byId(i); this.delItem(i); domConstruct.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 || kernel.global; var s = this.selection, e = 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 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 = dnd._empty; for(var i in this.selection){ if(i in e){ continue; } if(!this.getItem(i)){ t.push(i); } } array.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; }; Selector.superclass.insertNodes.call(this, data, before, anchor); this._normalizedCreator = oldCreator; return this; // self }, destroy: function(){ // summary: // prepares the object to be garbage-collected 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 && !dnd.getCopyKeyState(e) && !e.shiftKey && (this.current.id in this.selection)){ this.simpleSelection = true; if(mouse.isLeft(e)){ // Accept the left button and stop the event. Stopping the event prevents text selection while // dragging. However, don't stop the event on mobile because that prevents a click event, // and also prevents scroll (see #15838). // For IE we don't stop event when multiple buttons are pressed. e.stopPropagation(); e.preventDefault(); } return; } if(!this.singular && e.shiftKey){ if(!dnd.getCopyKeyState(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, node; for(; i < c.length; ++i){ node = c[i]; if(node == this.anchor || node == this.current){ break; } } for(++i; i < c.length; ++i){ 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(dnd.getCopyKeyState(e)){ this.selectNone(); } }else{ this.selectNone(); this.anchor = this.current; this._addItemClass(this.anchor, "Anchor"); this.selection[this.current.id] = 1; } }else{ if(dnd.getCopyKeyState(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; } } } } e.stopPropagation(); e.preventDefault(); }, 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 = on(this.node, touch.move, lang.hitch(this, "onMouseMove")); }, onOutEvent: function(){ // summary: // this function is called once, when mouse is out of our container if(this.onmousemoveEvent){ this.onmousemoveEvent.remove(); delete this.onmousemoveEvent; } }, _removeSelection: function(){ // summary: // unselects all items var e = dnd._empty; for(var i in this.selection){ if(i in e){ continue; } var node = dom.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 Selector; });