can-key-tree

can-key-tree
can be used to store items in a tree-like structure where the nodes of
the tree can be any type that works with can-reflect.
Use
Import the KeyTree
constructor from can-key-tree
:
import KeyTree from 'can-key-tree';
Create an instance of KeyTree
with an array of types. An instance of each type
will be used as the nodes of the tree. The following creates a tree structure
3 levels deep:
var keyTree = new KeyTree([Object,Object,Array],{onFirst, onEmpty})
Once you've created a keyTree
, you can .add
, .delete
and .get
values from
it.
.add(keys)
The following adds three handlers
:
function handler1(){}
function handler2(){}
function handler3(){}
keyTree.add(["click","li", handler1]);
keyTree.add(["click","li", handler2]);
keyTree.add(["click","span", handler3]);
The keyTree
data structure will look like:
{
"click": {
"li": [handler1, handler2],
"span": [handler3]
}
}
.get(keys)
To get all the li
click
handlers, use .get
:
keyTree.get(["click","li"])
To get all click
handlers, you can also use .get
:
keyTree.get(["click"])
.delete(keys)
To delete a handler, use .delete
:
keyTree.delete(["click","li", handler1]);
The keyTree
data structure will look like:
{
"click": {
"li": [handler1],
"span": [handler3]
}
}
To delete the remaining click
handlers:
keyTree.delete(["click"]);
The keyTree
data structure will look like:
{}
Advanced Use
Often, when a node is created, there needs to be some initial setup, and when a
node is empty, some teardown.
This can be achieved by creating custom types. For example, perhaps we want to
build an event delegation system where we can delegate from an element like:
eventTree.add([document.body, "click", "li", handler]);
And remove that handler like:
eventTree.delete([document.body, "click", "li", handler])
We can do that as follows:
var Delegator = function(parentKey){
this.element = parentKey;
this.events = {};
this.delegated = {};
};
canReflect.assignSymbols( Delegator.prototype, {
"can.setKeyValue": function(eventName, handlersBySelector){
this.delegated[eventName] = function(ev){
canReflect.each(handlersBySelector, function(handlers, selector){
var cur = ev.target;
do {
if (cur.matches(selector)) {
handlers.forEach(function(handler){
handler.call(cur, ev);
});
}
cur = cur.parentNode;
} while (cur && cur !== ev.currentTarget);
});
};
this.events[eventName] = handlersBySelector;
this.element.addEventListener(eventName,this.delegated[eventName]);
},
"can.getKeyValue": function(eventName) {
return this.events[eventName];
},
"can.deleteKeyValue": function(eventName) {
this.element.removeEventListener(eventName,this.delegated[eventName]);
delete this.delegated[eventName];
delete this.events[eventName];
},
"can.getOwnEnumerableKeys": function(){
return Object.keys(this.events);
}
});
var eventTree = new KeyTree([Map, Delegator, Object, Array]);
function handler() {
console.log("an li clicked");
}
eventTree.add([document.body, "click", "li", handler]);
eventTree.delete([document.body, "click", "li", handler]);
eventTree.delete([document.body, "click"]);
eventTree.delete([document.body]);