/* * Released under BSD License * Copyright (c) 2014-2016 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.4.6'; // 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:{ hmargin:100, vmargin:50, line_width:2, line_color:'#555' }, layout:{ hspace:30, vspace:20, pspace:13 }, default_event_handle:{ enable_mousedown_handle:true, enable_click_handle:true, enable_dblclick_handle:true }, shortcut:{ enable:true, handles:{ }, mapping:{ addchild : 45, // Insert 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.inited = false; this.mind = null; this.event_handles = []; this.init(); }; // ============= static object ============================================= jm.direction = {left:-1,center:0,right:1}; jm.event_type = {show:1,resize:2,edit:3,select:4}; jm.node = function(sId,iIndex,sTopic,oData,bIsRoot,oParent,eDirection,bExpanded){ if(!sId){logger.error('invalid nodeid');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.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); }else{ logger.error('root node is already exist'); } }, add_node:function(parent_node, nodeid, topic, data, idx, direction, expanded){ if(!jm.util.is_node(parent_node)){ var the_parent_node = this.get_node(parent_node); if(!the_parent_node){ logger.error('the parent_node[id='+parent_node+'] can not be found.'); return null; }else{ return this.add_node(the_parent_node, nodeid, topic, data, idx, direction, expanded); } } var nodeindex = idx || -1; var node = null; if(parent_node.isroot){ var d = jm.direction.right; if(isNaN(direction)){ var children = parent_node.children; var children_len = children.length; var r = 0; for(var i=0;i 1 && r > 0) ? jm.direction.left : jm.direction.right }else{ d = (direction != jm.direction.left) ? jm.direction.right : jm.direction.left; } node = new jm.node(nodeid,nodeindex,topic,data,false,parent_node,d,expanded); }else{ node = new jm.node(nodeid,nodeindex,topic,data,false,parent_node,parent_node.direction,expanded); } 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){ if(!jm.util.is_node(node_before)){ var the_node_before = this.get_node(node_before); if(!the_node_before){ logger.error('the node_before[id='+node_before+'] can not be found.'); return null; }else{ return this.insert_node_before(the_node_before, nodeid, topic, data); } } var node_index = node_before.index-0.5; return this.add_node(node_before.parent, nodeid, topic, data, 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){ if(!jm.util.is_node(node_after)){ var the_node_after = this.get_node(node_before); if(!the_node_after){ logger.error('the node_after[id='+node_after+'] can not be found.'); return null; }else{ return this.insert_node_after(the_node_after, nodeid, topic, data); } } var node_index = node_after.index + 0.5; return this.add_node(node_after.parent, nodeid, topic, data, 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, beforeid, parentid, direction){ 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.move_node(the_node, beforeid, parentid, direction); } } if(!parentid){ parentid = node.parent.id; } return this._move_node(node, beforeid, parentid, 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){ 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 = this.get_node(parentid); node.parent.children.push(node); } if(node.parent.isroot){ if(direction == jsMind.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)){ 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.remove_node(the_node); } } if(!node){ logger.error('fail, the node can not be found'); 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 0){ o.children = []; for(var i=0;i 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" }, 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(''); df._buildmap(mind.root, xmllines); xmllines.push(''); 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'); // store expanded status as an attribute xmllines.push(''); // for attributes var node_data = node.data; if(node_data != null){ for(var k in node_data){ xmllines.push(''); } } // for children var children = node.children; for(var i=0;i'); }, }, }; // ============= utility object ============================================= jm.util = { is_node: function(node){ return !!node && node instanceof jm.node; }, ajax:{ _xhr:function(){ var xhr = null; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ try{ xhr = new ActiveXObject('Microsoft.XMLHTTP'); }catch(e){} } return xhr; }, _eurl:function(url){ return encodeURIComponent(url); }, 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(a._eurl(k)+'='+a._eurl(param[k])); } if(tmp_param.length>0){ p = tmp_param.join('&'); } var xhr = a._xhr(); 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); } } }, canvas:{ bezierto: function(ctx,x1,y1,x2,y2){ ctx.beginPath(); ctx.moveTo(x1,y1); ctx.bezierCurveTo(x1+(x2-x1)*2/3,y1,x1,y2,x2,y2); ctx.stroke(); }, lineto : function(ctx,x1,y1,x2,y2){ ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); }, clear:function(ctx,x,y,w,h){ ctx.clearRect(x,y,w,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){ if(!!JSON){ try{ var json_str = JSON.stringify(json); return json_str; }catch(e){ logger.warn(e); logger.warn('can not convert to string'); return null; } } }, string2json:function(json_str){ if(!!JSON){ try{ var json = JSON.parse(json_str); return json; }catch(e){ logger.warn(e); logger.warn('can not parse to json'); return null; } } }, 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).substr(2)).substr(2,16); } }, text:{ is_empty:function(s){ if(!s){return true;} return s.replace(/\s*/,'').length == 0; } } }; jm.prototype={ init : function(){ if(this.inited){return;} this.inited = 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, hmargin:opts.view.hmargin, vmargin:opts.view.vmargin, line_width:opts.view.line_width, line_color:opts.view.line_color }; // 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); }, 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){ 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); } } }, 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(nodeid){ return this.mind.get_node(nodeid); }, add_node:function(parent_node, nodeid, topic, data){ if(this.get_editable()){ var node = this.mind.add_node(parent_node, nodeid, topic, data); if(!!node){ this.view.add_node(node); this.layout.layout(); this.view.show(false); this.view.reset_node_custom_style(node); this.expand_node(parent_node); this.invoke_event_handle(jm.event_type.edit,{evt:'add_node',data:[parent_node.id,nodeid,topic,data],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){ if(this.get_editable()){ var beforeid = jm.util.is_node(node_before) ? node_before.id : node_before; var node = this.mind.insert_node_before(node_before, nodeid, topic, data); 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:[beforeid,nodeid,topic,data],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){ if(this.get_editable()){ var afterid = jm.util.is_node(node_after) ? node_after.id : node_after; var node = this.mind.insert_node_after(node_after, nodeid, topic, data); 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:[afterid,nodeid,topic,data],node:nodeid}); } return node; }else{ logger.error('fail, this mind map is not editable'); return null; } }, remove_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 false; }else{ return this.remove_node(the_node); } } if(this.get_editable()){ if(node.isroot){ logger.error('fail, can not remove root node'); return false; } var nodeid = node.id; var parentid = node.parent.id; var parent_node = this.get_node(parentid); this.view.save_location(parent_node); this.view.remove_node(node); this.mind.remove_node(node); this.layout.layout(); this.view.show(false); this.view.restore_location(parent_node); this.invoke_event_handle(jm.event_type.edit,{evt:'remove_node',data:[nodeid],node:parentid}); return true; }else{ logger.error('fail, this mind map is not editable'); return false; } }, update_node:function(nodeid, topic){ if(this.get_editable()){ if(jm.util.text.is_empty(topic)){ logger.warn('fail, topic can not be empty'); return; } var node = this.get_node(nodeid); if(!!node){ if(node.topic === topic){ logger.info('nothing changed'); this.view.update_node(node); return; } node.topic = topic; this.view.update_node(node); this.layout.layout(); this.view.show(false); this.invoke_event_handle(jm.event_type.edit,{evt:'update_node',data:[nodeid,topic],node:nodeid}); } }else{ logger.error('fail, this mind map is not editable'); return; } }, move_node:function(nodeid, beforeid, parentid, direction){ if(this.get_editable()){ var node = this.mind.move_node(nodeid,beforeid,parentid,direction); if(!!node){ this.view.update_node(node); this.layout.layout(); this.view.show(false); this.invoke_event_handle(jm.event_type.edit,{evt:'move_node',data:[nodeid,beforeid,parentid,direction],node:nodeid}); } }else{ logger.error('fail, this mind map is not editable'); return; } }, select_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.select_node(the_node); } } if(!this.layout.is_visible(node)){ return; } this.mind.selected = node; this.view.select_node(node); }, get_selected_node:function(){ if(!!this.mind){ return this.mind.selected; }else{ return null; } }, select_clear:function(){ if(!!this.mind){ this.mind.selected = null; this.view.select_clear(); } }, is_node_visible:function(node){ return this.layout.is_visible(node); }, find_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; }else{ return this.find_node_before(the_node); } } if(node.isroot){return null;} var n = null; if(node.parent.isroot){ var c = node.parent.children; var prev = null; var ni = null; for(var i=0;i=boundary){ this._layout_direction_side(children[i],jm.direction.left, children_count-i-1); }else{ this._layout_direction_side(children[i],jm.direction.right, i); } }*/ } }, _layout_direction_side:function(node, direction, side_index){ var layout_data = null; if('layout' in node._data){ layout_data = node._data.layout; }else{ layout_data = {}; node._data.layout = layout_data; } var children = node.children; var children_count = children.length; layout_data.direction = direction; layout_data.side_index = side_index; var i = children_count; while(i--){ this._layout_direction_side(children[i], direction, i); } }, layout_offset:function(){ var node = this.jm.mind.root; var layout_data = node._data.layout; layout_data.offset_x = 0; layout_data.offset_y = 0; layout_data.outer_height = 0; var children = node.children; var i = children.length; var left_nodes = []; var right_nodes = []; var subnode = null; while(i--){ subnode = children[i]; if(subnode._data.layout.direction == jm.direction.right){ right_nodes.unshift(subnode); }else{ left_nodes.unshift(subnode); } } layout_data.left_nodes = left_nodes; layout_data.right_nodes = right_nodes; layout_data.outer_height_left = this._layout_offset_subnodes(left_nodes); layout_data.outer_height_right = this._layout_offset_subnodes(right_nodes); this.bounds.e=node._data.view.width/2; this.bounds.w=0-this.bounds.e; //logger.debug(this.bounds.w); this.bounds.n=0; this.bounds.s = Math.max(layout_data.outer_height_left,layout_data.outer_height_right); }, // layout both the x and y axis _layout_offset_subnodes:function(nodes){ var total_height = 0; var nodes_count = nodes.length; var i = nodes_count; var node = null; var node_outer_height = 0; var layout_data = null; var base_y = 0; var pd = null; // parent._data while(i--){ node = nodes[i]; layout_data = node._data.layout; if(pd == null){ pd = node.parent._data; } node_outer_height = this._layout_offset_subnodes(node.children); if(!node.expanded){ node_outer_height=0; this.set_visible(node.children,false); } node_outer_height = Math.max(node._data.view.height,node_outer_height); layout_data.outer_height = node_outer_height; layout_data.offset_y = base_y - node_outer_height/2; layout_data.offset_x = this.opts.hspace * layout_data.direction + pd.view.width * (pd.layout.direction + layout_data.direction)/2; if(!node.parent.isroot){ layout_data.offset_x += this.opts.pspace * layout_data.direction; } base_y = base_y - node_outer_height - this.opts.vspace; total_height += node_outer_height; } if(nodes_count>1){ total_height += this.opts.vspace * (nodes_count-1); } i = nodes_count; var middle_height = total_height/2; while(i--){ node = nodes[i]; node._data.layout.offset_y += middle_height; } return total_height; }, // layout the y axis only, for collapse/expand a node _layout_offset_subnodes_height:function(nodes){ var total_height = 0; var nodes_count = nodes.length; var i = nodes_count; var node = null; var node_outer_height = 0; var layout_data = null; var base_y = 0; var pd = null; // parent._data while(i--){ node = nodes[i]; layout_data = node._data.layout; if(pd == null){ pd = node.parent._data; } node_outer_height = this._layout_offset_subnodes_height(node.children); if(!node.expanded){ node_outer_height=0; } node_outer_height = Math.max(node._data.view.height,node_outer_height); layout_data.outer_height = node_outer_height; layout_data.offset_y = base_y - node_outer_height/2; base_y = base_y - node_outer_height - this.opts.vspace; total_height += node_outer_height; } if(nodes_count>1){ total_height += this.opts.vspace * (nodes_count-1); } i = nodes_count; var middle_height = total_height/2; while(i--){ node = nodes[i]; node._data.layout.offset_y += middle_height; //logger.debug(node.topic); //logger.debug(node._data.layout.offset_y); } return total_height; }, get_node_offset:function(node){ var layout_data = node._data.layout; var offset_cache = null; if(('_offset_' in layout_data) && this.cache_valid){ offset_cache = layout_data._offset_; }else{ offset_cache = {x:-1, y:-1}; layout_data._offset_ = offset_cache; } if(offset_cache.x == -1 || offset_cache.y == -1){ var x = layout_data.offset_x; var y = layout_data.offset_y; if(!node.isroot){ var offset_p = this.get_node_offset(node.parent); x += offset_p.x; y += offset_p.y; } offset_cache.x = x; offset_cache.y = y; } return offset_cache; }, get_node_point:function(node){ var view_data = node._data.view; var offset_p = this.get_node_offset(node); //logger.debug(offset_p); var p = {}; p.x = offset_p.x + view_data.width*(node._data.layout.direction-1)/2; p.y = offset_p.y-view_data.height/2; //logger.debug(p); return p; }, get_node_point_in:function(node){ var p = this.get_node_offset(node); return p; }, get_node_point_out:function(node){ var layout_data = node._data.layout; var pout_cache = null; if(('_pout_' in layout_data) && this.cache_valid){ pout_cache = layout_data._pout_; }else{ pout_cache = {x:-1, y:-1}; layout_data._pout_ = pout_cache; } if(pout_cache.x == -1 || pout_cache.y == -1){ if(node.isroot){ pout_cache.x = 0; pout_cache.y = 0; }else{ var view_data = node._data.view; var offset_p = this.get_node_offset(node); pout_cache.x = offset_p.x + (view_data.width+this.opts.pspace)*node._data.layout.direction; pout_cache.y = offset_p.y; //logger.debug('pout'); //logger.debug(pout_cache); } } return pout_cache; }, get_expander_point:function(node){ var p = this.get_node_point_out(node); var ex_p = {}; if(node._data.layout.direction == jm.direction.right){ ex_p.x = p.x - this.opts.pspace; }else{ ex_p.x = p.x; } ex_p.y = p.y - Math.ceil(this.opts.pspace/2); return ex_p; }, get_min_size:function(){ var nodes = this.jm.mind.nodes; var node = null; var pout = null; for(var nodeid in nodes){ node = nodes[nodeid]; pout = this.get_node_point_out(node); //logger.debug(pout.x); if(pout.x > this.bounds.e){this.bounds.e = pout.x;} if(pout.x < this.bounds.w){this.bounds.w = pout.x;} } return { w:this.bounds.e - this.bounds.w, h:this.bounds.s - this.bounds.n } }, toggle_node:function(node){ if(node.isroot){ return; } if(node.expanded){ this.collapse_node(node); }else{ this.expand_node(node); } }, expand_node:function(node){ node.expanded = true; this.part_layout(node); this.set_visible(node.children,true); }, collapse_node:function(node){ node.expanded = false; this.part_layout(node); this.set_visible(node.children,false); }, expand_all:function(){ var nodes = this.jm.mind.nodes; var c = 0; var node; for(var nodeid in nodes){ node = nodes[nodeid]; if(!node.expanded){ node.expanded = true; c++; } } if(c>0){ var root = this.jm.mind.root; this.part_layout(root); this.set_visible(root.children,true); } }, collapse_all:function(){ var nodes = this.jm.mind.nodes; var c = 0; var node; for(var nodeid in nodes){ node = nodes[nodeid]; if(node.expanded && !node.isroot){ node.expanded = false c++; } } if(c>0){ var root = this.jm.mind.root; this.part_layout(root); this.set_visible(root.children,true); } }, expand_to_depth:function(target_depth,curr_nodes,curr_depth){ if(target_depth < 1){return;} var nodes = curr_nodes || this.jm.mind.root.children; var depth = curr_depth || 1; var i = nodes.length; var node = null; while(i--){ node = nodes[i]; if(depth < target_depth){ if(!node.expanded){ this.expand_node(node); } this.expand_to_depth(target_depth, node.children, depth+1); } if(depth == target_depth){ if(node.expanded){ this.collapse_node(node); } } } }, part_layout:function(node){ var root = this.jm.mind.root; if(!!root){ var root_layout_data = root._data.layout; if(node.isroot){ root_layout_data.outer_height_right=this._layout_offset_subnodes_height(root_layout_data.right_nodes); root_layout_data.outer_height_left=this._layout_offset_subnodes_height(root_layout_data.left_nodes); }else{ if(node._data.layout.direction == jm.direction.right){ root_layout_data.outer_height_right=this._layout_offset_subnodes_height(root_layout_data.right_nodes); }else{ root_layout_data.outer_height_left=this._layout_offset_subnodes_height(root_layout_data.left_nodes); } } this.bounds.s = Math.max(root_layout_data.outer_height_left,root_layout_data.outer_height_right); this.cache_valid = false; }else{ logger.warn('can not found root node'); } }, set_visible:function(nodes,visible){ var i = nodes.length; var node = null; var layout_data = null; while(i--){ node = nodes[i]; layout_data = node._data.layout; if(node.expanded){ this.set_visible(node.children,visible); }else{ this.set_visible(node.children,false); } if(!node.isroot){ node._data.layout.visible = visible; } } }, is_expand:function(node){ return node.expanded; }, is_visible:function(node){ var layout_data = node._data.layout; if(('visible' in layout_data) && !layout_data.visible){ return false; }else{ return true; } }, }; // view provider jm.view_provider= function(jm, options){ this.opts = options; this.jm = jm; this.layout = jm.layout; this.container = null; this.e_panel = null; this.e_nodes= null; this.e_canvas = null; this.canvas_ctx = null; this.size = {w:0,h:0}; this.selected_node = null; this.editing_node = null; }; jm.view_provider.prototype={ init:function(){ logger.debug('view.init'); this.container = $i(this.opts.container) ? this.opts.container : $g(this.opts.container); if(!this.container){ logger.error('the options.view.container was not be found in dom'); return; } this.e_panel = $c('div'); this.e_canvas = $c('canvas'); this.e_nodes = $c('jmnodes'); this.e_editor = $c('input'); this.e_panel.className = 'jsmind-inner'; this.e_panel.appendChild(this.e_canvas); this.e_panel.appendChild(this.e_nodes); this.e_editor.className = 'jsmind-editor'; this.e_editor.type = 'text'; this.actualZoom = 1; this.zoomStep = 0.1; this.minZoom = 0.5; this.maxZoom = 2; var v = this; jm.util.dom.add_event(this.e_editor,'keydown',function(e){ var evt = e || event; if(evt.keyCode == 13){v.edit_node_end();evt.stopPropagation();} }); jm.util.dom.add_event(this.e_editor,'blur',function(e){ v.edit_node_end(); }); this.container.appendChild(this.e_panel); this.init_canvas(); }, add_event:function(obj,event_name,event_handle){ jm.util.dom.add_event(this.e_nodes,event_name,function(e){ var evt = e || event; event_handle.call(obj,evt); }); }, get_binded_nodeid:function(element){ if(element == null){ return null; } var tagName = element.tagName.toLowerCase(); if(tagName == 'jmnodes' || tagName == 'body' || tagName == 'html'){ return null; } if(tagName == 'jmnode' || tagName == 'jmexpander'){ return element.getAttribute('nodeid'); }else{ return this.get_binded_nodeid(element.parentElement); } }, is_expander:function(element){ return (element.tagName.toLowerCase() == 'jmexpander'); }, reset:function(){ logger.debug('view.reset'); this.selected_node = null; this.clear_lines(); this.clear_nodes(); this.reset_theme(); }, reset_theme:function(){ var theme_name = this.jm.options.theme; if(!!theme_name){ this.e_nodes.className = 'theme-' + theme_name; }else{ this.e_nodes.className = ''; } }, reset_custom_style:function(){ var nodes = this.jm.mind.nodes; for(var nodeid in nodes){ this.reset_node_custom_style(nodes[nodeid]); } }, load:function(){ logger.debug('view.load'); this.init_nodes(); }, expand_size:function(){ var min_size = this.layout.get_min_size(); var min_width = min_size.w + this.opts.hmargin*2; var min_height = min_size.h + this.opts.vmargin*2; var client_w = this.e_panel.clientWidth; var client_h = this.e_panel.clientHeight; if(client_w < min_width){client_w = min_width;} if(client_h < min_height){client_h = min_height;} this.size.w = client_w; this.size.h = client_h; }, init_canvas:function(){ var ctx = this.e_canvas.getContext('2d'); this.canvas_ctx = ctx; }, init_nodes_size:function(node){ var view_data = node._data.view; view_data.width = view_data.element.clientWidth; view_data.height = view_data.element.clientHeight; }, init_nodes:function(){ var nodes = this.jm.mind.nodes; var doc_frag = $d.createDocumentFragment(); for(var nodeid in nodes){ this.create_node_element(nodes[nodeid],doc_frag); } this.e_nodes.appendChild(doc_frag); for(var nodeid in nodes){ this.init_nodes_size(nodes[nodeid]); } }, add_node:function(node){ this.create_node_element(node,this.e_nodes); this.init_nodes_size(node); }, create_node_element:function(node,parent_node){ var view_data = null; if('view' in node._data){ view_data = node._data.view; }else{ view_data = {}; node._data.view = view_data; } var d = $c('jmnode'); if(node.isroot){ d.className = 'root'; }else{ var d_e = $c('jmexpander'); $t(d_e,'-'); d_e.setAttribute('nodeid',node.id); d_e.style.visibility = 'hidden'; parent_node.appendChild(d_e); view_data.expander = d_e; } if (!!node.topic) { if(this.opts.support_html){ $h(d,node.topic); }else{ $t(d,node.topic); } } d.setAttribute('nodeid',node.id); d.style.visibility='hidden'; this._reset_node_custom_style(d, node.data); parent_node.appendChild(d); view_data.element = d; }, remove_node:function(node){ if(this.selected_node != null && this.selected_node.id == node.id){ this.selected_node = null; } if(this.editing_node != null && this.editing_node.id == node.id){ node._data.view.element.removeChild(this.e_editor); this.editing_node = null; } var children = node.children; var i = children.length; while(i--){ this.remove_node(children[i]); } if(node._data.view){ var element = node._data.view.element; var expander = node._data.view.expander; this.e_nodes.removeChild(element); this.e_nodes.removeChild(expander); node._data.view.element = null; node._data.view.expander = null; } }, update_node:function(node){ var view_data = node._data.view; var element = view_data.element; if (!!node.topic) { if(this.opts.support_html){ $h(element,node.topic); }else{ $t(element,node.topic); } } view_data.width = element.clientWidth; view_data.height = element.clientHeight; }, select_node:function(node){ if(!!this.selected_node){ this.selected_node._data.view.element.className = this.selected_node._data.view.element.className.replace(/\s*selected\b/i,''); this.reset_node_custom_style(this.selected_node); } if(!!node){ this.selected_node = node; node._data.view.element.className += ' selected'; this.clear_node_custom_style(node); } }, select_clear:function(){ this.select_node(null); }, get_editing_node:function(){ return this.editing_node; }, is_editing:function(){ return (!!this.editing_node); }, edit_node_begin:function(node){ if(!node.topic) { logger.warn("don't edit image nodes"); return; } if(this.editing_node != null){ this.edit_node_end(); } this.editing_node = node; var view_data = node._data.view; var element = view_data.element; var topic = node.topic; var ncs = getComputedStyle(element); this.e_editor.value = topic; this.e_editor.style.width = (element.clientWidth-parseInt(ncs.getPropertyValue('padding-left'))-parseInt(ncs.getPropertyValue('padding-right')))+'px'; element.innerHTML = ''; element.appendChild(this.e_editor); element.style.zIndex = 5; this.e_editor.focus(); this.e_editor.select(); }, edit_node_end:function(){ if(this.editing_node != null){ var node = this.editing_node; this.editing_node = null; var view_data = node._data.view; var element = view_data.element; var topic = this.e_editor.value; element.style.zIndex = 'auto'; element.removeChild(this.e_editor); if(jm.util.text.is_empty(topic) || node.topic === topic){ if(this.opts.support_html){ $h(element,node.topic); }else{ $t(element,node.topic); } }else{ this.jm.update_node(node.id,topic); } } }, get_view_offset:function(){ var bounds = this.layout.bounds; var _x = (this.size.w - bounds.e - bounds.w)/2; var _y = this.size.h / 2; return{x:_x, y:_y}; }, resize:function(){ this.e_canvas.width = 1; this.e_canvas.height = 1; this.e_nodes.style.width = '1px'; this.e_nodes.style.height = '1px'; this.expand_size(); this._show(); }, _show:function(){ this.e_canvas.width = this.size.w; this.e_canvas.height = this.size.h; this.e_nodes.style.width = this.size.w+'px'; this.e_nodes.style.height = this.size.h+'px'; this.show_nodes(); this.show_lines(); //this.layout.cache_valid = true; this.jm.invoke_event_handle(jm.event_type.resize,{data:[]}); }, zoomIn: function() { return this.setZoom(this.actualZoom + this.zoomStep); }, zoomOut: function() { return this.setZoom(this.actualZoom - this.zoomStep); }, setZoom: function(zoom) { if ((zoom < this.minZoom) || (zoom > this.maxZoom)) { return false; } this.actualZoom = zoom; for (var i=0; i < this.e_panel.children.length; i++) { this.e_panel.children[i].style.transform = 'scale(' + zoom + ')'; }; this.show(true); return true; }, _center_root:function(){ // center root node var outer_w = this.e_panel.clientWidth; var outer_h = this.e_panel.clientHeight; if(this.size.w > outer_w){ var _offset = this.get_view_offset(); this.e_panel.scrollLeft = _offset.x - outer_w/2; } if(this.size.h > outer_h){ this.e_panel.scrollTop = (this.size.h - outer_h)/2; } }, show:function(keep_center){ logger.debug('view.show'); this.expand_size(); this._show(); if(!!keep_center){ this._center_root(); } }, relayout:function(){ this.expand_size(); this._show(); }, save_location:function(node){ var vd = node._data.view; vd._saved_location={ x:parseInt(vd.element.style.left)-this.e_panel.scrollLeft, y:parseInt(vd.element.style.top)-this.e_panel.scrollTop, }; }, restore_location:function(node){ var vd = node._data.view; this.e_panel.scrollLeft = parseInt(vd.element.style.left)-vd._saved_location.x; this.e_panel.scrollTop = parseInt(vd.element.style.top)-vd._saved_location.y; }, clear_nodes:function(){ var mind = this.jm.mind; if(mind == null){ return; } var nodes = mind.nodes; var node = null; for(var nodeid in nodes){ node = nodes[nodeid]; node._data.view.element = null; node._data.view.expander = null; } this.e_nodes.innerHTML = ''; }, show_nodes:function(){ var nodes = this.jm.mind.nodes; var node = null; var node_element = null; var expander = null; var p = null; var p_expander= null; var expander_text = '-'; var view_data = null; var _offset = this.get_view_offset(); for(var nodeid in nodes){ node = nodes[nodeid]; view_data = node._data.view; node_element = view_data.element; expander = view_data.expander; if(!this.layout.is_visible(node)){ node_element.style.display = 'none'; expander.style.display = 'none'; continue; } this.reset_node_custom_style(node); p = this.layout.get_node_point(node); view_data.abs_x = _offset.x + p.x; view_data.abs_y = _offset.y + p.y; node_element.style.left = (_offset.x+p.x) + 'px'; node_element.style.top = (_offset.y+p.y) + 'px'; node_element.style.display = ''; node_element.style.visibility = 'visible'; if(!node.isroot && node.children.length>0){ expander_text = node.expanded?'-':'+'; p_expander= this.layout.get_expander_point(node); expander.style.left = (_offset.x + p_expander.x) + 'px'; expander.style.top = (_offset.y + p_expander.y) + 'px'; expander.style.display = ''; expander.style.visibility = 'visible'; $t(expander,expander_text); } // hide expander while all children have been removed if(!node.isroot && node.children.length==0){ expander.style.display = 'none'; expander.style.visibility = 'hidden'; } } }, reset_node_custom_style:function(node){ this._reset_node_custom_style(node._data.view.element, node.data); }, _reset_node_custom_style:function(node_element, node_data){ if('background-color' in node_data){ node_element.style.backgroundColor = node_data['background-color']; } if('foreground-color' in node_data){ node_element.style.color = node_data['foreground-color']; } if('width' in node_data){ node_element.style.width = node_data['width']+'px'; } if('height' in node_data){ node_element.style.height = node_data['height']+'px'; } if('font-size' in node_data){ node_element.style.fontSize = node_data['font-size']+'px'; } if('font-weight' in node_data){ node_element.style.fontWeight = node_data['font-weight']; } if('font-style' in node_data){ node_element.style.fontStyle = node_data['font-style']; } if('background-image' in node_data) { var backgroundImage = node_data['background-image']; if (backgroundImage.startsWith('data') && node_data['width'] && node_data['height']) { var img = new Image(); img.onload = function() { var c = $c('canvas'); c.width = node_element.clientWidth; c.height = node_element.clientHeight; var img = this; if(c.getContext) { var ctx = c.getContext('2d'); ctx.drawImage(img, 2, 2, node_element.clientWidth, node_element.clientHeight); var scaledImageData = c.toDataURL(); node_element.style.backgroundImage='url('+scaledImageData+')'; } }; img.src = backgroundImage; } else { node_element.style.backgroundImage='url('+backgroundImage+')'; } node_element.style.backgroundSize='99%'; if('background-rotation' in node_data){ node_element.style.transform = 'rotate(' + node_data['background-rotation'] + 'deg)'; } } }, clear_node_custom_style:function(node){ var node_element = node._data.view.element; node_element.style.backgroundColor = ""; node_element.style.color = ""; }, clear_lines:function(canvas_ctx){ var ctx = canvas_ctx || this.canvas_ctx; jm.util.canvas.clear(ctx,0,0,this.size.w,this.size.h); }, show_lines:function(canvas_ctx){ this.clear_lines(canvas_ctx); var nodes = this.jm.mind.nodes; var node = null; var pin = null; var pout = null; var _offset = this.get_view_offset(); for(var nodeid in nodes){ node = nodes[nodeid]; if(!!node.isroot){continue;} if(('visible' in node._data.layout) && !node._data.layout.visible){continue;} pin = this.layout.get_node_point_in(node); pout = this.layout.get_node_point_out(node.parent); this.draw_line(pout,pin,_offset,canvas_ctx); } }, draw_line:function(pin,pout,offset,canvas_ctx){ var ctx = canvas_ctx || this.canvas_ctx; ctx.strokeStyle = this.opts.line_color; ctx.lineWidth = this.opts.line_width; ctx.lineCap = 'round'; jm.util.canvas.bezierto( ctx, pin.x + offset.x, pin.y + offset.y, pout.x + offset.x, pout.y + offset.y); }, }; // shortcut provider jm.shortcut_provider= function(jm, options){ this.jm = jm; this.opts = options; this.mapping = options.mapping; this.handles = options.handles; this._mapping = {}; }; jm.shortcut_provider.prototype = { init : function(){ jm.util.dom.add_event($d,'keydown',this.handler.bind(this)); this.handles['addchild'] = this.handle_addchild; this.handles['addbrother'] = this.handle_addbrother; this.handles['editnode'] = this.handle_editnode; this.handles['delnode'] = this.handle_delnode; this.handles['toggle'] = this.handle_toggle; this.handles['up'] = this.handle_up; this.handles['down'] = this.handle_down; this.handles['left'] = this.handle_left; this.handles['right'] = this.handle_right; for(var handle in this.mapping){ if(!!this.mapping[handle] && (handle in this.handles)){ this._mapping[this.mapping[handle]] = this.handles[handle]; } } }, enable_shortcut : function(){ this.opts.enable = true; }, disable_shortcut : function(){ this.opts.enable = false; }, handler : function(e){ if(this.jm.view.is_editing()){return;} var evt = e || event; if(!this.opts.enable){return true;} var kc = evt.keyCode; if(kc in this._mapping){ this._mapping[kc].call(this,this.jm,e); } }, handle_addchild: function(_jm,e){ var selected_node = _jm.get_selected_node(); if(!!selected_node){ var nodeid = jm.util.uuid.newid(); var node = _jm.add_node(selected_node, nodeid, 'New Node'); if(!!node){ _jm.select_node(nodeid); _jm.begin_edit(nodeid); } } }, handle_addbrother:function(_jm,e){ var selected_node = _jm.get_selected_node(); if(!!selected_node && !selected_node.isroot){ var nodeid = jm.util.uuid.newid(); var node = _jm.insert_node_after(selected_node, nodeid, 'New Node'); if(!!node){ _jm.select_node(nodeid); _jm.begin_edit(nodeid); } } }, handle_editnode:function(_jm,e){ var selected_node = _jm.get_selected_node(); if(!!selected_node){ _jm.begin_edit(selected_node); } }, handle_delnode:function(_jm,e){ var selected_node = _jm.get_selected_node(); if(!!selected_node && !selected_node.isroot){ _jm.select_node(selected_node.parent); _jm.remove_node(selected_node); } }, handle_toggle:function(_jm,e){ var evt = e || event; var selected_node = _jm.get_selected_node(); if(!!selected_node){ _jm.toggle_node(selected_node.id); evt.stopPropagation(); evt.preventDefault(); } }, handle_up:function(_jm,e){ var evt = e || event; var selected_node = _jm.get_selected_node(); if(!!selected_node){ var up_node = _jm.find_node_before(selected_node); if(!up_node){ var np = _jm.find_node_before(selected_node.parent); if(!!np && np.children.length > 0){ up_node = np.children[np.children.length-1]; } } if(!!up_node){ _jm.select_node(up_node); } evt.stopPropagation(); evt.preventDefault(); } }, handle_down:function(_jm,e){ var evt = e || event; var selected_node = _jm.get_selected_node(); if(!!selected_node){ var down_node = _jm.find_node_after(selected_node); if(!down_node){ var np = _jm.find_node_after(selected_node.parent); if(!!np && np.children.length > 0){ down_node = np.children[0]; } } if(!!down_node){ _jm.select_node(down_node); } evt.stopPropagation(); evt.preventDefault(); } }, handle_left:function(_jm,e){ this._handle_direction(_jm,e,jm.direction.left); }, handle_right:function(_jm,e){ this._handle_direction(_jm,e,jm.direction.right); }, _handle_direction:function(_jm,e,d){ var evt = e || event; var selected_node = _jm.get_selected_node(); var node = null; if(!!selected_node){ if(selected_node.isroot){ var c = selected_node.children; var children = []; for(var i=0;i 0){ node = children[Math.floor((childrencount-1)/2)] } }else{ node = selected_node.parent; } if(!!node){ _jm.select_node(node); } evt.stopPropagation(); evt.preventDefault(); } }, }; // plugin jm.plugin = function(name,init){ this.name = name; this.init = init; }; jm.plugins = []; jm.register_plugin = function(plugin){ if(plugin instanceof jm.plugin){ jm.plugins.push(plugin); } }; jm.init_plugins = function(sender){ $w.setTimeout(function(){ jm._init_plugins(sender); },0); }; jm._init_plugins = function(sender){ var l = jm.plugins.length; var fn_init = null; for(var i=0;i