control-freak-ide/server/nodejs/dist/web/dojo/dnd/Selector.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

372 lines
13 KiB
JavaScript

/** @module dojo/dnd/Selector **/
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
});
=====*/
/**
* @class module:dojo/dnd/Selector
* @extends module:dojo/dnd/Container
*/
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;
}
});
return Selector;
});