(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"; if($.jstree){ return; } // internal variables var instance_counter=0,// jstree实例个数 ccp_node=false,// 缓存拷贝或剪贴到的节点数据,数组形式,可供粘贴 ccp_mode=false,// 拷贝方式,后续调用的方法,cut方法为move_node,copy方法为copy_node ccp_inst=false,// 拷贝或剪切到的节点数据归属的jstree实例 themes_loaded=[],// 缓存信息记录已加载样式文件 src=$('script:last').attr('src'),// jstree文件所在路径 document=window.document; // _node创建理想子节点,clone方法创建实际子节点,随后插入文档 var _node=document.createElement('LI'),_temp1,_temp2; _node.setAttribute('role','treeitem'); _temp1=document.createElement('I'); _temp1.className='jstree-icon jstree-ocl'; _temp1.setAttribute('role','presentation'); _node.appendChild(_temp1); _temp1=document.createElement('A'); _temp1.className='jstree-anchor'; _temp1.setAttribute('href','#'); _temp1.setAttribute('tabindex','-1'); _temp2=document.createElement('I'); _temp2.className='jstree-icon jstree-themeicon'; _temp2.setAttribute('role','presentation'); _temp1.appendChild(_temp2); _node.appendChild(_temp1); _temp1=_temp2=null; $.jstree={ version:'{{VERSION}}', defaults:{// 预先激活的插件 plugins:[] }, plugins:{},// 缓存加载的插件 path:src && src.indexOf('/')!==-1 ? src.replace(/\/[^\/]+$/,'') : '',// jstree文件所在目录 idregex:/[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g, root:'#'// 理想根节点 }; // $.jstree.create静态方法创建jstree实例,options通过{core:{}}形式传入 $.jstree.create=function (el, options){ var tmp=new $.jstree.core(++instance_counter), opt=options; options=$.extend(true, {}, $.jstree.defaults, options); if(opt && opt.plugins){ options.plugins=opt.plugins; } $.each(options.plugins, function (i, k){ if( i!=='core' ){ tmp=tmp.plugin(k, options[k]); } }); $(el).data('jstree', tmp);// 实例缓存在元素的data-jstree属性中 tmp.init(el, options); return tmp; }; // 调用实例的destroy方法销毁所有实例 $.jstree.destroy=function(){ $('.jstree:jstree').jstree('destroy'); $(document).off('.jstree'); }; // jstree实例构造函数,添加相关属性,id为已创建实例的序号值 $.jstree.core=function (id){ this._id=id; this._cnt=0;// 用于生成单个树节点的id this._wrk=null; this._data={ core:{ themes:{ name:false, dots:false, icons:false }, selected:[],// 缓存选中的节点 last_error:{},// 报错信息 working:false, worker_queue:[], focused:null// 以id或节点数据形式传入,使某个节点的a标签被选中 } }; }; // 通过元素获取jstree实例,obj作为闭包缓存,传参可为dom元素或选择器,向上查找'.jstree'元素 $.jstree.reference=function (needle){ var tmp=null, obj=null; if( needle && needle.id && (!needle.tagName || !needle.nodeType) ){ needle=needle.id; } if( !obj || !obj.length ){ try{ obj=$(needle); }catch(ignore){} } if( !obj || !obj.length ){ try{ obj=$('#'+needle.replace($.jstree.idregex,'\\$&')); }catch(ignore){} } if( obj && obj.length && (obj=obj.closest('.jstree')).length && (obj=obj.data('jstree')) ){ tmp=obj; }else { $('.jstree').each(function (){ var inst=$(this).data('jstree'); if( inst && inst._model.data[needle] ){ tmp=inst; return false; } }); } return tmp; }; // 首参字符串获取实例的方法并执行,或者首参true获取实例,或者首参对象创建实例 $.fn.jstree=function (arg){ var is_method=(typeof arg==='string'), args=Array.prototype.slice.call(arguments, 1), result=null; if( arg===true && !this.length ) return false; this.each(function (){ var instance=$.jstree.reference(this), method=is_method && instance ? instance[arg] : null; result = is_method && method ? method.apply(instance, args) : null; if( !instance && !is_method && (arg===undefined || $.isPlainObject(arg)) ){ $.jstree.create(this, arg); } if( (instance && !is_method) || arg===true ){ result=instance || false; } if( result!==null && result!==undefined ){// 执行方法取得真值或取得实例后,中断遍历 return false; } }); return result!==null && result!==undefined ? result : this; }; // 创建伪类选择器:jstree,搜索样式中含有jstree,且有data-jstree属性 $.expr.pseudos.jstree=$.expr.createPseudo(function(search){ return function(a){ return $(a).hasClass('jstree') && $(a).data('jstree')!==undefined; }; }); // jstree的默认配置项 $.jstree.defaults.core = { /** 用户配置节点数据 * $('#tree').jstree({// ajax形式 * 'core':{// 核心模块配置 * 'data':{ * 'url':'/get/children/',// ajax请求url * 'data':function(node){ return {'id':node.id}; }// ajax携带参数 * } * }); * * $('#tree').jstree({// 普通对象形式 * 'core':{ * 'data':[ * 'Simple root node', * { 'id':'node_2', * 'text':'Root node with options', * 'state':{ 'opened':true, 'selected':true }, * 'children':[ {'text':'Child 1'}, 'Child 2' ] } * ] * } * }); * * $('#tree').jstree({// 函数形式 * 'core':{ * 'data':function(obj,callback){ * callback.call(this,['Root 1','Root 2']); * } * }); */ data:false, // 函数或对象形式,将jstree中配置的'Loading ...'作为函数的参数或者对象的属性,获取文案 strings:false, /**判断节点是否拥有create_node、rename_node、delete_node、copy_node、move_node的权限 * 布尔值直接判断,函数通过函数返回值判断 * $('#tree').jstree({ * 'core':{ * 'check_callback':function(operation,node,node_parent,node_position,more){ * return operation==='rename_node' ? true : false; * } * } * }); */ check_callback:false, error:$.noop,// 用户配置报错函数 animation:200,// 展开和折叠节点的所需时间,默认200毫秒,false关闭 multiple:true,// 支持节点多选 themes:{ name:false,// 主题名,false时取默认主题 url:false,// 设置为true时自动查询加载,false手动添加 dir:false,// 加载样式的文件目录 dots:true,// 是否展示虚线 icons:true,// 是否展示图标 stripes:false,// 是否展示间行色 variant:false,// 节点图标字体大小,可设置variant为large等 responsive:false// 响应式布局 }, expand_selected_onload:true,// 加载完成时选中的节点展开 worker:true,// 真值时用web workers处理json串 force_text:false,// true时以text方法填充纯文本,false时html方法 dblclick_toggle:true// 双击是否切换节点的显示隐藏状况 }; $.jstree.core.prototype={ // 调用插件plugins[deco],并用opts配置插件 plugin:function(deco,opts){ var Child=$.jstree.plugins[deco]; if( Child ){ this._data[deco]={}; Child.prototype=this; return new Child(opts,this); } return this; }, // 实例初始化,绑定事件,触发init、loading事件,显示加载中文本,插入树形节点 // options为用户配置和默认配置混合后的结果 // 样式相关属性由this.setting.core从用户配置添加到this._data.core中 init:function (el,options){ this._model={ data:{},// 存储转化后的数据,转化前的数据存储在this.setting.core.data中 changed:[],// 缓存已改变节点的id,redraw方法将重绘该节点 force_full_redraw:false,// 真值时redraw方法将重绘整棵树 redraw_timeout : false, // 默认状态信息,节点的信息数据state开启自定义 default_state:{ loaded:true, opened:false, selected:false, disabled:false } }; // 初始化时保存理想空节点"#"的id、parent、children、state // 加载节点过程中保存用户传入的节点数据信息,以树形节点的id作为属性 this._model.data[$.jstree.root]={ id:$.jstree.root,// 树节点的id,同时作为li的id parent:null,// 直系父节点 parents:[],// 祖先节点,凭此可以获取树节点的层级 children:[],// 直系子节点 children_d:[],// 所有子孙节点 state:{loaded:false}// 树节点的状态 // li_attr 树节点li的属性,以树节点的id作为id属性 // a_attr 树节点a的属性 // text 显示文本 // icon 显示图标的url // original 保存用户传入的该节点的原始数据 }; this.element=$(el).addClass('jstree jstree-'+this._id); this.settings=options;// 哟欧股配置项 // this._data.core.select=[] 数组形式存储选中的节点 this._data.core.ready=false; this._data.core.loaded=false; this._data.core.rtl=(this.element.css("direction")==="rtl"); this.element[this._data.core.rtl ? 'addClass' : 'removeClass']("jstree-rtl"); this.element.attr('role','tree'); if( this.settings.core.multiple ){ this.element.attr('aria-multiselectable', true); } if( !this.element.attr('tabindex') ){ this.element.attr('tabindex','0'); } this.bind();// 绑定事件中包含init和loading事件,以此加载样式文件,显示隐藏虚线、图标、间行色 this.trigger("init");// this.bind()绑定事件后触发init事件 // $ele.addBack()将之前匹配的元素加入到当前元素中 // $ele.contents()获取ele的直接文本和注释节点子元素 // 获取触发节点内的li元素,保留注释节点 this._data.core.original_container_html=this.element.find(">ul>li").clone(true); this._data.core.original_container_html .find("li").addBack() .contents().filter(function(){// 保留文本节点,滤过注释节点 return this.nodeType===3 && (!this.nodeValue || /^\s+$/.test(this.nodeValue)); }) .remove(); // 显示加载中文本 this.element.html("<"+"ul class='jstree-container-ul jstree-children' role='group'><" +"li id='j"+this._id+"_loading' " +"class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'>" +"<i class='jstree-icon jstree-ocl'></i><a class='jstree-anchor' href='#'>" +"<i class='jstree-icon jstree-themeicon-hidden'></i>" +this.get_string("Loading ...")+"</a></li></ul>"); this.element.attr('aria-activedescendant','j'+this._id+'_loading'); // 树形组件li的高度 this._data.core.li_height=this.get_container_ul().children("li").first().height() || 24; this.trigger("loading");// 加载中文本显示后,树形节点插入前,触发loading事件 this.load_node($.jstree.root); }, // 销毁实例,清空web worker,keep_html参数决定是否清除节点内容 destroy:function(keep_html){ if( this._wrk ){ try{ window.URL.revokeObjectURL(this._wrk); this._wrk=null; }catch(ignore){ } } if( !keep_html ) this.element.empty(); this.teardown(); }, // 移除实例,清除节点的jstree相关样式 teardown:function(){ this.unbind(); this.element .removeClass('jstree') .removeData('jstree') .find("[class^='jstree']") .addBack() .attr("class", function(){ return this.className.replace(/jstree[^ ]*|$/ig,''); }); this.element=null; }, // 初始化时绑定事件,初始化过程中执行事件 bind:function(){ var word='', tout=null, was_click=0; this.element .on("dblclick.jstree",function(e){ if( e.target.tagName && e.target.tagName.toLowerCase()==="input" ) return true; // 清空选中文本 if( document.selection && document.selection.empty ){ document.selection.empty(); }else{ if( window.getSelection ){ var sel=window.getSelection(); try { sel.removeAllRanges(); sel.collapse(); }catch(ignore){ } } } }) .on("mousedown.jstree",$.proxy(function(e){ if( e.target===this.element[0] ){ e.preventDefault(); // prevent losing focus when clicking scroll arrows (FF, Chrome) was_click=+(new Date()); // ie does not allow to prevent losing focus } },this)) .on("mousedown.jstree", ".jstree-ocl", function (e) { e.preventDefault(); // prevent any node inside from losing focus when clicking the open/close icon }) // 切换节点的显示隐藏状况 .on("click.jstree", ".jstree-ocl", $.proxy(function (e){ this.toggle_node(e.target); }, this)) // this.settings.core.dblclick_toggle为真时,双击切换节点的显示隐藏状况 .on("dblclick.jstree", ".jstree-anchor", $.proxy(function(e){ if( e.target.tagName && e.target.tagName.toLowerCase()==="input" ) return true; if( this.settings.core.dblclick_toggle ) this.toggle_node(e.target); },this)) // 节点获得焦点 .on("click.jstree",".jstree-anchor",$.proxy(function(e){ e.preventDefault(); if( e.currentTarget!==document.activeElement ) $(e.currentTarget).focus(); this.activate_node(e.currentTarget,e); }, this)) .on('keydown.jstree','.jstree-anchor',$.proxy(function(e){ if( e.target.tagName && e.target.tagName.toLowerCase()==="input" ) return true; if( e.which!==32 && e.which!==13 && (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey) ) return true; var o=null; if( this._data.core.rtl ){ if( e.which===37 ){ e.which=39; }else if( e.which===39 ){ e.which=37; } } switch(e.which){ case 32:// 空格+ctrl键触发点击事件 if( e.ctrlKey ){ e.type="click"; $(e.currentTarget).trigger(e); } break; case 13:// enter键触发点击事件 e.type="click"; $(e.currentTarget).trigger(e); break; case 37:// left键,当前节点展开则关闭,否则父节点的a标签选中 e.preventDefault(); if( this.is_open(e.currentTarget) ){ this.close_node(e.currentTarget); }else{ o=this.get_parent(e.currentTarget); if( o && o.id!==$.jstree.root ) this.get_node(o,true).children('.jstree-anchor').focus(); } break; case 38:// 前一个节点选中 e.preventDefault(); o=this.get_prev_dom(e.currentTarget); if( o && o.length ) o.children('.jstree-anchor').focus(); break; case 39:// right键,若节点折叠,展开后再选中;若节点已展开,则选中 e.preventDefault(); if( this.is_closed(e.currentTarget) ){ this.open_node(e.currentTarget,function(o){ this.get_node(o,true).children('.jstree-anchor').focus(); }); }else if( this.is_open(e.currentTarget) ){ o=this.get_node(e.currentTarget, true).children('.jstree-children')[0]; if( o ) $(this._firstChild(o)).children('.jstree-anchor').focus(); } break; case 40:// down键,下一个子节点选中 e.preventDefault(); o=this.get_next_dom(e.currentTarget); if( o && o.length ) o.children('.jstree-anchor').focus(); break; case 106:// aria defines * on numpad as open_all - not very common this.open_all(); break; case 36: // home e.preventDefault(); o=this._firstChild(this.get_container_ul()[0]); if( o ) $(o).children('.jstree-anchor').filter(':visible').focus(); break; case 35:// end键,最后一个可见的节点选中 e.preventDefault(); this.element.find('.jstree-anchor').filter(':visible').last().focus(); break; case 113:// f2键开启编辑功能 e.preventDefault(); this.edit(e.currentTarget); break; default: break; } }, this)) // 加载完成首个树形节点记录焦点标志,或者根据this.settings.core.expand_selected_onload展开选中状态的子节点 .on("load_node.jstree",$.proxy(function(e,data){ if( data.status ){ if( data.node.id===$.jstree.root && !this._data.core.loaded ){ this._data.core.loaded=true; if( this._firstChild(this.get_container_ul()[0]) ){ this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id); } this.trigger("loaded"); } if( !this._data.core.ready ){ setTimeout($.proxy(function(){ if( this.element && !this.get_container_ul().find('.jstree-loading').length ){ this._data.core.ready=true; if( this._data.core.selected.length ){ if( this.settings.core.expand_selected_onload ){ var tmp=[], i, j; for( i=0, j=this._data.core.selected.length; i<j; i++ ){ tmp=tmp.concat(this._model.data[this._data.core.selected[i]].parents); } tmp=$.vakata.array_unique(tmp); for( i=0, j=tmp.length; i<j; i++ ){ this.open_node(tmp[i],false,0); } } this.trigger('changed',{'action':'ready','selected':this._data.core.selected}); } this.trigger("ready"); } },this),0); } } }, this)) // quick searching when the tree is focused .on('keypress.jstree', $.proxy(function (e) { if(e.target.tagName && e.target.tagName.toLowerCase() === "input") { return true; } if(tout) { clearTimeout(tout); } tout = setTimeout(function () { word = ''; }, 500); var chr = String.fromCharCode(e.which).toLowerCase(), col = this.element.find('.jstree-anchor').filter(':visible'), ind = col.index(document.activeElement) || 0, end = false; word += chr; // match for whole word from current node down (including the current node) if(word.length > 1) { col.slice(ind).each($.proxy(function (i, v) { if($(v).text().toLowerCase().indexOf(word) === 0) { $(v).focus(); end = true; return false; } }, this)); if(end) { return; } // match for whole word from the beginning of the tree col.slice(0, ind).each($.proxy(function (i, v) { if($(v).text().toLowerCase().indexOf(word) === 0) { $(v).focus(); end = true; return false; } }, this)); if(end) { return; } } // list nodes that start with that letter (only if word consists of a single char) if(new RegExp('^' + chr.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '+$').test(word)) { // search for the next node starting with that letter col.slice(ind + 1).each($.proxy(function (i, v) { if($(v).text().toLowerCase().charAt(0) === chr) { $(v).focus(); end = true; return false; } }, this)); if(end) { return; } // search from the beginning col.slice(0, ind + 1).each($.proxy(function (i, v) { if($(v).text().toLowerCase().charAt(0) === chr) { $(v).focus(); end = true; return false; } }, this)); if(end) { return; } } }, this)) // THEME RELATED .on("init.jstree", $.proxy(function (){ var s=this.settings.core.themes; this._data.core.themes.dots=s.dots;// 是否显示虚线 this._data.core.themes.stripes=s.stripes;// 是否显示间行色 this._data.core.themes.icons=s.icons;// 是否显示图标 this.set_theme(s.name || "default",s.url);// 加载样式文件 this.set_theme_variant(s.variant);// 更新主题变量相关样式信息 },this)) .on("loading.jstree", $.proxy(function (){// 显示或隐藏虚线、图表、间行色 this[this._data.core.themes.dots ? "show_dots" : "hide_dots"](); this[this._data.core.themes.icons ? "show_icons" : "hide_icons"](); this[this._data.core.themes.stripes ? "show_stripes" : "hide_stripes"](); }, this)) .on('blur.jstree', '.jstree-anchor', $.proxy(function (e) { this._data.core.focused = null; $(e.currentTarget).filter('.jstree-hovered').mouseleave(); this.element.attr('tabindex', '0'); }, this)) .on('focus.jstree','.jstree-anchor',$.proxy(function(e){ var tmp=this.get_node(e.currentTarget); if( tmp && tmp.id ) this._data.core.focused=tmp.id; this.element.find('.jstree-hovered').not(e.currentTarget).mouseleave(); $(e.currentTarget).mouseenter(); this.element.attr('tabindex', '-1'); }, this)) // 获得焦点 .on('focus.jstree',$.proxy(function(){ if( +(new Date())-was_click>500 && !this._data.core.focused ){ was_click=0; var act=this.get_node(this.element.attr('aria-activedescendant'),true); if( act ) act.find('> .jstree-anchor').focus(); } }, this)) // 鼠标移入,执行hover_node方法,呈现悬停效果 .on('mouseenter.jstree', '.jstree-anchor',$.proxy(function(e){ this.hover_node(e.currentTarget); }, this)) // 鼠标移出,执行dehover_node方法,移除悬停效果 .on('mouseleave.jstree', '.jstree-anchor', $.proxy(function (e) { this.dehover_node(e.currentTarget); }, this)); }, // 解绑jstree事件命名空间下的所有事件,同时document对象也解绑当前实例的所有事件 unbind:function(){ this.element.off('.jstree'); $(document).off('.jstree-'+this._id); }, // 触发ev事件,传入的数据data中包含instance属性为当前实例this trigger:function(ev,data){ if( !data ) data={}; data.instance=this; this.element.triggerHandler(ev.replace('.jstree','')+'.jstree',data); }, // 触发元素,实例包裹元素 get_container:function (){ return this.element; }, // 树形组件的顶层元素.jstree-children,作为触发元素的子节点创建 get_container_ul : function () { return this.element.children(".jstree-children").first(); }, // 从传参options中获取用户配置的文案,函数或对象形式 get_string:function (key){ var a=this.settings.core.strings; if( $.isFunction(a) ) return a.call(this, key); if( a && a[key] ) return a[key]; return key; }, // 获取首个子节点 _firstChild:function (dom){ dom=dom ? dom.firstChild : null; while( dom!==null && dom.nodeType!==1 ){ dom=dom.nextSibling; } return dom; }, // 获取下一个兄弟节点 _nextSibling:function (dom){ dom=dom ? dom.nextSibling : null; while( dom!==null && dom.nodeType!==1 ){ dom=dom.nextSibling; } return dom; }, // 获取上一个兄弟节点 _previousSibling:function (dom){ dom = dom ? dom.previousSibling : null; while( dom!==null && dom.nodeType!==1 ){ dom=dom.previousSibling; } return dom; }, // as_dom为真获取树形子节点.jstree-node或者触发元素this.element,为否获取树形节点数据 // obj传入"#"获取触发元素this.element,或者通过jquery元素、dom元素、id获取子节点 // 也可以是树形节点jstree-node的子节点,或者节点数据再通过id获取 get_node:function (obj,as_dom){ if( obj && obj.id ){ obj=obj.id; } var dom; try { if( this._model.data[obj] ){ obj=this._model.data[obj]; }else if( typeof obj==="string" && this._model.data[obj.replace(/^#/, '')] ){ obj=this._model.data[obj.replace(/^#/,'')]; }else if( typeof obj==="string" && (dom=$('#'+obj.replace($.jstree.idregex,'\\$&'),this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')] ){ obj=this._model.data[dom.closest('.jstree-node').attr('id')]; }else if( (dom=$(obj,this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')] ){ obj=this._model.data[dom.closest('.jstree-node').attr('id')]; }else if( (dom=$(obj, this.element)).length && dom.hasClass('jstree') ){ obj=this._model.data[$.jstree.root]; }else{ return false; } if( as_dom ){ obj=obj.id===$.jstree.root ? this.element : $('#'+obj.id.replace($.jstree.idregex,'\\$&'), this.element); } return obj; }catch (ex){return false;} }, // 获取祖先节点的路径,glue是否以字符串形式输出,ids以节点id或文本text形式输出 get_path:function(obj,glue,ids){ obj=obj.parents ? obj : this.get_node(obj); if( !obj || obj.id===$.jstree.root || !obj.parents ){ return false; } var i, j, p=[]; p.push(ids ? obj.id : obj.text); for( i=0, j=obj.parents.length; i<j; i++ ){ p.push(ids ? obj.parents[i] : this.get_text(obj.parents[i])); } p=p.reverse().slice(1); return glue ? p.join(glue) : p; }, // 获取可见的第一个子节点或者可见兄弟树形节点,strict为真时只获取下一个兄弟节点,不一定是树形节点 // 树形子节点为数据顺序的后一个 get_next_dom:function(obj,strict){ var tmp; obj=this.get_node(obj, true); if( obj[0]===this.element[0] ){// 触发元素获取第一个可见的子节点 tmp=this._firstChild(this.get_container_ul()[0]); while( tmp && tmp.offsetHeight===0 ){// offsetHeight判断可见性 tmp=this._nextSibling(tmp); } return tmp ? $(tmp) : false; } if( !obj || !obj.length ) return false; if( strict ){ tmp=obj[0]; do{ tmp=this._nextSibling(tmp); }while( tmp && tmp.offsetHeight===0 ); return tmp ? $(tmp) : false; } if( obj.hasClass("jstree-open") ){ tmp=this._firstChild(obj.children('.jstree-children')[0]); while( tmp && tmp.offsetHeight===0 ){ tmp=this._nextSibling(tmp); } if( tmp!==null ) return $(tmp); } tmp=obj[0]; do{ tmp=this._nextSibling(tmp); }while( tmp && tmp.offsetHeight===0 ); if( tmp!==null ) return $(tmp); return obj.parentsUntil(".jstree",".jstree-node").nextAll(".jstree-node:visible").first(); }, // 获取可见的前一个树形节点的最后一个子节点或者可见的前一个树形节点,strict为真时只获取上一个兄弟节点,不一定是树形节点 // 树形子节点为数据顺序的前一个 get_prev_dom:function(obj,strict){ var tmp; obj=this.get_node(obj,true); if( obj[0]===this.element[0] ){// 触发元素获取最后一个可见的子节点 tmp=this.get_container_ul()[0].lastChild; while( tmp && tmp.offsetHeight===0 ){ tmp=this._previousSibling(tmp); } return tmp ? $(tmp) : false; } if( !obj || !obj.length ) return false; if( strict ){ tmp=obj[0]; do{ tmp=this._previousSibling(tmp); }while( tmp && tmp.offsetHeight===0 ); return tmp ? $(tmp) : false; } tmp=obj[0]; do{ tmp=this._previousSibling(tmp); }while( tmp && tmp.offsetHeight===0 ); if( tmp!==null ){ obj=$(tmp); while( obj.hasClass("jstree-open") ){ obj=obj.children(".jstree-children").first().children(".jstree-node:visible:last"); } return obj; } tmp=obj[0].parentNode.parentNode; return tmp && tmp.className && tmp.className.indexOf('jstree-node')!==-1 ? $(tmp) : false; }, // 获取父节点的id get_parent:function(obj){ obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; return obj.parent; }, // 以jquery对象形式获取树形子节点jstree-node get_children_dom:function(obj){ obj=this.get_node(obj,true); if( obj[0]===this.element[0] ) return this.get_container_ul().children(".jstree-node"); if( !obj || !obj.length ) return false; return obj.children(".jstree-children").children(".jstree-node"); }, // 未曾加载或者含有子节点 is_parent:function(obj){ obj=this.get_node(obj); return obj && (obj.state.loaded===false || obj.children.length>0); }, // 是否加载 is_loaded:function(obj){ obj=this.get_node(obj); return obj && obj.state.loaded; }, // 加载中 is_loading:function(obj){ obj=this.get_node(obj); return obj && obj.state && obj.state.loading; }, // 是否展开 is_open:function(obj){ obj=this.get_node(obj); return obj && obj.state.opened; }, // 未加载且折叠,或有子节点且折叠 is_closed:function(obj){ obj=this.get_node(obj); return obj && this.is_parent(obj) && !obj.state.opened; }, // 末梢子节点,不作为父节点 is_leaf:function (obj){ return !this.is_parent(obj); }, // obj为数组时,调用_load_nodes,否则在obj.state.loaded为真值时调用_load_node重新加载节点 // 加载成功或失败时,改变节点的数据属性和样式,触发load_node事件,执行回调函数 load_node:function(obj,callback){ var k, l, i, j, c; if( $.isArray(obj) ){ this._load_nodes(obj.slice(),callback); return true; } obj=this.get_node(obj); if( !obj ){ if( callback ) callback.call(this,obj,false); return false; } if( obj.state.loaded ){ obj.state.loaded=false; for( i=0, j=obj.parents.length; i<j; i++ ){// 祖先节点的children_d属性移除当前节点的子孙 this._model.data[obj.parents[i]].children_d=$.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function(v){ return $.inArray(v,obj.children_d)===-1; } ); } for( k=0, l=obj.children_d.length; k<l; k++ ){// this._model.data移除当前节点的子孙 if(this._model.data[obj.children_d[k]].state.selected) c=true; delete this._model.data[obj.children_d[k]]; } if( c ){// this._data.core.selected滤除当前节点的子孙 this._data.core.selected=$.vakata.array_filter(this._data.core.selected, function (v) { return $.inArray(v, obj.children_d)===-1; }); } obj.children=[]; obj.children_d=[]; if( c ) this.trigger('changed',{'action':'load_node','node':obj,'selected':this._data.core.selected}); } obj.state.failed=false; obj.state.loading=true; this.get_node(obj,true).addClass("jstree-loading").attr('aria-busy',true); this._load_node(obj,$.proxy(function(status){ // 加载成功或失败时,改变节点的数据属性和样式,触发load_node事件,执行回调函数 obj=this._model.data[obj.id]; obj.state.loading=false; obj.state.loaded=status; obj.state.failed=!obj.state.loaded; var dom=this.get_node(obj,true), i=0, j=0, m=this._model.data, has_children=false; for( i=0, j=obj.children.length; i<j; i++ ){ if( m[obj.children[i]] && !m[obj.children[i]].state.hidden ){ has_children=true; break; } } if( obj.state.loaded && dom && dom.length ){ dom.removeClass('jstree-closed jstree-open jstree-leaf'); if ( !has_children ){ dom.addClass('jstree-leaf'); }else{ if( obj.id!=='#' ){ dom.addClass(obj.state.opened ? 'jstree-open' : 'jstree-closed'); } } } dom.removeClass("jstree-loading").attr('aria-busy',false); this.trigger('load_node',{"node":obj,"status":status}); if( callback ){ callback.call(this,obj,status); } },this)); return true; }, // 未加载或未曾加载失败时或强制加载时,调用load_node加载节点,加载失败或成功触发callback回调 _load_nodes:function(nodes,callback,is_callback,force_reload){ var r=true, c=function(){this._load_nodes(nodes,callback,true);}, m=this._model.data, i, j, tmp=[]; for( i=0, j=nodes.length; i<j; i++ ){ if( m[nodes[i]] && ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || (!is_callback && force_reload) ) ){ if( !this.is_loading(nodes[i]) ) this.load_node(nodes[i],c); r=false; } } if( r ){// 所有nodes均加载或数据未定义或加载失败等执行 for( i=0, j=nodes.length; i<j; i++ ){ if( m[nodes[i]] && m[nodes[i]].state.loaded ) tmp.push(nodes[i]); } if( callback && !callback.done ){ callback.call(this,tmp); callback.done=true; } } }, // 调用_load_nodes方法加载节点及其子节点,加载完成递归调用load_all方法触发回调callback和load_all事件 load_all:function(obj,callback){ if( !obj ) obj=$.jstree.root; obj=this.get_node(obj); if( !obj ) return false; var to_load=[], m=this._model.data, c=m[obj.id].children_d, i,j; if( obj.state && !obj.state.loaded ) to_load.push(obj.id); for( i=0, j=c.length; i<j; i++ ){ if( m[c[i]] && m[c[i]].state && !m[c[i]].state.loaded ) to_load.push(c[i]); } if( to_load.length ){ this._load_nodes(to_load,function(){ this.load_all(obj,callback);// 触发回调callback和load_all事件的需要 }); }else{ if( callback ) callback.call(this, obj); this.trigger('load_all',{"node":obj}); } }, // load_all、_load_nodes、load_node最终通过调用_load_node方法加载子节点 // 通过用户配置数据this.settings.core.data调用_append_html_data或_append_json_data方法,调用redraw方法绘制节点 // this.settings.core.data为字符串、数组、普通对象只允许绘制整棵树,其余ajax、函数可以绘制部分 _load_node:function (obj, callback){ var s=this.settings.core.data,t; var notTextOrCommentNode = function notTextOrCommentNode () { return this.nodeType !== 3 && this.nodeType !== 8; }; // 没有设置数据时用原始html填充触发元素 if( !s ){ if( obj.id===$.jstree.root ){ return this._append_html_data(obj,this._data.core.original_container_html.clone(true),function(status){ callback.call(this,status); }); }else{ return callback.call(this,false); } } // 用户设置data为函数时,执行并获取html文本或json数据,调用_append_html_data或_append_json_data方法 if( $.isFunction(s) ){ return s.call(this,obj,$.proxy(function(d){ if( d===false ){ callback.call(this,false); }else{ this[typeof d==='string' ? '_append_html_data' : '_append_json_data'](obj,typeof d==='string' ? $($.parseHTML(d)).filter(notTextOrCommentNode) : d, function(status){ callback.call(this,status); } ); } },this)); } if( typeof s==='object' ){ // 用户设置data带url时,远程ajax获取数据,调用_append_html_data或_append_json_data方法 if( s.url ){ s=$.extend(true,{},s); if( $.isFunction(s.url) ) s.url=s.url.call(this,obj);// ajax请求url if( $.isFunction(s.data) ) s.data=s.data.call(this,obj);// ajax请求发送的数据 return $.ajax(s) .done($.proxy(function(d,t,x){ var type=x.getResponseHeader('Content-Type'); // 返回json数据,调用_append_json_data方法 if( (type && type.indexOf('json')!==-1) || typeof d==="object" ){ return this._append_json_data(obj,d,function(status){ callback.call(this,status); }); } // 返回html,调用_append_html_data方法 if( (type && type.indexOf('html')!==-1) || typeof d==="string" ){ return this._append_html_data(obj, $($.parseHTML(d)).filter(notTextOrCommentNode), function(status){ callback.call(this,status); } ); } // ajax请求出错,设置core.error函数抛出错误 this._data.core.last_error={'error':'ajax','plugin':'core','id':'core_04','reason':'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : x }) }; this.settings.core.error.call(this,this._data.core.last_error); return callback.call(this, false); }, this)) .fail($.proxy(function(f){ callback.call(this,false); this._data.core.last_error={'error':'ajax','plugin':'core','id':'core_04','reason':'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : f }) }; this.settings.core.error.call(this,this._data.core.last_error); }, this)); } // 用户配置data数据为普通对象或数组时,只接受调用_append_json_data绘制整棵树,否则可以抛出错误 t=( $.isArray(s) || $.isPlainObject(s) ) ? JSON.parse(JSON.stringify(s)) : s; if( obj.id===$.jstree.root ){ return this._append_json_data(obj,t,function(status){ callback.call(this,status); }); }else{ this._data.core.last_error={'error':'nodata','plugin':'core','id':'core_05','reason':'Could not load node','data':JSON.stringify({ 'id' : obj.id }) }; this.settings.core.error.call(this,this._data.core.last_error); return callback.call(this, false); } } // 用户配置data数据为字符串时,只接受调用_append_html_data绘制整棵树,否则可以抛出错误 if( typeof s==='string' ){ if( obj.id===$.jstree.root ){ return this._append_html_data(obj,$($.parseHTML(s)).filter(notTextOrCommentNode),function(status){ callback.call(this,status); }); }else{ this._data.core.last_error={'error':'nodata','plugin':'core','id':'core_06','reason':'Could not load node','data':JSON.stringify({ 'id' : obj.id }) }; this.settings.core.error.call(this,this._data.core.last_error); return callback.call(this,false); } } return callback.call(this,false); }, // 将已改变节点的id添加到this._model.changed,可调用this.redraw方法重绘该节点 _node_changed:function(obj){ obj=this.get_node(obj); if( obj ) this._model.changed.push(obj.id); }, // 获取用户通过html配置的节点数据存储到this._model.data中,调用this.redraw重绘部分或整棵树 _append_html_data:function(dom,data,cb){ dom=this.get_node(dom); dom.children=[]; dom.children_d=[]; var dat=data.is('ul') ? data.children() : data, par=dom.id,// 通过html插入节点的父节点 chd=[],// 直系子节点 dpc=[],// 所有字段节点 m=this._model.data,// 用户配置html配置的节点数据获取更新到this._model.data中 p=m[par], s=this._data.core.selected.length, tmp, i, j; dat.each($.proxy(function(i,v){ tmp=this._parse_model_from_html($(v),par,p.parents.concat()); if( tmp ){ chd.push(tmp); dpc.push(tmp); if( m[tmp].children_d.length ) dpc=dpc.concat(m[tmp].children_d); } },this)); p.children=chd; p.children_d=dpc; for( i=0, j=p.parents.length; i<j; i++ ){ m[p.parents[i]].children_d=m[p.parents[i]].children_d.concat(dpc); } this.trigger('model', { "nodes":dpc, 'parent':par }); if( par!==$.jstree.root ){ this._node_changed(par); this.redraw(); }else{ this.get_container_ul().children('.jstree-initial-node').remove(); this.redraw(true); } if( this._data.core.selected.length!==s ){ this.trigger('changed',{'action':'model','selected':this._data.core.selected}); } cb.call(this,true); }, // 更新this._data.core.selected选中项,this._model.data转化后的节点数据 // 调用redraw方法重绘节点,触发model、changed事件 // dom为插入元素,data为传入数据,sb为回调函数 _append_json_data:function (dom,data,cb,force_processing){ if( this.element===null ) return; dom=this.get_node(dom);// jquery形式获取触发元素或jstree-node节点 dom.children=[]; dom.children_d=[]; if( data.d ){ data=data.d; if( typeof data==="string" ) data=JSON.parse(data); } if( !$.isArray(data) ) data=[data]; var w=null, args={ 'df':this._model.default_state,// 默认state信息 'dat':data,// 用户配置的数据,未转化前 'par':dom.id,// 插入目标节点的id 'm':this._model.data,// 转化后存储的节点数据 't_id':this._id,// 已创建jstree实例的个数 't_cnt':this._cnt,// 初始化时为0,节点的个数 'sel':this._data.core.selected// 数组形式包含选中的节点 }, // 非window.Worker方法调用时,参数data即args func=function(data,undefined){ if( data.data ) data=data.data; var dat=data.dat,// 用户配置的节点数据 par=data.par,// dom元素的id,作为父节点 chd=[],// 存储直系子节点 dpc=[],// 存储所有子孙节点 add=[],// 缓存选中的节点id df=data.df,// 默认state信息 t_id=data.t_id,// 已创建jstree实例的个数 t_cnt=data.t_cnt,// 初始化时为0,树形节点的个数 m=data.m,// 转化后的节点数据 p=m[par],// 父节点的数据 sel=data.sel,// 用于更新this._data.core.selected选中的节点 tmp,i,j,rslt, // 节点数据设置父节点的情况下,转化用户配置的节点数据,更新_data.core.selected及_data.core.data // 参数d为节点数据,p为直系父节点,ps为祖先节点 parse_flat=function (d,p,ps){ if( !ps ){ ps=[]; }else{ ps=ps.concat(); } if( p ) ps.unshift(p); var tid=d.id.toString(), i, j, c, e, tmp={ id:tid,// 节点id text:d.text || '',// 节点文本 icon:d.icon !== undefined ? d.icon : true,// 节点图标 parent:p,// 节点直系父节点id parents:ps,// 节点的祖先节点 children:d.children || [],// 节点的直系子节点 children_d:d.children_d || [],// 节点的子孙节点 data:d.data,// 节点附加的数据 state:{ },// 节点的状态信息 li_attr:{ id : false },// 节点内部li标签的dom属性 a_attr:{ href : '#' },// 节点内部a标签的dom属性 original:false// 节点的原始数据信息 }; for( i in df ){// 获取默认状态数据并赋值 if( df.hasOwnProperty(i) ) tmp.state[i]=df[i]; } if( d && d.data && d.data.jstree && d.data.jstree.icon ){ tmp.icon=d.data.jstree.icon; } if( tmp.icon===undefined || tmp.icon===null || tmp.icon==="" ){ tmp.icon=true; } if( d && d.data ){ tmp.data = d.data; if( d.data.jstree ){ for( i in d.data.jstree ){ if( d.data.jstree.hasOwnProperty(i) ){ tmp.state[i]=d.data.jstree[i]; } } } } if( d && typeof d.state==='object' ){ for ( i in d.state ){ if( d.state.hasOwnProperty(i) ) tmp.state[i]=d.state[i]; } } if( d && typeof d.li_attr==='object' ){ for ( i in d.li_attr ){ if( d.li_attr.hasOwnProperty(i) ) tmp.li_attr[i]=d.li_attr[i]; } } if( !tmp.li_attr.id ) tmp.li_attr.id=tid; if( d && typeof d.a_attr === 'object' ){ for ( i in d.a_attr ){ if( d.a_attr.hasOwnProperty(i) ) tmp.a_attr[i]=d.a_attr[i]; } } if( d && d.children && d.children===true ){ tmp.state.loaded=false; tmp.children=[]; tmp.children_d=[]; } m[tmp.id]=tmp; for( i=0, j=tmp.children.length; i<j; i++ ){ c=parse_flat(m[tmp.children[i]], tmp.id, ps); e=m[c]; tmp.children_d.push(c); if( e.children_d.length ){ tmp.children_d=tmp.children_d.concat(e.children_d); } } delete d.data; delete d.children; m[tmp.id].original=d; if( tmp.state.selected ) add.push(tmp.id); return tmp.id; }, // 转化用户传入的节点数据,存储在this._model.data中,add中以id缓存选中节点,返回id // 参数d为用户传入的节点数据,p为节点的parent,ps为节点的parents parse_nest=function(d,p,ps){ if( !ps ){ ps=[]; }else{ ps=ps.concat(); } if(p) ps.unshift(p); var tid=false, i, j, c, e, tmp; // 自动生成的树节点id do{ tid='j'+t_id+'_'+(++t_cnt); }while(m[tid]); tmp={ id:false,// 节点id text:typeof d==='string' ? d : '',// 节点文本 icon:typeof d==='object' && d.icon!==undefined ? d.icon : true,// 节点图标 parent:p,// 直系父节点 parents:ps,// 祖先节点 children:[],// 直系子节点 children_d:[],// 所有子孙节点 data:null, state:{},// 节点状态信息 li_attr:{id:false},// 节点内部li标签的dom属性 a_attr:{href:'#'},// 节点内部a标签的dom属性 original:false// 节点的原始 }; // 节点的初始化状态信息、id修正、text显示文本修正 for( i in df ){ if( df.hasOwnProperty(i) ) tmp.state[i]=df[i]; } if( d && d.id ) tmp.id=d.id.toString(); if( d && d.text ) tmp.text=d.text; // 传入数据d下data.jstree属性可设置icon、state相关信息,tmp作相应调整 if( d && d.data && d.data.jstree && d.data.jstree.icon ){ tmp.icon=d.data.jstree.icon; } if( tmp.icon===undefined || tmp.icon===null || tmp.icon==="" ){ tmp.icon=true; } if( d && d.data ){ tmp.data=d.data; if( d.data.jstree ){ for( i in d.data.jstree ){ if( d.data.jstree.hasOwnProperty(i) ) tmp.state[i]=d.data.jstree[i]; } } } if( d && typeof d.state==='object' ){ for ( i in d.state ){ if( d.state.hasOwnProperty(i) ) tmp.state[i]=d.state[i]; } } // d.li_attr赋予树节点li的属性,d.a_attr赋予a的属性,获取或添加id属性 if( d && typeof d.li_attr==='object' ){ for ( i in d.li_attr ){ if( d.li_attr.hasOwnProperty(i) ) tmp.li_attr[i]=d.li_attr[i]; } } if( tmp.li_attr.id && !tmp.id ) tmp.id=tmp.li_attr.id.toString(); if( !tmp.id ) tmp.id=tid; if( !tmp.li_attr.id ) tmp.li_attr.id=tmp.id; if( d && typeof d.a_attr==='object' ){ for ( i in d.a_attr ){ if( d.a_attr.hasOwnProperty(i) ) tmp.a_attr[i]=d.a_attr[i]; } } // 转化子孙节点的数据,并将直系子节点添加到children属性,子孙节点添加到children_d属性中 if( d && d.children && d.children.length ){ for( i=0, j=d.children.length; i<j; i++ ){ c=parse_nest(d.children[i],tmp.id,ps); e=m[c]; tmp.children.push(c); if( e.children_d.length ){ tmp.children_d=tmp.children_d.concat(e.children_d); } } tmp.children_d=tmp.children_d.concat(tmp.children); } if( d && d.children && d.children===true ){ tmp.state.loaded=false; tmp.children=[]; tmp.children_d=[]; } delete d.data; delete d.children; tmp.original=d; m[tmp.id]=tmp; if( tmp.state.selected ) add.push(tmp.id); return tmp.id; }; // 用户配置的json节点数据首个含parent及id,即为插入节点 if( dat.length && dat[0].id!==undefined && dat[0].parent!==undefined ){ // 获取用户配置的json数据,更新到this._modal.core.data中 for( i=0, j=dat.length; i<j; i++ ){ if( !dat[i].children ) dat[i].children=[]; m[dat[i].id.toString()]=dat[i]; } // 更新父节点的子节点树形children以及子孙节点属性children_d for( i=0, j=dat.length; i<j; i++ ){ m[dat[i].parent.toString()].children.push(dat[i].id.toString()); p.children_d.push(dat[i].id.toString()); } // 获取新添加的所有子节点 for( i=0, j=p.children.length; i<j; i++ ){ tmp=parse_flat(m[p.children[i]],par,p.parents.concat()); dpc.push(tmp); if( m[tmp].children_d.length ) dpc=dpc.concat(m[tmp].children_d); } for(i = 0, j = p.parents.length; i < j; i++) { m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc); } rslt={ 'cnt':t_cnt,// 树形节点的 'mod':m,// 转化后的节点数据this._model.data 'sel':sel,// 选中的节点_data.core.selected 'par':par,// 父节点的id 'dpc':dpc,// 添加的所有子节点 'add':add// 选中的节点 }; // data数据首项没有父节点parent或者没有id,以理想空节点为父节点 }else{ for( i=0, j=dat.length; i<j; i++ ){ // 初始化时par为触发元素的id,p.parents.concat()为空 tmp=parse_nest(dat[i],par,p.parents.concat()); if( tmp ){ chd.push(tmp); dpc.push(tmp); if( m[tmp].children_d.length ) dpc=dpc.concat(m[tmp].children_d); } } p.children=chd; p.children_d=dpc; for( i=0, j=p.parents.length; i<j; i++ ){ m[p.parents[i]].children_d=m[p.parents[i]].children_d.concat(dpc); } rslt={ 'cnt':t_cnt,// 树节点的个数 'mod':m,// 全部树节点的数据this._model.data 'sel':sel,// 选中的节点_data.core.selected 'par':par,// 父节点的id 'dpc':dpc,// 添加的所有子节点 'add':add// 选中的节点 }; } if( typeof window==='undefined' || typeof window.document==='undefined' ){ postMessage(rslt); }else{ return rslt; } }, // 更新this._data.core.selected选中项,this._model.data转化后的节点数据 // 调用redraw方法重绘节点,触发model、changed事件 rslt=function(rslt,worker){ if( this.element ===null ) return; this._cnt=rslt.cnt; var i, m=this._model.data; for ( i in m ){ if ( m.hasOwnProperty(i) && m[i].state && m[i].state.loading && rslt.mod[i] ){ rslt.mod[i].state.loading = true; } } this._model.data=rslt.mod; // breaks the reference in load_node - careful if( worker ){ var j, a=rslt.add, r=rslt.sel, s=this._data.core.selected.slice(); m=this._model.data; // if selection was changed while calculating in worker if( r.length!==s.length || $.vakata.array_unique(r.concat(s)).length!==r.length ){ for( i=0, j=r.length; i < j; i++ ){ if( $.inArray(r[i], a)===-1 && $.inArray(r[i], s)===-1 ){ m[r[i]].state.selected = false; } } for( i=0, j=s.length; i<j; i++ ){ if( $.inArray(s[i],r)===-1 ) m[s[i]].state.selected=true; } } } if( rslt.add.length ){ this._data.core.selected=this._data.core.selected.concat(rslt.add); } this.trigger('model',{"nodes":rslt.dpc,'parent':rslt.par}); if( rslt.par!==$.jstree.root ){ this._node_changed(rslt.par); this.redraw(); }else{ this.redraw(true); } if( rslt.add.length ){ this.trigger('changed',{'action':'model', 'selected':this._data.core.selected}); } cb.call(this, true); }; // window.Worker使js实现多线程,var worker=new window.Worker("backbone.js") // window.Blob文件对象直接赋值js脚本内容,var blob=window.Blob(jsContent) // window.URL.createObjectURL为执行文本生成url,var url=window.URL.createObjectURL(blob); // window.Worker(url)多线程后台执行脚本 if( this.settings.core.worker && window.Blob && window.URL && window.Worker ){ try { if( this._wrk===null ){ this._wrk=window.URL.createObjectURL( new window.Blob( ['self.onmessage='+func.toString()], {type:"text/javascript"} ) ); } if( !this._data.core.working || force_processing ){ this._data.core.working=true; w=new window.Worker(this._wrk); w.onmessage=$.proxy(function (e){ rslt.call(this, e.data, true); try { w.terminate(); w=null; } catch(ignore) { } if(this._data.core.worker_queue.length) { this._append_json_data.apply(this, this._data.core.worker_queue.shift()); } else { this._data.core.working = false; } }, this); if(!args.par) { if(this._data.core.worker_queue.length) { this._append_json_data.apply(this, this._data.core.worker_queue.shift()); } else { this._data.core.working = false; } } else { w.postMessage(args); } } else { this._data.core.worker_queue.push([dom, data, cb, true]); } } catch(e) { rslt.call(this, func(args), false); if(this._data.core.worker_queue.length) { this._append_json_data.apply(this, this._data.core.worker_queue.shift()); } else { this._data.core.working = false; } } }else{ rslt.call(this,func(args),false); } }, // 通过用户配置的html获取节点数据存入this._model.data,同时选中项添加到this._data.core.selected // 参数d待绘制节点的jQuery对象形式,p父节点,ps祖先节点 _parse_model_from_html:function(d,p,ps){ if( !ps ){ ps=[]; }else{ ps=[].concat(ps); } if( p ) ps.unshift(p); var c, e, m=this._model.data, data={ id:false, text:false, icon:true, parent:p, parents:ps, children:[], children_d:[], data:null, state:{ }, li_attr:{ id:false }, a_attr:{ href:'#' }, original:false }, i, tmp, tid; for( i in this._model.default_state ){ if( this._model.default_state.hasOwnProperty(i) ){ data.state[i]=this._model.default_state[i]; } } tmp=$.vakata.attributes(d,true); $.each(tmp,function(i,v){ v=$.trim(v); if( !v.length ) return true; data.li_attr[i]=v; if( i==='id' ) data.id=v.toString(); }); tmp=d.children('a').first(); if( tmp.length ){ tmp=$.vakata.attributes(tmp,true); $.each(tmp,function(i,v){ v=$.trim(v); if( v.length ) data.a_attr[i]=v; }); } tmp=d.children("a").first().length ? d.children("a").first().clone() : d.clone(); tmp.children("ins, i, ul").remove(); tmp=tmp.html(); tmp=$('<div />').html(tmp); data.text=this.settings.core.force_text ? tmp.text() : tmp.html(); tmp=d.data(); data.data=tmp ? $.extend(true, {}, tmp) : null; data.state.opened=d.hasClass('jstree-open'); data.state.selected=d.children('a').hasClass('jstree-clicked'); data.state.disabled=d.children('a').hasClass('jstree-disabled'); if( data.data && data.data.jstree ){ for( i in data.data.jstree ){ if( data.data.jstree.hasOwnProperty(i) ) data.state[i]=data.data.jstree[i]; } } tmp=d.children("a").children(".jstree-themeicon"); if( tmp.length ) data.icon=tmp.hasClass('jstree-themeicon-hidden') ? false : tmp.attr('rel'); if( data.state.icon!==undefined ) data.icon=data.state.icon; if( data.icon===undefined || data.icon===null || data.icon==="" ) data.icon = true; tmp=d.children("ul").children("li"); do{ tid='j'+this._id+'_'+(++this._cnt); }while(m[tid]); data.id=data.li_attr.id ? data.li_attr.id.toString() : tid; if( tmp.length ){ tmp.each($.proxy(function(i,v){ c=this._parse_model_from_html($(v),data.id,ps);// 递归转化子节点 e=this._model.data[c]; data.children.push(c); if( e.children_d.length ) data.children_d=data.children_d.concat(e.children_d); },this)); data.children_d=data.children_d.concat(data.children); }else{ if( d.hasClass('jstree-closed') ) data.state.loaded=false; } if( data.li_attr['class'] ){ data.li_attr['class']=data.li_attr['class'].replace('jstree-closed','').replace('jstree-open',''); } if( data.a_attr['class'] ){ data.a_attr['class']=data.a_attr['class'].replace('jstree-clicked','').replace('jstree-disabled',''); } m[data.id]=data; if( data.state.selected ) this._data.core.selected.push(data.id); return data.id; }, // 从json配置获取节点数据,更新this._model.data,返回节点的id _parse_model_from_flat_json:function(d,p,ps){ if( !ps ){ ps=[]; }else{ ps=ps.concat(); } if( p ) ps.unshift(p); var tid=d.id.toString(), m=this._model.data, df=this._model.default_state, i, j, c, e, tmp={ id:tid, text:d.text || '', icon:d.icon!==undefined ? d.icon : true, parent:p, parents:ps, children:d.children || [], children_d:d.children_d || [], data:d.data, state:{ }, li_attr:{ id:false }, a_attr:{ href:'#' }, original:false }; for( i in df ){ if( df.hasOwnProperty(i) ) tmp.state[i]=df[i]; } if( d && d.data && d.data.jstree && d.data.jstree.icon ){ tmp.icon = d.data.jstree.icon; } if( tmp.icon===undefined || tmp.icon===null || tmp.icon==="" ){ tmp.icon=true; } if( d && d.data ){ tmp.data=d.data; if( d.data.jstree ){ for( i in d.data.jstree ){ if( d.data.jstree.hasOwnProperty(i) ){ tmp.state[i]=d.data.jstree[i]; } } } } if( d && typeof d.state==='object' ){ for ( i in d.state ){ if( d.state.hasOwnProperty(i) ) tmp.state[i] = d.state[i]; } } if( d && typeof d.li_attr==='object' ){ for ( i in d.li_attr ){ if( d.li_attr.hasOwnProperty(i) ) tmp.li_attr[i]=d.li_attr[i]; } } if( !tmp.li_attr.id ) tmp.li_attr.id=tid; if( d && typeof d.a_attr === 'object' ){ for ( i in d.a_attr ){ if( d.a_attr.hasOwnProperty(i) ) tmp.a_attr[i]=d.a_attr[i]; } } if( d && d.children && d.children===true ){ tmp.state.loaded=false; tmp.children=[]; tmp.children_d=[]; } m[tmp.id]=tmp; for( i=0, j=tmp.children.length; i<j; i++ ){ c=this._parse_model_from_flat_json(m[tmp.children[i]],tmp.id,ps); e=m[c]; tmp.children_d.push(c); if( e.children_d.length ) tmp.children_d = tmp.children_d.concat(e.children_d); } delete d.data; delete d.children; m[tmp.id].original=d; if( tmp.state.selected ) this._data.core.selected.push(tmp.id); return tmp.id; }, // 从json配置获取节点数据,更新this._model.data,返回节点的id _parse_model_from_json:function(d,p,ps){ if( !ps ){ ps=[]; }else{ ps=ps.concat(); } if( p ) ps.unshift(p); var tid=false, i, j, c, e, m=this._model.data, df=this._model.default_state, tmp; do{ tid='j'+this._id+'_'+(++this._cnt); }while( m[tid] ); tmp={ id:false, text:typeof d==='string' ? d : '', icon:typeof d === 'object' && d.icon !== undefined ? d.icon : true, parent:p, parents:ps, children:[], children_d:[], data:null, state:{ }, li_attr:{ id:false }, a_attr:{ href:'#' }, original:false }; for( i in df ){ if( df.hasOwnProperty(i) ) tmp.state[i]=df[i]; } if( d && d.id ) tmp.id=d.id.toString(); if( d && d.text ) tmp.text=d.text; if( d && d.data && d.data.jstree && d.data.jstree.icon ){ tmp.icon=d.data.jstree.icon; } if( tmp.icon===undefined || tmp.icon===null || tmp.icon==="" ){ tmp.icon=true; } if( d && d.data ){ tmp.data=d.data; if( d.data.jstree ){ for( i in d.data.jstree ){ if( d.data.jstree.hasOwnProperty(i) ){ tmp.state[i]=d.data.jstree[i]; } } } } if( d && typeof d.state==='object' ) { for (i in d.state) { if( d.state.hasOwnProperty(i) ) tmp.state[i]=d.state[i]; } } if( d && typeof d.li_attr==='object' ) { for (i in d.li_attr) { if( d.li_attr.hasOwnProperty(i) ) tmp.li_attr[i]=d.li_attr[i]; } } if( tmp.li_attr.id && !tmp.id ) tmp.id=tmp.li_attr.id.toString(); if( !tmp.id ) tmp.id=tid; if( !tmp.li_attr.id ) tmp.li_attr.id=tmp.id; if( d && typeof d.a_attr==='object' ){ for ( i in d.a_attr ) { if( d.a_attr.hasOwnProperty(i) ) tmp.a_attr[i]=d.a_attr[i]; } } if( d && d.children && d.children.length ){ for( i=0, j=d.children.length; i<j; i++ ){ c=this._parse_model_from_json(d.children[i], tmp.id, ps); e=m[c]; tmp.children.push(c); if( e.children_d.length ){ tmp.children_d=tmp.children_d.concat(e.children_d); } } tmp.children_d = tmp.children_d.concat(tmp.children); } if( d && d.children && d.children===true ){ tmp.state.loaded=false; tmp.children=[]; tmp.children_d=[]; } delete d.data; delete d.children; tmp.original=d; m[tmp.id]=tmp; if( tmp.state.selected ) this._data.core.selected.push(tmp.id) return tmp.id; }, // 通过this.redraw_node重绘整棵树或树中被改变的部分,以及选中某个节点 _redraw:function(){ var nodes=this._model.force_full_redraw ? this._model.data[$.jstree.root].children.concat([]) : this._model.changed.concat([]), f=document.createElement('UL'), tmp, i, j, fe=this._data.core.focused; for( i=0, j=nodes.length; i<j; i++ ){ tmp=this.redraw_node(nodes[i], true, this._model.force_full_redraw); if( tmp && this._model.force_full_redraw ) f.appendChild(tmp); } if( this._model.force_full_redraw ){ f.className=this.get_container_ul()[0].className; f.setAttribute('role','group'); this.element.empty().append(f); } if( fe!==null ){ tmp=this.get_node(fe,true); if( tmp && tmp.length && tmp.children('.jstree-anchor')[0]!==document.activeElement ){ tmp.children('.jstree-anchor').focus(); }else{ this._data.core.focused=null; } } this._model.force_full_redraw=false; this._model.changed=[]; this.trigger('redraw',{"nodes":nodes }); }, // full为真时重绘整棵树,为否时根据this._model.changed重绘部分节点 redraw:function(full){ if( full ) this._model.force_full_redraw=true; this._redraw(); }, // 绘制子节点,特别当传参node.id==“#”时绘制整棵树 draw_children:function(node){ var obj=this.get_node(node), i=false, j=false, k=false, d=document; if( !obj ) return false; if( obj.id===$.jstree.root ) return this.redraw(true); node=this.get_node(node,true); if( !node || !node.length ) return false; node.children('.jstree-children').remove(); node=node[0]; if( obj.children.length && obj.state.loaded ){ k=d.createElement('UL'); k.setAttribute('role','group'); k.className='jstree-children'; for( i=0, j=obj.children.length; i < j; i++ ){ k.appendChild(this.redraw_node(obj.children[i],true,true)); } node.appendChild(k); } }, // 绘制节点,并插入父节点中,is_callback为真只获取节点 // 参数node待渲染的节点,deep子节点是否重绘,is_callback是否递归调用,force_render当父节点未展开强制渲染 // is_callback为真时只展开节点,获取node节点,_redraw方法中插入 redraw_node:function(node,deep,is_callback,force_render){ var obj=this.get_node(node),// 获取树形节点数据 par = false,// 获取父节点 ind=false,// 节点在父节点中的序号值 old = false,// 子节点无需渲染时,缓存原有子节点,通过ul标签创建jstree-children子节点 i=false, j=false,// 遍历所需 k=false,// 用于创建子节点jstree-children c='',// 用于拼接class d=document, m=this._model.data,// 用户传入的树形节点数据,经转化后 f=false,// 节点下的a标签是否获得焦点状态,重绘后依然获得焦点 s=false, tmp=null,// 用于获取或创建父节点下的jstree-children节点 t=0,l=0,// 缓存触发元素scrollTop、scrollLeft,当前节点的a锚点获得焦点后,更新触发元素scrollTop、scrollLeft has_children=false,// 用于判断节点是否有子节点,添加样式所需 last_sibling=false;// 用于判断节点是否父节点下的最末一个节点,用于添加样式 if( !obj ) return false; if( obj.id===$.jstree.root ) return this.redraw(true); deep=deep || obj.children.length===0; node=!document.querySelector ? document.getElementById(obj.id) : this.element[0].querySelector('#' +("0123456789".indexOf(obj.id[0])!==-1 ? '\\3'+obj.id[0]+' '+obj.id.substr(1).replace($.jstree.idregex,'\\$&') : obj.id.replace($.jstree.idregex,'\\$&')) ); // 分别处理页面中已存在或未存在节点时 if( !node ){ deep=true;// 当前节点尚未在页面上渲染时,deep赋值为真,渲染子节点 if( !is_callback ){ par=obj.parent!==$.jstree.root ? $('#'+obj.parent.replace($.jstree.idregex,'\\$&'), this.element)[0] : null; // 父节点未展开 if( par!==null && (!par || !m[obj.parent].state.opened) ) return false; ind=$.inArray(obj.id, par===null ? m[$.jstree.root].children : m[obj.parent].children); } }else{ node=$(node); if( !is_callback ){ par=node.parent().parent()[0]; if( par===this.element[0] ) par=null; ind=node.index(); } // 有子节点且子节点未渲染时,deep赋值为真,渲染子节点 if( !deep && obj.children.length && !node.children('.jstree-children').length ){ deep=true; } // 子节点无需渲染时,缓存原有子节点 if( !deep ) old=node.children('.jstree-children')[0]; f=node.children('.jstree-anchor')[0]===document.activeElement; node.remove(); } // 创建树形节点,赋予展开叠起、显示隐藏、id等属性 node=_node.cloneNode(true); c='jstree-node '; for( i in obj.li_attr ){ if( obj.li_attr.hasOwnProperty(i) ){ if( i==='id' ) continue; if( i!=='class' ){ node.setAttribute(i,obj.li_attr[i]); }else{ c+=obj.li_attr[i]; } } } if( !obj.a_attr.id ) obj.a_attr.id=obj.id+'_anchor'; node.setAttribute('aria-selected',!!obj.state.selected); node.setAttribute('aria-level',obj.parents.length); node.setAttribute('aria-labelledby',obj.a_attr.id); if( obj.state.disabled ) node.setAttribute('aria-disabled',true); // 没有子节点,影响样式相关配置 for( i=0, j=obj.children.length; i<j; i++ ){ if( !m[obj.children[i]].state.hidden ){ has_children=true; break; } } // 当前节点是否同一个父节点下最末一个显示的节点,影响样式相关配置 if( obj.parent!==null && m[obj.parent] && !obj.state.hidden ){ i=$.inArray(obj.id, m[obj.parent].children); last_sibling=obj.id; if( i!==-1 ){ i++; for( j=m[obj.parent].children.length; i<j; i++ ){ if(!m[m[obj.parent].children[i]].state.hidden){ last_sibling=m[obj.parent].children[i]; } if( last_sibling!==obj.id ){ break; } } } } if( obj.state.hidden ) c+=' jstree-hidden'; if( obj.state.loaded && !has_children ){ c+=' jstree-leaf'; }else{ c+=obj.state.opened && obj.state.loaded ? ' jstree-open' : ' jstree-closed'; node.setAttribute('aria-expanded',(obj.state.opened && obj.state.loaded)); } if( last_sibling===obj.id ) c+=' jstree-last'; node.id=obj.id; node.className=c; // 树节点a标签相关属性配置 c=( obj.state.selected ? ' jstree-clicked' : '')+( obj.state.disabled ? ' jstree-disabled' : ''); for( j in obj.a_attr ){ if( obj.a_attr.hasOwnProperty(j) ){ if( j==='href' && obj.a_attr[j]==='#' ) continue; if( j!=='class' ){ node.childNodes[1].setAttribute(j,obj.a_attr[j]); }else{ c+=' '+obj.a_attr[j]; } } } if( c.length ){ node.childNodes[1].className='jstree-anchor '+c; } // 图标相关属性配置 if( (obj.icon && obj.icon!==true) || obj.icon===false ) { if( obj.icon===false ){ node.childNodes[1].childNodes[0].className += ' jstree-themeicon-hidden'; }else if( obj.icon.indexOf('/')===-1 && obj.icon.indexOf('.')===-1 ){ node.childNodes[1].childNodes[0].className+=' '+obj.icon+' jstree-themeicon-custom'; }else{ node.childNodes[1].childNodes[0].style.backgroundImage='url("'+obj.icon+'")'; node.childNodes[1].childNodes[0].style.backgroundPosition='center center'; node.childNodes[1].childNodes[0].style.backgroundSize='auto'; node.childNodes[1].childNodes[0].className+=' jstree-themeicon-custom'; } } // 强制创建文本节点 if( this.settings.core.force_text ){ node.childNodes[1].appendChild(d.createTextNode(obj.text)); }else { node.childNodes[1].innerHTML+=obj.text; } // 渲染当前节点的子节点 if( deep && obj.children.length && (obj.state.opened || force_render) && obj.state.loaded ){ k=d.createElement('UL'); k.setAttribute('role','group'); k.className='jstree-children'; for( i=0, j=obj.children.length; i<j; i++ ){ k.appendChild(this.redraw_node(obj.children[i],deep,true)); } node.appendChild(k); } // 插入原有子节点 if( old ) node.appendChild(old); if( !is_callback ){ // 未曾有父节点时,par赋值为触发元素 if( !par ) par=this.element[0]; // 找到或创建父节点下的jstree-children,并插入node节点 for( i=0, j=par.childNodes.length; i<j; i++ ){ if( par.childNodes[i] && par.childNodes[i].className && par.childNodes[i].className.indexOf('jstree-children')!==-1 ){ tmp=par.childNodes[i]; break; } } if( !tmp ){ tmp=d.createElement('UL'); tmp.setAttribute('role', 'group'); tmp.className='jstree-children'; par.appendChild(tmp); } par=tmp; if( ind<par.childNodes.length ){ par.insertBefore(node,par.childNodes[ind]); }else{ par.appendChild(node); } if( f ){ t=this.element[0].scrollTop; l=this.element[0].scrollLeft; node.childNodes[1].focus(); this.element[0].scrollTop=t; this.element[0].scrollLeft=l; } } // 节点需展开未加载,调用open_node方法加载子节点,并实现显示动效 if( obj.state.opened && !obj.state.loaded ){ obj.state.opened=false; setTimeout($.proxy(function (){ this.open_node(obj.id,false,0); },this),0); } return node; }, // 加载或绘制子节点,实现子节点缓慢显示的动效,触发before_open、open_node、after_open事件 open_node:function(obj,callback,animation){ var t1, t2, d, t; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.open_node(obj[t1],callback,animation); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; animation=animation===undefined ? this.settings.core.animation : animation; // 已展开直接执行回调函数 if( !this.is_closed(obj) ){ if( callback ) callback.call(this, obj, false); return false; } // 加载中状态延时调用open_node方法,未加载调用load_node方法加载 if( !this.is_loaded(obj) ){ if( this.is_loading(obj) ){ return setTimeout($.proxy(function(){ this.open_node(obj,callback,animation); },this),500); } this.load_node(obj,function(o,ok){ return ok ? this.open_node(o,callback,animation) : (callback ? callback.call(this,o,false) : false); }); }else{ d=this.get_node(obj,true);// 次参true获取jQuery对象 t=this; if(d.length) { if( animation && d.children(".jstree-children").length ){ d.children(".jstree-children").stop(true,true);// 停止动画 } // 子节点尚未绘制,调用draw_children方法绘制子节点 if( obj.children.length && !this._firstChild(d.children('.jstree-children')[0]) ){ this.draw_children(obj); } if( !animation ){ this.trigger('before_open', {"node":obj}); d[0].className=d[0].className.replace('jstree-closed','jstree-open'); d[0].setAttribute("aria-expanded",true); }else{ this.trigger('before_open',{"node":obj}); d.children(".jstree-children").css("display","none").end() .removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded",true) .children(".jstree-children").stop(true,true) .slideDown(animation,function(){ this.style.display=""; if ( t.element ){ t.trigger("after_open",{"node":obj}); } }); } } obj.state.opened=true; if( callback ) callback.call(this,obj,true); if( !d.length ) this.trigger('before_open',{"node":obj}); this.trigger('open_node',{"node":obj}); if( !animation || !d.length ) this.trigger("after_open",{"node":obj}); return true; } }, // 以节点数据或id传入,展开该节点的所有父节点,返回该节点的jQuery对象形式 _open_to:function(obj){ obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; var i, j, p=obj.parents; for( i=0, j=p.length; i<j; i+=1 ){ if( i!==$.jstree.root ){ this.open_node(p[i],false,0); } } return $('#'+obj.id.replace($.jstree.idregex,'\\$&'),this.element); }, // 使用样式方法折叠节点,可以是多个节点(以id或节点数据),触发close_node、after_close事件 close_node:function(obj,animation){ var t1, t2, t, d; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.close_node(obj[t1],animation); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; if( this.is_closed(obj) ) return false; animation=animation===undefined ? this.settings.core.animation : animation; t=this; d=this.get_node(obj,true); obj.state.opened=false; this.trigger('close_node',{"node":obj}); if( !d.length ){ this.trigger("after_close",{"node":obj}); }else{ if( !animation ){ d[0].className=d[0].className.replace('jstree-open', 'jstree-closed'); d.attr("aria-expanded",false).children('.jstree-children').remove(); this.trigger("after_close",{"node":obj}); }else{ d.children(".jstree-children").attr("style","display:block !important").end() .removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded",false) .children(".jstree-children").stop(true,true).slideUp(animation,function(){ this.style.display=""; d.children('.jstree-children').remove(); if( t.element ) t.trigger("after_close",{"node":obj}); }); } } }, // 展开或折叠节点,调用open_node或close_node方法 toggle_node:function(obj){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.toggle_node(obj[t1]); } return true; } if( this.is_closed(obj) ){ return this.open_node(obj); } if( this.is_open(obj) ){ return this.close_node(obj); } }, // 展开所有节点(包含子节点),未加载(页面上未显现),改变节点数据,等到加载时展开节点 // 否则通过找到页面节点展开子孙节点,original_obj设置触发open_all事件的参数 open_all:function(obj,animation,original_obj){ if( !obj ) obj=$.jstree.root; obj=this.get_node(obj); if( !obj ) return false; var dom=obj.id===$.jstree.root ? this.get_container_ul() : this.get_node(obj,true), i, j, _this; if( !dom.length ){ for( i=0, j=obj.children_d.length; i<j; i++ ){ if( this.is_closed(this._model.data[obj.children_d[i]]) ){ this._model.data[obj.children_d[i]].state.opened=true; } } return this.trigger('open_all',{"node":obj}); } original_obj=original_obj || dom; _this=this; dom=this.is_closed(obj)?dom.find('.jstree-closed').addBack():dom.find('.jstree-closed'); dom.each(function(){ _this.open_node( this, function(node,status){ if( status && this.is_parent(node) ){ this.open_all(node,animation,original_obj); } }, animation || 0 ); }); if( original_obj.find('.jstree-closed').length===0 ){ this.trigger('open_all',{"node":this.get_node(original_obj)}); } }, // 用jQuery选择器找到所有jstree-open节点并调用close_node方法展开,更改节点数据state信息 close_all:function(obj,animation){ if( !obj ) obj=$.jstree.root; obj=this.get_node(obj); if( !obj ) return false; var dom=obj.id===$.jstree.root ? this.get_container_ul() : this.get_node(obj,true), _this=this, i, j; if( dom.length ){ dom=this.is_open(obj)?dom.find('.jstree-open').addBack():dom.find('.jstree-open'); $(dom.get().reverse()).each(function(){ _this.close_node(this, animation || 0); }); } for( i=0, j=obj.children_d.length; i<j; i++ ){ this._model.data[obj.children_d[i]].state.opened=false; } this.trigger('close_all',{"node":obj}); }, // 判断节点是否可选择disabled属性 is_disabled:function (obj){ obj=this.get_node(obj); return obj && obj.state && obj.state.disabled; }, // 设置节点可选择,触发enable_node事件 enable_node:function(obj){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.enable_node(obj[t1]); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; obj.state.disabled=false; this.get_node(obj,true).children('.jstree-anchor').removeClass('jstree-disabled').attr('aria-disabled',false); this.trigger('enable_node',{'node':obj}); }, // 设置节点不可选择,触发disable_node事件 disable_node:function(obj){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.disable_node(obj[t1]); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; obj.state.disabled=true; this.get_node(obj,true).children('.jstree-anchor').addClass('jstree-disabled').attr('aria-disabled', true); this.trigger('disable_node',{'node':obj}); }, // 判断节点是否隐藏 is_hidden:function(obj){ obj=this.get_node(obj); return obj.state.hidden===true; }, // 改变节点数据的hidden属性,重绘使其隐藏,skip_redraw跳过重绘,触发hide_node事件 hide_node:function(obj,skip_redraw){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.hide_node(obj[t1],true); } if ( !skip_redraw ) this.redraw(); return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; if( !obj.state.hidden ){ obj.state.hidden=true; this._node_changed(obj.parent); if( !skip_redraw ) this.redraw(); this.trigger('hide_node',{'node':obj}); } }, // 改变节点数据的hidden属性,重绘使其显示,skip_redraw跳过重绘,触发show_node事件 show_node:function(obj,skip_redraw){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.show_node(obj[t1],true); } if( !skip_redraw ) this.redraw(); return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; if( obj.state.hidden ){ obj.state.hidden=false; this._node_changed(obj.parent); if( !skip_redraw ) this.redraw(); this.trigger('show_node',{'node':obj}); } }, // 改变所有节点的hidden属性,重绘整棵树,skip_redraw跳过重绘,触发hide_all事件 hide_all:function(skip_redraw){ var i, m=this._model.data, ids=[]; for( i in m ){ if( m.hasOwnProperty(i) && i!==$.jstree.root && !m[i].state.hidden ){ m[i].state.hidden=true; ids.push(i); } } this._model.force_full_redraw=true; if( !skip_redraw ) this.redraw(); this.trigger('hide_all',{'nodes':ids}); return ids; }, // 改变所有节点的hidden属性,重绘整棵树,skip_redraw跳过重绘,触发hshow_all事件 show_all:function(skip_redraw){ var i, m=this._model.data, ids=[]; for( i in m ){ if( m.hasOwnProperty(i) && i!==$.jstree.root && m[i].state.hidden ){ m[i].state.hidden=false; ids.push(i); } } this._model.force_full_redraw=true; if( !skip_redraw ) this.redraw(); this.trigger('show_all',{'nodes':ids}); return ids; }, // 选中的撤销选中,未选中的选中,需要针对多选状况 activate_node:function(obj,e){ if( this.is_disabled(obj) ) return false; if( !e || typeof e!=='object' ) e={}; // ensure last_clicked is still in the DOM, make it fresh (maybe it was moved?) and make sure it is still selected, if not - make last_clicked the last selected node this._data.core.last_clicked=this._data.core.last_clicked && this._data.core.last_clicked.id!==undefined ? this.get_node(this._data.core.last_clicked.id) : null; if( this._data.core.last_clicked && !this._data.core.last_clicked.state.selected ){ this._data.core.last_clicked=null; } if( !this._data.core.last_clicked && this._data.core.selected.length ){ this._data.core.last_clicked=this.get_node(this._data.core.selected[this._data.core.selected.length-1]); } if( !this.settings.core.multiple || (!e.metaKey && !e.ctrlKey && !e.shiftKey) || (e.shiftKey && (!this._data.core.last_clicked || !this.get_parent(obj) || this.get_parent(obj) !== this._data.core.last_clicked.parent ) ) ){ if( !this.settings.core.multiple && (e.metaKey || e.ctrlKey || e.shiftKey) && this.is_selected(obj) ){ this.deselect_node(obj, false, e); }else { this.deselect_all(true); this.select_node(obj, false, false, e); this._data.core.last_clicked=this.get_node(obj); } }else{ if( e.shiftKey ){ var o=this.get_node(obj).id, l=this._data.core.last_clicked.id, p=this.get_node(this._data.core.last_clicked.parent).children, c=false, i, j; for( i=0, j=p.length; i<j; i+=1 ){ if( p[i]===o ) c=!c; if( p[i]===l ) c=!c; if( !this.is_disabled(p[i]) && (c || p[i]===o || p[i]===l) ){ if ( !this.is_hidden(p[i]) ) this.select_node(p[i],true,false,e); }else{ this.deselect_node(p[i],true,e); } } this.trigger('changed',{'action':'select_node','node':this.get_node(obj),'selected':this._data.core.selected, 'event' : e }); }else{ if( !this.is_selected(obj) ){ this.select_node(obj,false,false,e); }else{ this.deselect_node(obj,false,e); } } } this.trigger('activate_node',{'node':this.get_node(obj),'event':e}); }, // 添加悬停样式 hover_node:function(obj){ obj=this.get_node(obj, true); if( !obj || !obj.length || obj.children('.jstree-hovered').length ){ return false; } var o=this.element.find('.jstree-hovered'), t=this.element; if( o && o.length ) this.dehover_node(o); obj.children('.jstree-anchor').addClass('jstree-hovered'); this.trigger('hover_node', { 'node' : this.get_node(obj) }); setTimeout(function(){ t.attr('aria-activedescendant',obj[0].id); }, 0); }, // 移除悬停样式 dehover_node:function(obj){ obj=this.get_node(obj, true); if( !obj || !obj.length || !obj.children('.jstree-hovered').length ){ return false; } obj.children('.jstree-anchor').removeClass('jstree-hovered'); this.trigger('dehover_node', {'node':this.get_node(obj)}); }, // 改变节点的样式选中节点,更新this._data.core.selected,触发select_node、changed事件 // prevent_open为真时阻止父节点展开,supress_event为真时不触发changed事件 select_node:function(obj,supress_event,prevent_open,e){ var dom, t1, t2, th; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.select_node(obj[t1], supress_event, prevent_open, e); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; dom=this.get_node(obj, true); if( !obj.state.selected ){ obj.state.selected=true; this._data.core.selected.push(obj.id); if( !prevent_open ) dom=this._open_to(obj); if( dom && dom.length ){ dom.attr('aria-selected',true).children('.jstree-anchor').addClass('jstree-clicked'); } this.trigger('select_node',{'node':obj, 'selected':this._data.core.selected, 'event':e}); if( !supress_event ){ this.trigger('changed',{'action':'select_node', 'node':obj, 'selected':this._data.core.selected, 'event':e}); } } }, // 使节点处于不选中状态,this._data.core.selected移除节点,触发deselect_node事件 // supress_event为否时触发changed事件,为真时不触发 deselect_node:function(obj,supress_event,e){ var t1, t2, dom; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.deselect_node(obj[t1],supress_event,e); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; dom=this.get_node(obj,true); if( obj.state.selected ){ obj.state.selected=false; this._data.core.selected=$.vakata.array_remove_item(this._data.core.selected,obj.id); if( dom.length ){ dom.attr('aria-selected',false).children('.jstree-anchor').removeClass('jstree-clicked'); } this.trigger('deselect_node',{'node':obj, 'selected':this._data.core.selected, 'event':e}); if( !supress_event ){ this.trigger('changed',{'action':'deselect_node', 'node':obj, 'selected':this._data.core.selected, 'event':e }); } } }, // 使所有节点处于选中状态,重绘整棵树,触发select_all事件,supress_event为否时触发changed事件 select_all:function(supress_event){ var tmp=this._data.core.selected.concat([]), i, j; this._data.core.selected=this._model.data[$.jstree.root].children_d.concat(); for( i=0, j=this._data.core.selected.length; i<j; i++ ){ if( this._model.data[this._data.core.selected[i]] ){ this._model.data[this._data.core.selected[i]].state.selected=true; } } this.redraw(true); this.trigger('select_all',{'selected':this._data.core.selected}); if( !supress_event ){ this.trigger('changed',{'action':'select_all', 'selected':this._data.core.selected, 'old_selection':tmp}); } }, // 使所有节点处于不选中状态,重绘整棵树,触发deselect_all事件,supress_event为否时触发changed事件 deselect_all:function(supress_event){ var tmp=this._data.core.selected.concat([]), i, j; for( i=0, j=this._data.core.selected.length; i<j; i++ ){ if( this._model.data[this._data.core.selected[i]] ){ this._model.data[this._data.core.selected[i]].state.selected=false; } } this._data.core.selected=[]; this.element.find('.jstree-clicked').removeClass('jstree-clicked').parent().attr('aria-selected',false); this.trigger('deselect_all',{'selected':this._data.core.selected, 'node':tmp}); if( !supress_event ){ this.trigger('changed',{'action':'deselect_all', 'selected':this._data.core.selected, 'old_selection':tmp}); } }, // 节点是否被选中 is_selected:function(obj){ obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; return obj.state.selected; }, // full为真时以数组形式获取选中节点的全部数据,否时获取选中节点的id get_selected:function(full){ return full ? $.map(this._data.core.selected,$.proxy(function(i){return this.get_node(i);}, this)) : this._data.core.selected.slice(); }, // 获取顶层选中的节点(作为某节点的子节点就删除),full为真时返回节点的所有数据,为否时只返回id get_top_selected:function(full){ var tmp=this.get_selected(true), obj={}, i, j, k, l; for( i=0, j=tmp.length; i<j; i++ ){ obj[tmp[i].id]=tmp[i]; } for( i=0, j=tmp.length; i<j; i++ ){ for( k=0, l=tmp[i].children_d.length; k<l; k++ ){ if( obj[tmp[i].children_d[k]] ) delete obj[tmp[i].children_d[k]]; } } tmp=[]; for( i in obj ){ if( obj.hasOwnProperty(i) ) tmp.push(i); } return full ? $.map(tmp,$.proxy(function(i){return this.get_node(i);},this)) : tmp; }, // 获取选中状态的底层节点(通过是否有子节点判断),full为真时返回节点的所有数据,为否时只返回id get_bottom_selected:function(full){ var tmp=this.get_selected(true), obj=[], i, j; for( i=0, j=tmp.length; i<j; i++ ){ if( !tmp[i].children.length ) obj.push(tmp[i].id); } return full ? $.map(obj, $.proxy(function(i){return this.get_node(i);},this)) : obj; }, // 获取整棵树的展开节点id和选中节点id,以及触发元素的scrollLeft和scrollTop get_state:function(){ var state={ 'core':{ 'open':[], 'scroll':{ 'left':this.element.scrollLeft(), 'top':this.element.scrollTop() }, 'selected':[] } },i; for( i in this._model.data ){ if( this._model.data.hasOwnProperty(i) ){ if( i!==$.jstree.root ){ if( this._model.data[i].state.opened ) state.core.open.push(i); if( this._model.data[i].state.selected ) state.core.selected.push(i); } } } return state; }, // 设置整棵树的状态,展开选中节点和触发元素的scrollLeft、scrollTop,通过递归调用set_state逐步设置属性 // state.core针对主模块,state[else]针对插件,设置完成后执行回调,并触发set_state事件 set_state:function(state,callback){ if( state ){ if( state.core ){ var res, n, t, _this, i; if( state.core.open ){ if( !$.isArray(state.core.open) || !state.core.open.length ){ delete state.core.open; this.set_state(state,callback);// 一项state树形设置完成,递归调用set_state方法设置下一项state树形 }else { this._load_nodes(state.core.open,function(nodes){ this.open_node(nodes,false,0); delete state.core.open; this.set_state(state,callback); }); } return false; } if( state.core.scroll ){ if( state.core.scroll && state.core.scroll.left!==undefined ){ this.element.scrollLeft(state.core.scroll.left); } if( state.core.scroll && state.core.scroll.top!==undefined ){ this.element.scrollTop(state.core.scroll.top); } delete state.core.scroll; this.set_state(state,callback); return false; } if( state.core.selected ){ _this=this; this.deselect_all(); $.each(state.core.selected,function(i,v){ _this.select_node(v,false,true); }); delete state.core.selected; this.set_state(state,callback); return false; } for( i in state ){ if( state.hasOwnProperty(i) && i!=="core" && $.inArray(i,this.settings.plugins)===-1 ){ delete state[i]; } } if( $.isEmptyObject(state.core) ){ delete state.core; this.set_state(state,callback); return false; } } if( $.isEmptyObject(state) ){ state=null; if( callback ) callback.call(this); this.trigger('set_state'); return false; } return true; } return false; }, // 调用load_node方法重绘整棵树,this._model.data重新由this.setting.core.data生成,触发refresh事件 // forget_state为否时清空节点状态,有值时替换节点状态,否则不处理 refresh:function(skip_loading,forget_state){ this._data.core.state=forget_state===true ? {} : this.get_state(); if( forget_state && $.isFunction(forget_state) ){ this._data.core.state=forget_state.call(this, this._data.core.state); } this._cnt=0; this._model.data={}; this._model.data[$.jstree.root]={ id:$.jstree.root, parent:null, parents:[], children:[], children_d:[], state:{loaded:false} }; this._data.core.selected=[]; this._data.core.last_clicked=null; this._data.core.focused=null; var c=this.get_container_ul()[0].className; if( !skip_loading ){ this.element.html("<"+"ul class='"+c+"' role='group'><"+"li class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='treeitem' id='j"+this._id+"_loading'><i class='jstree-icon jstree-ocl'></i><"+"a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>" + this.get_string("Loading ...") + "</a></li></ul>"); this.element.attr('aria-activedescendant','j'+this._id+'_loading'); } this.load_node($.jstree.root,function(o,s){ if(s) { this.get_container_ul()[0].className=c; if( this._firstChild(this.get_container_ul()[0]) ){ this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id); } this.set_state($.extend(true,{},this._data.core.state),function(){ this.trigger('refresh'); }); } this._data.core.state=null; }); }, // 调用_load_nodes从this.setting.core.data中生成节点数据并插入文档 // 起先展开的节点添加到opened数组中,在回调中调用open_node将其展开,触发refresh_node事件 refresh_node:function(obj){ obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; var opened=[], to_load=[], s=this._data.core.selected.concat([]); to_load.push(obj.id); if( obj.state.opened===true ) opened.push(obj.id); this.get_node(obj,true).find('.jstree-open').each(function(){ to_load.push(this.id); opened.push(this.id); }); this._load_nodes(to_load,$.proxy(function(nodes){ this.open_node(opened,false,0); this.select_node(s); this.trigger('refresh_node',{'node':obj, 'nodes':nodes}); },this),false,true); }, // 设置节点的id,更新this._model.data、this._data.core.selected信息,更新dom元素属性等 set_id : function (obj, id) { obj=this.get_node(obj); if( !obj || obj.id=== $.jstree.root ) return false; var i, j, m=this._model.data, old=obj.id; id=id.toString(); m[obj.parent].children[$.inArray(obj.id,m[obj.parent].children)]=id; for( i=0, j=obj.parents.length; i<j; i++ ){ m[obj.parents[i]].children_d[$.inArray(obj.id, m[obj.parents[i]].children_d)]=id; } for( i=0, j=obj.children.length; i<j; i++ ){ m[obj.children[i]].parent=id; } for( i=0, j=obj.children_d.length; i<j; i++ ){ m[obj.children_d[i]].parents[$.inArray(obj.id, m[obj.children_d[i]].parents)]=id; } i=$.inArray(obj.id, this._data.core.selected); if( i!==-1 ) this._data.core.selected[i]=id; i=this.get_node(obj.id, true); if( i ){ i.attr('id',id); if( this.element.attr('aria-activedescendant')===obj.id ){ this.element.attr('aria-activedescendant',id); } } delete m[obj.id]; obj.id=id; obj.li_attr.id=id; m[id]=obj; this.trigger('set_id',{ "node":obj, "new":obj.id, "old":old }); return true; }, // 获取节点文本 get_text:function(obj){ obj=this.get_node(obj); return (!obj || obj.id===$.jstree.root) ? false : obj.text; }, // 设置节点数据的文本后,调用redraw_node方法重绘节点,触发set_text事件 set_text:function(obj,val){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.set_text(obj[t1],val); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; obj.text=val; if( this.get_node(obj, true).length ) this.redraw_node(obj.id); this.trigger('set_text',{ "obj":obj, "text":val }); return true; }, // 以json数据的形式返回节点数据,options设置哪些属性可忽略 // options.flat扁平化json数据返回,父子节点以数组的形式获取,否则为嵌套形式 get_json:function(obj,options,flat){ obj=this.get_node(obj || $.jstree.root); if( !obj ) return false; if( options && options.flat && !flat ) flat=[]; var tmp={ 'id':obj.id, 'text':obj.text, 'icon':this.get_icon(obj), 'li_attr':$.extend(true, {}, obj.li_attr), 'a_attr':$.extend(true, {}, obj.a_attr), 'state':{}, 'data':options && options.no_data ? false : $.extend(true, {}, obj.data) }, i, j; if( options && options.flat ){ tmp.parent=obj.parent; }else { tmp.children=[]; } if( !options || !options.no_state ){ for( i in obj.state ){ if( obj.state.hasOwnProperty(i) ){ tmp.state[i]=obj.state[i]; } } }else{ delete tmp.state; } if( options && options.no_li_attr ) delete tmp.li_attr; if( options && options.no_a_attr ) delete tmp.a_attr; if( options && options.no_id ){ delete tmp.id; if( tmp.li_attr && tmp.li_attr.id ){ delete tmp.li_attr.id; } if( tmp.a_attr && tmp.a_attr.id ){ delete tmp.a_attr.id; } } if( options && options.flat && obj.id!==$.jstree.root ) flat.push(tmp); if( !options || !options.no_children ){ for( i=0, j=obj.children.length; i<j; i++ ){ if( options && options.flat ){ this.get_json(obj.children[i], options, flat); }else{ tmp.children.push(this.get_json(obj.children[i], options)); } } } return options && options.flat ? flat : (obj.id===$.jstree.root ? tmp.children : tmp); }, // 创建子节点,par已存在的关系节点,node待创建节点的数据,pos可为before、after、insert、first、last // 调用_parse_model_from_json得到转化后的数据,redraw_node方法绘制改变的节点,触发create_node事件 create_node:function(par,node,pos,callback,is_loaded){ if( par===null ) par=$.jstree.root; par=this.get_node(par); if( !par ) return false; pos=pos===undefined ? "last" : pos; // 父节点未加载,create_node方法作为load_node方法的回调执行 if( !pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par) ){ return this.load_node(par, function(){ this.create_node(par,node,pos,callback,true); }); } if( !node ) node={ "text":this.get_string('New node') }; if( typeof node==="string" ) node={ "text":node }; if( node.text===undefined ) node.text = this.get_string('New node'); var tmp, dpc, i, j; if( par.id===$.jstree.root ){ if( pos==="before" ) pos="first"; if( pos==="after" ) pos="last"; } switch(pos){ case "before": tmp=this.get_node(par.parent); pos=$.inArray(par.id,tmp.children); par=tmp; break; case "after" : tmp=this.get_node(par.parent); pos=$.inArray(par.id, tmp.children)+1; par=tmp; break; case "inside": case "first": pos=0; break; case "last": pos=par.children.length; break; default: if( !pos ) pos=0; break; } if( pos>par.children.length ) pos=par.children.length; if( !node.id ) node.id=true; if( !this.check("create_node",node,par,pos) ){ this.settings.core.error.call(this, this._data.core.last_error); return false; } if( node.id===true ) { delete node.id; node=this._parse_model_from_json(node,par.id,par.parents.concat()); if( !node ) return false; tmp=this.get_node(node); dpc=[]; dpc.push(node); dpc=dpc.concat(tmp.children_d); this.trigger('model',{"nodes":dpc, "parent":par.id}); par.children_d=par.children_d.concat(dpc); for( i=0, j=par.parents.length; i<j; i++ ){ this._model.data[par.parents[i]].children_d=this._model.data[par.parents[i]].children_d.concat(dpc); } node=tmp; tmp=[]; for( i=0, j=par.children.length; i<j; i++ ){ tmp[i>=pos ? i+1 : i]=par.children[i]; } tmp[pos]=node.id; par.children=tmp; this.redraw_node(par,true); if( callback ){ callback.call(this, this.get_node(node)); } this.trigger('create_node',{"node":this.get_node(node), "parent":par.id, "position":pos}); return node.id; }, // 调用set_text方法改变显示文本,触发rename_node事件 rename_node:function(obj,val){ var t1, t2, old; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.rename_node(obj[t1], val); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; old=obj.text; if( !this.check("rename_node", obj, this.get_parent(obj), val) ){ this.settings.core.error.call(this, this._data.core.last_error); return false; } this.set_text(obj, val); this.trigger('rename_node',{"node":obj, "text":val, "old":old}); return true; }, // 祖先节点移除obj及其相关子节点,更新this._data.core.selected,this._model.data // 如obj及其相关子节点处于focus,obj的父节点focus获得焦点,触发delete_node事件,重绘obj的父节点 delete_node:function(obj){ var t1, t2, par, pos, tmp, i, j, k, l, c, top, lft; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1 < t2; t1++ ){ this.delete_node(obj[t1]); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; par=this.get_node(obj.parent); pos=$.inArray(obj.id,par.children); c=false; if( !this.check("delete_node",obj,par,pos) ){ this.settings.core.error.call(this,this._data.core.last_error); return false; } if( pos!==-1 ) par.children=$.vakata.array_remove(par.children,pos); tmp=obj.children_d.concat([]); tmp.push(obj.id); // obj的上层节点移除obj及其子节点 for( i=0, j=obj.parents.length; i<j; i++ ){ this._model.data[obj.parents[i]].children_d=$.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function(v){ return $.inArray(v,tmp)===-1; } ); } for( k=0, l=tmp.length; k<l; k++ ){ if( this._model.data[tmp[k]].state.selected ){ c=true; break; } } // this._data.core.selected移除obj节点及相关子节点 if( c ){ this._data.core.selected=$.vakata.array_filter(this._data.core.selected,function(v){ return $.inArray(v,tmp)===-1; }); } this.trigger('delete_node',{"node":obj, "parent":par.id}); if( c ){ this.trigger('changed',{'action':'delete_node', 'node':obj, 'selected':this._data.core.selected, 'parent':par.id}); } for( k=0, l=tmp.length; k<l; k++ ){ delete this._model.data[tmp[k]]; } if( $.inArray(this._data.core.focused,tmp)!==-1 ){ this._data.core.focused=null; top=this.element[0].scrollTop; lft=this.element[0].scrollLeft; if( par.id===$.jstree.root ){ if ( this._model.data[$.jstree.root].children[0] ){ this.get_node(this._model.data[$.jstree.root].children[0],true).children('.jstree-anchor').focus(); } }else{ this.get_node(par,true).children('.jstree-anchor').focus(); } this.element[0].scrollTop=top; this.element[0].scrollLeft=lft; } this.redraw_node(par,true); return true; }, // 用户配置的节点数据中有functions属性,通过functions["move_node"]判断是否拥有当前操作的权限 // 或者通过this.settings.core.check_callback判断节点是否拥有当前操作的权限 // chk操作名称如create_node、rename_node、delete_node、copy_node、move_node // obj待处理的节点,par待处理节点的父节点,pos待处理节点obj在par中的位置 check:function(chk,obj,par,pos,more){ obj=obj && obj.id ? obj : this.get_node(obj); par=par && par.id ? par : this.get_node(par); var tmp=chk.match(/^move_node|copy_node|create_node$/i) ? par : obj, chc=this.settings.core.check_callback; if( chk==="move_node" || chk==="copy_node" ){ // obj和par的id相同,或者当操作事件为move_node时,obj作为par的子节点,父节点含有obj子节点 if( (!more || !more.is_multi) && (obj.id===par.id || (chk==="move_node" && $.inArray(obj.id,par.children)===pos) || $.inArray(par.id,obj.children_d)!==-1) ){ this._data.core.last_error={ 'error':'check', 'plugin':'core', 'id':'core_01', 'reason':'Moving parent inside child', 'data':JSON.stringify({ 'chk':chk, 'pos':pos, 'obj':obj&&obj.id?obj.id:false, 'par':par&&par.id?par.id:false}) }; return false; } } if( tmp && tmp.data ) tmp=tmp.data; if( tmp && tmp.functions && (tmp.functions[chk]===false || tmp.functions[chk]===true) ){ if( tmp.functions[chk]===false ){ this._data.core.last_error={'error':'check', 'plugin':'core', 'id':'core_02', 'reason':'Node data prevents function: '+chk, 'data':JSON.stringify({ 'chk':chk, 'pos':pos, 'obj':obj&&obj.id?obj.id:false, 'par':par&&par.id?par.id:false})}; } return tmp.functions[chk]; } if( chc===false || ($.isFunction(chc) && chc.call(this,chk,obj,par,pos,more)===false) || (chc&&chc[chk]===false) ){ this._data.core.last_error={'error':'check', 'plugin':'core', 'id':'core_03', 'reason':'User config for core.check_callback prevents function: '+chk, 'data':JSON.stringify({ 'chk':chk, 'pos':pos, 'obj':obj&&obj.id?obj.id:false, 'par':par&&par.id?par.id:false})}; return false; } return true; }, // 返回最后的错误数据 last_error:function(){ return this._data.core.last_error; }, // 移动节点,区分从另一个实例中移动节点的情况,根据传参重绘,触发move_node事件 // obj待移动的节点,par新的父节点,pos位置,callback回调,is_loaded新的父节点是否加载 // skip_redraw是否重绘,origin判断节点是否来自另一个jstree实例 move_node:function(obj,par,pos,callback,is_loaded,skip_redraw,origin){ var t1, t2, old_par, old_pos, new_par, old_ins, is_multi, dpc, tmp, i, j, k, l, p; par=this.get_node(par); pos=pos===undefined ? 0 : pos; if( !par ) return false; if( !pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par) ){ return this.load_node(par,function(){this.move_node(obj,par,pos,callback,true,false,origin);}); } if( $.isArray(obj) ){ if( obj.length===1 ){ obj=obj[0]; }else{ for( t1=0, t2=obj.length; t1<t2; t1++ ){ if( (tmp=this.move_node(obj[t1],par,pos,callback,is_loaded, alse,origin)) ){ par=tmp; pos="after"; } } this.redraw(); return true; } } obj=obj && obj.id ? obj : this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; old_par=(obj.parent || $.jstree.root).toString(); new_par=(!pos.toString().match(/^(before|after)$/) || par.id===$.jstree.root) ? par : this.get_node(par.parent); old_ins=origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id)); is_multi=!old_ins || !old_ins._id || (this._id!==old_ins._id);// 多个实例 old_pos=old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id,old_ins._model.data[old_par].children) : -1; if( old_ins && old_ins._id ) obj=old_ins._model.data[obj.id]; if( is_multi ){ if( (tmp=this.copy_node(obj, par, pos, callback, is_loaded, false, origin)) ){ if( old_ins ) old_ins.delete_node(obj); return tmp; } return false; } if( par.id===$.jstree.root ){ if( pos==="before" ) pos="first"; if( pos==="after" ) pos="last"; } switch( pos ){ case "before": pos=$.inArray(par.id, new_par.children); break; case "after" : pos=$.inArray(par.id, new_par.children)+1; break; case "inside": case "first": pos=0; break; case "last": pos=new_par.children.length; break; default: if( !pos ) pos=0; break; } if( pos>new_par.children.length ) pos=new_par.children.length; if( !this.check("move_node", obj, new_par, pos, { 'core' : true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) { this.settings.core.error.call(this, this._data.core.last_error); return false; } // 父节点内部移动节点 if( obj.parent===new_par.id ){ dpc=new_par.children.concat(); tmp=$.inArray(obj.id, dpc); if( tmp!==-1 ){ dpc=$.vakata.array_remove(dpc, tmp); if( pos>tmp ) pos--; } tmp=[]; for( i=0, j=dpc.length; i<j; i++ ){ tmp[i>=pos ? i+1 : i]=dpc[i]; } tmp[pos]=obj.id; new_par.children=tmp; this._node_changed(new_par.id); this.redraw(new_par.id===$.jstree.root); }else{ tmp=obj.children_d.concat(); tmp.push(obj.id); // 从obj原先祖先节点children、children_d属性移除obj及其子节点 for( i=0, j=obj.parents.length; i<j; i++ ){ dpc=[]; p=old_ins._model.data[obj.parents[i]].children_d; for( k=0, l=p.length; k < l; k++ ){ if( $.inArray(p[k], tmp)===-1 ) dpc.push(p[k]); } old_ins._model.data[obj.parents[i]].children_d=dpc; } old_ins._model.data[old_par].children=$.vakata.array_remove_item(old_ins._model.data[old_par].children,obj.id); // 新节点children、children_d属性插入obj及其子节点 for( i=0, j=new_par.parents.length; i<j; i++ ){ this._model.data[new_par.parents[i]].children_d=this._model.data[new_par.parents[i]].children_d.concat(tmp); } dpc=[]; for( i=0, j=new_par.children.length; i<j; i++ ){ dpc[i>=pos ? i+1 : i]=new_par.children[i]; } dpc[pos]=obj.id; new_par.children=dpc; new_par.children_d.push(obj.id); new_par.children_d=new_par.children_d.concat(obj.children_d); // 更新obj及其子节点的parent、parents属性 obj.parent=new_par.id; tmp=new_par.parents.concat(); tmp.unshift(new_par.id); p=obj.parents.length; obj.parents=tmp; tmp=tmp.concat(); for( i=0, j=obj.children_d.length; i<j; i++ ){ this._model.data[obj.children_d[i]].parents=this._model.data[obj.children_d[i]].parents.slice(0,p*-1); Array.prototype.push.apply(this._model.data[obj.children_d[i]].parents, tmp); } if( old_par===$.jstree.root || new_par.id===$.jstree.root ){ this._model.force_full_redraw=true; } if( !this._model.force_full_redraw ){ this._node_changed(old_par); this._node_changed(new_par.id); } if( !skip_redraw ) this.redraw(); } if( callback ) callback.call(this,obj,new_par,pos); this.trigger('move_node',{"node":obj, "parent":new_par.id, "position":pos, "old_parent":old_par, "old_position" : old_pos, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this }); return obj.id; }, // 从当前实例或另一个实例中复制节点,按pos位置拷贝到par中,skip_redraw跳过渲染 copy_node:function(obj,par,pos,callback,is_loaded,skip_redraw,origin){ var t1, t2, dpc, tmp, i, j, node, old_par, new_par, old_ins, is_multi; par=this.get_node(par); pos=pos===undefined ? 0 : pos; if( !par ) return false; if( !pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par) ){ return this.load_node(par,function(){this.copy_node(obj,par,pos,callback,true,false,origin);}); } if( $.isArray(obj) ){ if( obj.length===1 ){ obj=obj[0]; }else{ for( t1=0, t2=obj.length; t1<t2; t1++ ) { if( (tmp=this.copy_node(obj[t1],par,pos,callback,is_loaded,true,origin)) ){ par=tmp; pos="after"; } } this.redraw(); return true; } } obj=obj && obj.id ? obj : this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; old_par=(obj.parent || $.jstree.root).toString(); new_par=(!pos.toString().match(/^(before|after)$/) || par.id===$.jstree.root) ? par : this.get_node(par.parent); old_ins=origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id)); is_multi=!old_ins || !old_ins._id || (this._id!==old_ins._id);// 多个实例 if( old_ins && old_ins._id ) obj=old_ins._model.data[obj.id]; if( par.id===$.jstree.root ){ if( pos==="before" ) pos = "first"; if( pos==="after" ) pos = "last"; } switch(pos){ case "before": pos=$.inArray(par.id,new_par.children); break; case "after": pos=$.inArray(par.id,new_par.children)+1; break; case "inside": case "first": pos=0; break; case "last": pos=new_par.children.length; break; default: if( !pos ) pos=0; break; } if( pos>new_par.children.length ) pos=new_par.children.length; if( !this.check("copy_node",obj,new_par,pos,{'core':true,'origin':origin,'is_multi':(old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) { this.settings.core.error.call(this, this._data.core.last_error); return false; } // 以get_json方法获取另一个实例的节点数据,不包含id、data、state node=old_ins ? old_ins.get_json(obj,{no_id:true, no_data:true, no_state:true}) : obj; if( !node ) return false; if( node.id===true ) delete node.id; node=this._parse_model_from_json(node,new_par.id,new_par.parents.concat()); if( !node ) return false; tmp=this.get_node(node);// 当前实例中已存在该节点 if( obj && obj.state && obj.state.loaded===false ) tmp.state.loaded=false; dpc=[]; dpc.push(node); dpc=dpc.concat(tmp.children_d); this.trigger('model',{"nodes":dpc, "parent":new_par.id}); for( i=0, j=new_par.parents.length; i<j; i++ ){ this._model.data[new_par.parents[i]].children_d=this._model.data[new_par.parents[i]].children_d.concat(dpc); } dpc=[]; for( i=0, j=new_par.children.length; i<j; i++ ){ dpc[i>=pos ? i+1 : i]=new_par.children[i]; } dpc[pos]=tmp.id; new_par.children=dpc; new_par.children_d.push(tmp.id); new_par.children_d=new_par.children_d.concat(tmp.children_d); if( new_par.id===$.jstree.root ) this._model.force_full_redraw=true; if( !this._model.force_full_redraw ) this._node_changed(new_par.id); if( !skip_redraw ) this.redraw(new_par.id===$.jstree.root); if( callback ){callback.call(this,tmp,new_par,pos);} this.trigger('copy_node',{"node":tmp,"original":obj,"parent":new_par.id,"position":pos,"old_parent":old_par,"old_position" : old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1,'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this }); return tmp.id; }, // 剪切,通过get_node方法获取节点数据或选中的节点数据,保存在ccp_node、ccp_inst中 cut:function(obj){ if( !obj ) obj=this._data.core.selected.concat(); if( !$.isArray(obj) ) obj=[obj]; if( !obj.length ) return false; var tmp=[], o, t1, t2; for( t1=0, t2=obj.length; t1<t2; t1++ ){ o=this.get_node(obj[t1]); if( o && o.id && o.id!==$.jstree.root ) tmp.push(o); } if( !tmp.length ) return false; ccp_node=tmp; ccp_inst=this; ccp_mode='move_node'; this.trigger('cut',{"node":obj}); }, // 拷贝,通过get_node方法获取节点数据或选中的节点数据,保存在ccp_node、ccp_inst中 copy:function(obj){ if( !obj ) obj=this._data.core.selected.concat(); if( !$.isArray(obj) ) obj=[obj]; if( !obj.length ) return false; var tmp=[], o, t1, t2; for( t1=0, t2=obj.length; t1<t2; t1++ ){ o=this.get_node(obj[t1]); if( o && o.id && o.id!==$.jstree.root ) tmp.push(o); } if( !tmp.length ) return false; ccp_node=tmp; ccp_inst=this; ccp_mode='copy_node'; this.trigger('copy',{"node":obj}); }, // 获取剪切或拷贝到的节点数据缓存值 get_buffer:function(){ return {'mode':ccp_mode,'node':ccp_node,'inst':ccp_inst}; }, // 缓存中是否有剪切或拷贝到节点数据,可供粘贴 can_paste:function(){ return ccp_mode!==false && ccp_node!==false; }, // 调用[ccp_mode]方法,也即move_node方法(针对cut方法)、copy_node方法(针对copy方法),实现粘贴 paste:function(obj,pos){ obj=this.get_node(obj); if( !obj || !ccp_mode || !ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node ) return false; if( this[ccp_mode](ccp_node,obj,pos,false,false,false,ccp_inst) ){ this.trigger('paste',{"parent":obj.id,"node":ccp_node,"mode":ccp_mode}); } ccp_node=false; ccp_mode=false; ccp_inst=false; }, // 清空剪切或拷贝到的节点数据copy_node等 clear_buffer:function(){ ccp_node=false; ccp_mode=false; ccp_inst=false; this.trigger('clear_buffer'); }, // 失去焦点的时候调用set_text设置显示文本,可以是html字符串或text纯文本 // 巧用$.replaceWith、$.proxy、e.stopImmediatePropagation,$(tag,props) edit:function(obj,default_text,callback){ var rtl, w, a, s, t, h1, h2, fn, tmp, cancel=false; obj=this.get_node(obj); if( !obj ) return false; if( this.settings.core.check_callback===false ){ this._data.core.last_error={ 'error':'check', 'plugin':'core', 'id':'core_07', 'reason':'Could not edit node because of check_callback' }; this.settings.core.error.call(this, this._data.core.last_error); return false; } tmp=obj; default_text=typeof default_text==='string' ? default_text : obj.text; this.set_text(obj,""); obj=this._open_to(obj); tmp.text=default_text; rtl=this._data.core.rtl; w=this.element.width(); this._data.core.focused=tmp.id; a=obj.children('.jstree-anchor').focus(); s=$('<span>'); t=default_text; h1=$("<div/>",{css:{"position":"absolute","top":"-200px","left":(rtl?"0px":"-1000px"),"visibility":"hidden"}}) .appendTo("body"); h2=$("<input/>",{ "value":t, "class":"jstree-rename-input", "css":{ "padding":"0", "border":"1px solid silver", "box-sizing":"border-box", "display":"inline-block", "height":(this._data.core.li_height)+"px", "lineHeight":(this._data.core.li_height)+"px", "width":"150px" }, "blur":$.proxy(function (e) { e.stopImmediatePropagation(); e.preventDefault(); var i=s.children(".jstree-rename-input"), v=i.val(), f=this.settings.core.force_text, nv; if( v==="" ) v=t; h1.remove(); s.replaceWith(a); s.remove(); t=f ? t : $('<div></div>').append($.parseHTML(t)).html(); this.set_text(obj, t); nv=!!this.rename_node(obj, f ? $('<div></div>').text(v).text() : $('<div></div>').append($.parseHTML(v)).html()); if( !nv ){ this.set_text(obj,t); } this._data.core.focused=tmp.id; setTimeout($.proxy(function(){ var node=this.get_node(tmp.id,true); if( node.length ){ this._data.core.focused=tmp.id; node.children('.jstree-anchor').focus(); } }, this), 0); if( callback ){ callback.call(this, tmp, nv, cancel); } h2=null; }, this), "keydown":function(e){ var key=e.which; if( key===27 ){ cancel=true; this.value=t; } if( key===27 || key===13 || key===37 || key===38 || key===39 || key===40 || key===32 ){ e.stopImmediatePropagation(); } if( key===27 || key===13 ){ e.preventDefault(); this.blur(); } }, "click":function (e){ e.stopImmediatePropagation(); }, "mousedown":function (e){ e.stopImmediatePropagation(); }, "keyup":function (e){ h2.width(Math.min(h1.text("pW"+this.value).width(),w)); }, "keypress":function(e){ if( e.which===13 ) return false; } }); fn={ fontFamily:a.css('fontFamily') || '', fontSize:a.css('fontSize') || '', fontWeight:a.css('fontWeight') || '', fontStyle:a.css('fontStyle') || '', fontStretch:a.css('fontStretch') || '', fontVariant:a.css('fontVariant') || '', letterSpacing:a.css('letterSpacing') || '', wordSpacing:a.css('wordSpacing') || '' }; s.attr('class', a.attr('class')).append(a.contents().clone()).append(h2); a.replaceWith(s); h1.css(fn); h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); $(document).one('mousedown.jstree touchstart.jstree dnd_start.vakata', function(e){ if ( h2 && e.target!==h2 ){ $(h2).blur(); } }); }, // 加载样式文件,并为触发元素设置样式相关信息,触发set_theme事件 set_theme:function(theme_name, theme_url){ if( !theme_name ) return false; // 自动查找时以jstree.js文件的祖父级目录下themes文件夹中按主题名查找 if( theme_url===true ){ var dir=this.settings.core.themes.dir; if( !dir ) dir=$.jstree.path+'/themes'; theme_url=dir+'/'+theme_name+'/style.css'; } if( theme_url && $.inArray(theme_url, themes_loaded)===-1 ){ $('head').append('<'+'link rel="stylesheet" href="'+theme_url+'" type="text/css"/>'); themes_loaded.push(theme_url); } if( this._data.core.themes.name ){ this.element.removeClass('jstree-'+this._data.core.themes.name); } this._data.core.themes.name=theme_name; this.element.addClass('jstree-'+theme_name); this.element[this.settings.core.themes.responsive ? 'addClass' : 'removeClass']('jstree-'+theme_name+'-responsive'); this.trigger('set_theme',{'theme':theme_name}); }, // 获取已加载样式的主题名 get_theme:function(){ return this._data.core.themes.name; }, // 设置主题变量时,触发元素更新相关样式信息 set_theme_variant:function(variant_name){ if( this._data.core.themes.variant ){ this.element.removeClass('jstree-'+this._data.core.themes.name+'-'+this._data.core.themes.variant); } this._data.core.themes.variant=variant_name; if( variant_name ){ this.element.addClass('jstree-'+this._data.core.themes.name+'-'+this._data.core.themes.variant); } }, // 获取主题变量 get_theme_variant:function(){ return this._data.core.themes.variant; }, // 显示隐藏间行色相关 show_stripes:function(){ this._data.core.themes.stripes=true; this.get_container_ul().addClass("jstree-striped"); }, hide_stripes:function(){ this._data.core.themes.stripes=false; this.get_container_ul().removeClass("jstree-striped"); }, toggle_stripes:function(){ if( this._data.core.themes.stripes){ this.hide_stripes(); }else{ this.show_stripes(); } }, // 显示隐藏虚线相关 show_dots:function(){ this._data.core.themes.dots=true; this.get_container_ul().removeClass("jstree-no-dots"); }, hide_dots:function(){ this._data.core.themes.dots=false; this.get_container_ul().addClass("jstree-no-dots"); }, toggle_dots:function(){ if( this._data.core.themes.dots ){ this.hide_dots(); }else{ this.show_dots(); } }, // 显示隐藏图标相关 show_icons:function(){ this._data.core.themes.icons=true; this.get_container_ul().removeClass("jstree-no-icons"); }, hide_icons:function(){ this._data.core.themes.icons=false; this.get_container_ul().addClass("jstree-no-icons"); }, toggle_icons:function(){ if( this._data.core.themes.icons ){ this.hide_icons(); }else{ this.show_icons(); } }, // 设置图标,icon为false时隐藏,为true时清空,不含url改变obj.icon,含url改变图标 set_icon:function(obj,icon){ var t1, t2, dom, old; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.set_icon(obj[t1],icon); } return true; } obj=this.get_node(obj); if( !obj || obj.id===$.jstree.root ) return false; old=obj.icon; obj.icon=icon===true || icon===null || icon===undefined || icon==='' ? true : icon; dom=this.get_node(obj,true).children(".jstree-anchor").children(".jstree-themeicon"); if( icon===false ){ this.hide_icon(obj); }else if( icon===true || icon===null || icon===undefined || icon==='' ){ dom.removeClass('jstree-themeicon-custom '+old).css("background","") .removeAttr("rel"); if( old===false ) this.show_icon(obj); }else if( icon.indexOf("/")===-1 && icon.indexOf(".")===-1 ){ dom.removeClass(old).css("background","") .addClass(icon+' jstree-themeicon-custom').attr("rel",icon); if( old===false ) this.show_icon(obj); }else { dom.removeClass(old).css("background",""); dom.addClass('jstree-themeicon-custom') .css("background","url('"+icon+"') center center no-repeat").attr("rel",icon); if( old===false ) this.show_icon(obj); } return true; }, // 获取节点图标数据 get_icon:function(obj){ obj=this.get_node(obj); return (!obj || obj.id===$.jstree.root) ? false : obj.icon; }, // 隐藏图标并更新节点图标数据obj hide_icon:function(obj){ var t1, t2; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.hide_icon(obj[t1]); } return true; } obj=this.get_node(obj); if( !obj || obj===$.jstree.root ) return false; obj.icon=false; this.get_node(obj,true).children(".jstree-anchor").children(".jstree-themeicon").addClass('jstree-themeicon-hidden'); return true; }, // 显示图标并更新节点图标数据obj,节点图标数据缓存在图标节点的rel属性中 show_icon:function(obj){ var t1, t2, dom; if( $.isArray(obj) ){ obj=obj.slice(); for( t1=0, t2=obj.length; t1<t2; t1++ ){ this.show_icon(obj[t1]); } return true; } obj=this.get_node(obj); if( !obj || obj===$.jstree.root ) return false; dom=this.get_node(obj, true); obj.icon=dom.length ? dom.children(".jstree-anchor").children(".jstree-themeicon").attr('rel') : true; if( !obj.icon ) obj.icon = true; dom.children(".jstree-anchor").children(".jstree-themeicon").removeClass('jstree-themeicon-hidden'); return true; } }; // helpers $.vakata = {}; // 获取dom元素的属性,with_values真值时为对象形式,否值时为数组形式存储属性名 $.vakata.attributes=function(node,with_values){ node=$(node)[0]; var attr=with_values ? {} : []; if( node && node.attributes ){ $.each(node.attributes,function(i,v){ if( $.inArray(v.name.toLowerCase(),['style','contenteditable','hasfocus','tabindex'])!==-1 ) return; if( v.value!==null && $.trim(v.value)!=='' ){ if( with_values ){ attr[v.name]=v.value; }else{ attr.push(v.name); } } }); } return attr; }; // 数组去重 $.vakata.array_unique=function(array){ var a=[], i, j, l, o={}; for( i = 0, l=array.length; i<l; i++ ){ if( o[array[i]]===undefined ){ a.push(array[i]); o[array[i]]=true; } } return a; }; // 从from位置移除一项数组元素 $.vakata.array_remove=function(array,from){ array.splice(from,1); return array; }; // 移除数组中的某项后返回 $.vakata.array_remove_item=function(array,item){ var tmp=$.inArray(item,array); return tmp!==-1 ? $.vakata.array_remove(array,tmp) : array; }; $.vakata.array_filter=function(c,a,b,d,e){ if( c.filter ) return c.filter(a, b); d=[]; for( e in c ){ if( ~~e+''===e+'' && e>=0 && a.call(b,c[e],+e,c) ) d.push(c[e]); } return d; }; }));
相关推荐
**jsTree 中文文档概述** jsTree 是一个流行的JavaScript库,用于在网页上创建交互式的树状视图。它主要用于组织结构化的数据,如文件系统、数据库目录或自定义项目结构。jsTree 支持多种操作,包括点击、拖放、...
**jstree 源码解析** `jstree` 是一个流行的JavaScript库,用于创建交互式的树形视图。这个库广泛应用于数据组织、文件系统展示、菜单系统以及任何需要层次结构展示的情况。在本篇文章中,我们将深入探讨 `jstree` ...
**jsTree API详解** jsTree 是一个流行的JavaScript库,用于创建、操作和展示交互式的HTML树状视图。它提供了一套丰富的API,使得开发者能够方便地实现树形结构的各种功能,如添加、删除、修改节点,以及节点的移动...
**jsTree:构建前端树形结构的利器** jsTree 是一个强大的 JavaScript 库,专用于在 Web 页面上创建交互式的树形结构。它基于纯 JavaScript 编写,无需依赖其他库,因此对于初学者和有经验的开发者来说,都是一个...
**jsTree.v.1.0中文文档** jsTree是一款基于JavaScript的开源库,主要用于创建、操作和展示HTML页面上的树状结构。它适用于构建复杂的交互式界面,如文件管理系统、组织架构图、导航菜单等。jsTree v.1.0是该库的一...
**jsTree 概述** jsTree 是一个基于 JavaScript 的开源库,专为创建交互式的树状视图而设计。它提供了丰富的功能,如动态加载、增删节点、拖放操作等,使得在网页中实现复杂的数据结构展示变得简单。jsTree 支持...
**JSTree:高效处理大数据量的JavaScript树形菜单组件** 在Web开发中,树形菜单是一种常见的数据展示形式,用于组织和展示层次结构的数据。JSTree是一款基于JavaScript的开源库,专为构建功能丰富的交互式树形菜单...
**jsTree 操作详解** jsTree 是一个基于 jQuery 的开源 JavaScript 库,用于创建交互式的树状视图。它提供了一种优雅的方式来呈现和操作数据结构,尤其适用于构建树形菜单或目录。jsTree 支持多种功能,包括动态...
在移动设备上,为了有效地展示层次结构数据,如文件系统、组织架构或导航菜单,"手机端js tree"成为了一种实用的解决方案。这个技术基于JavaScript,专为智能手机和平板电脑等移动端设备设计,提供了可自定义的树形...
**jsTree:构建交互式目录树的利器** jsTree是一款完全用JavaScript编写的开源库,专为实现跨浏览器的树状视图而设计。它在Web应用中扮演着目录树控件的角色,允许用户以树形结构展示数据,极大地提高了用户体验。...
**JsTree静态例子详解** JsTree是一款基于JavaScript的开源库,专门用于创建、操作和展示树状数据结构。它在Web应用中广泛用于构建可交互的目录结构、文件管理系统或者组织复杂的分类信息。本篇文章将深入探讨如何...
**JsTree 实例使用详解** JsTree 是一个强大的JavaScript库,专为构建交互式的树状视图而设计。它在Web开发中广泛应用于文件管理、菜单系统、组织结构展示等多种场景。JsTree 提供了丰富的功能,如动态加载、节点...
1. **安装与引入**:通常会提供如何通过CDN链接、npm或下载源码来引入jstree到项目中的指导。对于这个预1.0的修复版本,可能需要手动下载并添加到项目文件夹中。 2. **基本用法**:介绍如何初始化一个jstree实例,...
**jsTree:JavaScript实现的树形菜单** jsTree是一款基于JavaScript的开源库,专门用于创建交互式的树形菜单。它提供了丰富的功能和多种定制选项,适用于网页中的数据组织和展示,如导航菜单、文件系统视图或者数据...
**jstree用法大集合** `jstree` 是一个强大的JavaScript库,用于创建交互式的树状视图。在ASP.NET开发中,它经常被用来构建网站的导航菜单、组织结构图或文件系统浏览器。这个集合包含了多个压缩包文件,每个都提供...
**jsTree 实例详解** jsTree 是一个流行的 JavaScript 库,专门用于创建、操作和展示交互式的树型结构。在 Web 开发中,它常被用于构建目录结构、组织数据或者构建导航菜单。jsTree 提供了丰富的 API 和多种主题,...
jsTree 是一个 基于 jQuery 的 Tree 控件。支持 XML,JSON,Html 三种数据源。提供创建,重命名,移动,删除,拖 " 放节点操作。可以自己自定义创建,删 除,嵌套,重命名,选择节点的规则。在这些操作上可以添加...
Bootstrap JsTree是一个将jQuery库与Bootstrap框架相结合的插件,用于创建交互式的树形结构视图。这个简单Dome提供了一个快速入门的例子,展示了如何在网页中集成JsTree,并实现多选、单选、添加和删除节点等功能。...
jsTree-directive, jsTree的Angular 指令 文档 jstree指令jsTree的Angular 指令文档文档使用 bower 安装$ bower i jstree-directive教程使用 jsTree,Angularjs和Expressjs语言构建一个基于We
**jsTree UI 插件详解** jsTree 是一个流行的JavaScript库,用于在网页上创建交互式的树状视图。这个库特别适用于数据的层级展示,如文件系统、组织结构或导航菜单。在“jsTree例子3-ui”中,我们将深入探讨jsTree...