selecton
Version:
Selecton.js combines a searchbar and a dropdown menu with nested child lists.
1,796 lines (1,456 loc) • 63 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Selecton = factory());
}(this, (function () { 'use strict';
var xhtml = "http://www.w3.org/1999/xhtml";
var namespaces = {
svg: "http://www.w3.org/2000/svg",
xhtml: xhtml,
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
function namespace(name) {
var prefix = name += "", i = prefix.indexOf(":");
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
}
function creatorInherit(name) {
return function() {
var document = this.ownerDocument,
uri = this.namespaceURI;
return uri === xhtml && document.documentElement.namespaceURI === xhtml
? document.createElement(name)
: document.createElementNS(uri, name);
};
}
function creatorFixed(fullname) {
return function() {
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
};
}
function creator(name) {
var fullname = namespace(name);
return (fullname.local
? creatorFixed
: creatorInherit)(fullname);
}
function none() {}
function selector(selector) {
return selector == null ? none : function() {
return this.querySelector(selector);
};
}
function selection_select(select) {
if (typeof select !== "function") select = selector(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
}
}
}
return new Selection(subgroups, this._parents);
}
function empty() {
return [];
}
function selectorAll(selector) {
return selector == null ? empty : function() {
return this.querySelectorAll(selector);
};
}
function selection_selectAll(select) {
if (typeof select !== "function") select = selectorAll(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
subgroups.push(select.call(node, node.__data__, i, group));
parents.push(node);
}
}
}
return new Selection(subgroups, parents);
}
var matcher = function(selector) {
return function() {
return this.matches(selector);
};
};
if (typeof document !== "undefined") {
var element = document.documentElement;
if (!element.matches) {
var vendorMatches = element.webkitMatchesSelector
|| element.msMatchesSelector
|| element.mozMatchesSelector
|| element.oMatchesSelector;
matcher = function(selector) {
return function() {
return vendorMatches.call(this, selector);
};
};
}
}
var matcher$1 = matcher;
function selection_filter(match) {
if (typeof match !== "function") match = matcher$1(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Selection(subgroups, this._parents);
}
function sparse(update) {
return new Array(update.length);
}
function selection_enter() {
return new Selection(this._enter || this._groups.map(sparse), this._parents);
}
function EnterNode(parent, datum) {
this.ownerDocument = parent.ownerDocument;
this.namespaceURI = parent.namespaceURI;
this._next = null;
this._parent = parent;
this.__data__ = datum;
}
EnterNode.prototype = {
constructor: EnterNode,
appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
querySelector: function(selector) { return this._parent.querySelector(selector); },
querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
};
function constant(x) {
return function() {
return x;
};
}
var keyPrefix = "$"; // Protect against keys like “__proto__”.
function bindIndex(parent, group, enter, update, exit, data) {
var i = 0,
node,
groupLength = group.length,
dataLength = data.length;
// Put any non-null nodes that fit into update.
// Put any null nodes into enter.
// Put any remaining data into enter.
for (; i < dataLength; ++i) {
if (node = group[i]) {
node.__data__ = data[i];
update[i] = node;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Put any non-null nodes that don’t fit into exit.
for (; i < groupLength; ++i) {
if (node = group[i]) {
exit[i] = node;
}
}
}
function bindKey(parent, group, enter, update, exit, data, key) {
var i,
node,
nodeByKeyValue = {},
groupLength = group.length,
dataLength = data.length,
keyValues = new Array(groupLength),
keyValue;
// Compute the key for each node.
// If multiple nodes have the same key, the duplicates are added to exit.
for (i = 0; i < groupLength; ++i) {
if (node = group[i]) {
keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
if (keyValue in nodeByKeyValue) {
exit[i] = node;
} else {
nodeByKeyValue[keyValue] = node;
}
}
}
// Compute the key for each datum.
// If there a node associated with this key, join and add it to update.
// If there is not (or the key is a duplicate), add it to enter.
for (i = 0; i < dataLength; ++i) {
keyValue = keyPrefix + key.call(parent, data[i], i, data);
if (node = nodeByKeyValue[keyValue]) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue[keyValue] = null;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Add any remaining nodes that were not bound to data to exit.
for (i = 0; i < groupLength; ++i) {
if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
exit[i] = node;
}
}
}
function selection_data(value, key) {
if (!value) {
data = new Array(this.size()), j = -1;
this.each(function(d) { data[++j] = d; });
return data;
}
var bind = key ? bindKey : bindIndex,
parents = this._parents,
groups = this._groups;
if (typeof value !== "function") value = constant(value);
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
var parent = parents[j],
group = groups[j],
groupLength = group.length,
data = value.call(parent, parent && parent.__data__, j, parents),
dataLength = data.length,
enterGroup = enter[j] = new Array(dataLength),
updateGroup = update[j] = new Array(dataLength),
exitGroup = exit[j] = new Array(groupLength);
bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
// Now connect the enter nodes to their following update node, such that
// appendChild can insert the materialized enter node before this node,
// rather than at the end of the parent node.
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
if (previous = enterGroup[i0]) {
if (i0 >= i1) i1 = i0 + 1;
while (!(next = updateGroup[i1]) && ++i1 < dataLength);
previous._next = next || null;
}
}
}
update = new Selection(update, parents);
update._enter = enter;
update._exit = exit;
return update;
}
function selection_exit() {
return new Selection(this._exit || this._groups.map(sparse), this._parents);
}
function selection_merge(selection$$1) {
for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Selection(merges, this._parents);
}
function selection_order() {
for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
if (node = group[i]) {
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
next = node;
}
}
}
return this;
}
function selection_sort(compare) {
if (!compare) compare = ascending;
function compareNode(a, b) {
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
}
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group[i]) {
sortgroup[i] = node;
}
}
sortgroup.sort(compareNode);
}
return new Selection(sortgroups, this._parents).order();
}
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function selection_call() {
var callback = arguments[0];
arguments[0] = this;
callback.apply(null, arguments);
return this;
}
function selection_nodes() {
var nodes = new Array(this.size()), i = -1;
this.each(function() { nodes[++i] = this; });
return nodes;
}
function selection_node() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
var node = group[i];
if (node) return node;
}
}
return null;
}
function selection_size() {
var size = 0;
this.each(function() { ++size; });
return size;
}
function selection_empty() {
return !this.node();
}
function selection_each(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) callback.call(node, node.__data__, i, group);
}
}
return this;
}
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant(name, value) {
return function() {
this.setAttribute(name, value);
};
}
function attrConstantNS(fullname, value) {
return function() {
this.setAttributeNS(fullname.space, fullname.local, value);
};
}
function attrFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
function attrFunctionNS(fullname, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
else this.setAttributeNS(fullname.space, fullname.local, v);
};
}
function selection_attr(name, value) {
var fullname = namespace(name);
if (arguments.length < 2) {
var node = this.node();
return fullname.local
? node.getAttributeNS(fullname.space, fullname.local)
: node.getAttribute(fullname);
}
return this.each((value == null
? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
? (fullname.local ? attrFunctionNS : attrFunction)
: (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
}
function defaultView(node) {
return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
|| (node.document && node) // node is a Window
|| node.defaultView; // node is a Document
}
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
function styleFunction(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
function selection_style(name, value, priority) {
return arguments.length > 1
? this.each((value == null
? styleRemove : typeof value === "function"
? styleFunction
: styleConstant)(name, value, priority == null ? "" : priority))
: styleValue(this.node(), name);
}
function styleValue(node, name) {
return node.style.getPropertyValue(name)
|| defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
}
function propertyRemove(name) {
return function() {
delete this[name];
};
}
function propertyConstant(name, value) {
return function() {
this[name] = value;
};
}
function propertyFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) delete this[name];
else this[name] = v;
};
}
function selection_property(name, value) {
return arguments.length > 1
? this.each((value == null
? propertyRemove : typeof value === "function"
? propertyFunction
: propertyConstant)(name, value))
: this.node()[name];
}
function classArray(string) {
return string.trim().split(/^|\s+/);
}
function classList(node) {
return node.classList || new ClassList(node);
}
function ClassList(node) {
this._node = node;
this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
add: function(name) {
var i = this._names.indexOf(name);
if (i < 0) {
this._names.push(name);
this._node.setAttribute("class", this._names.join(" "));
}
},
remove: function(name) {
var i = this._names.indexOf(name);
if (i >= 0) {
this._names.splice(i, 1);
this._node.setAttribute("class", this._names.join(" "));
}
},
contains: function(name) {
return this._names.indexOf(name) >= 0;
}
};
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
return function() {
classedAdd(this, names);
};
}
function classedFalse(names) {
return function() {
classedRemove(this, names);
};
}
function classedFunction(names, value) {
return function() {
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
};
}
function selection_classed(name, value) {
var names = classArray(name + "");
if (arguments.length < 2) {
var list = classList(this.node()), i = -1, n = names.length;
while (++i < n) if (!list.contains(names[i])) return false;
return true;
}
return this.each((typeof value === "function"
? classedFunction : value
? classedTrue
: classedFalse)(names, value));
}
function textRemove() {
this.textContent = "";
}
function textConstant(value) {
return function() {
this.textContent = value;
};
}
function textFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
};
}
function selection_text(value) {
return arguments.length
? this.each(value == null
? textRemove : (typeof value === "function"
? textFunction
: textConstant)(value))
: this.node().textContent;
}
function htmlRemove() {
this.innerHTML = "";
}
function htmlConstant(value) {
return function() {
this.innerHTML = value;
};
}
function htmlFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
};
}
function selection_html(value) {
return arguments.length
? this.each(value == null
? htmlRemove : (typeof value === "function"
? htmlFunction
: htmlConstant)(value))
: this.node().innerHTML;
}
function raise() {
if (this.nextSibling) this.parentNode.appendChild(this);
}
function selection_raise() {
return this.each(raise);
}
function lower() {
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function selection_lower() {
return this.each(lower);
}
function selection_append(name) {
var create = typeof name === "function" ? name : creator(name);
return this.select(function() {
return this.appendChild(create.apply(this, arguments));
});
}
function constantNull() {
return null;
}
function selection_insert(name, before) {
var create = typeof name === "function" ? name : creator(name),
select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
return this.select(function() {
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
});
}
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
function selection_remove() {
return this.each(remove);
}
function selection_cloneShallow() {
return this.parentNode.insertBefore(this.cloneNode(false), this.nextSibling);
}
function selection_cloneDeep() {
return this.parentNode.insertBefore(this.cloneNode(true), this.nextSibling);
}
function selection_clone(deep) {
return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
}
function selection_datum(value) {
return arguments.length
? this.property("__data__", value)
: this.node().__data__;
}
var filterEvents = {};
var event = null;
if (typeof document !== "undefined") {
var element$1 = document.documentElement;
if (!("onmouseenter" in element$1)) {
filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
}
}
function filterContextListener(listener, index, group) {
listener = contextListener(listener, index, group);
return function(event) {
var related = event.relatedTarget;
if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
listener.call(this, event);
}
};
}
function contextListener(listener, index, group) {
return function(event1) {
var event0 = event; // Events can be reentrant (e.g., focus).
event = event1;
try {
listener.call(this, this.__data__, index, group);
} finally {
event = event0;
}
};
}
function parseTypenames(typenames) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
return {type: t, name: name};
});
}
function onRemove(typename) {
return function() {
var on = this.__on;
if (!on) return;
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
} else {
on[++i] = o;
}
}
if (++i) on.length = i;
else delete this.__on;
};
}
function onAdd(typename, value, capture) {
var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
return function(d, i, group) {
var on = this.__on, o, listener = wrap(value, i, group);
if (on) for (var j = 0, m = on.length; j < m; ++j) {
if ((o = on[j]).type === typename.type && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
this.addEventListener(o.type, o.listener = listener, o.capture = capture);
o.value = value;
return;
}
}
this.addEventListener(typename.type, listener, capture);
o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
if (!on) this.__on = [o];
else on.push(o);
};
}
function selection_on(typename, value, capture) {
var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
if (arguments.length < 2) {
var on = this.node().__on;
if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
for (i = 0, o = on[j]; i < n; ++i) {
if ((t = typenames[i]).type === o.type && t.name === o.name) {
return o.value;
}
}
}
return;
}
on = value ? onAdd : onRemove;
if (capture == null) capture = false;
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
return this;
}
function customEvent(event1, listener, that, args) {
var event0 = event;
event1.sourceEvent = event;
event = event1;
try {
return listener.apply(that, args);
} finally {
event = event0;
}
}
function dispatchEvent(node, type, params) {
var window = defaultView(node),
event = window.CustomEvent;
if (typeof event === "function") {
event = new event(type, params);
} else {
event = window.document.createEvent("Event");
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
else event.initEvent(type, false, false);
}
node.dispatchEvent(event);
}
function dispatchConstant(type, params) {
return function() {
return dispatchEvent(this, type, params);
};
}
function dispatchFunction(type, params) {
return function() {
return dispatchEvent(this, type, params.apply(this, arguments));
};
}
function selection_dispatch(type, params) {
return this.each((typeof params === "function"
? dispatchFunction
: dispatchConstant)(type, params));
}
var root = [null];
function Selection(groups, parents) {
this._groups = groups;
this._parents = parents;
}
function selection() {
return new Selection([[document.documentElement]], root);
}
Selection.prototype = selection.prototype = {
constructor: Selection,
select: selection_select,
selectAll: selection_selectAll,
filter: selection_filter,
data: selection_data,
enter: selection_enter,
exit: selection_exit,
merge: selection_merge,
order: selection_order,
sort: selection_sort,
call: selection_call,
nodes: selection_nodes,
node: selection_node,
size: selection_size,
empty: selection_empty,
each: selection_each,
attr: selection_attr,
style: selection_style,
property: selection_property,
classed: selection_classed,
text: selection_text,
html: selection_html,
raise: selection_raise,
lower: selection_lower,
append: selection_append,
insert: selection_insert,
remove: selection_remove,
clone: selection_clone,
datum: selection_datum,
on: selection_on,
dispatch: selection_dispatch
};
function d3select(selector) {
return typeof selector === "string"
? new Selection([[document.querySelector(selector)]], [document.documentElement])
: new Selection([[selector]], root);
}
function sourceEvent() {
var current = event, source;
while (source = current.sourceEvent) current = source;
return current;
}
function point(node, event) {
var svg = node.ownerSVGElement || node;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
point.x = event.clientX, point.y = event.clientY;
point = point.matrixTransform(node.getScreenCTM().inverse());
return [point.x, point.y];
}
var rect = node.getBoundingClientRect();
return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
}
function mouse(node) {
var event = sourceEvent();
if (event.changedTouches) event = event.changedTouches[0];
return point(node, event);
}
function touch(node, touches, identifier) {
if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
if ((touch = touches[i]).identifier === identifier) {
return point(node, touch);
}
}
return null;
}
var noop = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames$1(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames$1(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
function nopropagation() {
event.stopImmediatePropagation();
}
function noevent() {
event.preventDefault();
event.stopImmediatePropagation();
}
function nodrag(view) {
var root = view.document.documentElement,
selection$$1 = d3select(view).on("dragstart.drag", noevent, true);
if ("onselectstart" in root) {
selection$$1.on("selectstart.drag", noevent, true);
} else {
root.__noselect = root.style.MozUserSelect;
root.style.MozUserSelect = "none";
}
}
function yesdrag(view, noclick) {
var root = view.document.documentElement,
selection$$1 = d3select(view).on("dragstart.drag", null);
if (noclick) {
selection$$1.on("click.drag", noevent, true);
setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
}
if ("onselectstart" in root) {
selection$$1.on("selectstart.drag", null);
} else {
root.style.MozUserSelect = root.__noselect;
delete root.__noselect;
}
}
function constant$1(x) {
return function() {
return x;
};
}
function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
this.target = target;
this.type = type;
this.subject = subject;
this.identifier = id;
this.active = active;
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this._ = dispatch;
}
DragEvent.prototype.on = function() {
var value = this._.on.apply(this._, arguments);
return value === this._ ? this : value;
};
// Ignore right-click, since that should open the context menu.
function defaultFilter() {
return !event.button;
}
function defaultContainer() {
return this.parentNode;
}
function defaultSubject(d) {
return d == null ? {x: event.x, y: event.y} : d;
}
function defaultTouchable() {
return "ontouchstart" in this;
}
function d3drag() {
var filter = defaultFilter,
container = defaultContainer,
subject = defaultSubject,
touchable = defaultTouchable,
gestures = {},
listeners = dispatch("start", "drag", "end"),
active = 0,
mousedownx,
mousedowny,
mousemoving,
touchending,
clickDistance2 = 0;
function drag(selection$$1) {
selection$$1
.on("mousedown.drag", mousedowned)
.filter(touchable)
.on("touchstart.drag", touchstarted)
.on("touchmove.drag", touchmoved)
.on("touchend.drag touchcancel.drag", touchended)
.style("touch-action", "none")
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
}
function mousedowned() {
if (touchending || !filter.apply(this, arguments)) return;
var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
if (!gesture) return;
d3select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
nodrag(event.view);
nopropagation();
mousemoving = false;
mousedownx = event.clientX;
mousedowny = event.clientY;
gesture("start");
}
function mousemoved() {
noevent();
if (!mousemoving) {
var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
mousemoving = dx * dx + dy * dy > clickDistance2;
}
gestures.mouse("drag");
}
function mouseupped() {
d3select(event.view).on("mousemove.drag mouseup.drag", null);
yesdrag(event.view, mousemoving);
noevent();
gestures.mouse("end");
}
function touchstarted() {
if (!filter.apply(this, arguments)) return;
var touches$$1 = event.changedTouches,
c = container.apply(this, arguments),
n = touches$$1.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
nopropagation();
gesture("start");
}
}
}
function touchmoved() {
var touches$$1 = event.changedTouches,
n = touches$$1.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches$$1[i].identifier]) {
noevent();
gesture("drag");
}
}
}
function touchended() {
var touches$$1 = event.changedTouches,
n = touches$$1.length, i, gesture;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches$$1[i].identifier]) {
nopropagation();
gesture("end");
}
}
}
function beforestart(id, container, point$$1, that, args) {
var p = point$$1(container, id), s, dx, dy,
sublisteners = listeners.copy();
if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
if ((event.subject = s = subject.apply(that, args)) == null) return false;
dx = s.x - p[0] || 0;
dy = s.y - p[1] || 0;
return true;
})) return;
return function gesture(type) {
var p0 = p, n;
switch (type) {
case "start": gestures[id] = gesture, n = active++; break;
case "end": delete gestures[id], --active; // nobreak
case "drag": p = point$$1(container, id), n = active; break;
}
customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
};
}
drag.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$1(!!_), drag) : filter;
};
drag.container = function(_) {
return arguments.length ? (container = typeof _ === "function" ? _ : constant$1(_), drag) : container;
};
drag.subject = function(_) {
return arguments.length ? (subject = typeof _ === "function" ? _ : constant$1(_), drag) : subject;
};
drag.touchable = function(_) {
return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$1(!!_), drag) : touchable;
};
drag.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? drag : value;
};
drag.clickDistance = function(_) {
return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
};
return drag;
}
var preSelectedItems = null;
function getItemsByValue(arr, condition){
preSelectedItems = [];
filterItems(arr, { key: 'root' }, condition);
return preSelectedItems;
}
function filterItems(arr, parent, condition){
if (typeof(arr) === 'object') {
for (var i = 0; i < arr.length; i++) {
arr[i]._parent_ = parent.key;
(arr[i][condition[0]] === condition[1]) ? preSelectedItems.push(arr[i]) : null;
if(arr[i].children){
filterItems(arr[i].children, arr[i], condition);
}
}
}
}
function _getInputGroup(w){
return w.select('.selecton-input-group');
}
function _getInputSearch(w){
return _getInputGroup(w).select('.selecton-search');
}
function _getInputSearchField(w){
return _getInputSearch(w).select('.selecton-search-input');
}
function _getInputItems(w){
return _getInputSearch(w).selectAll('.input-item');
}
function _getDropdown(w){
return w.select('.selecton-dropdown');
}
function _getDropdownListWrapper(w){
return _getDropdown(w).selectAll('ul.list-wrapper');
}
function _getDropdownListitems(w){
return _getDropdownListWrapper(w).selectAll('li.dropdown-list-item');
}
function _dragstart (w){
var inputSearch = _getInputSearchField(w);
var inputItem = d3select(this.parentNode).classed('drag-active', true).node();
var clone = inputItem.cloneNode(true);
var eventX = event.sourceEvent.pageX;
var eventY = event.sourceEvent.pageY;
var rect = this.getBoundingClientRect();
var xDragOffset = eventX - rect.left;
var yDragOffset = eventY - rect.top - (window.scrollY || window.pageYOffset);
d3select(clone)
.attr('class', 'input-item-clone')
.style('transform-origin', xDragOffset + 'px ' + yDragOffset + 'px')
.style('left', eventX - xDragOffset + 'px')
.style('top', eventY - yDragOffset + 'px');
document.body.appendChild(clone);
inputSearch.remove();
return {
x : xDragOffset,
y : yDragOffset
};
}
function _drag (w, xDragOffset, yDragOffset){
var search = _getInputSearch(w);
var searchNode = search.node();
var draggedItem = this.parentNode;
var eventY = event.sourceEvent.pageY;
var eventX = event.sourceEvent.pageX;
var clone = d3select('div.input-item-clone').node();
var cloneTop = clone.getBoundingClientRect().top;
var cloneWidth = clone.clientWidth;
var inputItems = _getInputItems(w);
var itemsBefore = inputItems
.filter(function(){
var h = this.clientHeight;
var t = this.getBoundingClientRect().top;
return cloneTop > t - h / 2 && cloneTop < t + h / 2 && eventX < this.getBoundingClientRect().right - cloneWidth / 2;
}).nodes()[0];
var itemsAfter = inputItems
.filter(function(){
var h = this.clientHeight;
var t = this.getBoundingClientRect().top;
return cloneTop > t - h / 2 && cloneTop < t + h / 2 && eventX > this.getBoundingClientRect().left + cloneWidth / 2;
}).nodes()[0];
if(itemsBefore){
searchNode.insertBefore(draggedItem, itemsBefore);
}else if(itemsAfter && itemsBefore === undefined){
searchNode.append(draggedItem);
}
d3select('div.input-item-clone')
.style('left', eventX - xDragOffset + 'px')
.style('top', eventY - yDragOffset + 'px');
}
function _dragend (w, _handleKeyUpInteraction, _preventTabDefault){
d3select('div.input-item-clone').remove();
d3select(this.parentNode).classed('drag-active', false);
_getInputSearch(w)
.append('input')
.attr('class', 'selecton-search-input')
.on('keyup', _handleKeyUpInteraction)
.on('keydown', _preventTabDefault);
return {
x : 0,
y : 0
};
}
function _openAllParents(w, p, key){
openAllParents(w, p, key);
}
function openAllParents(w, p, key){
if(p !== 'root'){
var f = _getDropdownListitems(w).filter(function(d){ return key(d) === p; }).data()[0];
f.closed = false;
f.children.forEach(function(d){ d.closed = false; });
openAllParents(w, f._parent_, key);
}
}
function _hierarchyjump(w, key){
var item = d3select(this.parentNode);
var itemData = item.data()[0];
event.stopPropagation();
_openAllParents(w, itemData._parent_, key);
itemData._temporarilyHighlighted_ = true;
return itemData;
}
function _addItemToInput(w, d, options){
var item = w
.select('div.selecton-search')
.insert('div', 'input.selecton-search-input')
.style('background-color', 'color' in d ? d.color : null)
.attr('class', 'input-item');
item
.append('span')
.attr('class', 'input-item-content')
.html(options.render(d));
if(options.showHierarchyButton){
item
.append('span')
.attr('class', 'input-item-expand-hierachy-button')
.html(' ');
}
if(options.showRemoveButton){
item
.append('span')
.attr('class', 'input-item-remove-button')
.html(' ');
}
item.datum(d);
}
function _removeItemFromInput (w, d, options){
_getInputItems(w).nodes().forEach(function(item){
if(options.render(d) === d3select(item).select('span.input-item-content').html()){
d.selected = false;
d3select(item).remove();
return;
}
});
}
function _makeItemContent(d, searchTerm, renderFn){
//////////////////////////////////////////
// CREATE SPAN FOR LIST ITEM
//////////////////////////////////////////
var html = '';
var itemContent = d3select(document.createElement('span'));
itemContent
.attr('class', 'dropdown-list-item-content')
.html(d._search_ ? d._search_ : renderFn(d));
html += itemContent.node().outerHTML;
//////////////////////////////////////////
// IF ITEM HAS CHILDREN ADD TOGGLE BTN
//////////////////////////////////////////
if(d.children && d.children.length > 0 && !searchTerm){
var closed = d.children.every(function(el){ return el.closed === true || el.closed === undefined; });
var itemExpand = d3select(document.createElement('span'));
itemExpand
.attr('class', 'dropdown-list-item-expand-toggle')
.classed('dropdown-list-item-expand-toggle-closed', closed)
.classed('dropdown-list-item-expand-toggle-open', !closed)
.html(' ');
html += itemExpand.node().outerHTML;
}
return html;
}
function _setHidden(d, searchTerm, renderFn){
if(searchTerm && d.selectable){
var str = renderFn(d);
var re = new RegExp(searchTerm, 'gi');
var matches = str.match(re);
if(matches){
d._search_ = str.replace(re, replaceSearchString);
}else{
delete d._search_;
}
return (str.toLowerCase().indexOf(searchTerm) === -1) || d.selected;
}
if(!searchTerm){
delete d._search_;
return d.closed;
}
return false;
}
function replaceSearchString(string){
return '<span class="dropdown-list-item-highlighted">' + string + '</span>';
}
function _sortArraybyArr(keyArr, arr){
var sorted = [];
keyArr.forEach(function(key) {
var found = false;
arr = arr.filter(function(item) {
if(!found && item.key === key) {
delete item._temporarilyHighlighted_;
sorted.push(item);
found = true;
return false;
}
return true;
});
});
return sorted;
}
function _setPropertyForAllElements(arr, prop, value){
return setProp(arr, prop, value);
}
function setProp(arr, prop, value){
if (typeof(arr) === 'object') {
for (var i = 0; i < arr.length; i++) {
arr[i][prop] = value;
if(arr[i].children){
setProp(arr[i].children);
}
}
}
}
// import {_openDropdown} from './src/js/dropdownHandler';
// import {_toggleDropdown} from './src/js/dropdownHandler';
function index(dflts){
var depth = 0;
var dropdown = null;
var el = d3select(dflts.el);
var events = {};
var inputGroup = null;
var itemsInResultSize = 0;
var key = null;
var mode = null;
var keyCount = 0;
var open = null;
var preIconHtml = ' ';
var renderInputItem = null;
var renderDropdownItem = null;
var searchTerm = '';
var showHierarchyButton = null;
var showRemoveButton = null;
var sufIconHtml = '<div><span></span><span></span><span></span><span></span></div>';
var wrapper = null;
var xDragOffset = null;
var yDragOffset = null;
//////////////////////////////////////////
// STORE KEY CODES
//////////////////////////////////////////
var down = 40;
var enter = 13;
var esc = 27;
var tab = 9;
var up = 38;
//////////////////////////////////////////
// DEFINE DEFAULT SETTINGS
//////////////////////////////////////////
var defaults = {
key : function(d){ return d.key; },
open : false,
mode : 'select',
renderInputItem : function(d){ return d.key; },
renderDropdownItem : function(d){ return d.key; },
showHierarchyButton : true,
showRemoveButton : true,
};
//////////////////////////////////////////
// SET SETTINGS
//////////////////////////////////////////
key = ('key' in dflts) ? dflts.key : defaults.key;
mode = ('mode' in dflts) ? dflts.mode : defaults.mode;
open = ('open' in dflts) ? dflts.open : defaults.open;
renderDropdownItem = ('renderDropdownItem' in dflts) ? dflts.renderDropdownItem : defaults.renderDropdownItem;
renderInputItem = ('renderInputItem' in dflts) ? dflts.renderInputItem : defaults.renderInputItem;
showHierarchyButton = ('showHierarchyButton' in dflts) ? dflts.showHierarchyButton : defaults.showHierarchyButton;
showRemoveButton = ('showRemoveButton' in dflts) ? dflts.showRemoveButton : defaults.showHierarchyButton;
//////////////////////////////////////////
// PRIVATE FUNCTIONS
//////////////////////////////////////////
function _init(){
//////////////////////////////////////////
// CLEAR ELEMENT
//////////////////////////////////////////
el.html(null);
//////////////////////////////////////////
// WRAP ELEMENT
//////////////////////////////////////////
wrapper = el
.append('div')
.attr('class', 'selecton selecton-' + mode)
.classed('selecton-is-open', open);
//////////////////////////////////////////
// ADD INPUT GROUP
//////////////////////////////////////////
inputGroup = wrapper
.append('div')
.attr('class', 'selecton-input-group' );
inputGroup
.append('div')
.attr('class', 'selecton-input-group-pre')
.html(preIconHtml)
.on('click', focusSearch);
inputGroup
.append('div')
.attr('class', 'selecton-search')
.on('click', focusSearch)
.append('input')
.attr('class', 'selecton-search-input')
.on('keyup', _handleKeyUpInteraction)
.on('keydown', _preventTabDefault);
inputGroup
.append('div')
.attr('class', 'selecton-ghost')
.attr('contenteditable', 'true')
.style('position', 'absolute')
.style('top', '0')
.style('left', '0')
.style('visibility', 'hidden')
.style('width', 'auto');
if(mode === 'select'){
inputGroup
.append('div')
.html(sufIconHtml)
.attr('class', 'selecton-input-group-suf')
.on('click', _toggleDropdown);
}
//////////////////////////////////////////
// ADD DROPDOWN
//////////////////////////////////////////
dropdown = wrapper
.append('div')
.attr('class', 'selecton-dropdown')
.classed('open', open)
.classed('closed', !open);
}
function _update(data){
if(mode === 'select'){
var list = dropdown.selectAll('ul.list-wrapper').data(data, key);
var enterList = list
.enter()
.append('ul')
.attr('class', 'list-wrapper')
.classed('root-list', true)
.merge(list);
list
.exit()
.remove();
_generateList(enterList);
}
//////////////////////////////////////////
// HANDLE CLICK ON DROPDOWN LIST ITEM
//////////////////////////////////////////
dropdown.selectAll('.dropdown-list-item.dropdown-list-item-selectable span.dropdown-list-item-content').on('click', function(){
event.stopPropagation();
var item = this.parentNode.__data__;
_handleMultiselect(item);
item.selected = !item.selected;
_select(this.parentNode);
_updateList();
_emit('change', getSelectedItems());
});
//////////////////////////////////////////
// HANDLE CLICK ON EXPAND TOGGLE
//////////////////////////////////////////
dropdown.selectAll('span.dropdown-list-item-expand-toggle').on('click', function(){
event.stopPropagation();
_toggleChildren(this.parentNode.__data__.children);
_updateList();
});
///////////////////////////////////////////////////////////////
// HANDLE CLICK IN HIERACHY BUTTON
///////////////////////////////////////////////////////////////
inputGroup.select('div.selecton-search').selectAll('span.input-item-expand-hierachy-button').on('click', function(){
_closeAllItems();
var itemData = _hierarchyjump.call(this, wrapper, key);
var dropdown = _getDropdown(wrapper);
var dropdownNode = null;
var dropdownHeight = null;
_setSearchInputValue('');
focusSearch();
_updateList();
dropdownHeight = parseInt(dropdown.style('height'));
dropdownNode = _getDropdownListitems(wrapper).filter(function(d){ return key(d) === key(itemData); });
dropdown.node().scrollTop = dropdownNode.node().offsetTop - dropdownHeight / 2;
setTimeout(function() {
itemData._temporarilyHighlighted_ = false;
_updateList();
}, 750);
});
//////////////////////////////////////////
// HANDLE CLICK ON REMOVE BTN IN INPUT
//////////////////////////////////////////
inputGroup.select('div.selecton-search').selectAll('span.input-item-remove-button').on('click', function(){
event.stopPropagation();
_removeItemFromInput(wrapper, d3select(this.parentNode).data()[0], {
render: renderInputItem
});
_setSearchInputValue('');
_updateList();
_emit('change', getSelectedItems());
});
//////////////////////////////////////////
// HANDLE DRAG
//////////////////////////////////////////
wrapper.select('div.selecton-search').selectAll('div.input-item span.input-item-content')
.call(d3drag()
.on('start', _dragstarted)
.on('drag', _dragging)
.on('end', _dragended));
}
function _dragstarted(){
_setSearchInputValue('');
var dragOffset = _dragstart.call(this, wrapper);