UNPKG

jsmind-simbiotico

Version:

jsMind is a pure javascript library for mindmap, it base on html5 canvas. jsMind was released under BSD license, you can embed it in any project, if only you observe the license.

1,369 lines (1,262 loc) 112 kB
/** * @license BSD * @copyright 2014-2023 hizzgdev@163.com * * Project Home: * https://github.com/hizzgdev/jsmind/ */ ; (function ($w) { 'use strict'; // set 'jsMind' as the library name. // __name__ should be a const value, Never try to change it easily. var __name__ = 'jsMind'; // library version var __version__ = '0.5.2'; // author var __author__ = 'hizzgdev@163.com'; // an noop function define var _noop = function () { }; var logger = (typeof console === 'undefined') ? { log: _noop, debug: _noop, error: _noop, warn: _noop, info: _noop } : console; // check global variables if (typeof module === 'undefined' || !module.exports) { if (typeof $w[__name__] != 'undefined') { logger.log(__name__ + ' has been already exist.'); return; } } // shortcut of methods in dom var $d = $w.document; var $g = function (id) { return $d.getElementById(id); }; var $c = function (tag) { return $d.createElement(tag); }; var $t = function (n, t) { if (n.hasChildNodes()) { n.firstChild.nodeValue = t; } else { n.appendChild($d.createTextNode(t)); } }; var $h = function (n, t) { if (t instanceof HTMLElement) { n.innerHTML = ''; n.appendChild(t); } else { n.innerHTML = t; } }; // detect isElement var $i = function (el) { return !!el && (typeof el === 'object') && (el.nodeType === 1) && (typeof el.style === 'object') && (typeof el.ownerDocument === 'object'); }; if (typeof String.prototype.startsWith != 'function') { String.prototype.startsWith = function (p) { return this.slice(0, p.length) === p; }; } var DEFAULT_OPTIONS = { container: '', // id of the container editable: false, // you can change it in your options theme: null, mode: 'full', // full or side support_html: true, view: { engine: 'canvas', hmargin: 100, vmargin: 50, line_width: 2, line_color: '#555', draggable: false, // drag the mind map with your mouse, when it's larger that the container hide_scrollbars_when_draggable: false, // hide container scrollbars, when mind map is larger than container and draggable option is true. node_overflow: 'hidden' // hidden or wrap }, layout: { hspace: 30, vspace: 20, pspace: 13 }, default_event_handle: { enable_mousedown_handle: true, enable_click_handle: true, enable_dblclick_handle: true, enable_mousewheel_handle: true }, shortcut: { enable: true, handles: { }, mapping: { addchild: [45, 4096+13], // Insert, Ctrl+Enter addbrother: 13, // Enter editnode: 113,// F2 delnode: 46, // Delete toggle: 32, // Space left: 37, // Left up: 38, // Up right: 39, // Right down: 40, // Down } }, }; // core object var jm = function (options) { jm.current = this; this.version = __version__; var opts = {}; jm.util.json.merge(opts, DEFAULT_OPTIONS); jm.util.json.merge(opts, options); if (!opts.container) { logger.error('the options.container should not be null or empty.'); return; } this.options = opts; this.initialized = false; this.mind = null; this.event_handles = []; this.init(); }; // ============= static object ============================================= jm.direction = { left: -1, center: 0, right: 1, of: function (dir) { if (!dir || dir === -1 || dir === 0 || dir === 1) { return dir; } if (dir === '-1' || dir === '0' || dir === '1') { return parseInt(dir); } if (dir.toLowerCase() === 'left') { return this.left; } if (dir.toLowerCase() === 'right') { return this.right; } if (dir.toLowerCase() === 'center') { return this.center; } } }; jm.event_type = { show: 1, resize: 2, edit: 3, select: 4 }; jm.key = { meta: 1 << 13, ctrl: 1 << 12, alt: 1 << 11, shift: 1 << 10 }; jm.node = function (sId, iIndex, sTopic, oData, bIsRoot, oParent, eDirection, bExpanded) { if (!sId) { logger.error('invalid node id'); return; } if (typeof iIndex != 'number') { logger.error('invalid node index'); return; } if (typeof bExpanded === 'undefined') { bExpanded = true; } this.id = sId; this.index = iIndex; this.topic = sTopic; this.data = oData || {}; this.isroot = bIsRoot; this.parent = oParent; this.direction = eDirection; this.expanded = !!bExpanded; this.children = []; this._data = {}; }; jm.node.compare = function (node1, node2) { // '-1' is alwary the last var r = 0; var i1 = node1.index; var i2 = node2.index; if (i1 >= 0 && i2 >= 0) { r = i1 - i2; } else if (i1 == -1 && i2 == -1) { r = 0; } else if (i1 == -1) { r = 1; } else if (i2 == -1) { r = -1; } else { r = 0; } //logger.debug(i1+' <> '+i2+' = '+r); return r; }; jm.node.inherited = function (pnode, node) { if (!!pnode && !!node) { if (pnode.id === node.id) { return true; } if (pnode.isroot) { return true; } var pid = pnode.id; var p = node; while (!p.isroot) { p = p.parent; if (p.id === pid) { return true; } } } return false; }; jm.node.is_node = function (n) { return !!n && n instanceof jm.node; }; jm.node.prototype = { get_location: function () { var vd = this._data.view; return { x: vd.abs_x, y: vd.abs_y }; }, get_size: function () { var vd = this._data.view; return { w: vd.width, h: vd.height } } }; jm.mind = function () { this.name = null; this.author = null; this.version = null; this.root = null; this.selected = null; this.nodes = {}; }; jm.mind.prototype = { get_node: function (nodeid) { if (nodeid in this.nodes) { return this.nodes[nodeid]; } else { logger.warn('the node[id=' + nodeid + '] can not be found'); return null; } }, set_root: function (nodeid, topic, data) { if (this.root == null) { this.root = new jm.node(nodeid, 0, topic, data, true); this._put_node(this.root); return this.root; } else { logger.error('root node is already exist'); return null; } }, add_node: function (parent_node, nodeid, topic, data, direction, expanded, idx) { if (!jm.util.is_node(parent_node)) { logger.error('the parent_node ' + parent_node + ' is not a node.'); return null; } var node_index = idx || -1; var node = new jm.node(nodeid, node_index, topic, data, false, parent_node, parent_node.direction, expanded); if (parent_node.isroot) { node.direction = direction || jm.direction.right; } if (this._put_node(node)) { parent_node.children.push(node); this._reindex(parent_node); } else { logger.error('fail, the nodeid \'' + node.id + '\' has been already exist.'); node = null; } return node; }, insert_node_before: function (node_before, nodeid, topic, data, direction) { if (!jm.util.is_node(node_before)) { logger.error('the node_before ' + node_before + ' is not a node.'); return null; } var node_index = node_before.index - 0.5; return this.add_node(node_before.parent, nodeid, topic, data, direction, true, node_index); }, get_node_before: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return null; } else { return this.get_node_before(the_node); } } if (node.isroot) { return null; } var idx = node.index - 2; if (idx >= 0) { return node.parent.children[idx]; } else { return null; } }, insert_node_after: function (node_after, nodeid, topic, data, direction) { if (!jm.util.is_node(node_after)) { logger.error('the node_after ' + node_after + ' is not a node.'); return null; } var node_index = node_after.index + 0.5; return this.add_node(node_after.parent, nodeid, topic, data, direction, true, node_index); }, get_node_after: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return null; } else { return this.get_node_after(the_node); } } if (node.isroot) { return null; } var idx = node.index; var brothers = node.parent.children; if (brothers.length > idx) { return node.parent.children[idx]; } else { return null; } }, move_node: function (node, before_id, parent_id, direction) { if (!jm.util.is_node(node)) { logger.error('the parameter node ' + node + ' is not a node.'); return null; } if (!parent_id) { parent_id = node.parent.id; } return this._move_node(node, before_id, parent_id, direction); }, _flow_node_direction: function (node, direction) { if (typeof direction === 'undefined') { direction = node.direction; } else { node.direction = direction; } var len = node.children.length; while (len--) { this._flow_node_direction(node.children[len], direction); } }, _move_node_internal: function (node, beforeid) { if (!!node && !!beforeid) { if (beforeid == '_last_') { node.index = -1; this._reindex(node.parent); } else if (beforeid == '_first_') { node.index = 0; this._reindex(node.parent); } else { var node_before = (!!beforeid) ? this.get_node(beforeid) : null; if (node_before != null && node_before.parent != null && node_before.parent.id == node.parent.id) { node.index = node_before.index - 0.5; this._reindex(node.parent); } } } return node; }, _move_node: function (node, beforeid, parentid, direction) { if (!!node && !!parentid) { var parent_node = this.get_node(parentid) if (jm.node.inherited(node, parent_node)) { logger.error('can not move a node to its children'); return null; } if (node.parent.id != parentid) { // remove from parent's children var sibling = node.parent.children; var si = sibling.length; while (si--) { if (sibling[si].id == node.id) { sibling.splice(si, 1); break; } } node.parent = parent_node; parent_node.children.push(node); } if (node.parent.isroot) { if (direction == jm.direction.left) { node.direction = direction; } else { node.direction = jm.direction.right; } } else { node.direction = node.parent.direction; } this._move_node_internal(node, beforeid); this._flow_node_direction(node); } return node; }, remove_node: function (node) { if (!jm.util.is_node(node)) { logger.error('the parameter node ' + node + ' is not a node.'); return false; } if (node.isroot) { logger.error('fail, can not remove root node'); return false; } if (this.selected != null && this.selected.id == node.id) { this.selected = null; } // clean all subordinate nodes var children = node.children; var ci = children.length; while (ci--) { this.remove_node(children[ci]); } // clean all children children.length = 0; // remove from parent's children var sibling = node.parent.children; var si = sibling.length; while (si--) { if (sibling[si].id == node.id) { sibling.splice(si, 1); break; } } // remove from global nodes delete this.nodes[node.id]; // clean all properties for (var k in node) { delete node[k]; } // remove it's self node = null; //delete node; return true; }, _put_node: function (node) { if (node.id in this.nodes) { logger.warn('the nodeid \'' + node.id + '\' has been already exist.'); return false; } else { this.nodes[node.id] = node; return true; } }, _reindex: function (node) { if (node instanceof jm.node) { node.children.sort(jm.node.compare); for (var i = 0; i < node.children.length; i++) { node.children[i].index = i + 1; } } }, }; jm.format = { node_tree: { example: { "meta": { "name": __name__, "author": __author__, "version": __version__ }, "format": "node_tree", "data": { "id": "root", "topic": "jsMind Example" } }, get_mind: function (source) { var df = jm.format.node_tree; var mind = new jm.mind(); mind.name = source.meta.name; mind.author = source.meta.author; mind.version = source.meta.version; df._parse(mind, source.data); return mind; }, get_data: function (mind) { var df = jm.format.node_tree; var json = {}; json.meta = { name: mind.name, author: mind.author, version: mind.version }; json.format = 'node_tree'; json.data = df._buildnode(mind.root); return json; }, _parse: function (mind, node_root) { var df = jm.format.node_tree; var data = df._extract_data(node_root); mind.set_root(node_root.id, node_root.topic, data); if ('children' in node_root) { var children = node_root.children; for (var i = 0; i < children.length; i++) { df._extract_subnode(mind, mind.root, children[i]); } } }, _extract_data: function (node_json) { var data = {}; for (var k in node_json) { if (k == 'id' || k == 'topic' || k == 'children' || k == 'direction' || k == 'expanded') { continue; } data[k] = node_json[k]; } return data; }, _extract_subnode: function (mind, node_parent, node_json) { var df = jm.format.node_tree; var data = df._extract_data(node_json); var d = null; if (node_parent.isroot) { d = node_json.direction == 'left' ? jm.direction.left : jm.direction.right; } var node = mind.add_node(node_parent, node_json.id, node_json.topic, data, d, node_json.expanded); if (!!node_json['children']) { var children = node_json.children; for (var i = 0; i < children.length; i++) { df._extract_subnode(mind, node, children[i]); } } }, _buildnode: function (node) { var df = jm.format.node_tree; if (!(node instanceof jm.node)) { return; } var o = { id: node.id, topic: node.topic, expanded: node.expanded }; if (!!node.parent && node.parent.isroot) { o.direction = node.direction == jm.direction.left ? 'left' : 'right'; } if (node.data != null) { var node_data = node.data; for (var k in node_data) { o[k] = node_data[k]; } } var children = node.children; if (children.length > 0) { o.children = []; for (var i = 0; i < children.length; i++) { o.children.push(df._buildnode(children[i])); } } return o; } }, node_array: { example: { "meta": { "name": __name__, "author": __author__, "version": __version__ }, "format": "node_array", "data": [ { "id": "root", "topic": "jsMind Example", "isroot": true } ] }, get_mind: function (source) { var df = jm.format.node_array; var mind = new jm.mind(); mind.name = source.meta.name; mind.author = source.meta.author; mind.version = source.meta.version; df._parse(mind, source.data); return mind; }, get_data: function (mind) { var df = jm.format.node_array; var json = {}; json.meta = { name: mind.name, author: mind.author, version: mind.version }; json.format = 'node_array'; json.data = []; df._array(mind, json.data); return json; }, _parse: function (mind, node_array) { var df = jm.format.node_array; var narray = node_array.slice(0); // reverse array for improving looping performance narray.reverse(); var root_node = df._extract_root(mind, narray); if (!!root_node) { df._extract_subnode(mind, root_node, narray); } else { logger.error('root node can not be found'); } }, _extract_root: function (mind, node_array) { var df = jm.format.node_array; var i = node_array.length; while (i--) { if ('isroot' in node_array[i] && node_array[i].isroot) { var root_json = node_array[i]; var data = df._extract_data(root_json); var node = mind.set_root(root_json.id, root_json.topic, data); node_array.splice(i, 1); return node; } } return null; }, _extract_subnode: function (mind, parent_node, node_array) { var df = jm.format.node_array; var i = node_array.length; var node_json = null; var data = null; var extract_count = 0; while (i--) { node_json = node_array[i]; if (node_json.parentid == parent_node.id) { data = df._extract_data(node_json); var d = null; var node_direction = node_json.direction; if (!!node_direction) { d = node_direction == 'left' ? jm.direction.left : jm.direction.right; } var node = mind.add_node(parent_node, node_json.id, node_json.topic, data, d, node_json.expanded); node_array.splice(i, 1); extract_count++; var sub_extract_count = df._extract_subnode(mind, node, node_array); if (sub_extract_count > 0) { // reset loop index after extract subordinate node i = node_array.length; extract_count += sub_extract_count; } } } return extract_count; }, _extract_data: function (node_json) { var data = {}; for (var k in node_json) { if (k == 'id' || k == 'topic' || k == 'parentid' || k == 'isroot' || k == 'direction' || k == 'expanded') { continue; } data[k] = node_json[k]; } return data; }, _array: function (mind, node_array) { var df = jm.format.node_array; df._array_node(mind.root, node_array); }, _array_node: function (node, node_array) { var df = jm.format.node_array; if (!(node instanceof jm.node)) { return; } var o = { id: node.id, topic: node.topic, expanded: node.expanded }; if (!!node.parent) { o.parentid = node.parent.id; } if (node.isroot) { o.isroot = true; } if (!!node.parent && node.parent.isroot) { o.direction = node.direction == jm.direction.left ? 'left' : 'right'; } if (node.data != null) { var node_data = node.data; for (var k in node_data) { o[k] = node_data[k]; } } node_array.push(o); var ci = node.children.length; for (var i = 0; i < ci; i++) { df._array_node(node.children[i], node_array); } }, }, freemind: { example: { "meta": { "name": __name__, "author": __author__, "version": __version__ }, "format": "freemind", "data": "<map version=\"1.0.1\"><node ID=\"root\" TEXT=\"freemind Example\"/></map>" }, get_mind: function (source) { var df = jm.format.freemind; var mind = new jm.mind(); mind.name = source.meta.name; mind.author = source.meta.author; mind.version = source.meta.version; var xml = source.data; var xml_doc = df._parse_xml(xml); var xml_root = df._find_root(xml_doc); df._load_node(mind, null, xml_root); return mind; }, get_data: function (mind) { var df = jm.format.freemind; var json = {}; json.meta = { name: mind.name, author: mind.author, version: mind.version }; json.format = 'freemind'; var xmllines = []; xmllines.push('<map version=\"1.0.1\">'); df._buildmap(mind.root, xmllines); xmllines.push('</map>'); json.data = xmllines.join(' '); return json; }, _parse_xml: function (xml) { var xml_doc = null; if (window.DOMParser) { var parser = new DOMParser(); xml_doc = parser.parseFromString(xml, 'text/xml'); } else { // Internet Explorer xml_doc = new ActiveXObject('Microsoft.XMLDOM'); xml_doc.async = false; xml_doc.loadXML(xml); } return xml_doc; }, _find_root: function (xml_doc) { var nodes = xml_doc.childNodes; var node = null; var root = null; var n = null; for (var i = 0; i < nodes.length; i++) { n = nodes[i]; if (n.nodeType == 1 && n.tagName == 'map') { node = n; break; } } if (!!node) { var ns = node.childNodes; node = null; for (var i = 0; i < ns.length; i++) { n = ns[i]; if (n.nodeType == 1 && n.tagName == 'node') { node = n; break; } } } return node; }, _load_node: function (mind, parent_node, xml_node) { var df = jm.format.freemind; var node_id = xml_node.getAttribute('ID'); var node_topic = xml_node.getAttribute('TEXT'); // look for richcontent if (node_topic == null) { var topic_children = xml_node.childNodes; var topic_child = null; for (var i = 0; i < topic_children.length; i++) { topic_child = topic_children[i]; //logger.debug(topic_child.tagName); if (topic_child.nodeType == 1 && topic_child.tagName === 'richcontent') { node_topic = topic_child.textContent; break; } } } var node_data = df._load_attributes(xml_node); var node_expanded = ('expanded' in node_data) ? (node_data.expanded == 'true') : true; delete node_data.expanded; var node_position = xml_node.getAttribute('POSITION'); var node_direction = null; if (!!node_position) { node_direction = node_position == 'left' ? jm.direction.left : jm.direction.right; } //logger.debug(node_position +':'+ node_direction); var node = null; if (!!parent_node) { node = mind.add_node(parent_node, node_id, node_topic, node_data, node_direction, node_expanded); } else { node = mind.set_root(node_id, node_topic, node_data); } var children = xml_node.childNodes; var child = null; for (var i = 0; i < children.length; i++) { child = children[i]; if (child.nodeType == 1 && child.tagName == 'node') { df._load_node(mind, node, child); } } }, _load_attributes: function (xml_node) { var children = xml_node.childNodes; var attr = null; var attr_data = {}; for (var i = 0; i < children.length; i++) { attr = children[i]; if (attr.nodeType == 1 && attr.tagName === 'attribute') { attr_data[attr.getAttribute('NAME')] = attr.getAttribute('VALUE'); } } return attr_data; }, _buildmap: function (node, xmllines) { var df = jm.format.freemind; var pos = null; if (!!node.parent && node.parent.isroot) { pos = node.direction === jm.direction.left ? 'left' : 'right'; } xmllines.push('<node'); xmllines.push('ID=\"' + node.id + '\"'); if (!!pos) { xmllines.push('POSITION=\"' + pos + '\"'); } xmllines.push('TEXT=\"' + node.topic + '\">'); // store expanded status as an attribute xmllines.push('<attribute NAME=\"expanded\" VALUE=\"' + node.expanded + '\"/>'); // for attributes var node_data = node.data; if (node_data != null) { for (var k in node_data) { xmllines.push('<attribute NAME=\"' + k + '\" VALUE=\"' + node_data[k] + '\"/>'); } } // for children var children = node.children; for (var i = 0; i < children.length; i++) { df._buildmap(children[i], xmllines); } xmllines.push('</node>'); }, }, }; // ============= utility object ============================================= jm.util = { is_node: function (node) { return !!node && node instanceof jm.node; }, ajax: { request: function (url, param, method, callback, fail_callback) { var a = jm.util.ajax; var p = null; var tmp_param = []; for (var k in param) { tmp_param.push(encodeURIComponent(k) + '=' + encodeURIComponent(param[k])); } if (tmp_param.length > 0) { p = tmp_param.join('&'); } var xhr = new XMLHttpRequest(); if (!xhr) { return; } xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200 || xhr.status == 0) { if (typeof callback === 'function') { var data = jm.util.json.string2json(xhr.responseText); if (data != null) { callback(data); } else { callback(xhr.responseText); } } } else { if (typeof fail_callback === 'function') { fail_callback(xhr); } else { logger.error('xhr request failed.', xhr); } } } } method = method || 'GET'; xhr.open(method, url, true); xhr.setRequestHeader('If-Modified-Since', '0'); if (method == 'POST') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8'); xhr.send(p); } else { xhr.send(); } }, get: function (url, callback) { return jm.util.ajax.request(url, {}, 'GET', callback); }, post: function (url, param, callback) { return jm.util.ajax.request(url, param, 'POST', callback); } }, dom: { //target,eventType,handler add_event: function (t, e, h) { if (!!t.addEventListener) { t.addEventListener(e, h, false); } else { t.attachEvent('on' + e, h); } } }, file: { read: function (file_data, fn_callback) { var reader = new FileReader(); reader.onload = function () { if (typeof fn_callback === 'function') { fn_callback(this.result, file_data.name); } }; reader.readAsText(file_data); }, save: function (file_data, type, name) { var blob; if (typeof $w.Blob === 'function') { blob = new Blob([file_data], { type: type }); } else { var BlobBuilder = $w.BlobBuilder || $w.MozBlobBuilder || $w.WebKitBlobBuilder || $w.MSBlobBuilder; var bb = new BlobBuilder(); bb.append(file_data); blob = bb.getBlob(type); } if (navigator.msSaveBlob) { navigator.msSaveBlob(blob, name); } else { var URL = $w.URL || $w.webkitURL; var bloburl = URL.createObjectURL(blob); var anchor = $c('a'); if ('download' in anchor) { anchor.style.visibility = 'hidden'; anchor.href = bloburl; anchor.download = name; $d.body.appendChild(anchor); var evt = $d.createEvent('MouseEvents'); evt.initEvent('click', true, true); anchor.dispatchEvent(evt); $d.body.removeChild(anchor); } else { location.href = bloburl; } } } }, json: { json2string: function (json) { return JSON.stringify(json); }, string2json: function (json_str) { return JSON.parse(json_str); }, merge: function (b, a) { for (var o in a) { if (o in b) { if (typeof b[o] === 'object' && Object.prototype.toString.call(b[o]).toLowerCase() == '[object object]' && !b[o].length) { jm.util.json.merge(b[o], a[o]); } else { b[o] = a[o]; } } else { b[o] = a[o]; } } return b; } }, uuid: { newid: function () { return (new Date().getTime().toString(16) + Math.random().toString(16).substring(2)).substring(2, 18); } }, text: { is_empty: function (s) { if (!s) { return true; } return s.replace(/\s*/, '').length == 0; } } }; jm.prototype = { init: function () { if (this.initialized) { return; } this.initialized = true; var opts = this.options; var opts_layout = { mode: opts.mode, hspace: opts.layout.hspace, vspace: opts.layout.vspace, pspace: opts.layout.pspace } var opts_view = { container: opts.container, support_html: opts.support_html, engine: opts.view.engine, hmargin: opts.view.hmargin, vmargin: opts.view.vmargin, line_width: opts.view.line_width, line_color: opts.view.line_color, draggable: opts.view.draggable, hide_scrollbars_when_draggable: opts.view.hide_scrollbars_when_draggable, node_overflow: opts.view.node_overflow }; // create instance of function provider this.data = new jm.data_provider(this); this.layout = new jm.layout_provider(this, opts_layout); this.view = new jm.view_provider(this, opts_view); this.shortcut = new jm.shortcut_provider(this, opts.shortcut); this.data.init(); this.layout.init(); this.view.init(); this.shortcut.init(); this._event_bind(); jm.init_plugins(this); }, enable_edit: function () { this.options.editable = true; }, disable_edit: function () { this.options.editable = false; }, // call enable_event_handle('dblclick') // options are 'mousedown', 'click', 'dblclick' enable_event_handle: function (event_handle) { this.options.default_event_handle['enable_' + event_handle + '_handle'] = true; }, // call disable_event_handle('dblclick') // options are 'mousedown', 'click', 'dblclick' disable_event_handle: function (event_handle) { this.options.default_event_handle['enable_' + event_handle + '_handle'] = false; }, get_editable: function () { return this.options.editable; }, set_theme: function (theme) { var theme_old = this.options.theme; this.options.theme = (!!theme) ? theme : null; if (theme_old != this.options.theme) { this.view.reset_theme(); this.view.reset_custom_style(); } }, _event_bind: function () { this.view.add_event(this, 'mousedown', this.mousedown_handle); this.view.add_event(this, 'click', this.click_handle); this.view.add_event(this, 'dblclick', this.dblclick_handle); this.view.add_event(this, "mousewheel", this.mousewheel_handle) }, mousedown_handle: function (e) { if (!this.options.default_event_handle['enable_mousedown_handle']) { return; } var element = e.target || event.srcElement; var nodeid = this.view.get_binded_nodeid(element); if (!!nodeid) { if (element.tagName.toLowerCase() == 'jmnode') { this.select_node(nodeid); } } else { this.select_clear(); } }, click_handle: function (e) { if (!this.options.default_event_handle['enable_click_handle']) { return; } var element = e.target || event.srcElement; var isexpander = this.view.is_expander(element); if (isexpander) { var nodeid = this.view.get_binded_nodeid(element); if (!!nodeid) { this.toggle_node(nodeid); } } }, dblclick_handle: function (e) { if (!this.options.default_event_handle['enable_dblclick_handle']) { return; } if (this.get_editable()) { var element = e.target || event.srcElement; var nodeid = this.view.get_binded_nodeid(element); if (!!nodeid) { this.begin_edit(nodeid); } } }, // Use [Ctrl] + Mousewheel, to zoom in/out. mousewheel_handle: function (event) { // Test if mousewheel option is enabled and Ctrl key is pressed. if (!this.options.default_event_handle["enable_mousewheel_handle"] || !window.event.ctrlKey) { return } // Avoid default page scrolling behavior. event.preventDefault() if (event.deltaY < 0) { this.view.zoomIn() } else { this.view.zoomOut() } }, begin_edit: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return false; } else { return this.begin_edit(the_node); } } if (this.get_editable()) { this.view.edit_node_begin(node); } else { logger.error('fail, this mind map is not editable.'); return; } }, end_edit: function () { this.view.edit_node_end(); }, toggle_node: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return; } else { return this.toggle_node(the_node); } } if (node.isroot) { return; } this.view.save_location(node); this.layout.toggle_node(node); this.view.relayout(); this.view.restore_location(node); }, expand_node: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return; } else { return this.expand_node(the_node); } } if (node.isroot) { return; } this.view.save_location(node); this.layout.expand_node(node); this.view.relayout(); this.view.restore_location(node); }, collapse_node: function (node) { if (!jm.util.is_node(node)) { var the_node = this.get_node(node); if (!the_node) { logger.error('the node[id=' + node + '] can not be found.'); return; } else { return this.collapse_node(the_node); } } if (node.isroot) { return; } this.view.save_location(node); this.layout.collapse_node(node); this.view.relayout(); this.view.restore_location(node); }, expand_all: function () { this.layout.expand_all(); this.view.relayout(); }, collapse_all: function () { this.layout.collapse_all(); this.view.relayout(); }, expand_to_depth: function (depth) { this.layout.expand_to_depth(depth); this.view.relayout(); }, _reset: function () { this.view.reset(); this.layout.reset(); this.data.reset(); }, _show: function (mind) { var m = mind || jm.format.node_array.example; this.mind = this.data.load(m); if (!this.mind) { logger.error('data.load error'); return; } else { logger.debug('data.load ok'); } this.view.load(); logger.debug('view.load ok'); this.layout.layout(); logger.debug('layout.layout ok'); this.view.show(true); logger.debug('view.show ok'); this.invoke_event_handle(jm.event_type.show, { data: [mind] }); }, show: function (mind) { this._reset(); this._show(mind); }, get_meta: function () { return { name: this.mind.name, author: this.mind.author, version: this.mind.version }; }, get_data: function (data_format) { var df = data_format || 'node_tree'; return this.data.get_data(df); }, get_root: function () { return this.mind.root; }, get_node: function (node) { if (jm.util.is_node(node)) { return node; } return this.mind.get_node(node); }, add_node: function (parent_node, nodeid, topic, data, direction) { if (this.get_editable()) { var the_parent_node = this.get_node(parent_node); var dir = jm.direction.of(direction) if (dir === undefined) { dir = this.layout.calculate_next_child_direction(the_parent_node); } var node = this.mind.add_node(the_parent_node, nodeid, topic, data, dir); if (!!node) { this.view.add_node(node); this.layout.layout(); this.view.show(false); this.view.reset_node_custom_style(node); this.expand_node(the_parent_node); this.invoke_event_handle(jm.event_type.edit, { evt: 'add_node', data: [the_parent_node.id, nodeid, topic, data, dir], node: nodeid }); } return node; } else { logger.error('fail, this mind map is not editable'); return null; } }, insert_node_before: function (node_before, nodeid, topic, data, direction) { if (this.get_editable()) { var the_node_before = this.get_node(node_before); var dir = jm.direction.of(direction) if (dir === undefined) { dir = this.layout.calculate_next_child_direction(the_node_before.parent); } var node = this.mind.insert_node_before(the_node_before, nodeid, topic, data, dir); if (!!node) { this.view.add_node(node); this.layout.layout(); this.view.show(false); this.invoke_event_handle(jm.event_type.edit, { evt: 'insert_node_before', data: [the_node_before.id, nodeid, topic, data, dir], node: nodeid }); } return node; } else { logger.error('fail, this mind map is not editable'); return null; } }, insert_node_after: function (node_after, nodeid, topic, data, direction) { if (this.get_editable()) { var the_node_after = this.get_node(node_after); var dir = jm.direction.of(direction) if (dir === undefined) { dir = this.layout.calculate_next_child_direction(the_node_after.parent); } var node = this.mind.insert_node_after(the_node_after, nodeid, topic, data, dir); if (!!node) { this.view.add_node(node); this.layout.layout(); this.view.show(false); this.invoke_event_handle(jm.event_type.edit, { evt: 'insert_node_after', data: [the_node_after.id, nodeid, topic, data, dir], node: nodeid }); } return node; } else { logger.error('fail, thi