jstree-actions
Version:
jstree plugin that allows adding actions on each node
195 lines (163 loc) • 6.24 kB
JavaScript
(function (factory) {
"use strict";
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
}
else if(typeof module !== 'undefined' && module.exports) {
module.exports = factory(require('jquery'));
}
else {
factory(jQuery);
}
}(function ($, undefined) {
"use strict";
$.jstree.defaults.actions = $.noop;
$.jstree.plugins.actions = function (options, parent) {
this._actions = {};
/**
* @param node_id Can be a single node id or an array of node ids.
* @param action An object representing the action that should be added to <node>.
*
* The <node id> is the "id" key of each element of the "core.data" array.
* A special value "all" is allowed, in which case the action will be added to all nodes.
*
* The actions object can contain the following keys:
* id <- string An ID which identifies the action. The same ID can be shared across different nodes
* text <- string The action's text
* class <- string (a string containing all the classes you want to add to the action (space separated)
* title <- string The actions title for display of tooltip (optional)
* selector <- a selector that would specify where to insert the action. Note that this is a plain JavaScript selector and not a jQuery one.
* after <- bool (insert the action after (true) or before (false) the element matching the <selector> key
* event <- string The event on which the trigger will be called
* callback <- function that will be called when the action is clicked
*
* NOTES: Please keep in mind that:
* - the id's are strictly compared (===)
* - the selector has access to all children on nodes with leafs/children, so most probably you'd want to use :first or similar
*/
this.add_action = function (node_id, action) {
var self = this;
var node_ids = typeof node_id === 'object' ? node_id : [node_id];
var should_redraw_all = node_ids.indexOf("all") > -1;
for (var i = 0; i < node_ids.length; i++) {
var _node_id = node_ids[i];
var actions = self._actions[_node_id] = self._actions[_node_id] || [];
if (!self._has_action(_node_id, action.id)) {
actions.push(action);
if (!should_redraw_all) this.redraw_node(_node_id);
}
}
if (should_redraw_all) this.redraw(true);
};
/**
* @param node_id Can be a single node id or an array of node ids
* @param action_id The ID of the action to be removed
*
* The <node id> is the "id" key of each element of the "core.data" array.
* A special value "all" is allowed, in which case the action_id will be removed from all nodes.
*
* The action_id is the unique identifier for each action.
* A special value "all" is allowed, in which case all the actions of node_id will be removed.
*/
this.remove_action = function (node_id, action_id) {
var self = this;
var node_ids = typeof node_id === 'object' ? node_id :
node_id === "all" ? Object.keys(this._actions) : [node_id];
var should_redraw_all = node_ids.indexOf("all") > -1;
for (var i = 0; i < node_ids.length; i++) {
node_id = node_ids[i];
var actions = self._actions[node_id] || [];
var new_actions = [];
for (var j = 0; j < actions.length; j++) {
var action = actions[j];
if(action.id !== action_id && action_id !== "all") {
new_actions.push(action);
}
}
var ids = actions.map(function(x) { return x.id; });
var new_ids = new_actions.map(function(x) { return x.id; });
if (ids.length != new_ids.length || ids.filter(function(n) { return new_ids.indexOf(n) === -1; }).length) {
self._actions[node_id] = new_actions;
if (!should_redraw_all) this.redraw_node(node_id);
}
}
if (should_redraw_all) {
this.redraw(true);
}
};
this._create_action = function (node_id, action_id) {
var self = this;
var action = this._get_action(node_id, action_id);
if (action === null) return null;
var action_el = document.createElement("i");
action_el.className = action.class;
action_el.textContent = action.text;
if(action.title && action.title.length > 0){
action_el.title = action.title;
}
action_el.onclick = function(e) {
var node = self.get_node(action_el);
action.callback(node_id, node, action_id, action_el, e);
};
return {
"action": action,
"action_el": action_el
};
};
this._get_action = function (node_id, action_id) {
var actions = this._actions[node_id] || [];
var v = null;
for (var i = 0; i < actions.length; i++) {
var action = actions[i];
if (action.id === action_id) {
//TODO: fill empty fields with default values?
v = action;
}
}
return v;
};
this._set_action = function (node_id, obj, action) {
if (action === null) return;
var place = obj.querySelector(action.action.selector);
if (action.action.after) {
place.parentNode.insertBefore(action.action_el, place.nextSibling);
} else {
obj.insertBefore(action.action_el, place);
}
};
this._has_action = function (node_id, action_id) {
var found = false;
var actions = this._actions;
if (actions.hasOwnProperty(node_id)) {
for (var i = 0; i < actions[node_id].length; i++) {
if (actions[node_id][i].id === action_id) found = true;
}
}
if (this._actions.hasOwnProperty('all')) {
for (i = 0; i < actions['all'].length; i++) {
if (actions['all'][i].id === action_id) found = true;
}
}
return found;
};
this.redraw_node = function (obj, deep, callback, force_draw) {
var self = this;
var node_id = typeof obj === "object" ? obj.id : obj;
var el = parent.redraw_node.call(this, obj, deep, callback, force_draw);
if (el) {
//Check if we have any specific actions for this node
var actions = this._actions[node_id] || [];
for (var i = 0; i < actions.length; i++) {
var _action = self._create_action(node_id, actions[i].id);
self._set_action(node_id, el, _action);
}
actions = this._actions["all"] || [];
for (i = 0; i < actions.length; i++) {
_action = self._create_action("all", actions[i].id);
self._set_action(node_id, el, _action);
}
}
return el;
};
}
}));