fancytree-rails 2.0.0.pre.6.pre.1 → 2.0.0.pre.11.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Rakefile +6 -7
  4. data/lib/fancytree/rails/version.rb +2 -2
  5. data/vendor/assets/images/fancytree/skin-win8-xxl/icons.gif +0 -0
  6. data/vendor/assets/images/fancytree/skin-win8-xxl/loading.gif +0 -0
  7. data/vendor/assets/javascripts/fancytree.js +1 -1
  8. data/vendor/assets/javascripts/fancytree/MIT-LICENSE.txt +21 -0
  9. data/vendor/assets/javascripts/fancytree/jquery.fancytree-all.js +1267 -475
  10. data/vendor/assets/javascripts/fancytree/jquery.fancytree-custom.min.js +41 -0
  11. data/vendor/assets/javascripts/fancytree/jquery.fancytree.js +582 -310
  12. data/vendor/assets/javascripts/fancytree/jquery.fancytree.min.js +14 -7
  13. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.childcounter.js +185 -0
  14. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.clones.js +417 -0
  15. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.columnview.js +149 -0
  16. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.debug.js +142 -0
  17. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.dnd.js +539 -0
  18. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.edit.js +318 -0
  19. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.filter.js +173 -0
  20. data/vendor/assets/javascripts/fancytree/{jquery.fancytree.awesome.js → src/jquery.fancytree.glyph.js} +28 -26
  21. data/vendor/assets/javascripts/fancytree/{jquery.fancytree.gridnav.js → src/jquery.fancytree.gridnav.js} +77 -41
  22. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.js +4027 -0
  23. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.menu.js +155 -0
  24. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.persist.js +345 -0
  25. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.table.js +345 -0
  26. data/vendor/assets/javascripts/fancytree/src/jquery.fancytree.themeroller.js +82 -0
  27. data/vendor/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.css +29 -15
  28. data/vendor/assets/stylesheets/fancytree/skin-awesome/ui.fancytree.min.css +1 -1
  29. data/vendor/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.css +366 -0
  30. data/vendor/assets/stylesheets/fancytree/skin-bootstrap/ui.fancytree.min.css +6 -0
  31. data/vendor/assets/stylesheets/fancytree/skin-lion/ui.fancytree.css +34 -7
  32. data/vendor/assets/stylesheets/fancytree/skin-lion/ui.fancytree.min.css +1 -1
  33. data/vendor/assets/stylesheets/fancytree/skin-vista/ui.fancytree.css +34 -7
  34. data/vendor/assets/stylesheets/fancytree/skin-vista/ui.fancytree.min.css +1 -1
  35. data/vendor/assets/stylesheets/fancytree/skin-win7/ui.fancytree.css +34 -7
  36. data/vendor/assets/stylesheets/fancytree/skin-win7/ui.fancytree.min.css +1 -1
  37. data/vendor/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.css +507 -0
  38. data/vendor/assets/stylesheets/fancytree/skin-win8-xxl/ui.fancytree.min.css +11 -0
  39. data/vendor/assets/stylesheets/fancytree/skin-win8/ui.fancytree.css +34 -7
  40. data/vendor/assets/stylesheets/fancytree/skin-win8/ui.fancytree.min.css +1 -1
  41. data/vendor/assets/stylesheets/fancytree/skin-xp/ui.fancytree.css +34 -7
  42. data/vendor/assets/stylesheets/fancytree/skin-xp/ui.fancytree.min.css +1 -1
  43. metadata +24 -13
  44. data/vendor/assets/javascripts/fancytree/jquery.fancytree-all.min.js +0 -7
  45. data/vendor/assets/javascripts/fancytree/jquery.fancytree-all.min.js.map +0 -1
  46. data/vendor/assets/javascripts/fancytree/jquery.fancytree.min.js.map +0 -1
  47. data/vendor/assets/stylesheets/fancytree/skin-lion/ui.fancytree-org.css +0 -460
  48. data/vendor/assets/stylesheets/fancytree/skin-themeroller/ui.fancytree-org.css +0 -505
  49. data/vendor/assets/stylesheets/fancytree/skin-vista/ui.fancytree-org.css +0 -610
  50. data/vendor/assets/stylesheets/fancytree/skin-win7/ui.fancytree-org.css +0 -592
  51. data/vendor/assets/stylesheets/fancytree/skin-win8/ui.fancytree-org.css +0 -602
  52. data/vendor/assets/stylesheets/fancytree/skin-xp/ui.fancytree-org.css +0 -578
@@ -0,0 +1,41 @@
1
+ /*! jQuery Fancytree Plugin - 2.0.0-11 - 2014-04-27T22:28
2
+ * https://github.com/mar10/fancytree
3
+ * Copyright (c) 2014 Martin Wendt; Licensed MIT */
4
+ (function( factory ) {
5
+ if ( typeof define === "function" && define.amd ) {
6
+ define( [ "jquery" ], factory );
7
+ } else {
8
+ factory( jQuery );
9
+ }
10
+ }(function( $ ) {
11
+
12
+ !function(a,b,c,d){"use strict";function e(b){b=b||"",a.error("Not implemented: "+b)}function f(b,c){b||(c=c?": "+c:"",a.error("Assertion failed"+c))}function g(a,c){var d,e,f=b.console?b.console[a]:null;if(f)if(f.apply)f.apply(b.console,c);else{for(e="",d=0;d<c.length;d++)e+=c[d];f(e)}}function h(b){var c,d,e,f=a.map(a.trim(b).split("."),function(a){return parseInt(a,10)}),g=a.map(Array.prototype.slice.call(arguments,1),function(a){return parseInt(a,10)});for(c=0;c<g.length;c++)if(d=f[c]||0,e=g[c]||0,d!==e)return d>e;return!0}function i(a,b,c,d,e){var f=function(){var c=b[a],f=d[a],g=b.ext[e],h=function(){return c.apply(b,arguments)};return function(){var a=b._local,c=b._super;try{return b._local=g,b._super=h,f.apply(b,arguments)}finally{b._local=a,b._super=c}}}();return f}function j(b,c,d,e){for(var f in d)"function"==typeof d[f]?"function"==typeof b[f]?b[f]=i(f,b,c,d,e):"_"===f.charAt(0)?b.ext[e][f]=i(f,b,c,d,e):a.error("Could not override tree."+f+". Use prefix '_' to create tree."+e+"._"+f):"options"!==f&&(b.ext[e][f]=d[f])}function k(b,c){return b===d?a.Deferred(function(){this.resolve()}).promise():a.Deferred(function(){this.resolveWith(b,c)}).promise()}function l(b,c){return b===d?a.Deferred(function(){this.reject()}).promise():a.Deferred(function(){this.rejectWith(b,c)}).promise()}function m(a,b){return function(){a.resolveWith(b)}}function n(b){var c=a.extend({},b.data()),d=c.json;return delete c.fancytree,d&&(delete c.json,c=a.extend(c,d)),c}function o(a){return a=a.toLowerCase(),function(b){return b.title.toLowerCase().indexOf(a)>=0}}function p(b,c){var d,e,g,h;for(this.parent=b,this.tree=b.tree,this.ul=null,this.li=null,this.statusNodeType=null,this._isLoading=!1,this._error=null,this.data={},d=0,e=w.length;e>d;d++)g=w[d],this[g]=c[g];c.data&&a.extend(this.data,c.data);for(g in c)x[g]||a.isFunction(c[g])||y[g]||(this.data[g]=c[g]);null==this.key&&(this.tree.options.defaultKey?(this.key=this.tree.options.defaultKey(this),f(this.key,"defaultKey() must return a unique key")):this.key="_"+s._nextNodeKey++),c.active&&(f(null===this.tree.activeNode,"only one active node allowed"),this.tree.activeNode=this),c.selected&&(this.tree.lastSelectedNode=this),this.children=null,h=c.children,h&&h.length&&this._setChildren(h),this.tree._callHook("treeRegisterNode",this.tree,!0,this)}function q(b){this.widget=b,this.$div=b.element,this.options=b.options,this.options&&a.isFunction(this.options.lazyload)&&(a.isFunction(this.options.lazyLoad)||(this.options.lazyLoad=function(){s.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."),b.options.lazyload.apply(this,arguments)})),this.ext={},this.data=n(this.$div),this._id=a.ui.fancytree._nextId++,this._ns=".fancytree-"+this._id,this.activeNode=null,this.focusNode=null,this._hasFocus=null,this.lastSelectedNode=null,this.systemFocusElement=null,this.statusClassPropName="span",this.ariaPropName="li",this.nodeContainerAttrName="li",this.$div.find(">ul.fancytree-container").remove();var c,d={tree:this};this.rootNode=new p(d,{title:"root",key:"root_"+this._id,children:null,expanded:!0}),this.rootNode.parent=null,c=a("<ul>",{"class":"ui-fancytree fancytree-container"}).appendTo(this.$div),this.$container=c,this.rootNode.ul=c[0],null==this.options.debugLevel&&(this.options.debugLevel=s.debugLevel),this.$container.attr("tabindex",this.options.tabbable?"0":"-1"),this.options.aria&&this.$container.attr("role","tree").attr("aria-multiselectable",!0)}if(a.ui.fancytree&&a.ui.fancytree.version)return void a.ui.fancytree.warn("Fancytree: ignored duplicate include");var r,s=null,t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},u="active expanded focus folder hideCheckbox lazy selected unselectable".split(" "),v={},w="expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "),x={},y={active:!0,children:!0,data:!0,focus:!0};for(r=0;r<u.length;r++)v[u[r]]=!0;for(r=0;r<w.length;r++)x[w[r]]=!0;p.prototype={_findDirectChild:function(a){var b,c,d=this.children;if(d)if("string"==typeof a){for(b=0,c=d.length;c>b;b++)if(d[b].key===a)return d[b]}else{if("number"==typeof a)return this.children[a];if(a.parent===this)return a}return null},_setChildren:function(a){f(a&&(!this.children||0===this.children.length),"only init supported"),this.children=[];for(var b=0,c=a.length;c>b;b++)this.children.push(new p(this,a[b]))},addChildren:function(b,c){var d,e,g,h=null,i=[];for(a.isPlainObject(b)&&(b=[b]),this.children||(this.children=[]),d=0,e=b.length;e>d;d++)i.push(new p(this,b[d]));return h=i[0],null==c?this.children=this.children.concat(i):(c=this._findDirectChild(c),g=a.inArray(c,this.children),f(g>=0,"insertBefore must be an existing child"),this.children.splice.apply(this.children,[g,0].concat(i))),(!this.parent||this.parent.ul||this.tr)&&this.render(),3===this.tree.options.selectMode&&this.fixSelection3FromEndNodes(),h},addNode:function(a,b){switch((b===d||"over"===b)&&(b="child"),b){case"after":return this.getParent().addChildren(a,this.getNextSibling());case"before":return this.getParent().addChildren(a,this);case"child":case"over":return this.addChildren(a)}f(!1,"Invalid mode: "+b)},appendSibling:function(a){return this.addNode(a,"after")},applyPatch:function(b){if(null===b)return this.remove(),k(this);var c,d,e,f={children:!0,expanded:!0,parent:!0};for(c in b)e=b[c],f[c]||a.isFunction(e)||(x[c]?this[c]=e:this.data[c]=e);return b.hasOwnProperty("children")&&(this.removeChildren(),b.children&&this._setChildren(b.children)),this.isVisible()&&(this.renderTitle(),this.renderStatus()),d=b.hasOwnProperty("expanded")?this.setExpanded(b.expanded):k(this)},collapseSiblings:function(){return this.tree._callHook("nodeCollapseSiblings",this)},copyTo:function(a,b,c){return a.addNode(this.toDict(!0,c),b)},countChildren:function(a){var b,c,d,e=this.children;if(!e)return 0;if(d=e.length,a!==!1)for(b=0,c=d;c>b;b++)d+=e[b].countChildren();return d},debug:function(){this.tree.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),g("debug",arguments))},discard:function(){return this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."),this.resetLazy()},findAll:function(b){b=a.isFunction(b)?b:o(b);var c=[];return this.visit(function(a){b(a)&&c.push(a)}),c},findFirst:function(b){b=a.isFunction(b)?b:o(b);var c=null;return this.visit(function(a){return b(a)?(c=a,!1):void 0}),c},_changeSelectStatusAttrs:function(a){var b=!1;switch(a){case!1:b=this.selected||this.partsel,this.selected=!1,this.partsel=!1;break;case!0:b=!this.selected||!this.partsel,this.selected=!0,this.partsel=!0;break;case d:b=this.selected||!this.partsel,this.selected=!1,this.partsel=!0;break;default:f(!1,"invalid state: "+a)}return b&&this.renderStatus(),b},fixSelection3AfterClick:function(){var a=this.isSelected();this.visit(function(b){b._changeSelectStatusAttrs(a)}),this.fixSelection3FromEndNodes()},fixSelection3FromEndNodes:function(){function a(b){var c,e,f,g,h,i,j,k=b.children;if(k){for(i=!0,j=!1,c=0,e=k.length;e>c;c++)f=k[c],g=a(f),g!==!1&&(j=!0),g!==!0&&(i=!1);h=i?!0:j?d:!1}else h=!!b.selected;return b._changeSelectStatusAttrs(h),h}f(3===this.tree.options.selectMode,"expected selectMode 3"),a(this),this.visitParents(function(a){var b,c,e,f,g=a.children,h=!0,i=!1;for(b=0,c=g.length;c>b;b++)e=g[b],(e.selected||e.partsel)&&(i=!0),e.unselectable||e.selected||(h=!1);f=h?!0:i?d:!1,a._changeSelectStatusAttrs(f)})},fromDict:function(b){for(var c in b)x[c]?this[c]=b[c]:"data"===c?a.extend(this.data,b.data):a.isFunction(b[c])||y[c]||(this.data[c]=b[c]);b.children?(this.removeChildren(),this.addChildren(b.children)):this.renderTitle()},getChildren:function(){return this.hasChildren()===d?d:this.children},getFirstChild:function(){return this.children?this.children[0]:null},getIndex:function(){return a.inArray(this,this.parent.children)},getIndexHier:function(b){b=b||".";var c=[];return a.each(this.getParentList(!1,!0),function(a,b){c.push(b.getIndex()+1)}),c.join(b)},getKeyPath:function(a){var b=[],c=this.tree.options.keyPathSeparator;return this.visitParents(function(a){a.parent&&b.unshift(a.key)},!a),c+b.join(c)},getLastChild:function(){return this.children?this.children[this.children.length-1]:null},getLevel:function(){for(var a=0,b=this.parent;b;)a++,b=b.parent;return a},getNextSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=0,b=c.length-1;b>a;a++)if(c[a]===this)return c[a+1]}return null},getParent:function(){return this.parent},getParentList:function(a,b){for(var c=[],d=b?this:this.parent;d;)(a||d.parent)&&c.unshift(d),d=d.parent;return c},getPrevSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=1,b=c.length;b>a;a++)if(c[a]===this)return c[a-1]}return null},hasChildren:function(){return this.lazy?null==this.children?d:0===this.children.length?!1:1===this.children.length&&this.children[0].isStatusNode()?d:!0:!!this.children},hasFocus:function(){return this.tree.hasFocus()&&this.tree.focusNode===this},isActive:function(){return this.tree.activeNode===this},isChildOf:function(a){return this.parent&&this.parent===a},isDescendantOf:function(a){if(!a||a.tree!==this.tree)return!1;for(var b=this.parent;b;){if(b===a)return!0;b=b.parent}return!1},isExpanded:function(){return!!this.expanded},isFirstSibling:function(){var a=this.parent;return!a||a.children[0]===this},isFolder:function(){return!!this.folder},isLastSibling:function(){var a=this.parent;return!a||a.children[a.children.length-1]===this},isLazy:function(){return!!this.lazy},isLoaded:function(){return!this.lazy||this.hasChildren()!==d},isLoading:function(){return!!this._isLoading},isRoot:function(){return this.tree.rootNode===this},isSelected:function(){return!!this.selected},isStatusNode:function(){return!!this.statusNodeType},isUndefined:function(){return this.hasChildren()===d},isVisible:function(){var a,b,c=this.getParentList(!1,!1);for(a=0,b=c.length;b>a;a++)if(!c[a].expanded)return!1;return!0},lazyLoad:function(a){return this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."),this.load(a)},load:function(a){var b,c,d=this;return f(this.isLazy(),"load() requires a lazy node"),f(a||this.isUndefined(),"Pass forceReload=true to re-load a lazy node"),this.isLoaded()&&this.resetLazy(),c=this.tree._triggerNodeEvent("lazyLoad",this),c===!1?k(this):(f("boolean"!=typeof c,"lazyLoad event must return source in data.result"),b=this.tree._callHook("nodeLoadChildren",this,c),this.expanded&&b.always(function(){d.render()}),b)},makeVisible:function(b){var c,d=this,e=[],f=new a.Deferred,g=this.getParentList(!1,!1),h=g.length,i=!(b&&b.noAnimation===!0),j=!(b&&b.scrollIntoView===!1);for(c=h-1;c>=0;c--)e.push(g[c].setExpanded(!0,b));return a.when.apply(a,e).done(function(){j?d.scrollIntoView(i).done(function(){f.resolve()}):f.resolve()}),f.promise()},moveTo:function(b,c,e){(c===d||"over"===c)&&(c="child");var g,h=this.parent,i="child"===c?b:b.parent;if(this!==b){if(!this.parent)throw"Cannot move system root";if(i.isDescendantOf(this))throw"Cannot move a node to its own descendant";if(1===this.parent.children.length?(this.parent.children=this.parent.lazy?[]:null,this.parent.expanded=!1):(g=a.inArray(this,this.parent.children),f(g>=0),this.parent.children.splice(g,1)),this.parent=i,i.hasChildren())switch(c){case"child":i.children.push(this);break;case"before":g=a.inArray(b,i.children),f(g>=0),i.children.splice(g,0,this);break;case"after":g=a.inArray(b,i.children),f(g>=0),i.children.splice(g+1,0,this);break;default:throw"Invalid mode "+c}else i.children=[this];e&&b.visit(e,!0),this.tree!==b.tree&&(this.warn("Cross-tree moveTo is experimantal!"),this.visit(function(a){a.tree=b.tree},!0)),h.isDescendantOf(i)||h.render(),i.isDescendantOf(h)||i===h||i.render()}},navigate:function(b,c){function d(d){return d?(d.makeVisible(),a(d.span).is(":visible")?c===!1?d.setFocus():d.setActive():(d.debug("Navigate: skipping hidden node"),void d.navigate(b,c))):void 0}var e,f,g=!0,h=a.ui.keyCode,i=null;switch(b){case h.BACKSPACE:this.parent&&this.parent.parent&&d(this.parent);break;case h.LEFT:this.expanded?(this.setExpanded(!1),d(this)):this.parent&&this.parent.parent&&d(this.parent);break;case h.RIGHT:this.expanded||!this.children&&!this.lazy?this.children&&this.children.length&&d(this.children[0]):(this.setExpanded(),d(this));break;case h.UP:for(i=this.getPrevSibling();i&&i.expanded&&i.children&&i.children.length;)i=i.children[i.children.length-1];!i&&this.parent&&this.parent.parent&&(i=this.parent),d(i);break;case h.DOWN:if(this.expanded&&this.children&&this.children.length)i=this.children[0];else for(f=this.getParentList(!1,!0),e=f.length-1;e>=0&&!(i=f[e].getNextSibling());e--);d(i);break;default:g=!1}},remove:function(){return this.parent.removeChild(this)},removeChild:function(a){return this.tree._callHook("nodeRemoveChild",this,a)},removeChildren:function(){return this.tree._callHook("nodeRemoveChildren",this)},render:function(a,b){return this.tree._callHook("nodeRender",this,a,b)},renderTitle:function(){return this.tree._callHook("nodeRenderTitle",this)},renderStatus:function(){return this.tree._callHook("nodeRenderStatus",this)},resetLazy:function(){this.removeChildren(),this.expanded=!1,this.lazy=!0,this.children=d,this.renderStatus()},scheduleAction:function(a,b){this.tree.timer&&clearTimeout(this.tree.timer),this.tree.timer=null;var c=this;switch(a){case"cancel":break;case"expand":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger expand"),c.setExpanded(!0)},b);break;case"activate":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger activate"),c.setActive(!0)},b);break;default:throw"Invalid mode "+a}},scrollIntoView:function(b,c){b=b===!0?{duration:200,queue:!1}:b;var d,e=new a.Deferred,f=this,g=a(this.span).position().top,h=a(this.span).height(),i=this.tree.$container,j=i[0].scrollTop,k=Math.max(0,i.innerHeight()-i[0].clientHeight),l=i.height()-k,m=null;return 0>g?m=j+g:g+h>l&&(m=j+g-l+h,c&&(d=c?a(c.span).position().top:0,g-d>l&&(m=j+d))),null!==m?b?(b.complete=function(){e.resolveWith(f)},i.animate({scrollTop:m},b)):(i[0].scrollTop=m,e.resolveWith(this)):e.resolveWith(this),e.promise()},setActive:function(a,b){return this.tree._callHook("nodeSetActive",this,a,b)},setExpanded:function(a,b){return this.tree._callHook("nodeSetExpanded",this,a,b)},setFocus:function(a){return this.tree._callHook("nodeSetFocus",this,a)},setSelected:function(a){return this.tree._callHook("nodeSetSelected",this,a)},setTitle:function(a){this.title=a,this.renderTitle()},sortChildren:function(a,b){var c,d,e=this.children;if(e){if(a=a||function(a,b){var c=a.title.toLowerCase(),d=b.title.toLowerCase();return c===d?0:c>d?1:-1},e.sort(a),b)for(c=0,d=e.length;d>c;c++)e[c].children&&e[c].sortChildren(a,"$norender$");"$norender$"!==b&&this.render()}},toDict:function(b,c){var d,e,f,g={},h=this;if(a.each(w,function(a,b){(h[b]||h[b]===!1)&&(g[b]=h[b])}),a.isEmptyObject(this.data)||(g.data=a.extend({},this.data),a.isEmptyObject(g.data)&&delete g.data),c&&c(g),b&&this.hasChildren())for(g.children=[],d=0,e=this.children.length;e>d;d++)f=this.children[d],f.isStatusNode()||g.children.push(f.toDict(!0,c));return g},toggleExpanded:function(){return this.tree._callHook("nodeToggleExpanded",this)},toggleSelected:function(){return this.tree._callHook("nodeToggleSelected",this)},toString:function(){return"<FancytreeNode(#"+this.key+", '"+this.title+"')>"},visit:function(a,b){var c,d,e=!0,f=this.children;if(b===!0&&(e=a(this),e===!1||"skip"===e))return e;if(f)for(c=0,d=f.length;d>c&&(e=f[c].visit(a,!0),e!==!1);c++);return e},visitParents:function(a,b){if(b&&a(this)===!1)return!1;for(var c=this.parent;c;){if(a(c)===!1)return!1;c=c.parent}return!0},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),g("warn",arguments)}},q.prototype={_makeHookContext:function(b,c,e){var f,g;return b.node!==d?(c&&b.originalEvent!==c&&a.error("invalid args"),f=b):b.tree?(g=b.tree,f={node:b,tree:g,widget:g.widget,options:g.widget.options,originalEvent:c}):b.widget?f={node:null,tree:b,widget:b.widget,options:b.widget.options,originalEvent:c}:a.error("invalid args"),e&&a.extend(f,e),f},_callHook:function(b,c){var d=this._makeHookContext(c),e=this[b],f=Array.prototype.slice.call(arguments,2);return a.isFunction(e)||a.error("_callHook('"+b+"') is not a function"),f.unshift(d),e.apply(this,f)},_requireExtension:function(b,c,d,e){d=!!d;var g=this._local.name,h=this.options.extensions,i=a.inArray(b,h)<a.inArray(g,h),j=c&&null==this.ext[b],k=!j&&null!=d&&d!==i;return f(g&&g!==b),j||k?(e||(j||c?(e="'"+g+"' extension requires '"+b+"'",k&&(e+=" to be registered "+(d?"before":"after")+" itself")):e="If used together, `"+b+"` must be registered "+(d?"before":"after")+" `"+g+"`"),a.error(e),!1):!0},activateKey:function(a){var b=this.getNodeByKey(a);return b?b.setActive():this.activeNode&&this.activeNode.setActive(!1),b},applyPatch:function(b){var c,d,e,g,h,i,j=b.length,k=[];for(d=0;j>d;d++)e=b[d],f(2===e.length,"patchList must be an array of length-2-arrays"),g=e[0],h=e[1],i=null===g?this.rootNode:this.getNodeByKey(g),i?(c=new a.Deferred,k.push(c),i.applyPatch(h).always(m(c,i))):this.warn("could not find node with key '"+g+"'");return a.when.apply(a,k).promise()},count:function(){return this.rootNode.countChildren()},debug:function(){this.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),g("debug",arguments))},generateFormElements:function(b,c){var d,e=b!==!1?"ft_"+this._id:b,f=c!==!1?"ft_"+this._id+"_active":c,g="fancytree_result_"+this._id,h=this.$container.find("div#"+g);h.length?h.empty():h=a("<div>",{id:g}).hide().appendTo(this.$container),e&&(d=this.getSelectedNodes(3===this.options.selectMode),a.each(d,function(b,c){h.append(a("<input>",{type:"checkbox",name:e,value:c.key,checked:!0}))})),f&&this.activeNode&&h.append(a("<input>",{type:"radio",name:f,value:this.activeNode.key,checked:!0}))},getActiveNode:function(){return this.activeNode},getFirstChild:function(){return this.rootNode.getFirstChild()},getFocusNode:function(){return this.focusNode},getNodeByKey:function(a,b){var d,e;return!b&&(d=c.getElementById(this.options.idPrefix+a))?d.ftnode?d.ftnode:null:(b=b||this.rootNode,e=null,b.visit(function(b){return b.key===a?(e=b,!1):void 0},!0),e)},getSelectedNodes:function(a){var b=[];return this.rootNode.visit(function(c){return c.selected&&(b.push(c),a===!0)?"skip":void 0}),b},hasFocus:function(){return!!this._hasFocus},info:function(){this.options.debugLevel>=1&&(Array.prototype.unshift.call(arguments,this.toString()),g("info",arguments))},loadKeyPath:function(b,c,e){function f(a,b,d){c.call(r,b,"loading"),b.load().done(function(){r.loadKeyPath.call(r,l[a],c,b).always(m(d,r))}).fail(function(){r.warn("loadKeyPath: error loading: "+a+" (parent: "+p+")"),c.call(r,b,"error"),d.reject()})}var g,h,i,j,k,l,n,o,p=e||this.rootNode,q=this.options.keyPathSeparator,r=this;for(a.isArray(b)||(b=[b]),l={},i=0;i<b.length;i++)for(j=b[i],j.charAt(0)===q&&(j=j.substr(1)),o=j.split(q);o.length;){if(k=o.shift(),n=p._findDirectChild(k),!n){this.warn("loadKeyPath: key not found: "+k+" (parent: "+p+")"),c.call(this,k,"error");break}if(0===o.length){c.call(this,n,"ok");break}if(n.lazy&&n.hasChildren()===d){c.call(this,n,"loaded"),l[k]?l[k].push(o.join(q)):l[k]=[o.join(q)];break}c.call(this,n,"loaded"),p=n}g=[];for(k in l)n=p._findDirectChild(k),h=new a.Deferred,g.push(h),f(k,n,h);return a.when.apply(a,g).promise()},reactivate:function(a){var b=this.activeNode;b&&(this.activeNode=null,b.setActive(),a&&b.setFocus())},reload:function(a){return this._callHook("treeClear",this),this._callHook("treeLoad",this,a)},render:function(a,b){return this.rootNode.render(a,b)},setFocus:function(a){return this._callHook("treeSetFocus",this,a)},toDict:function(a,b){var c=this.rootNode.toDict(!0,b);return a?c:c.children},toString:function(){return"<Fancytree(#"+this._id+")>"},_triggerNodeEvent:function(a,b,c,e){var f=this._makeHookContext(b,c,e),g=this.widget._trigger(a,c,f);return g!==!1&&f.result!==d?f.result:g},_triggerTreeEvent:function(a,b){var c=this._makeHookContext(this,b),e=this.widget._trigger(a,b,c);return e!==!1&&c.result!==d?c.result:e},visit:function(a){return this.rootNode.visit(a,!1)},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),g("warn",arguments)}},a.extend(q.prototype,{nodeClick:function(a){var b,c,d=a.originalEvent,e=a.targetType,f=a.node;if("expander"===e)this._callHook("nodeToggleExpanded",a);else if("checkbox"===e)this._callHook("nodeToggleSelected",a),this._callHook("nodeSetFocus",a,!0);else{if(c=!1,b=!0,f.folder)switch(a.options.clickFolderMode){case 2:c=!0,b=!1;break;case 3:b=!0,c=!0}b&&(this.nodeSetFocus(a),this._callHook("nodeSetActive",a,!0)),c&&this._callHook("nodeToggleExpanded",a)}"a"===d.target.localName&&"fancytree-title"===d.target.className&&d.preventDefault()},nodeCollapseSiblings:function(a,b){var c,d,e,f=a.node;if(f.parent)for(c=f.parent.children,d=0,e=c.length;e>d;d++)c[d]!==f&&c[d].expanded&&this._callHook("nodeSetExpanded",c[d],!1,b)},nodeDblclick:function(a){"title"===a.targetType&&4===a.options.clickFolderMode&&this._callHook("nodeToggleExpanded",a),"title"===a.targetType&&a.originalEvent.preventDefault()},nodeKeydown:function(b){var c,d=b.originalEvent,e=b.node,f=b.tree,g=b.options,h=!0,i=!(d.ctrlKey||!g.autoActivate),j=a.ui.keyCode;switch(e||(this.rootNode.getFirstChild().setFocus(),e=b.node=this.focusNode,e.debug("Keydown force focus on first node")),d.which){case j.NUMPAD_ADD:case 187:f.nodeSetExpanded(b,!0);break;case j.NUMPAD_SUBTRACT:case 189:f.nodeSetExpanded(b,!1);break;case j.SPACE:g.checkbox?f.nodeToggleSelected(b):f.nodeSetActive(b,!0);break;case j.ENTER:f.nodeSetActive(b,!0);break;case j.BACKSPACE:case j.LEFT:case j.RIGHT:case j.UP:case j.DOWN:c=e.navigate(d.which,i);break;default:h=!1}h&&d.preventDefault()},nodeLoadChildren:function(b,c){var d,e,g=b.tree,h=b.node;return a.isFunction(c)&&(c=c()),c.url&&(d=a.extend({},b.options.ajax,c),d.debugDelay?(e=d.debugDelay,a.isArray(e)&&(e=e[0]+Math.random()*(e[1]-e[0])),h.debug("nodeLoadChildren waiting debug delay "+Math.round(e)+"ms"),d.debugDelay=!1,c=a.Deferred(function(b){setTimeout(function(){a.ajax(d).done(function(){b.resolveWith(this,arguments)}).fail(function(){b.rejectWith(this,arguments)})},e)})):c=a.ajax(d),c=c.pipe(function(c){var d;return"string"==typeof c&&a.error("Ajax request returned a string (did you get the JSON dataType wrong?)."),b.options.postProcess?(d=g._triggerNodeEvent("postProcess",b,b.originalEvent,{response:c,dataType:this.dataType}),c=a.isArray(d)?d:c):c&&c.hasOwnProperty("d")&&b.options.enableAspx&&(c="string"==typeof c.d?a.parseJSON(c.d):c.d),c},function(a,b,c){return g._makeHookContext(h,null,{error:a,args:Array.prototype.slice.call(arguments),message:c,details:a.status+": "+c})})),a.isFunction(c.promise)&&(f(!h.isLoading()),g.nodeSetStatus(b,"loading"),c.done(function(){g.nodeSetStatus(b,"ok")}).fail(function(a){var c;c=a.node&&a.error&&a.message?a:g._makeHookContext(h,null,{error:a,args:Array.prototype.slice.call(arguments),message:a?a.message||a.toString():""}),g._triggerNodeEvent("loaderror",c,null),g.nodeSetStatus(b,"error",c.message,c.details)})),a.when(c).done(function(b){var c;a.isPlainObject(b)&&(f(a.isArray(b.children),"source must contain (or be) an array of children"),f(h.isRoot(),"source may only be an object for root nodes"),c=b,b=b.children,delete c.children,a.extend(g.data,c)),f(a.isArray(b),"expected array of children"),h._setChildren(b),g._triggerNodeEvent("loadChildren",h)})},nodeLoadKeyPath:function(){},nodeRemoveChild:function(b,c){var d,e=b.node,g=b.options,h=a.extend({},b,{node:c}),i=e.children;return 1===i.length?(f(c===i[0]),this.nodeRemoveChildren(b)):(this.activeNode&&(c===this.activeNode||this.activeNode.isDescendantOf(c))&&this.activeNode.setActive(!1),this.focusNode&&(c===this.focusNode||this.focusNode.isDescendantOf(c))&&(this.focusNode=null),this.nodeRemoveMarkup(h),this.nodeRemoveChildren(h),d=a.inArray(c,i),f(d>=0),c.visit(function(a){a.parent=null},!0),this._callHook("treeRegisterNode",this,!1,c),g.removeNode&&g.removeNode.call(b.tree,{type:"removeNode"},h),void i.splice(d,1))},nodeRemoveChildMarkup:function(b){var c=b.node;c.ul&&(c.isRoot()?a(c.ul).empty():(a(c.ul).remove(),c.ul=null),c.visit(function(a){a.li=a.ul=null}))},nodeRemoveChildren:function(b){var c,d=b.tree,e=b.node,f=e.children,g=b.options;f&&(this.activeNode&&this.activeNode.isDescendantOf(e)&&this.activeNode.setActive(!1),this.focusNode&&this.focusNode.isDescendantOf(e)&&(this.focusNode=null),this.nodeRemoveChildMarkup(b),c=a.extend({},b),e.visit(function(a){a.parent=null,d._callHook("treeRegisterNode",d,!1,a),g.removeNode&&(c.node=a,g.removeNode.call(b.tree,{type:"removeNode"},c))}),e.children=e.lazy?[]:null,this.nodeRenderStatus(b))},nodeRemoveMarkup:function(b){var c=b.node;c.li&&(a(c.li).remove(),c.li=null),this.nodeRemoveChildMarkup(b)},nodeRender:function(b,d,e,g,h){var i,j,k,l,m,n,o,p=b.node,q=b.tree,r=b.options,s=r.aria,t=!1,u=p.parent,v=!u,w=p.children;if(v||u.ul){if(f(v||u.ul,"parent UL must exist"),v||(p.li&&(d||p.li.parentNode!==p.parent.ul)&&(p.li.parentNode!==p.parent.ul&&this.warn("unlink "+p+" (must be child of "+p.parent+")"),this.nodeRemoveMarkup(b)),p.li?this.nodeRenderStatus(b):(t=!0,p.li=c.createElement("li"),p.li.ftnode=p,p.key&&r.generateIds&&(p.li.id=r.idPrefix+p.key),p.span=c.createElement("span"),p.span.className="fancytree-node",s&&a(p.span).attr("aria-labelledby","ftal_"+p.key),p.li.appendChild(p.span),this.nodeRenderTitle(b),r.createNode&&r.createNode.call(q,{type:"createNode"},b)),r.renderNode&&r.renderNode.call(q,{type:"renderNode"},b)),w){if(v||p.expanded||e===!0){for(p.ul||(p.ul=c.createElement("ul"),(g===!0&&!h||!p.expanded)&&(p.ul.style.display="none"),s&&a(p.ul).attr("role","group"),p.li?p.li.appendChild(p.ul):p.tree.$div.append(p.ul)),l=0,m=w.length;m>l;l++)o=a.extend({},b,{node:w[l]}),this.nodeRender(o,d,e,!1,!0);for(i=p.ul.firstChild;i;)k=i.ftnode,k&&k.parent!==p?(p.debug("_fixParent: remove missing "+k,i),n=i.nextSibling,i.parentNode.removeChild(i),i=n):i=i.nextSibling;for(i=p.ul.firstChild,l=0,m=w.length-1;m>l;l++)j=w[l],k=i.ftnode,j!==k?p.ul.insertBefore(j.li,k.li):i=i.nextSibling}}else p.ul&&(this.warn("remove child markup for "+p),this.nodeRemoveChildMarkup(b));v||t&&u.ul.appendChild(p.li)}},nodeRenderTitle:function(a,b){var c,e,f,g,h,i,j=a.node,k=a.tree,l=a.options,m=l.aria,n=j.getLevel(),o=[],p=j.data.icon;b!==d&&(j.title=b),j.span&&(n<l.minExpandLevel?n>1&&o.push(m?"<span role='button' class='fancytree-expander'></span>":"<span class='fancytree-expander'></span>"):o.push(m?"<span role='button' class='fancytree-expander'></span>":"<span class='fancytree-expander'></span>"),l.checkbox&&j.hideCheckbox!==!0&&!j.isStatusNode()&&o.push(m?"<span role='checkbox' class='fancytree-checkbox'></span>":"<span class='fancytree-checkbox'></span>"),g=m?" role='img'":"",p&&"string"==typeof p?(e="/"===p.charAt(0)?p:l.imagePath+p,o.push("<img src='"+e+"' alt='' />")):j.data.iconclass?o.push("<span "+g+" class='fancytree-custom-icon "+j.data.iconclass+"'></span>"):(p===!0||p!==!1&&l.icons!==!1)&&o.push("<span "+g+" class='fancytree-icon'></span>"),f="",l.renderTitle&&(f=l.renderTitle.call(k,{type:"renderTitle"},a)||""),f||(i=j.tooltip?" title='"+s.escapeHtml(j.tooltip)+"'":"",c=m?" id='ftal_"+j.key+"'":"",g=m?" role='treeitem'":"",h=l.titlesTabbable?" tabindex='0'":"",f="<span "+g+" class='fancytree-title'"+c+i+h+">"+j.title+"</span>"),o.push(f),j.span.innerHTML=o.join(""),this.nodeRenderStatus(a))},nodeRenderStatus:function(b){var c=b.node,d=b.tree,e=b.options,f=c.hasChildren(),g=c.isLastSibling(),h=e.aria,i=a(c.span).find(".fancytree-title"),j=e._classNames,k=[],l=c[d.statusClassPropName];l&&(k.push(j.node),d.activeNode===c&&k.push(j.active),d.focusNode===c?(k.push(j.focused),h&&i.attr("aria-activedescendant",!0)):h&&i.removeAttr("aria-activedescendant"),c.expanded?(k.push(j.expanded),h&&i.attr("aria-expanded",!0)):h&&i.removeAttr("aria-expanded"),c.folder&&k.push(j.folder),f!==!1&&k.push(j.hasChildren),g&&k.push(j.lastsib),c.lazy&&null==c.children&&k.push(j.lazy),c.partsel&&k.push(j.partsel),c._isLoading&&k.push(j.loading),c._error&&k.push(j.error),c.selected?(k.push(j.selected),h&&i.attr("aria-selected",!0)):h&&i.attr("aria-selected",!1),c.extraClasses&&k.push(c.extraClasses),k.push(f===!1?j.combinedExpanderPrefix+"n"+(g?"l":""):j.combinedExpanderPrefix+(c.expanded?"e":"c")+(c.lazy&&null==c.children?"d":"")+(g?"l":"")),k.push(j.combinedIconPrefix+(c.expanded?"e":"c")+(c.folder?"f":"")),l.className=k.join(" "),c.li&&(c.li.className=g?j.lastsib:""))},nodeSetActive:function(b,c,d){d=d||{};var e,g=b.node,h=b.tree,i=b.options,j=d.noEvents===!0,m=g===h.activeNode;return c=c!==!1,m===c?k(g):c&&!j&&this._triggerNodeEvent("beforeActivate",g,b.originalEvent)===!1?l(g,["rejected"]):void(c?(h.activeNode&&(f(h.activeNode!==g,"node was active (inconsistency)"),e=a.extend({},b,{node:h.activeNode}),h.nodeSetActive(e,!1),f(null===h.activeNode,"deactivate was out of sync?")),i.activeVisible&&g.makeVisible(),h.activeNode=g,h.nodeRenderStatus(b),h.nodeSetFocus(b),j||h._triggerNodeEvent("activate",g,b.originalEvent)):(f(h.activeNode===g,"node was not active (inconsistency)"),h.activeNode=null,this.nodeRenderStatus(b),j||b.tree._triggerNodeEvent("deactivate",g,b.originalEvent)))},nodeSetExpanded:function(b,c,e){e=e||{};var f,g,h,i,j,m,n=b.node,o=b.tree,p=b.options,q=e.noAnimation===!0,r=e.noEvents===!0;if(c=c!==!1,n.expanded&&c||!n.expanded&&!c)return k(n);if(c&&!n.lazy&&!n.hasChildren())return k(n);if(!c&&n.getLevel()<p.minExpandLevel)return l(n,["locked"]);if(!r&&this._triggerNodeEvent("beforeExpand",n,b.originalEvent)===!1)return l(n,["rejected"]);if(q||n.isVisible()||(q=e.noAnimation=!0),g=new a.Deferred,c&&!n.expanded&&p.autoCollapse){j=n.getParentList(!1,!0),m=p.autoCollapse;try{for(p.autoCollapse=!1,h=0,i=j.length;i>h;h++)this._callHook("nodeCollapseSiblings",j[h],e)}finally{p.autoCollapse=m}}return g.done(function(){p.autoScroll&&!q?n.getLastChild().scrollIntoView(!0,n).always(function(){r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}):r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}),f=function(d){var e,f,g,h;if(n.expanded=c,o._callHook("nodeRender",b,!1,!1,!0),n.ul)if(g="none"!==n.ul.style.display,h=!!n.expanded,g===h)n.warn("nodeSetExpanded: UL.style.display already set");else{if(p.fx&&!q)return e=p.fx.duration||200,f=p.fx.easing,void a(n.ul).animate(p.fx,e,f,function(){d()});n.ul.style.display=n.expanded||!parent?"":"none"}d()},c&&n.lazy&&n.hasChildren()===d?n.load().done(function(){g.notifyWith&&g.notifyWith(n,["loaded"]),f(function(){g.resolveWith(n)})}).fail(function(a){f(function(){g.rejectWith(n,["load failed ("+a+")"])})}):f(function(){g.resolveWith(n)}),g.promise()},nodeSetFocus:function(b,c){var d,e=b.tree,f=b.node;if(c=c!==!1,e.focusNode){if(e.focusNode===f&&c)return;d=a.extend({},b,{node:e.focusNode}),e.focusNode=null,this._triggerNodeEvent("blur",d),this._callHook("nodeRenderStatus",d)}c&&(this.hasFocus()||(f.debug("nodeSetFocus: forcing container focus"),this._callHook("treeSetFocus",b,!0,!0)),f.makeVisible(),e.focusNode=f,this._triggerNodeEvent("focus",b),b.options.autoScroll&&f.scrollIntoView(),this._callHook("nodeRenderStatus",b))},nodeSetSelected:function(a,b){var c=a.node,d=a.tree,e=a.options;if(b=b!==!1,c.debug("nodeSetSelected("+b+")",a),!c.unselectable){if(c.selected&&b||!c.selected&&!b)return!!c.selected;if(this._triggerNodeEvent("beforeSelect",c,a.originalEvent)===!1)return!!c.selected;b&&1===e.selectMode?d.lastSelectedNode&&d.lastSelectedNode.setSelected(!1):3===e.selectMode&&(c.selected=b,c.fixSelection3AfterClick()),c.selected=b,this.nodeRenderStatus(a),d.lastSelectedNode=b?c:null,d._triggerNodeEvent("select",a)}},nodeSetStatus:function(b,c,d,e){function f(){var a=h.children?h.children[0]:null;if(a&&a.isStatusNode()){try{h.ul&&(h.ul.removeChild(a.li),a.li=null)
13
+ }catch(b){}1===h.children.length?h.children=[]:h.children.shift()}}function g(b,c){var d=h.children?h.children[0]:null;return d&&d.isStatusNode()?(a.extend(d,b),i._callHook("nodeRender",d)):(b.key="_statusNode",h._setChildren([b]),h.children[0].statusNodeType=c,i.render()),h.children[0]}var h=b.node,i=b.tree;switch(c){case"ok":f(),h._isLoading=!1,h._error=null,h.renderStatus();break;case"loading":h.parent||g({title:i.options.strings.loading+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-wait"},c),h._isLoading=!0,h._error=null,h.renderStatus();break;case"error":g({title:i.options.strings.loadError+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-error"},c),h._isLoading=!1,h._error={message:d,details:e},h.renderStatus();break;default:a.error("invalid node status "+c)}},nodeToggleExpanded:function(a){return this.nodeSetExpanded(a,!a.node.expanded)},nodeToggleSelected:function(a){return this.nodeSetSelected(a,!a.node.selected)},treeClear:function(a){var b=a.tree;b.activeNode=null,b.focusNode=null,b.$div.find(">ul.fancytree-container").empty(),b.rootNode.children=null},treeCreate:function(){},treeDestroy:function(){},treeInit:function(a){this.treeLoad(a)},treeLoad:function(b,c){var d,f,g,h=b.tree,i=b.widget.element,j=a.extend({},b,{node:this.rootNode});if(h.rootNode.children&&this.treeClear(b),c=c||this.options.source)"string"==typeof c&&e();else switch(d=i.data("type")||"html"){case"html":f=i.find(">ul:first"),f.addClass("ui-fancytree-source ui-helper-hidden"),c=a.ui.fancytree.parseHtml(f),this.data=a.extend(this.data,n(f));break;case"json":c=a.parseJSON(i.text()),c.children&&(c.title&&(h.title=c.title),c=c.children);break;default:a.error("Invalid data-type: "+d)}return g=this.nodeLoadChildren(j,c).done(function(){h.render(),3===b.options.selectMode&&h.rootNode.fixSelection3FromEndNodes(),h._triggerTreeEvent("init",!0)}).fail(function(){h.render(),h._triggerTreeEvent("init",!1)})},treeRegisterNode:function(){},treeSetFocus:function(a,b){b=b!==!1,b!==this.hasFocus()&&(this._hasFocus=b,this.$container.toggleClass("fancytree-treefocus",b),this._triggerTreeEvent(b?"focusTree":"blurTree"))}}),a.widget("ui.fancytree",{options:{activeVisible:!0,ajax:{type:"GET",cache:!1,dataType:"json"},aria:!1,autoActivate:!0,autoCollapse:!1,autoScroll:!1,checkbox:!1,clickFolderMode:4,debugLevel:null,disabled:!1,enableAspx:!0,extensions:[],fx:{height:"toggle",duration:200},generateIds:!1,icons:!0,idPrefix:"ft_",keyboard:!0,keyPathSeparator:"/",minExpandLevel:1,selectMode:2,strings:{loading:"Loading&#8230;",loadError:"Load error!"},tabbable:!0,titlesTabbable:!1,_classNames:{node:"fancytree-node",folder:"fancytree-folder",combinedExpanderPrefix:"fancytree-exp-",combinedIconPrefix:"fancytree-ico-",hasChildren:"fancytree-has-children",active:"fancytree-active",selected:"fancytree-selected",expanded:"fancytree-expanded",lazy:"fancytree-lazy",focused:"fancytree-focused",partsel:"fancytree-partsel",lastsib:"fancytree-lastsib",loading:"fancytree-loading",error:"fancytree-error"},lazyLoad:null,postProcess:null},_create:function(){this.tree=new q(this),this.$source=this.source||"json"===this.element.data("type")?this.element:this.element.find(">ul:first");var b,c,e,g=this.options.extensions,h=this.tree;for(e=0;e<g.length;e++)c=g[e],b=a.ui.fancytree._extensions[c],b||a.error("Could not apply extension '"+c+"' (it is not registered, did you forget to include it?)"),this.tree.options[c]=a.extend(!0,{},b.options,this.tree.options[c]),f(this.tree.ext[c]===d,"Extension name must not exist as Fancytree.ext attribute: '"+c+"'"),this.tree.ext[c]={},j(this.tree,h,b,c),h=b;this.tree._callHook("treeCreate",this.tree)},_init:function(){this.tree._callHook("treeInit",this.tree),this._bind()},_setOption:function(b,c){var d=!0,e=!1;switch(b){case"aria":case"checkbox":case"icons":case"minExpandLevel":case"tabbable":this.tree._callHook("treeCreate",this.tree),e=!0;break;case"source":d=!1,this.tree._callHook("treeLoad",this.tree,c)}this.tree.debug("set option "+b+"="+c+" <"+typeof c+">"),d&&a.Widget.prototype._setOption.apply(this,arguments),e&&this.tree.render(!0,!1)},destroy:function(){this._unbind(),this.tree._callHook("treeDestroy",this.tree),this.tree.$div.find(">ul.fancytree-container").remove(),this.$source&&this.$source.removeClass("ui-helper-hidden"),a.Widget.prototype.destroy.call(this)},_unbind:function(){var b=this.tree._ns;this.element.unbind(b),this.tree.$container.unbind(b),a(c).unbind(b)},_bind:function(){var a=this,b=this.options,c=this.tree,d=c._ns;this._unbind(),c.$container.on("focusin"+d+" focusout"+d,function(a){var b=s.getNode(a),d="focusin"===a.type;b?c._callHook("nodeSetFocus",b,d):c._callHook("treeSetFocus",c,d)}).on("selectstart"+d,"span.fancytree-title",function(a){a.preventDefault()}).on("keydown"+d,function(a){if(b.disabled||b.keyboard===!1)return!0;var d,e=c.focusNode,f=c._makeHookContext(e||c,a),g=c.phase;try{return c.phase="userEvent",d=e?c._triggerNodeEvent("keydown",e,a):c._triggerTreeEvent("keydown",a),"preventNav"===d?d=!0:d!==!1&&(d=c._callHook("nodeKeydown",f)),d}finally{c.phase=g}}).on("click"+d+" dblclick"+d,function(c){if(b.disabled)return!0;var d,e=s.getEventTarget(c),f=e.node,g=a.tree,h=g.phase;if(!f)return!0;d=g._makeHookContext(f,c);try{switch(g.phase="userEvent",c.type){case"click":return d.targetType=e.type,g._triggerNodeEvent("click",d,c)===!1?!1:g._callHook("nodeClick",d);case"dblclick":return d.targetType=e.type,g._triggerNodeEvent("dblclick",d,c)===!1?!1:g._callHook("nodeDblclick",d)}}finally{g.phase=h}})},getActiveNode:function(){return this.tree.activeNode},getNodeByKey:function(a){return this.tree.getNodeByKey(a)},getRootNode:function(){return this.tree.rootNode},getTree:function(){return this.tree}}),s=a.ui.fancytree,a.extend(a.ui.fancytree,{version:"2.0.0-11",buildType: "production",debugLevel: 1,_nextId:1,_nextNodeKey:1,_extensions:{},_FancytreeClass:q,_FancytreeNodeClass:p,jquerySupports:{positionMyOfs:h(a.ui.version,1,9)},assert:function(a,b){return f(a,b)},debug:function(){a.ui.fancytree.debugLevel>=2&&g("log",arguments)},error:function(){g("error",arguments)},escapeHtml:function(a){return(""+a).replace(/[&<>"'\/]/g,function(a){return t[a]})},unescapeHtml:function(a){var b=c.createElement("div");return b.innerHTML=a,0===b.childNodes.length?"":b.childNodes[0].nodeValue},getEventTargetType:function(a){return this.getEventTarget(a).type},getEventTarget:function(a){var b=a&&a.target?a.target.className:"",c={node:this.getNode(a.target),type:d};return/\bfancytree-title\b/.test(b)?c.type="title":/\bfancytree-expander\b/.test(b)?c.type=c.node.hasChildren()===!1?"prefix":"expander":/\bfancytree-checkbox\b/.test(b)||/\bfancytree-radio\b/.test(b)?c.type="checkbox":/\bfancytree-icon\b/.test(b)?c.type="icon":/\bfancytree-node\b/.test(b)&&(c.type="title"),c},getNode:function(a){if(a instanceof p)return a;for(a.selector!==d?a=a[0]:a.originalEvent!==d&&(a=a.target);a;){if(a.ftnode)return a.ftnode;a=a.parentNode}return null},info:function(){a.ui.fancytree.debugLevel>=1&&g("info",arguments)},parseHtml:function(b){var c,e,f,g,h,i,j,k,l=b.find(">li"),m=[];return l.each(function(){var l,o=a(this),p=o.find(">span:first",this),q=p.length?null:o.find(">a:first"),r={tooltip:null,data:{}};for(p.length?r.title=p.html():q&&q.length?(r.title=q.html(),r.data.href=q.attr("href"),r.data.target=q.attr("target"),r.tooltip=q.attr("title")):(r.title=o.html(),g=r.title.search(/<ul/i),g>=0&&(r.title=r.title.substring(0,g))),r.title=a.trim(r.title),e=0,f=u.length;f>e;e++)r[u[e]]=d;for(j=this.className.split(" "),c=[],e=0,f=j.length;f>e;e++)k=j[e],v[k]?r[k]=!0:c.push(k);if(r.extraClasses=c.join(" "),h=o.attr("title"),h&&(r.tooltip=h),h=o.attr("id"),h&&(r.key=h),l=n(o),l&&!a.isEmptyObject(l)){for(e=0,f=w.length;f>e;e++)h=w[e],i=l[h],null!=i&&(delete l[h],r[h]=i);a.extend(r.data,l)}b=o.find(">ul:first"),r.children=b.length?a.ui.fancytree.parseHtml(b):r.lazy?d:null,m.push(r)}),m},registerExtension:function(b){f(null!=b.name,"extensions must have a `name` property."),f(null!=b.version,"extensions must have a `version` property."),a.ui.fancytree._extensions[b.name]=b},warn:function(){g("warn",arguments)}})}(jQuery,window,document);
14
+
15
+ /*! Extension 'jquery.fancytree.childcounter.min.js' */
16
+ !function(a){"use strict";a.ui.fancytree._FancytreeClass.prototype.countSelected=function(a){{var b=this;b.options}return b.getSelectedNodes(a).length},a.ui.fancytree._FancytreeNodeClass.prototype.toUpper=function(){var a=this;return a.setTitle(a.title.toUpperCase())},a.ui.fancytree.prototype.widgetMethod1=function(a){this.tree;return a},a.ui.fancytree.registerExtension({name:"childcounter",version:"1.0.0",options:{deep:!0,hideZeros:!0,hideExpanded:!1},foo:42,_appendCounter:function(){},treeInit:function(a){a.options,a.options.childcounter;this._super(a),this.$container.addClass("fancytree-ext-childcounter")},treeDestroy:function(a){this._super(a)},nodeRenderTitle:function(b,c){var d=b.node,e=b.options.childcounter,f=null==d.data.childCounter?d.countChildren(e.deep):+d.data.childCounter;this._super(b,c),!f&&e.hideZeros||d.isExpanded()&&e.hideExpanded||a("span.fancytree-icon",d.span).append(a("<span class='fancytree-childcounter'/>").text(f))},nodeSetExpanded:function(a,b,c){{var d=a.tree;a.node}return this._super(a,b,c).always(function(){d.nodeRenderTitle(a)})}})}(jQuery);
17
+
18
+ /*! Extension 'jquery.fancytree.dnd.min.js' */
19
+ !function(a,b,c,d){"use strict";function e(a){return 0===a?"":a>0?"+"+a:""+a}function f(b){var c=b.options.dnd||null;c&&g(),c&&c.dragStart&&b.widget.element.draggable(a.extend({addClasses:!1,appendTo:"body",containment:!1,delay:0,distance:4,revert:!1,scroll:!0,scrollSpeed:7,scrollSensitivity:10,connectToFancytree:!0,helper:function(b){var c=a.ui.fancytree.getNode(b.target);return c?c.tree.ext.dnd._onDragEvent("helper",c,null,b,null,null):"<div>ERROR?: helper requested but sourceNode not found</div>"},start:function(a,b){var c=b.helper.data("ftSourceNode");return!!c}},b.options.dnd.draggable)),c&&c.dragDrop&&b.widget.element.droppable(a.extend({addClasses:!1,tolerance:"intersect",greedy:!1},b.options.dnd.droppable))}function g(){i||(a.ui.plugin.add("draggable","connectToFancytree",{start:function(b,c){var d=a(this).data("ui-draggable")||a(this).data("draggable"),e=c.helper.data("ftSourceNode")||null;return e?(d.offset.click.top=-2,d.offset.click.left=16,e.tree.ext.dnd._onDragEvent("start",e,null,b,c,d)):void 0},drag:function(b,c){var d,e=a(this).data("ui-draggable")||a(this).data("draggable"),f=c.helper.data("ftSourceNode")||null,g=c.helper.data("ftTargetNode")||null,i=a.ui.fancytree.getNode(b.target);return b.target&&!i&&(d=a(b.target).closest("div.fancytree-drag-helper,#fancytree-drop-marker").length>0)?void h("Drag event over helper: ignored."):(c.helper.data("ftTargetNode",i),g&&g!==i&&g.tree.ext.dnd._onDragEvent("leave",g,f,b,c,e),void(i&&i.tree.options.dnd.dragDrop&&(i===g?i.tree.ext.dnd._onDragEvent("over",i,f,b,c,e):i.tree.ext.dnd._onDragEvent("enter",i,f,b,c,e))))},stop:function(b,c){var d=a(this).data("ui-draggable")||a(this).data("draggable"),e=c.helper.data("ftSourceNode")||null,f=c.helper.data("ftTargetNode")||null,g=b.type,i="mouseup"===g&&1===b.which;i||h("Drag was cancelled"),f&&(i&&f.tree.ext.dnd._onDragEvent("drop",f,e,b,c,d),f.tree.ext.dnd._onDragEvent("leave",f,e,b,c,d)),e&&e.tree.ext.dnd._onDragEvent("stop",e,null,b,c,d)}}),i=!0)}var h=a.ui.fancytree.debug,i=!1;a.ui.fancytree.registerExtension({name:"dnd",version:"0.1.0",options:{dragStart:null,dragStop:null,autoExpandMS:1e3,preventVoidMoves:!0,preventRecursiveMoves:!0,dragEnter:null,dragOver:null,dragDrop:null,dragLeave:null,draggable:null,droppable:null},treeInit:function(a){var b=a.tree;this._super(a),f(b)},nodeKeydown:function(b){var c=b.originalEvent;return c.which===a.ui.keyCode.ESCAPE&&this._local._cancelDrag(),this._super(b)},_setDndStatus:function(b,c,d,f,g){var h,i=0,j="center",k=this._local,l=b?a(b.span):null,m=a(c.span);if(k.$dropMarker||(k.$dropMarker=a("<div id='fancytree-drop-marker'></div>").hide().css({"z-index":1e3}).prependTo(a(this.$div).parent())),"after"===f||"before"===f||"over"===f){switch(f){case"before":k.$dropMarker.removeClass("fancytree-drop-after fancytree-drop-over"),k.$dropMarker.addClass("fancytree-drop-before"),j="top";break;case"after":k.$dropMarker.removeClass("fancytree-drop-before fancytree-drop-over"),k.$dropMarker.addClass("fancytree-drop-after"),j="bottom";break;default:k.$dropMarker.removeClass("fancytree-drop-after fancytree-drop-before"),k.$dropMarker.addClass("fancytree-drop-over"),m.addClass("fancytree-drop-target"),i=8}h=a.ui.fancytree.jquerySupports.positionMyOfs?{my:"left"+e(i)+" center",at:"left "+j,of:m}:{my:"left center",at:"left "+j,of:m,offset:""+i+" 0"},k.$dropMarker.show().position(h)}else m.removeClass("fancytree-drop-target"),k.$dropMarker.hide();"after"===f?m.addClass("fancytree-drop-after"):m.removeClass("fancytree-drop-after"),"before"===f?m.addClass("fancytree-drop-before"):m.removeClass("fancytree-drop-before"),g===!0?(l&&l.addClass("fancytree-drop-accept"),m.addClass("fancytree-drop-accept"),d.addClass("fancytree-drop-accept")):(l&&l.removeClass("fancytree-drop-accept"),m.removeClass("fancytree-drop-accept"),d.removeClass("fancytree-drop-accept")),g===!1?(l&&l.addClass("fancytree-drop-reject"),m.addClass("fancytree-drop-reject"),d.addClass("fancytree-drop-reject")):(l&&l.removeClass("fancytree-drop-reject"),m.removeClass("fancytree-drop-reject"),d.removeClass("fancytree-drop-reject"))},_onDragEvent:function(b,c,e,f,g,i){"over"!==b&&h("tree.ext.dnd._onDragEvent(%s, %o, %o) - %o",b,c,e,this);var j,k,l,m,n,o,p,q=this.options,r=q.dnd,s=this._makeHookContext(c,f,{otherNode:e,ui:g,draggable:i}),t=null,u=a(c.span);switch(b){case"helper":j=a("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>").append(u.find("span.fancytree-title").clone()),a("ul.fancytree-container",c.tree.$div).append(j),j.data("ftSourceNode",c),t=j;break;case"start":c.isStatusNode()?t=!1:r.dragStart&&(t=r.dragStart(c,s)),t===!1?(this.debug("tree.dragStart() cancelled"),g.helper.trigger("mouseup"),g.helper.hide()):u.addClass("fancytree-drag-source");break;case"enter":p=r.preventRecursiveMoves&&c.isDescendantOf(e)?!1:r.dragEnter?r.dragEnter(c,s):null,t=p?a.isArray(p)?{over:a.inArray("over",p)>=0,before:a.inArray("before",p)>=0,after:a.inArray("after",p)>=0}:{over:p===!0||"over"===p,before:p===!0||"before"===p,after:p===!0||"after"===p}:!1,g.helper.data("enterResponse",t),h("helper.enterResponse: %o",t);break;case"over":n=g.helper.data("enterResponse"),o=null,n===!1||("string"==typeof n?o=n:(k=u.offset(),l={x:f.pageX-k.left,y:f.pageY-k.top},m={x:l.x/u.width(),y:l.y/u.height()},n.after&&m.y>.75?o="after":!n.over&&n.after&&m.y>.5?o="after":n.before&&m.y<=.25?o="before":!n.over&&n.before&&m.y<=.5?o="before":n.over&&(o="over"),r.preventVoidMoves&&(c===e?(h(" drop over source node prevented"),o=null):"before"===o&&e&&c===e.getNextSibling()?(h(" drop after source node prevented"),o=null):"after"===o&&e&&c===e.getPrevSibling()?(h(" drop before source node prevented"),o=null):"over"===o&&e&&e.parent===c&&e.isLastSibling()&&(h(" drop last child over own parent prevented"),o=null)),g.helper.data("hitMode",o))),"over"===o&&r.autoExpandMS&&c.hasChildren()!==!1&&!c.expanded&&c.scheduleAction("expand",r.autoExpandMS),o&&r.dragOver&&(s.hitMode=o,t=r.dragOver(c,s)),this._local._setDndStatus(e,c,g.helper,o,t!==!1&&null!==o);break;case"drop":o=g.helper.data("hitMode"),o&&r.dragDrop&&(s.hitMode=o,r.dragDrop(c,s));break;case"leave":c.scheduleAction("cancel"),g.helper.data("enterResponse",null),g.helper.data("hitMode",null),this._local._setDndStatus(e,c,g.helper,"out",d),r.dragLeave&&r.dragLeave(c,s);break;case"stop":u.removeClass("fancytree-drag-source"),r.dragStop&&r.dragStop(c,s);break;default:throw"Unsupported drag event: "+b}return t},_cancelDrag:function(){var b=a.ui.ddmanager.current;b&&b.cancel()}})}(jQuery,window,document);
20
+
21
+ /*! Extension 'jquery.fancytree.edit.min.js' */
22
+ !function(a,b,c){"use strict";var d=/Mac/.test(navigator.platform),e=a.ui.fancytree.escapeHtml,f=a.ui.fancytree.unescapeHtml;a.ui.fancytree._FancytreeNodeClass.prototype.editStart=function(){var b,d=this,e=this.tree,g=e.ext.edit,h=d.title,i=e.options.edit,j=a(".fancytree-title",d.span),k={node:d,tree:e,options:e.options};return i.beforeEdit.call(d,{type:"beforeEdit"},k)===!1?!1:(h=d.title,d.debug("editStart"),e.widget._unbind(),a(c).on("mousedown.fancytree-edit",function(b){a(b.target).hasClass("fancytree-edit-input")||d.editEnd(!0,b)}),b=a("<input />",{"class":"fancytree-edit-input",value:f(h)}),null!=i.adjustWidthOfs&&b.width(j.width()+i.adjustWidthOfs),null!=i.inputCss&&b.css(i.inputCss),k.input=b,j.html(b),a.ui.fancytree.assert(!g.currentNode,"recursive edit"),g.currentNode=this,b.focus().change(function(){b.addClass("fancytree-edit-dirty")}).keydown(function(b){switch(b.which){case a.ui.keyCode.ESCAPE:d.editEnd(!1,b);break;case a.ui.keyCode.ENTER:return d.editEnd(!0,b),!1}}).blur(function(a){return d.editEnd(!0,a)}),void i.edit.call(d,{type:"edit"},k))},a.ui.fancytree._FancytreeNodeClass.prototype.editEnd=function(b,d){var f=this,g=this.tree,h=g.ext.edit,i=g.options.edit,j=a(".fancytree-title",f.span),k=j.find("input.fancytree-edit-input"),l=k.val(),m=k.hasClass("fancytree-edit-dirty"),n=(b||m&&b!==!1)&&l!==f.title,o={node:f,tree:g,options:g.options,originalEvent:d,dirty:m,save:n,input:k,value:l};return i.beforeClose.call(f,{type:"beforeClose"},o)===!1?!1:n&&i.save.call(f,{type:"save"},o)===!1?!1:(k.removeClass("fancytree-edit-dirty").unbind(),a(c).off(".fancytree-edit"),n?f.setTitle(e(l)):f.renderTitle(),g.widget._bind(),h.currentNode=null,f.setFocus(),a(g.$container).focus(),o.input=null,i.close.call(f,{type:"close"},o),!0)},a.ui.fancytree._FancytreeNodeClass.prototype.startEdit=function(){return this.warn("FancytreeNode.startEdit() is deprecated since 2014-01-04. Use .editStart() instead."),this.editStart.apply(this,arguments)},a.ui.fancytree._FancytreeNodeClass.prototype.endEdit=function(){return this.warn("FancytreeNode.endEdit() is deprecated since 2014-01-04. Use .editEnd() instead."),this.editEnd.apply(this,arguments)},a.ui.fancytree._FancytreeClass.prototype.isEditing=function(){return this.ext.edit.currentNode},a.ui.fancytree._FancytreeNodeClass.prototype.isEditing=function(){return this.tree.ext.edit.currentNode===this},a.ui.fancytree.registerExtension({name:"edit",version:"0.1.0",options:{adjustWidthOfs:4,inputCss:{minWidth:"3em"},triggerCancel:["esc","tab","click"],triggerStart:["f2","shift+click","mac+enter"],beforeClose:a.noop,beforeEdit:a.noop,close:a.noop,edit:a.noop,save:a.noop},currentNode:null,treeInit:function(a){this._super(a),this.$container.addClass("fancytree-ext-edit")},nodeClick:function(b){return a.inArray("shift+click",b.options.edit.triggerStart)>=0&&b.originalEvent.shiftKey?(b.node.editStart(),!1):void this._super(b)},nodeDblclick:function(b){return a.inArray("dblclick",b.options.edit.triggerStart)>=0?(b.node.editStart(),!1):this._super(b)},nodeKeydown:function(b){switch(b.originalEvent.which){case 113:if(a.inArray("f2",b.options.edit.triggerStart)>=0)return b.node.editStart(),!1;break;case a.ui.keyCode.ENTER:if(a.inArray("mac+enter",b.options.edit.triggerStart)>=0&&d)return b.node.editStart(),!1}return this._super(b)}})}(jQuery,window,document);
23
+
24
+ /*! Extension 'jquery.fancytree.filter.min.js' */
25
+ !function(a){"use strict";function b(a){return(a+"").replace(/([.?*+\^\$\[\]\\(){}|-])/g,"\\$1")}a.ui.fancytree._FancytreeClass.prototype.applyFilter=function(a){var c,d,e=0,f="hide"===this.options.filter.mode,g=this.options.filter.leavesOnly;return"string"==typeof a&&(c=b(a),d=new RegExp(".*"+c+".*","i"),a=function(a){return!!d.exec(a.title)}),this.enableFilter=!0,this.$div.addClass("fancytree-ext-filter"),this.$div.addClass(f?"fancytree-ext-filter-hide":"fancytree-ext-filter-dimm"),this.visit(function(a){delete a.match,delete a.subMatch}),this.visit(function(b){g&&null!=b.children||!a(b)||(e++,b.match=!0,b.visitParents(function(a){a.subMatch=!0}))}),this.render(),e},a.ui.fancytree._FancytreeClass.prototype.clearFilter=function(){this.visit(function(a){delete a.match,delete a.subMatch}),this.enableFilter=!1,this.$div.removeClass("fancytree-ext-filter fancytree-ext-filter-dimm fancytree-ext-filter-hide"),this.render()},a.ui.fancytree.registerExtension({name:"filter",version:"0.0.2",options:{mode:"dimm",leavesOnly:!1},treeInit:function(a){this._super(a)},treeDestroy:function(a){this._super(a)},nodeRenderStatus:function(b){var c,d=b.node,e=b.tree,f=a(d[e.statusClassPropName]);return c=this._super(b),f.length&&e.enableFilter?(f.toggleClass("fancytree-match",!!d.match),f.toggleClass("fancytree-submatch",!!d.subMatch),f.toggleClass("fancytree-hide",!(d.match||d.subMatch)),c):c}})}(jQuery,window,document);
26
+
27
+ /*! Extension 'jquery.fancytree.glyph.min.js' */
28
+ !function(a){"use strict";function b(a,b){return a.map[b]}a.ui.fancytree.registerExtension({name:"glyph",version:"0.0.2",options:{prefix:"icon-",extra:null,map:{doc:"icon-file-alt",docOpen:"icon-file-alt",checkbox:"icon-check-empty",checkboxSelected:"icon-check",checkboxUnknown:"icon-check icon-muted",error:"icon-exclamation-sign",expanderClosed:"icon-caret-right",expanderLazy:"icon-angle-right",expanderOpen:"icon-caret-down",folder:"icon-folder-close-alt",folderOpen:"icon-folder-open-alt",loading:"icon-refresh icon-spin",noExpander:""},icon:null},treeInit:function(a){var b=a.tree;this._super(a),b.$container.addClass("fancytree-ext-glyph")},nodeRenderStatus:function(c){var d,e,f=c.node,g=c.options.glyph,h=g.map;this._super(c),f.isRoot()||(e=a("span.fancytree-expander",f.span).get(0),e&&(d=f.isLoading()?"loading":f.expanded?"expanderOpen":f.isUndefined()?"expanderLazy":f.hasChildren()?"expanderClosed":"noExpander",e.className="fancytree-expander "+h[d]),e=a("span.fancytree-checkbox",f.tr||f.span).get(0),e&&(d=f.selected?"checkboxSelected":f.partsel?"checkboxUnknown":"checkbox",e.className="fancytree-checkbox "+h[d]),e=a("span.fancytree-icon",f.span).get(0),e&&(d=f.folder?f.expanded?b(g,"folderOpen"):b(g,"folder"):f.expanded?b(g,"docOpen"):b(g,"doc"),e.className="fancytree-icon "+d))},nodeSetStatus:function(c,d,e,f){var g,h=c.options.glyph,i=c.node;this._super(c,d,e,f),g=i.parent?a("span.fancytree-expander",i.span).get(0):a(".fancytree-statusnode-wait, .fancytree-statusnode-error",i[this.nodeContainerAttrName]).find("span.fancytree-expander").get(0),"loading"===d?g.className="fancytree-expander "+b(h,"loading"):"error"===d&&(g.className="fancytree-expander "+b(h,"error"))}})}(jQuery,window,document);
29
+
30
+ /*! Extension 'jquery.fancytree.gridnav.min.js' */
31
+ !function(a){"use strict";function b(b,c){var d,e=c.get(0),f=0;return b.children().each(function(){return this===e?!1:(d=a(this).prop("colspan"),void(f+=d?d:1))}),f}function c(b,c){var d,e=null,f=0;return b.children().each(function(){return f>=c?(e=a(this),!1):(d=a(this).prop("colspan"),void(f+=d?d:1))}),e}function d(a,d){var f,g,h=a.closest("td"),i=null;switch(d){case e.LEFT:i=h.prev();break;case e.RIGHT:i=h.next();break;case e.UP:case e.DOWN:for(f=h.parent(),g=b(f,h);;){if(f=d===e.UP?f.prev():f.next(),!f.length)break;if(!f.is(":hidden")&&(i=c(f,g),i&&i.find(":input").length))break}}return i}var e=a.ui.keyCode,f={text:[e.UP,e.DOWN],checkbox:[e.UP,e.DOWN,e.LEFT,e.RIGHT],radiobutton:[e.UP,e.DOWN,e.LEFT,e.RIGHT],"select-one":[e.LEFT,e.RIGHT],"select-multiple":[e.LEFT,e.RIGHT]};a.ui.fancytree.registerExtension({name:"gridnav",version:"0.0.1",options:{autofocusInput:!1,handleCursorKeys:!0},treeInit:function(b){this._requireExtension("table",!0,!0),this._super(b),this.$container.addClass("fancytree-ext-gridnav"),this.$container.on("focusin",function(c){var d,e=a.ui.fancytree.getNode(c.target);e&&!e.isActive()&&(d=b.tree._makeHookContext(e,c),b.tree._callHook("nodeSetActive",d,!0))})},nodeSetActive:function(b,c){var d,e=b.options.gridnav,f=b.node,g=b.originalEvent||{},h=a(g.target).is(":input");c=c!==!1,this._super(b,c),c&&(b.options.titlesTabbable?(h||(a(f.span).find("span.fancytree-title").focus(),f.setFocus()),b.tree.$container.attr("tabindex","-1")):e.autofocusInput&&!h&&(d=a(f.tr||f.span),d.find(":input:enabled:first").focus()))},nodeKeydown:function(b){var c,e,g,h=b.options.gridnav,i=b.originalEvent,j=a(i.target);return c=j.is(":input:enabled")?j.prop("type"):null,c&&h.handleCursorKeys?(e=f[c],e&&a.inArray(i.which,e)>=0&&(g=d(j,i.which),g&&g.length)?(g.find(":input:enabled").focus(),!1):!0):(b.tree.debug("ext-gridnav NOT HANDLED",i,c),this._super(b))}})}(jQuery,window,document);
32
+
33
+ /*! Extension 'jquery.fancytree.persist.min.js' */
34
+ !function(a,b,c,d){"use strict";function e(b,c){c=c||"",b||a.error("Assertion failed "+c)}function f(b,c,d,e,g){var i,j,k,l,m=!1,n=[],o=[];for(d=d||[],g=g||a.Deferred(),i=0,k=d.length;k>i;i++)j=d[i],l=b.getNodeByKey(j),l?e&&l.isUndefined()?(m=!0,b.debug("_loadLazyNodes: "+l+" is lazy: loading..."),n.push("expand"===e?l.setExpanded():l.load())):(b.debug("_loadLazyNodes: "+l+" already loaded."),l.setExpanded()):(o.push(j),b.debug("_loadLazyNodes: "+l+" was not yet found."));return a.when.apply(a,n).always(function(){if(m&&o.length>0)f(b,c,o,e,g);else{if(o.length)for(b.warn("_loadLazyNodes: could not load those keys: ",o),i=0,k=o.length;k>i;i++)j=d[i],c._setKey(h,d[i],!1);g.resolve()}}),g}var g="active",h="expanded",i="focus",j="selected";a.ui.fancytree._FancytreeClass.prototype.clearCookies=function(b){var c=this.ext.persist,d=c.cookiePrefix;b=b||"active expanded focus selected",b.indexOf(g)>=0&&a.removeCookie(d+g),b.indexOf(h)>=0&&a.removeCookie(d+h),b.indexOf(i)>=0&&a.removeCookie(d+i),b.indexOf(j)>=0&&a.removeCookie(d+j)},a.ui.fancytree._FancytreeClass.prototype.getPersistData=function(){var b=this.ext.persist,c=this.options.persist,d=c.cookieDelimiter,e={};return e[g]=a.cookie(b.cookiePrefix+g),e[h]=(a.cookie(b.cookiePrefix+h)||"").split(d),e[j]=(a.cookie(b.cookiePrefix+j)||"").split(d),e[i]=a.cookie(b.cookiePrefix+i),e},a.ui.fancytree.registerExtension({name:"persist",version:"0.2.0",options:{cookieDelimiter:"~",cookiePrefix:d,cookie:{raw:!1,expires:"",path:"",domain:"",secure:!1},expandLazy:!1,overrideSource:!1,types:"active expanded focus selected"},_setKey:function(b,c,d){c=""+c;var e=this._local,f=this.options.persist,g=e.cookiePrefix+b,h=a.cookie(g),i=h?h.split(f.cookieDelimiter):[],j=a.inArray(c,i);j>=0&&i.splice(j,1),d&&i.push(c),a.cookie(g,i.join(f.cookieDelimiter),f.cookie)},treeInit:function(b){var k=b.tree,l=b.options,m=this._local,n=this.options.persist;e(a.cookie,"Missing required plugin for 'persist' extension: jquery.cookie.js"),m.cookiePrefix=n.cookiePrefix||"fancytree-"+k._id+"-",m.storeActive=n.types.indexOf(g)>=0,m.storeExpanded=n.types.indexOf(h)>=0,m.storeSelected=n.types.indexOf(j)>=0,m.storeFocus=n.types.indexOf(i)>=0,k.$div.bind("fancytreeinit",function(){var b,e,o,p,q,r=a.cookie(m.cookiePrefix+i);k.debug("COOKIE "+c.cookie),b=a.cookie(m.cookiePrefix+h),p=b&&b.split(n.cookieDelimiter),e=m.storeExpanded?f(k,m,p,n.expandLazy?"expand":!1,null):(new a.Deferred).resolve(),e.done(function(){if(m.storeSelected&&(b=a.cookie(m.cookiePrefix+j)))for(p=b.split(n.cookieDelimiter),o=0;o<p.length;o++)q=k.getNodeByKey(p[o]),q?(q.selected===d||n.overrideSource&&q.selected===!1)&&(q.selected=!0,q.renderStatus()):m._setKey(j,p[o],!1);m.storeActive&&(b=a.cookie(m.cookiePrefix+g),!b||!l.persist.overrideSource&&k.activeNode||(q=k.getNodeByKey(b),q&&q.setActive())),m.storeFocus&&r&&(q=k.getNodeByKey(r),q&&q.setFocus())})}),this._super(b)},nodeSetActive:function(b,c,d){var e=this._local,f=this.options.persist;c=c!==!1,this._super(b,c,d),e.storeActive&&a.cookie(e.cookiePrefix+g,this.activeNode?this.activeNode.key:null,f.cookie)},nodeSetExpanded:function(a,b,c){var d,e=a.node,f=this._local;return b=b!==!1,d=this._super(a,b,c),f.storeExpanded&&f._setKey(h,e.key,b),d},nodeSetFocus:function(b){var c=this._local,d=this.options.persist;this._super(b),c.storeFocus&&a.cookie(c.cookiePrefix+i,this.focusNode?this.focusNode.key:null,d.cookie)},nodeSetSelected:function(a,b){var c=a.node,d=this._local;b=b!==!1,this._super(a,b),d.storeSelected&&d._setKey(j,c.key,b)}})}(jQuery,window,document);
35
+
36
+ /*! Extension 'jquery.fancytree.table.min.js' */
37
+ !function(a,b,c){"use strict";function d(b,c){c=c||"",b||a.error("Assertion failed "+c)}function e(a,b){a.parentNode.insertBefore(b,a.nextSibling)}function f(a,b){a.visit(function(a){var c=a.tr;return c&&(c.style.display=a.hide||!b?"none":""),a.expanded?void 0:"skip"})}function g(b){var c,e,f,g=b.parent,h=g?g.children:null;if(h&&h.length>1&&h[0]!==b)for(c=a.inArray(b,h),f=h[c-1],d(f.tr);f.children&&(e=f.children[f.children.length-1],e.tr);)f=e;else f=g;return f}a.ui.fancytree.registerExtension({name:"table",version:"0.2.0",options:{checkboxColumnIdx:null,customStatus:!1,indentation:16,nodeColumnIdx:0},treeInit:function(b){var d,e,f,g=b.tree,h=g.widget.element;for(h.addClass("fancytree-container fancytree-ext-table"),g.tbody=h.find("> tbody")[0],g.columnCount=a("thead >tr >th",h).length,a(g.tbody).empty(),g.rowFragment=c.createDocumentFragment(),e=a("<tr />"),f="",b.options.aria&&(e.attr("role","row"),f=" role='gridcell'"),d=0;d<g.columnCount;d++)e.append(b.options.table.nodeColumnIdx===d?"<td"+f+"><span class='fancytree-node' /></td>":"<td"+f+" />");g.rowFragment.appendChild(e.get(0)),g.statusClassPropName="tr",g.ariaPropName="tr",this.nodeContainerAttrName="tr",this._super(b),a(g.rootNode.ul).remove(),g.rootNode.ul=null,g.$container=h,this.$container.attr("tabindex",this.options.tabbable?"0":"-1"),this.options.aria&&g.$container.attr("role","treegrid").attr("aria-readonly",!0)},nodeRemoveChildMarkup:function(b){var c=b.node;c.visit(function(b){b.tr&&(a(b.tr).remove(),b.tr=null)})},nodeRemoveMarkup:function(b){var c=b.node;c.tr&&(a(c.tr).remove(),c.tr=null),this.nodeRemoveChildMarkup(b)},nodeRender:function(b,c,h,i,j){var k,l,m,n,o,p,q,r,s=b.tree,t=b.node,u=b.options,v=!t.parent;if(j||(b.hasCollapsedParents=t.parent&&!t.parent.expanded),!v)if(t.tr)c?this.nodeRenderTitle(b):this.nodeRenderStatus(b);else{if(b.hasCollapsedParents)return void t.debug("nodeRender ignored due to unrendered parent");o=s.rowFragment.firstChild.cloneNode(!0),p=g(t),d(p),i===!0&&j?o.style.display="none":h&&b.hasCollapsedParents&&(o.style.display="none"),p.tr?e(p.tr,o):(d(!p.parent,"prev. row must have a tr, or is system root"),s.tbody.appendChild(o)),t.tr=o,t.key&&u.generateIds&&(t.tr.id=u.idPrefix+t.key),t.tr.ftnode=t,u.aria&&a(t.tr).attr("aria-labelledby","ftal_"+t.key),t.span=a("span.fancytree-node",t.tr).get(0),this.nodeRenderTitle(b),u.createNode&&u.createNode.call(s,{type:"createNode"},b)}if(u.renderNode&&u.renderNode.call(s,{type:"renderNode"},b),k=t.children,k&&(v||h||t.expanded))for(m=0,n=k.length;n>m;m++)r=a.extend({},b,{node:k[m]}),r.hasCollapsedParents=r.hasCollapsedParents||!t.expanded,this.nodeRender(r,c,h,i,!0);k&&!j&&(q=t.tr||null,l=s.tbody.firstChild,t.visit(function(a){if(a.tr){if(a.parent.expanded||"none"===a.tr.style.display||(a.tr.style.display="none",f(a,!1)),a.tr.previousSibling!==q){t.debug("_fixOrder: mismatch at node: "+a);var b=q?q.nextSibling:l;s.tbody.insertBefore(a.tr,b)}q=a.tr}}))},nodeRenderTitle:function(b){var c,d=b.node,e=b.options;this._super(b),e.checkbox&&null!=e.table.checkboxColumnIdx&&(c=a("span.fancytree-checkbox",d.span).detach(),a(d.tr).find("td:first").html(c)),d.isRoot()||this.nodeRenderStatus(b),!e.table.customStatus&&d.isStatusNode()||e.renderColumns&&e.renderColumns.call(b.tree,{type:"renderColumns"},b)},nodeRenderStatus:function(b){var c,d=b.node,e=b.options;this._super(b),a(d.tr).removeClass("fancytree-node"),c=(d.getLevel()-1)*e.table.indentation,a(d.span).css({marginLeft:c+"px"})},nodeSetExpanded:function(b,c,d){function e(a){c=c!==!1,f(b.node,c),h.noEvents||b.tree._triggerNodeEvent(c?"expand":"collapse",b),a?g.resolveWith(b.node):g.rejectWith(b.node)}var g=new a.Deferred,h=d||{};return d=a.extend({},d,{noEvents:!0,noAnimation:!0}),this._super(b,c,d).done(function(){e(!0)}).fail(function(){e(!1)}),g.promise()},nodeSetStatus:function(b,c,d,e){if("ok"===c){var f=b.node,g=f.children?f.children[0]:null;g&&g.isStatusNode()&&a(g.tr).remove()}this._super(b,c,d,e)},treeClear:function(a){return this.nodeRemoveChildMarkup(this._makeHookContext(this.rootNode)),this._super(a)}})}(jQuery,window,document);
38
+
39
+ /*! Extension 'jquery.fancytree.themeroller.min.js' */
40
+ !function(a){"use strict";a.ui.fancytree.registerExtension({name:"themeroller",version:"0.0.1",options:{activeClass:"ui-state-active",foccusClass:"ui-state-focus",hoverClass:"ui-state-hover",selectedClass:"ui-state-highlight"},treeInit:function(b){this._super(b);var c=b.widget.element;"TABLE"===c[0].nodeName?(c.addClass("ui-widget ui-corner-all"),c.find(">thead tr").addClass("ui-widget-header"),c.find(">tbody").addClass("ui-widget-conent")):c.addClass("ui-widget ui-widget-content ui-corner-all"),c.delegate(".fancytree-node","mouseenter mouseleave",function(b){var c=a.ui.fancytree.getNode(b.target),d="mouseenter"===b.type;c.debug("hover: "+d),a(c.span).toggleClass("ui-state-hover ui-corner-all",d)})},treeDestroy:function(a){this._super(a),a.widget.element.removeClass("ui-widget ui-widget-content ui-corner-all")},nodeRenderStatus:function(b){var c=b.node,d=a(c.span);this._super(b),d.toggleClass("ui-state-active",c.isActive()),d.toggleClass("ui-state-focus",c.hasFocus()),d.toggleClass("ui-state-highlight",c.isSelected())}})}(jQuery,window,document);
41
+ }));
@@ -7,8 +7,8 @@
7
7
  * Released under the MIT license
8
8
  * https://github.com/mar10/fancytree/wiki/LicenseInfo
9
9
  *
10
- * @version 2.0.0-6
11
- * @date 2014-02-10T10:52
10
+ * @version 2.0.0-11
11
+ * @date 2014-04-27T22:28
12
12
  */
13
13
 
14
14
  /** Core Fancytree module.
@@ -168,6 +168,20 @@ function _makeResolveFunc(deferred, context){
168
168
  }
169
169
 
170
170
 
171
+ function _getElementDataAsDict($el){
172
+ // Evaluate 'data-NAME' attributes with special treatment for 'data-json'.
173
+ var d = $.extend({}, $el.data()),
174
+ json = d.json;
175
+ delete d.fancytree; // added to container by widget factory
176
+ if( json ) {
177
+ delete d.json;
178
+ // <li data-json='...'> is already returned as object (http://api.jquery.com/data/#data-html5)
179
+ d = $.extend(d, json);
180
+ }
181
+ return d;
182
+ }
183
+
184
+
171
185
  // TODO: use currying
172
186
  function _makeNodeTitleMatcher(s){
173
187
  s = s.toLowerCase();
@@ -178,11 +192,12 @@ function _makeNodeTitleMatcher(s){
178
192
 
179
193
  var i,
180
194
  FT = null, // initialized below
195
+ ENTITY_MAP = {"&": "&amp;", "<": "&lt;", ">": "&gt;", "\"": "&quot;", "'": "&#39;", "/": "&#x2F;"},
181
196
  //boolean attributes that can be set with equivalent class names in the LI tags
182
- CLASS_ATTRS = "active expanded focus folder lazy selected unselectable".split(" "),
197
+ CLASS_ATTRS = "active expanded focus folder hideCheckbox lazy selected unselectable".split(" "),
183
198
  CLASS_ATTR_MAP = {},
184
199
  // Top-level Fancytree node attributes, that can be set by dict
185
- NODE_ATTRS = "expanded extraClasses folder hideCheckbox key lazy selected title tooltip unselectable".split(" "),
200
+ NODE_ATTRS = "expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "),
186
201
  NODE_ATTR_MAP = {},
187
202
  // Attribute names that should NOT be added to node.data
188
203
  NONE_NODE_DATA_MAP = {"active": true, "children": true, "data": true, "focus": true};
@@ -205,21 +220,22 @@ for(i=0; i<NODE_ATTRS.length; i++){ NODE_ATTR_MAP[NODE_ATTRS[i]] = true; }
205
220
  * @param {FancytreeNode} parent
206
221
  * @param {NodeData} obj
207
222
  *
208
- * @property {Fancytree} tree
209
- * @property {FancytreeNode} parent Parent node
210
- * @property {string} key
211
- * @property {string} title
223
+ * @property {Fancytree} tree The tree instance
224
+ * @property {FancytreeNode} parent The parent node
225
+ * @property {string} key Node id (must be unique inside the tree)
226
+ * @property {string} title Display name (may contain HTML)
212
227
  * @property {object} data Contains all extra data that was passed on node creation
213
- * @property {FancytreeNode[] | null | undefined} children list of child nodes
214
- * @property {boolean} isStatusNode
215
- * @property {boolean} expanded
216
- * @property {boolean} folder
217
- * @property {string} extraClasses
218
- * @property {boolean} lazy
219
- * @property {boolean} selected
220
- * @property {string} tooltip
221
- * @property {string} data.href
222
- * @property {string} data.target
228
+ * @property {FancytreeNode[] | null | undefined} children Array of child nodes.<br>
229
+ * For lazy nodes, null or undefined means 'not yet loaded'. Use an empty array
230
+ * to define a node that has no children.
231
+ * @property {boolean} expanded Use isExpanded(), setExpanded() to access this property.
232
+ * @property {string} extraClasses Addtional CSS classes, added to the node's `&lt;span>`
233
+ * @property {boolean} folder Folder nodes have different default icons and click behavior.<br>
234
+ * Note: Also non-folders may have children.
235
+ * @property {string} statusNodeType null or type of temporarily generated system node like 'loading', or 'error'.
236
+ * @property {boolean} lazy True if this node is loaded on demand, i.e. on first expansion.
237
+ * @property {boolean} selected Use isSelected(), setSelected() to access this property.
238
+ * @property {string} tooltip Alternative description used as hover banner
223
239
  */
224
240
  function FancytreeNode(parent, obj){
225
241
  var i, l, name, cl;
@@ -228,7 +244,9 @@ function FancytreeNode(parent, obj){
228
244
  this.tree = parent.tree;
229
245
  this.ul = null;
230
246
  this.li = null; // <li id='key' ftnode=this> tag
231
- this.isStatusNode = false;
247
+ this.statusNodeType = null; // if this is a temp. node to display the status of its parent
248
+ this._isLoading = false; // if this node itself is loading
249
+ this._error = null; // {message: '...'} if a load error occured
232
250
  this.data = {};
233
251
 
234
252
  // TODO: merge this code with node.toDict()
@@ -251,8 +269,14 @@ function FancytreeNode(parent, obj){
251
269
 
252
270
  // Fix missing key
253
271
  if( this.key == null ){ // test for null OR undefined
254
- this.key = "_" + (FT._nextNodeKey++);
272
+ if( this.tree.options.defaultKey ) {
273
+ this.key = this.tree.options.defaultKey(this);
274
+ _assert(this.key, "defaultKey() must return a unique key");
275
+ } else {
276
+ this.key = "_" + (FT._nextNodeKey++);
277
+ }
255
278
  }
279
+
256
280
  // Fix tree.activeNode
257
281
  // TODO: not elegant: we use obj.active as marker to set tree.activeNode
258
282
  // when loading from a dictionary.
@@ -260,6 +284,9 @@ function FancytreeNode(parent, obj){
260
284
  _assert(this.tree.activeNode === null, "only one active node allowed");
261
285
  this.tree.activeNode = this;
262
286
  }
287
+ if( obj.selected ){ // #186
288
+ this.tree.lastSelectedNode = this;
289
+ }
263
290
  // TODO: handle obj.focus = true
264
291
  // Create child nodes
265
292
  this.children = null;
@@ -267,6 +294,10 @@ function FancytreeNode(parent, obj){
267
294
  if(cl && cl.length){
268
295
  this._setChildren(cl);
269
296
  }
297
+ // Add to key/ref map (except for root node)
298
+ // if( parent ) {
299
+ this.tree._callHook("treeRegisterNode", this.tree, true, this);
300
+ // }
270
301
  }
271
302
 
272
303
 
@@ -368,6 +399,17 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
368
399
  }
369
400
  _assert(false, "Invalid mode: " + mode);
370
401
  },
402
+ /**
403
+ * Append new node after this.
404
+ *
405
+ * This a convenience function that calls addNode(node, 'after')
406
+ *
407
+ * @param {NodeData} node node definition
408
+ * @returns {FancytreeNode} new node
409
+ */
410
+ appendSibling: function(node){
411
+ return this.addNode(node, "after");
412
+ },
371
413
  /**
372
414
  * Modify existing child nodes.
373
415
  *
@@ -417,7 +459,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
417
459
  }
418
460
  return promise;
419
461
  },
420
- /**
462
+ /** Collapse all sibling nodes.
421
463
  * @returns {$.Promise}
422
464
  */
423
465
  collapseSiblings: function() {
@@ -462,12 +504,12 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
462
504
  consoleApply("debug", arguments);
463
505
  }
464
506
  },
465
- /** Remove all children of a lazy node and collapse.*/
507
+ /** Deprecated.
508
+ * @deprecated since 2014-02-16. Use resetLazy() instead.
509
+ */
466
510
  discard: function(){
467
- if(this.lazy && $.isArray(this.children)){
468
- this.removeChildren();
469
- return this.setExpanded(false);
470
- }
511
+ this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead.");
512
+ return this.resetLazy();
471
513
  },
472
514
  // TODO: expand(flag)
473
515
  /**Find all nodes that contain `match` in the title.
@@ -529,7 +571,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
529
571
  default:
530
572
  _assert(false, "invalid state: " + state);
531
573
  }
532
- this.debug("fixSelection3AfterLoad() _changeSelectStatusAttrs()", state, changed);
574
+ // this.debug("fixSelection3AfterLoad() _changeSelectStatusAttrs()", state, changed);
533
575
  if( changed ){
534
576
  this.renderStatus();
535
577
  }
@@ -658,23 +700,31 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
658
700
  this.addChild(children);
659
701
  */
660
702
  },
661
- /** @returns {FancytreeNode[] | undefined} list of child nodes (undefined for unexpanded lazy nodes).*/
703
+ /** Return the list of child nodes (undefined for unexpanded lazy nodes).
704
+ * @returns {FancytreeNode[] | undefined}
705
+ */
662
706
  getChildren: function() {
663
707
  if(this.hasChildren() === undefined){ // TODO: only required for lazy nodes?
664
708
  return undefined; // Lazy node: unloaded, currently loading, or load error
665
709
  }
666
710
  return this.children;
667
711
  },
668
- /** @returns {FancytreeNode | null}*/
712
+ /** Return the first child node or null.
713
+ * @returns {FancytreeNode | null}
714
+ */
669
715
  getFirstChild: function() {
670
716
  return this.children ? this.children[0] : null;
671
717
  },
672
- /** @returns {int} 0-based child index.*/
718
+ /** Return the 0-based child index.
719
+ * @returns {int}
720
+ */
673
721
  getIndex: function() {
674
722
  // return this.parent.children.indexOf(this);
675
723
  return $.inArray(this, this.parent.children); // indexOf doesn't work in IE7
676
724
  },
677
- /**@returns {string} hierarchical child index (1-based: '3.2.4').*/
725
+ /** Return the hierarchical child index (1-based, e.g. '3.2.4').
726
+ * @returns {string}
727
+ */
678
728
  getIndexHier: function(separator) {
679
729
  separator = separator || ".";
680
730
  var res = [];
@@ -683,9 +733,9 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
683
733
  });
684
734
  return res.join(separator);
685
735
  },
686
- /**
736
+ /** Return the parent keys separated by options.keyPathSeparator, e.g. "id_1/id_17/id_32".
687
737
  * @param {boolean} [excludeSelf=false]
688
- * @returns {string} parent keys separated by options.keyPathSeparator
738
+ * @returns {string}
689
739
  */
690
740
  getKeyPath: function(excludeSelf) {
691
741
  var path = [],
@@ -697,11 +747,15 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
697
747
  }, !excludeSelf);
698
748
  return sep + path.join(sep);
699
749
  },
700
- /**@returns {FancytreeNode | null} last child of this node.*/
750
+ /** Return the last child of this node or null.
751
+ * @returns {FancytreeNode | null}
752
+ */
701
753
  getLastChild: function() {
702
754
  return this.children ? this.children[this.children.length - 1] : null;
703
755
  },
704
- /** @returns {int} node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, .... */
756
+ /** Return node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, ... .
757
+ * @returns {int}
758
+ */
705
759
  getLevel: function() {
706
760
  var level = 0,
707
761
  dtn = this.parent;
@@ -711,7 +765,9 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
711
765
  }
712
766
  return level;
713
767
  },
714
- /** @returns {FancytreeNode | null} */
768
+ /** Return the successor node (under the same parent) or null.
769
+ * @returns {FancytreeNode | null}
770
+ */
715
771
  getNextSibling: function() {
716
772
  // TODO: use indexOf, if available: (not in IE6)
717
773
  if( this.parent ){
@@ -726,14 +782,16 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
726
782
  }
727
783
  return null;
728
784
  },
729
- /** @returns {FancytreeNode | null} returns null for the system root node*/
785
+ /** Return the parent node (null for the system root node).
786
+ * @returns {FancytreeNode | null}
787
+ */
730
788
  getParent: function() {
731
789
  // TODO: return null for top-level nodes?
732
790
  return this.parent;
733
791
  },
734
- /**
735
- * @param {boolean} [includeRoot=false]
736
- * @param {boolean} [includeSelf=false]
792
+ /** Return an array of all parent nodes (top-down).
793
+ * @param {boolean} [includeRoot=false] Include the invisible system root node.
794
+ * @param {boolean} [includeSelf=false] Include the node itself.
737
795
  * @returns {FancytreeNode[]}
738
796
  */
739
797
  getParentList: function(includeRoot, includeSelf) {
@@ -747,7 +805,9 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
747
805
  }
748
806
  return l;
749
807
  },
750
- /** @returns {FancytreeNode | null} */
808
+ /** Return the predecessor node (under the same parent) or null.
809
+ * @returns {FancytreeNode | null}
810
+ */
751
811
  getPrevSibling: function() {
752
812
  if( this.parent ){
753
813
  var i, l,
@@ -761,7 +821,9 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
761
821
  }
762
822
  return null;
763
823
  },
764
- /** @returns {boolean | undefined} Check if node has children (returns undefined, if not sure). */
824
+ /** Return true if node has children. Return undefined if not sure, i.e. the node is lazy and not yet loaded).
825
+ * @returns {boolean | undefined}
826
+ */
765
827
  hasChildren: function() {
766
828
  if(this.lazy){
767
829
  if(this.children == null ){
@@ -770,7 +832,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
770
832
  }else if(this.children.length === 0){
771
833
  // Loaded, but response was empty
772
834
  return false;
773
- }else if(this.children.length === 1 && this.children[0].isStatusNode ){
835
+ }else if(this.children.length === 1 && this.children[0].isStatusNode() ){
774
836
  // Currently loading or load error
775
837
  return undefined;
776
838
  }
@@ -778,24 +840,28 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
778
840
  }
779
841
  return !!this.children;
780
842
  },
781
- /**@returns {boolean} true, if node has keyboard focus*/
843
+ /** Return true if node has keyboard focus.
844
+ * @returns {boolean}
845
+ */
782
846
  hasFocus: function() {
783
847
  return (this.tree.hasFocus() && this.tree.focusNode === this);
784
848
  },
785
- /**@returns {boolean} true, if node is active*/
849
+ /** Return true if node is active (see also FancytreeNode#isSelected).
850
+ * @returns {boolean}
851
+ */
786
852
  isActive: function() {
787
853
  return (this.tree.activeNode === this);
788
854
  },
789
- /**
855
+ /** Return true if node is a direct child of otherNode.
790
856
  * @param {FancytreeNode} otherNode
791
- * @returns {boolean} true, if node is a direct child of otherNode
857
+ * @returns {boolean}
792
858
  */
793
859
  isChildOf: function(otherNode) {
794
860
  return (this.parent && this.parent === otherNode);
795
861
  },
796
- /**
862
+ /** Return true, if node is a direct or indirect sub node of otherNode.
797
863
  * @param {FancytreeNode} otherNode
798
- * @returns {boolean} true, if node is a sub node of otherNode
864
+ * @returns {boolean}
799
865
  */
800
866
  isDescendantOf: function(otherNode) {
801
867
  if(!otherNode || otherNode.tree !== this.tree){
@@ -810,45 +876,79 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
810
876
  }
811
877
  return false;
812
878
  },
813
- /** @returns {boolean} true, if node is expanded*/
879
+ /** Return true if node is expanded.
880
+ * @returns {boolean}
881
+ */
814
882
  isExpanded: function() {
815
883
  return !!this.expanded;
816
884
  },
817
- /** @returns {boolean}*/
885
+ /** Return true if node is the first node of its parent's children.
886
+ * @returns {boolean}
887
+ */
818
888
  isFirstSibling: function() {
819
889
  var p = this.parent;
820
890
  return !p || p.children[0] === this;
821
891
  },
822
- /** @returns {boolean}*/
892
+ /** Return true if node is a folder, i.e. has the node.folder attribute set.
893
+ * @returns {boolean}
894
+ */
823
895
  isFolder: function() {
824
896
  return !!this.folder;
825
897
  },
826
- /** @returns {boolean}*/
898
+ /** Return true if node is the last node of its parent's children.
899
+ * @returns {boolean}
900
+ */
827
901
  isLastSibling: function() {
828
902
  var p = this.parent;
829
903
  return !p || p.children[p.children.length-1] === this;
830
904
  },
831
- /** @returns {boolean} true, if node is lazy (even if data was already loaded)*/
905
+ /** Return true if node is lazy (even if data was already loaded)
906
+ * @returns {boolean}
907
+ */
832
908
  isLazy: function() {
833
909
  return !!this.lazy;
834
910
  },
835
- /** @returns {boolean} true, if children are currently beeing loaded*/
911
+ /** Return true if node is lazy and loaded. For non-lazy nodes always return true.
912
+ * @returns {boolean}
913
+ */
914
+ isLoaded: function() {
915
+ return !this.lazy || this.hasChildren() !== undefined; // Also checks if the only child is a status node
916
+ },
917
+ /** Return true if children are currently beeing loaded, i.e. a Ajax request is pending.
918
+ * @returns {boolean}
919
+ */
836
920
  isLoading: function() {
837
- _raiseNotImplemented(); // TODO: implement
921
+ return !!this._isLoading;
838
922
  },
839
- /**@returns {boolean} true, if node is the (invisible) system root node*/
923
+ /** Return true if this is the (invisible) system root node.
924
+ * @returns {boolean}
925
+ */
840
926
  isRoot: function() {
841
927
  return (this.tree.rootNode === this);
842
928
  },
843
- /** @returns {boolean} true, if node is selected (e.g. has a checkmark set)*/
929
+ /** Return true if node is selected, i.e. has a checkmark set (see also FancytreeNode#isActive).
930
+ * @returns {boolean}
931
+ */
844
932
  isSelected: function() {
845
933
  return !!this.selected;
846
934
  },
847
- // TODO: use _isStatusNode as class attribute name
848
- // isStatusNode: function() {
849
- // return (this.data.isStatusNode === true);
850
- // },
851
- /** Return true, if all parents are expanded. */
935
+ /** Return true if this node is a temporarily generated system node like
936
+ * 'loading', or 'error' (node.statusNodeType contains the type).
937
+ * @returns {boolean}
938
+ */
939
+ isStatusNode: function() {
940
+ return !!this.statusNodeType;
941
+ },
942
+ /** Return true if node is lazy and not yet loaded. For non-lazy nodes always return false.
943
+ * @returns {boolean}
944
+ */
945
+ isUndefined: function() {
946
+ return this.hasChildren() === undefined; // also checks if the only child is a status node
947
+ },
948
+ /** Return true if all parent nodes are expanded. Note: this does not check
949
+ * whether the node is scrolled into the visible part of the screen.
950
+ * @returns {boolean}
951
+ */
852
952
  isVisible: function() {
853
953
  var i, l,
854
954
  parents = this.getParentList(false, false);
@@ -858,28 +958,87 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
858
958
  }
859
959
  return true;
860
960
  },
861
- /** Expand all parents and optionally scroll into visible area as neccessary (async).
862
- *
961
+ /** Deprecated.
962
+ * @deprecated since 2014-02-16: use load() instead.
863
963
  */
864
- makeVisible: function() {
865
- // TODO: implement scolling (http://www.w3.org/TR/wai-aria-practices/#visualfocus)
866
- // TODO: return $.promise
867
- var i, l,
868
- parents = this.getParentList(false, false);
964
+ lazyLoad: function(discard) {
965
+ this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead.");
966
+ return this.load(discard);
967
+ },
968
+ /**
969
+ * Load all children of a lazy node.
970
+ * @param {boolean} [forceReload=false] Pass true to discard any existing nodes before.
971
+ * @returns {$.Promise}
972
+ */
973
+ load: function(forceReload) {
974
+ var res, source,
975
+ that = this;
869
976
 
870
- for(i=0, l=parents.length; i<l; i++){
871
- parents[i].setExpanded(true);
977
+ _assert( this.isLazy(), "load() requires a lazy node" );
978
+ _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" );
979
+
980
+ if( this.isLoaded() ){
981
+ this.resetLazy(); // also collapses
872
982
  }
983
+ // This method is also called by setExpanded() and loadKeyPath(), so we
984
+ // have to avoid recursion.
985
+ source = this.tree._triggerNodeEvent("lazyLoad", this);
986
+ if( source === false ) { // #69
987
+ return _getResolvedPromise(this);
988
+ }
989
+ _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result");
990
+ res = this.tree._callHook("nodeLoadChildren", this, source);
991
+ if( this.expanded ) {
992
+ res.always(function(){
993
+ that.render();
994
+ });
995
+ }
996
+ return res;
997
+ },
998
+ /** Expand all parents and optionally scroll into visible area as neccessary.
999
+ * Promise is resolved, when lazy loading and animations are done.
1000
+ * @param {object} [opts] passed to `setExpanded()`.
1001
+ * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true}
1002
+ * @returns {$.Promise}
1003
+ */
1004
+ makeVisible: function(opts) {
1005
+ var i,
1006
+ that = this,
1007
+ deferreds = [],
1008
+ dfd = new $.Deferred(),
1009
+ parents = this.getParentList(false, false),
1010
+ len = parents.length,
1011
+ effects = !(opts && opts.noAnimation === true),
1012
+ scroll = !(opts && opts.scrollIntoView === false);
1013
+
1014
+ // Expand bottom-up, so only the top node is animated
1015
+ for(i = len - 1; i >= 0; i--){
1016
+ // that.debug("pushexpand" + parents[i]);
1017
+ deferreds.push(parents[i].setExpanded(true, opts));
1018
+ }
1019
+ $.when.apply($, deferreds).done(function(){
1020
+ // All expands have finished
1021
+ // that.debug("expand DONE", scroll);
1022
+ if( scroll ){
1023
+ that.scrollIntoView(effects).done(function(){
1024
+ // that.debug("scroll DONE");
1025
+ dfd.resolve();
1026
+ });
1027
+ } else {
1028
+ dfd.resolve();
1029
+ }
1030
+ });
1031
+ return dfd.promise();
873
1032
  },
874
1033
  /** Move this node to targetNode.
875
1034
  * @param {FancytreeNode} targetNode
876
- * @param {string} mode
1035
+ * @param {string} mode <pre>
877
1036
  * 'child': append this node as last child of targetNode.
878
1037
  * This is the default. To be compatble with the D'n'd
879
1038
  * hitMode, we also accept 'over'.
880
1039
  * 'before': add this node as sibling before targetNode.
881
- * 'after': add this node as sibling after targetNode.
882
- * @param [map] optional callback(FancytreeNode) to allow modifcations
1040
+ * 'after': add this node as sibling after targetNode.</pre>
1041
+ * @param {function} [map] optional callback(FancytreeNode) to allow modifcations
883
1042
  */
884
1043
  moveTo: function(targetNode, mode, map) {
885
1044
  if(mode === undefined || mode === "over"){
@@ -993,8 +1152,8 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
993
1152
  }
994
1153
 
995
1154
  // In multi-hier mode, update the parents selection state
996
- // issue #82: only if not initializing, because the children may not exist yet
997
- // if( !ftnode.data.isStatusNode && opts.selectMode==3 && !isInitializing )
1155
+ // DT issue #82: only if not initializing, because the children may not exist yet
1156
+ // if( !ftnode.data.isStatusNode() && opts.selectMode==3 && !isInitializing )
998
1157
  // ftnode._fixSelectionState();
999
1158
 
1000
1159
  // In multi-hier mode, update the parents selection state
@@ -1091,52 +1250,74 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1091
1250
  }
1092
1251
  },
1093
1252
  /**
1094
- * Discard and reload all children of a lazy node.
1095
- * @param {boolean} [discard=false]
1096
- * @returns $.Promise
1253
+ * Remove this node (not allowed for system root).
1097
1254
  */
1098
- lazyLoad: function(discard) {
1099
- if(discard || this.hasChildren() === undefined){
1100
- this.discard();
1101
- }
1102
- _assert(!$.isArray(this.children));
1103
- var source = this.tree._triggerNodeEvent("lazyload", this);
1104
- _assert(typeof source !== "boolean", "lazyload event must return source in data.result");
1105
- return this.tree._callHook("nodeLoadChildren", this, source);
1255
+ remove: function() {
1256
+ return this.parent.removeChild(this);
1257
+ },
1258
+ /**
1259
+ * Remove childNode from list of direct children.
1260
+ * @param {FancytreeNode} childNode
1261
+ */
1262
+ removeChild: function(childNode) {
1263
+ return this.tree._callHook("nodeRemoveChild", this, childNode);
1106
1264
  },
1107
1265
  /**
1108
- * @see Fancytree_Hooks#nodeRender
1266
+ * Remove all child nodes and descendents. This converts the node into a leaf.<br>
1267
+ * If this was a lazy node, it is still considered 'loaded'; call node.resetLazy()
1268
+ * in order to trigger lazyLoad on next expand.
1269
+ */
1270
+ removeChildren: function() {
1271
+ return this.tree._callHook("nodeRemoveChildren", this);
1272
+ },
1273
+ /**
1274
+ * This method renders and updates all HTML markup that is required
1275
+ * to display this node in its current state.<br>
1276
+ * Note:
1277
+ * <ul>
1278
+ * <li>It should only be neccessary to call this method after the node object
1279
+ * was modified by direct access to its properties, because the common
1280
+ * API methods (node.setTitle(), moveTo(), addChildren(), remove(), ...)
1281
+ * already handle this.
1282
+ * <li> {@link FancytreeNode#renderTitle} and {@link FancytreeNode#renderStatus}
1283
+ * are implied. If changes are more local, calling only renderTitle() or
1284
+ * renderStatus() may be sufficient and faster.
1285
+ * <li>If a node was created/removed, node.render() must be called <i>on the parent</i>.
1286
+ * </ul>
1287
+ *
1288
+ * @param {boolean} [force=false] re-render, even if html markup was already created
1289
+ * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed
1109
1290
  */
1110
1291
  render: function(force, deep) {
1111
1292
  return this.tree._callHook("nodeRender", this, force, deep);
1112
1293
  },
1113
- /**
1294
+ /** Create HTML markup for the node's outer <span> (expander, checkbox, icon, and title).
1114
1295
  * @see Fancytree_Hooks#nodeRenderTitle
1115
1296
  */
1116
1297
  renderTitle: function() {
1117
1298
  return this.tree._callHook("nodeRenderTitle", this);
1118
1299
  },
1119
- /**
1300
+ /** Update element's CSS classes according to node state.
1120
1301
  * @see Fancytree_Hooks#nodeRenderStatus
1121
1302
  */
1122
1303
  renderStatus: function() {
1123
1304
  return this.tree._callHook("nodeRenderStatus", this);
1124
1305
  },
1125
- /** Remove this node (not allowed for root).*/
1126
- remove: function() {
1127
- return this.parent.removeChild(this);
1128
- },
1129
- /**Remove childNode from list of direct children.*/
1130
- removeChild: function(childNode) {
1131
- return this.tree._callHook("nodeRemoveChild", this, childNode);
1132
- },
1133
- /**Remove all child nodes (and descendents).*/
1134
- removeChildren: function() {
1135
- return this.tree._callHook("nodeRemoveChildren", this);
1306
+ /**
1307
+ * Remove all children, collapse, and set the lazy-flag, so that the lazyLoad
1308
+ * event is triggered on next expand.
1309
+ */
1310
+ resetLazy: function() {
1311
+ this.removeChildren();
1312
+ this.expanded = false;
1313
+ this.lazy = true;
1314
+ this.children = undefined;
1315
+ this.renderStatus();
1136
1316
  },
1137
- // TODO: resetLazy()
1138
1317
  /** Schedule activity for delayed execution (cancel any pending request).
1139
1318
  * scheduleAction('cancel') will only cancel a pending request (if any).
1319
+ * @param {string} mode
1320
+ * @param {number} ms
1140
1321
  */
1141
1322
  scheduleAction: function(mode, ms) {
1142
1323
  if( this.tree.timer ) {
@@ -1171,12 +1352,13 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1171
1352
  * @param {boolean | PlainObject} [effects=false] animation options.
1172
1353
  * @param {FancytreeNode} [topNode=null] this node will remain visible in
1173
1354
  * any case, even if `this` is outside the scroll pane.
1174
- * @returns $.Promise
1355
+ * @returns {$.Promise}
1175
1356
  */
1176
1357
  scrollIntoView: function(effects, topNode) {
1177
1358
  effects = (effects === true) ? {duration: 200, queue: false} : effects;
1178
1359
  var topNodeY,
1179
1360
  dfd = new $.Deferred(),
1361
+ that = this,
1180
1362
  nodeY = $(this.span).position().top,
1181
1363
  nodeHeight = $(this.span).height(),
1182
1364
  $container = this.tree.$container,
@@ -1210,7 +1392,12 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1210
1392
  if(effects){
1211
1393
  // TODO: resolve dfd after animation
1212
1394
  // var that = this;
1213
- $container.animate({scrollTop: newScrollTop}, effects);
1395
+ effects.complete = function(){
1396
+ dfd.resolveWith(that);
1397
+ };
1398
+ $container.animate({
1399
+ scrollTop: newScrollTop
1400
+ }, effects);
1214
1401
  }else{
1215
1402
  $container[0].scrollTop = newScrollTop;
1216
1403
  dfd.resolveWith(this);
@@ -1245,10 +1432,10 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1245
1432
  setActive: function(flag, opts){
1246
1433
  return this.tree._callHook("nodeSetActive", this, flag, opts);
1247
1434
  },
1248
- /**Expand or collapse this node.
1435
+ /**Expand or collapse this node. Promise is resolved, when lazy loading and animations are done.
1249
1436
  * @param {boolean} [flag=true] pass false to collapse
1250
1437
  * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false}
1251
- * @returns {$.Promise} resolved, when lazy loading and animations are done
1438
+ * @returns {$.Promise}
1252
1439
  */
1253
1440
  setExpanded: function(flag, opts){
1254
1441
  return this.tree._callHook("nodeSetExpanded", this, flag, opts);
@@ -1261,7 +1448,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1261
1448
  return this.tree._callHook("nodeSetFocus", this, flag);
1262
1449
  },
1263
1450
  // TODO: setLazyNodeStatus
1264
- /**Select this node.
1451
+ /**Select this node, i.e. check the checkbox.
1265
1452
  * @param {boolean} [flag=true] pass false to deselect
1266
1453
  */
1267
1454
  setSelected: function(flag){
@@ -1334,7 +1521,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1334
1521
  dict.children = [];
1335
1522
  for(i=0, l=this.children.length; i<l; i++ ){
1336
1523
  node = this.children[i];
1337
- if( !node.isStatusNode ){
1524
+ if( !node.isStatusNode() ){
1338
1525
  dict.children.push(node.toDict(true, callback));
1339
1526
  }
1340
1527
  }
@@ -1355,12 +1542,14 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1355
1542
  toString: function() {
1356
1543
  return "<FancytreeNode(#" + this.key + ", '" + this.title + "')>";
1357
1544
  },
1358
- /** Call fn(node) for all child nodes. Stop iteration, if fn() returns false.
1359
- * Skip current branch, if fn() returns 'skip'.
1545
+ /** Call fn(node) for all child nodes.<br>
1546
+ * Stop iteration, if fn() returns false. Skip current branch, if fn() returns "skip".<br>
1547
+ * Return false if iteration was stopped.
1548
+ *
1360
1549
  * @param {function} fn the callback function.
1361
1550
  * Return false to stop iteration, return "skip" to skip this node and children only.
1362
1551
  * @param {boolean} [includeSelf=false]
1363
- * @returns {boolean} false, if the iterator was stopped.
1552
+ * @returns {boolean}
1364
1553
  */
1365
1554
  visit: function(fn, includeSelf) {
1366
1555
  var i, l,
@@ -1383,10 +1572,13 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1383
1572
  }
1384
1573
  return res;
1385
1574
  },
1386
- /**
1575
+ /** Call fn(node) for all parent nodes, bottom-up, including invisible system root.<br>
1576
+ * Stop iteration, if fn() returns false.<br>
1577
+ * Return false if iteration was stopped.
1387
1578
  *
1388
- * @param fn
1389
- * @param includeSelf
1579
+ * @param {function} fn the callback function.
1580
+ * Return false to stop iteration, return "skip" to skip this node and children only.
1581
+ * @param {boolean} [includeSelf=false]
1390
1582
  * @returns {boolean}
1391
1583
  */
1392
1584
  visitParents: function(fn, includeSelf) {
@@ -1421,7 +1613,7 @@ FancytreeNode.prototype = /** @lends FancytreeNode# */{
1421
1613
  * Construct a new tree object.
1422
1614
  *
1423
1615
  * @class Fancytree
1424
- * @classdesc A Fancytree is the controller behind a fancytree.
1616
+ * @classdesc The controller behind a fancytree.
1425
1617
  * This class also contains 'hook methods': see {@link Fancytree_Hooks}.
1426
1618
  *
1427
1619
  * @param {Widget} widget
@@ -1446,15 +1638,24 @@ function Fancytree(widget) {
1446
1638
  this.widget = widget;
1447
1639
  this.$div = widget.element;
1448
1640
  this.options = widget.options;
1641
+ if( this.options && $.isFunction(this.options.lazyload) ) {
1642
+ if( ! $.isFunction(this.options.lazyLoad ) ) {
1643
+ this.options.lazyLoad = function() {
1644
+ FT.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead.");
1645
+ widget.options.lazyload.apply(this, arguments);
1646
+ };
1647
+ }
1648
+ }
1449
1649
  this.ext = {}; // Active extension instances
1450
- this.data = {};
1650
+ // allow to init tree.data.foo from <div data-foo=''>
1651
+ this.data = _getElementDataAsDict(this.$div);
1451
1652
  this._id = $.ui.fancytree._nextId++;
1452
1653
  this._ns = ".fancytree-" + this._id; // append for namespaced events
1453
1654
  this.activeNode = null;
1454
1655
  this.focusNode = null;
1455
1656
  this._hasFocus = null;
1456
1657
  this.lastSelectedNode = null;
1457
- this.systemFocusElement = null,
1658
+ this.systemFocusElement = null;
1458
1659
 
1459
1660
  this.statusClassPropName = "span";
1460
1661
  this.ariaPropName = "li";
@@ -1695,7 +1896,7 @@ Fancytree.prototype = /** @lends Fancytree# */{
1695
1896
  }
1696
1897
  },
1697
1898
  /**
1698
- * Return the currently active FancytreeNode or null.
1899
+ * Return the currently active node or null.
1699
1900
  * @returns {FancytreeNode}
1700
1901
  */
1701
1902
  getActiveNode: function() {
@@ -1862,13 +2063,13 @@ Fancytree.prototype = /** @lends Fancytree# */{
1862
2063
  // Avoid jshint warning 'Don't make functions within a loop.':
1863
2064
  function __lazyload(key, node, dfd){
1864
2065
  callback.call(self, node, "loading");
1865
- node.lazyLoad().done(function(){
1866
- self.loadKeyPath.call(self, loadMap[key], callback, node).always(_makeResolveFunc(dfd, self));
1867
- }).fail(function(errMsg){
1868
- self.warn("loadKeyPath: error loading: " + key + " (parent: " + root + ")");
1869
- callback.call(self, node, "error");
1870
- dfd.reject();
1871
- });
2066
+ node.load().done(function(){
2067
+ self.loadKeyPath.call(self, loadMap[key], callback, node).always(_makeResolveFunc(dfd, self));
2068
+ }).fail(function(errMsg){
2069
+ self.warn("loadKeyPath: error loading: " + key + " (parent: " + root + ")");
2070
+ callback.call(self, node, "error");
2071
+ dfd.reject();
2072
+ });
1872
2073
  }
1873
2074
  for(key in loadMap){
1874
2075
  node = root._findDirectChild(key);
@@ -1983,8 +2184,10 @@ Fancytree.prototype = /** @lends Fancytree# */{
1983
2184
  $.extend(Fancytree.prototype,
1984
2185
  /** @lends Fancytree_Hooks# */
1985
2186
  {
1986
-
1987
- /** _Default handling for mouse click events. */
2187
+ /** Default handling for mouse click events.
2188
+ *
2189
+ * @param {EventData} ctx
2190
+ */
1988
2191
  nodeClick: function(ctx) {
1989
2192
  // this.tree.logDebug("ftnode.onClick(" + event.type + "): ftnode:" + this + ", button:" + event.button + ", which: " + event.which);
1990
2193
  var activate, expand,
@@ -1997,11 +2200,11 @@ $.extend(Fancytree.prototype,
1997
2200
  if( targetType === "expander" ) {
1998
2201
  // Clicking the expander icon always expands/collapses
1999
2202
  this._callHook("nodeToggleExpanded", ctx);
2000
- // this._callHook("nodeSetFocus", ctx, true); // issue 95
2203
+ // this._callHook("nodeSetFocus", ctx, true); // DT issue 95
2001
2204
  } else if( targetType === "checkbox" ) {
2002
2205
  // Clicking the checkbox always (de)selects
2003
2206
  this._callHook("nodeToggleSelected", ctx);
2004
- this._callHook("nodeSetFocus", ctx, true); // issue 95
2207
+ this._callHook("nodeSetFocus", ctx, true); // DT issue 95
2005
2208
  } else {
2006
2209
  // Honor `clickFolderMode` for
2007
2210
  expand = false;
@@ -2037,6 +2240,11 @@ $.extend(Fancytree.prototype,
2037
2240
  }
2038
2241
  // TODO: return promise?
2039
2242
  },
2243
+ /** Collapse all other children of same parent.
2244
+ *
2245
+ * @param {EventData} ctx
2246
+ * @param {object} callOpts
2247
+ */
2040
2248
  nodeCollapseSiblings: function(ctx, callOpts) {
2041
2249
  // TODO: return promise?
2042
2250
  var ac, i, l,
@@ -2051,6 +2259,9 @@ $.extend(Fancytree.prototype,
2051
2259
  }
2052
2260
  }
2053
2261
  },
2262
+ /** Default handling for mouse douleclick events.
2263
+ * @param {EventData} ctx
2264
+ */
2054
2265
  nodeDblclick: function(ctx) {
2055
2266
  // TODO: return promise?
2056
2267
  if( ctx.targetType === "title" && ctx.options.clickFolderMode === 4) {
@@ -2066,6 +2277,7 @@ $.extend(Fancytree.prototype,
2066
2277
  /** Default handling for mouse keydown events.
2067
2278
  *
2068
2279
  * NOTE: this may be called with node == null if tree (but no node) has focus.
2280
+ * @param {EventData} ctx
2069
2281
  */
2070
2282
  nodeKeydown: function(ctx) {
2071
2283
  // TODO: return promise?
@@ -2128,17 +2340,12 @@ $.extend(Fancytree.prototype,
2128
2340
  // var event = ctx.originalEvent;
2129
2341
  // },
2130
2342
 
2131
- // /** Trigger lazyload event (async). */
2343
+ // /** Trigger lazyLoad event (async). */
2132
2344
  // nodeLazyLoad: function(ctx) {
2133
2345
  // var node = ctx.node;
2134
2346
  // if(this._triggerNodeEvent())
2135
2347
  // },
2136
- /** Load children (async).
2137
- * source may be
2138
- * - an array of children
2139
- * - a node object
2140
- * - an Ajax options object
2141
- * - an Ajax.promise
2348
+ /** Load child nodes (async).
2142
2349
  *
2143
2350
  * @param {EventData} ctx
2144
2351
  * @param {object[]|object|string|$.Promise|function} source
@@ -2178,9 +2385,12 @@ $.extend(Fancytree.prototype,
2178
2385
  }
2179
2386
 
2180
2387
  // TODO: change 'pipe' to 'then' for jQuery 1.8
2388
+ // $.pipe returns a new Promise with filtered results
2181
2389
  source = source.pipe(function (data, textStatus, jqXHR) {
2182
2390
  var res;
2183
- if(typeof data === "string"){ $.error("Ajax request returned a string (did you get the JSON dataType wrong?)."); }
2391
+ if(typeof data === "string"){
2392
+ $.error("Ajax request returned a string (did you get the JSON dataType wrong?).");
2393
+ }
2184
2394
  // postProcess is similar to the standard dataFilter hook,
2185
2395
  // but it is also called for JSONP
2186
2396
  if( ctx.options.postProcess ){
@@ -2202,8 +2412,11 @@ $.extend(Fancytree.prototype,
2202
2412
  }
2203
2413
 
2204
2414
  if($.isFunction(source.promise)){
2205
- // `source` is a promise
2415
+ // `source` is a deferred, i.e. ajax request
2416
+ _assert(!node.isLoading());
2417
+ // node._isLoading = true;
2206
2418
  tree.nodeSetStatus(ctx, "loading");
2419
+
2207
2420
  source.done(function () {
2208
2421
  tree.nodeSetStatus(ctx, "ok");
2209
2422
  }).fail(function(error){
@@ -2222,13 +2435,13 @@ $.extend(Fancytree.prototype,
2222
2435
  tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details);
2223
2436
  });
2224
2437
  }
2225
-
2438
+ // $.when(source) resolves also for non-deferreds
2226
2439
  return $.when(source).done(function(children){
2227
2440
  var metaData;
2228
2441
 
2229
2442
  if( $.isPlainObject(children) ){
2230
2443
  // We got {foo: 'abc', children: [...]}
2231
- // Copy extra properties to tree.data.
2444
+ // Copy extra properties to tree.data.foo
2232
2445
  _assert($.isArray(children.children), "source must contain (or be) an array of children");
2233
2446
  _assert(node.isRoot(), "source may only be an object for root nodes");
2234
2447
  metaData = children;
@@ -2238,34 +2451,18 @@ $.extend(Fancytree.prototype,
2238
2451
  }
2239
2452
  _assert($.isArray(children), "expected array of children");
2240
2453
  node._setChildren(children);
2241
- if(node.parent){
2242
- // trigger fancytreeloadchildren (except for tree-reload)
2243
- tree._triggerNodeEvent("loadChildren", node);
2244
- }
2454
+ // trigger fancytreeloadchildren
2455
+ // if( node.parent ) {
2456
+ tree._triggerNodeEvent("loadChildren", node);
2457
+ // }
2458
+ // }).always(function(){
2459
+ // node._isLoading = false;
2245
2460
  });
2246
2461
  },
2247
- // isVisible: function() {
2248
- // // Return true, if all parents are expanded.
2249
- // var parents = ctx.node.getParentList(false, false);
2250
- // for(var i=0, l=parents.length; i<l; i++){
2251
- // if( ! parents[i].expanded ){ return false; }
2252
- // }
2253
- // return true;
2254
- // },
2255
- /** Expand all keys that */
2462
+ /** [Not Implemented] */
2256
2463
  nodeLoadKeyPath: function(ctx, keyPathList) {
2257
2464
  // TODO: implement and improve
2258
- // http://code.google.com/p/fancytree/issues/detail?id=222
2259
- },
2260
- /** Expand all parents.*/
2261
- nodeMakeVisible: function(ctx) {
2262
- // TODO: also scroll as neccessary: http://stackoverflow.com/questions/8938352/fancytree-how-to-scroll-to-active-node
2263
- // Do we need an extra parameter?
2264
- var i, l,
2265
- parents = ctx.node.getParentList(false, false);
2266
- for(i=0, l=parents.length; i<l; i++){
2267
- parents[i].setExpanded(true);
2268
- }
2465
+ // http://code.google.com/p/dynatree/issues/detail?id=222
2269
2466
  },
2270
2467
  /**
2271
2468
  * Remove a single direct child of ctx.node.
@@ -2279,7 +2476,7 @@ $.extend(Fancytree.prototype,
2279
2476
  subCtx = $.extend({}, ctx, {node: childNode}),
2280
2477
  children = node.children;
2281
2478
 
2282
- FT.debug("nodeRemoveChild()", node.toString(), childNode.toString());
2479
+ // FT.debug("nodeRemoveChild()", node.toString(), childNode.toString());
2283
2480
 
2284
2481
  if( children.length === 1 ) {
2285
2482
  _assert(childNode === children[0]);
@@ -2300,6 +2497,7 @@ $.extend(Fancytree.prototype,
2300
2497
  childNode.visit(function(n){
2301
2498
  n.parent = null;
2302
2499
  }, true);
2500
+ this._callHook("treeRegisterNode", this, false, childNode);
2303
2501
  if ( opts.removeNode ){
2304
2502
  opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx);
2305
2503
  }
@@ -2312,7 +2510,7 @@ $.extend(Fancytree.prototype,
2312
2510
  nodeRemoveChildMarkup: function(ctx) {
2313
2511
  var node = ctx.node;
2314
2512
 
2315
- FT.debug("nodeRemoveChildMarkup()", node.toString());
2513
+ // FT.debug("nodeRemoveChildMarkup()", node.toString());
2316
2514
  // TODO: Unlink attr.ftnode to support GC
2317
2515
  if(node.ul){
2318
2516
  if( node.isRoot() ) {
@@ -2331,11 +2529,12 @@ $.extend(Fancytree.prototype,
2331
2529
  */
2332
2530
  nodeRemoveChildren: function(ctx) {
2333
2531
  var subCtx,
2532
+ tree = ctx.tree,
2334
2533
  node = ctx.node,
2335
2534
  children = node.children,
2336
2535
  opts = ctx.options;
2337
2536
 
2338
- FT.debug("nodeRemoveChildren()", node.toString());
2537
+ // FT.debug("nodeRemoveChildren()", node.toString());
2339
2538
  if(!children){
2340
2539
  return;
2341
2540
  }
@@ -2352,14 +2551,18 @@ $.extend(Fancytree.prototype,
2352
2551
  subCtx = $.extend({}, ctx);
2353
2552
  node.visit(function(n){
2354
2553
  n.parent = null;
2554
+ tree._callHook("treeRegisterNode", tree, false, n);
2355
2555
  if ( opts.removeNode ){
2356
2556
  subCtx.node = n;
2357
2557
  opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx);
2358
2558
  }
2359
2559
  });
2360
- // Set to 'undefined' which is interpreted as 'not yet loaded' for lazy nodes
2361
- node.children = undefined;
2362
- // TODO: ? this._isLoading = false;
2560
+ if( node.lazy ){
2561
+ // 'undefined' would be interpreted as 'not yet loaded' for lazy nodes
2562
+ node.children = [];
2563
+ } else{
2564
+ node.children = null;
2565
+ }
2363
2566
  this.nodeRenderStatus(ctx);
2364
2567
  },
2365
2568
  /**Remove HTML markup for ctx.node and all its descendents.
@@ -2367,7 +2570,7 @@ $.extend(Fancytree.prototype,
2367
2570
  */
2368
2571
  nodeRemoveMarkup: function(ctx) {
2369
2572
  var node = ctx.node;
2370
- FT.debug("nodeRemoveMarkup()", node.toString());
2573
+ // FT.debug("nodeRemoveMarkup()", node.toString());
2371
2574
  // TODO: Unlink attr.ftnode to support GC
2372
2575
  if(node.li){
2373
2576
  $(node.li).remove();
@@ -2376,7 +2579,7 @@ $.extend(Fancytree.prototype,
2376
2579
  this.nodeRemoveChildMarkup(ctx);
2377
2580
  },
2378
2581
  /**
2379
- * Create `<li><span>..</span> .. </li>` tags for this node.
2582
+ * Create `&lt;li>&lt;span>..&lt;/span> .. &lt;/li>` tags for this node.
2380
2583
  *
2381
2584
  * This method takes care that all HTML markup is created that is required
2382
2585
  * to display this node in it's current state.
@@ -2386,7 +2589,7 @@ $.extend(Fancytree.prototype,
2386
2589
  * nodeRenderTitle() and nodeRenderStatus() are implied.
2387
2590
  *
2388
2591
  * Note: if a node was created/removed, nodeRender() must be called for the
2389
- * parent!
2592
+ * parent.
2390
2593
  * <code>
2391
2594
  * <li id='KEY' ftnode=NODE>
2392
2595
  * <span class='fancytree-node fancytree-expanded fancytree-has-children fancytree-lastsib fancytree-exp-el fancytree-ico-e'>
@@ -2402,10 +2605,10 @@ $.extend(Fancytree.prototype,
2402
2605
  * </li>
2403
2606
  * </code>
2404
2607
  *
2405
- * @param: {EventData} ctx
2406
- * @param: {boolean} [force=false] re-render, even if html markup was already created
2407
- * @param: {boolean} [deep=false] also render all descendants, even if parent is collapsed
2408
- * @param: {boolean} [collapsed=false] force root node to be collapsed, so we can apply animated expand later
2608
+ * @param {EventData} ctx
2609
+ * @param {boolean} [force=false] re-render, even if html markup was already created
2610
+ * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed
2611
+ * @param {boolean} [collapsed=false] force root node to be collapsed, so we can apply animated expand later
2409
2612
  */
2410
2613
  nodeRender: function(ctx, force, deep, collapsed, _recursive) {
2411
2614
  /* This method must take care of all cases where the current data mode
@@ -2426,10 +2629,10 @@ $.extend(Fancytree.prototype,
2426
2629
  parent = node.parent,
2427
2630
  isRootNode = !parent,
2428
2631
  children = node.children;
2429
- FT.debug("nodeRender(" + !!force + ", " + !!deep + ")", node.toString());
2632
+ // FT.debug("nodeRender(" + !!force + ", " + !!deep + ")", node.toString());
2430
2633
 
2431
2634
  if( ! isRootNode && ! parent.ul ) {
2432
- // issue #105: calling node.collapse on a deep, unrendered node
2635
+ // Calling node.collapse on a deep, unrendered node
2433
2636
  return;
2434
2637
  }
2435
2638
  _assert(isRootNode || parent.ul, "parent UL must exist");
@@ -2485,6 +2688,7 @@ $.extend(Fancytree.prototype,
2485
2688
  }
2486
2689
  }else{
2487
2690
  // this.nodeRenderTitle(ctx);
2691
+ this.nodeRenderStatus(ctx);
2488
2692
  }
2489
2693
  // Allow tweaking after node state was rendered
2490
2694
  if ( opts.renderNode ){
@@ -2535,7 +2739,7 @@ $.extend(Fancytree.prototype,
2535
2739
  childNode1 = children[i];
2536
2740
  childNode2 = childLI.ftnode;
2537
2741
  if( childNode1 !== childNode2 ) {
2538
- node.debug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2);
2742
+ // node.debug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2);
2539
2743
  node.ul.insertBefore(childNode1.li, childNode2.li);
2540
2744
  } else {
2541
2745
  childLI = childLI.nextSibling;
@@ -2552,7 +2756,7 @@ $.extend(Fancytree.prototype,
2552
2756
  }
2553
2757
  if( !isRootNode ){
2554
2758
  // Update element classes according to node state
2555
- this.nodeRenderStatus(ctx);
2759
+ // this.nodeRenderStatus(ctx);
2556
2760
  // Finally add the whole structure to the DOM, so the browser can render
2557
2761
  if(firstTime){
2558
2762
  parent.ul.appendChild(node.li);
@@ -2560,7 +2764,10 @@ $.extend(Fancytree.prototype,
2560
2764
  }
2561
2765
  },
2562
2766
  /** Create HTML for the node's outer <span> (expander, checkbox, icon, and title).
2767
+ *
2768
+ * nodeRenderStatus() is implied.
2563
2769
  * @param {EventData} ctx
2770
+ * @param {string} [title] optinal new title
2564
2771
  */
2565
2772
  nodeRenderTitle: function(ctx, title) {
2566
2773
  // set node connector images, links and text
@@ -2600,7 +2807,7 @@ $.extend(Fancytree.prototype,
2600
2807
  }
2601
2808
  }
2602
2809
  // Checkbox mode
2603
- if( opts.checkbox && node.hideCheckbox !== true && !node.isStatusNode ) {
2810
+ if( opts.checkbox && node.hideCheckbox !== true && !node.isStatusNode() ) {
2604
2811
  if(aria){
2605
2812
  ares.push("<span role='checkbox' class='fancytree-checkbox'></span>");
2606
2813
  }else{
@@ -2628,7 +2835,7 @@ $.extend(Fancytree.prototype,
2628
2835
  }
2629
2836
  if(!nodeTitle){
2630
2837
  // TODO: escape tooltip string
2631
- tooltip = node.tooltip ? " title='" + node.tooltip.replace(/\"/g, "&quot;") + "'" : "";
2838
+ tooltip = node.tooltip ? " title='" + FT.escapeHtml(node.tooltip) + "'" : "";
2632
2839
  id = aria ? " id='ftal_" + node.key + "'" : "";
2633
2840
  role = aria ? " role='treeitem'" : "";
2634
2841
  tabindex = opts.titlesTabbable ? " tabindex='0'" : "";
@@ -2639,6 +2846,8 @@ $.extend(Fancytree.prototype,
2639
2846
  // Note: this will trigger focusout, if node had the focus
2640
2847
  //$(node.span).html(ares.join("")); // it will cleanup the jQuery data currently associated with SPAN (if any), but it executes more slowly
2641
2848
  node.span.innerHTML = ares.join("");
2849
+ // Update CSS classes
2850
+ this.nodeRenderStatus(ctx);
2642
2851
  },
2643
2852
  /** Update element classes according to node state.
2644
2853
  * @param {EventData} ctx
@@ -2668,7 +2877,7 @@ $.extend(Fancytree.prototype,
2668
2877
  cnList.push(cn.active);
2669
2878
  // $(">span.fancytree-title", statusElem).attr("tabindex", "0");
2670
2879
  // tree.$container.removeAttr("tabindex");
2671
- }else{
2880
+ // }else{
2672
2881
  // $(">span.fancytree-title", statusElem).removeAttr("tabindex");
2673
2882
  // tree.$container.attr("tabindex", "0");
2674
2883
  }
@@ -2712,6 +2921,12 @@ $.extend(Fancytree.prototype,
2712
2921
  if( node.partsel ){
2713
2922
  cnList.push(cn.partsel);
2714
2923
  }
2924
+ if( node._isLoading ){
2925
+ cnList.push(cn.loading);
2926
+ }
2927
+ if( node._error ){
2928
+ cnList.push(cn.error);
2929
+ }
2715
2930
  if( node.selected ){
2716
2931
  cnList.push(cn.selected);
2717
2932
  if(aria){
@@ -2755,7 +2970,7 @@ $.extend(Fancytree.prototype,
2755
2970
  * If flag is false, the node is deactivated (must be a synchronous operation)
2756
2971
  * @param {EventData} ctx
2757
2972
  * @param {boolean} [flag=true]
2758
- * @param {object} [opts] additional options. Defaults to {}
2973
+ * @param {object} [opts] additional options. Defaults to {noEvents: false}
2759
2974
  */
2760
2975
  nodeSetActive: function(ctx, flag, callOpts) {
2761
2976
  // Handle user click / [space] / [enter], according to clickFolderMode.
@@ -2765,16 +2980,17 @@ $.extend(Fancytree.prototype,
2765
2980
  tree = ctx.tree,
2766
2981
  opts = ctx.options,
2767
2982
  // userEvent = !!ctx.originalEvent,
2983
+ noEvents = (callOpts.noEvents === true),
2768
2984
  isActive = (node === tree.activeNode);
2769
2985
 
2770
2986
  // flag defaults to true
2771
2987
  flag = (flag !== false);
2772
- node.debug("nodeSetActive", flag);
2988
+ // node.debug("nodeSetActive", flag);
2773
2989
 
2774
2990
  if(isActive === flag){
2775
2991
  // Nothing to do
2776
2992
  return _getResolvedPromise(node);
2777
- }else if(flag && this._triggerNodeEvent("beforeActivate", node, ctx.originalEvent) === false ){
2993
+ }else if(flag && !noEvents && this._triggerNodeEvent("beforeActivate", node, ctx.originalEvent) === false ){
2778
2994
  // Callback returned false
2779
2995
  return _getRejectedPromise(node, ["rejected"]);
2780
2996
  }
@@ -2786,24 +3002,29 @@ $.extend(Fancytree.prototype,
2786
3002
  _assert(tree.activeNode === null, "deactivate was out of sync?");
2787
3003
  }
2788
3004
  if(opts.activeVisible){
2789
- tree.nodeMakeVisible(ctx);
3005
+ // tree.nodeMakeVisible(ctx);
3006
+ node.makeVisible();
2790
3007
  }
2791
3008
  tree.activeNode = node;
2792
3009
  tree.nodeRenderStatus(ctx);
2793
3010
  tree.nodeSetFocus(ctx);
2794
- tree._triggerNodeEvent("activate", node);
3011
+ if( !noEvents ) {
3012
+ tree._triggerNodeEvent("activate", node, ctx.originalEvent);
3013
+ }
2795
3014
  }else{
2796
3015
  _assert(tree.activeNode === node, "node was not active (inconsistency)");
2797
3016
  tree.activeNode = null;
2798
3017
  this.nodeRenderStatus(ctx);
2799
- ctx.tree._triggerNodeEvent("deactivate", node);
3018
+ if( !noEvents ) {
3019
+ ctx.tree._triggerNodeEvent("deactivate", node, ctx.originalEvent);
3020
+ }
2800
3021
  }
2801
3022
  },
2802
3023
  /** Expand or collapse node, return Deferred.promise.
2803
3024
  *
2804
3025
  * @param {EventData} ctx
2805
3026
  * @param {boolean} [flag=true]
2806
- * @param {object} [opts] additional options. Defaults to {noAnimation: false}
3027
+ * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false}
2807
3028
  * @returns {$.Promise} The deferred will be resolved as soon as the (lazy)
2808
3029
  * data was retrieved, rendered, and the expand animation finshed.
2809
3030
  */
@@ -2813,24 +3034,26 @@ $.extend(Fancytree.prototype,
2813
3034
  node = ctx.node,
2814
3035
  tree = ctx.tree,
2815
3036
  opts = ctx.options,
2816
- noAnimation = callOpts.noAnimation === true;
3037
+ noAnimation = (callOpts.noAnimation === true),
3038
+ noEvents = (callOpts.noEvents === true);
2817
3039
 
2818
3040
  // flag defaults to true
2819
3041
  flag = (flag !== false);
2820
3042
 
2821
- node.debug("nodeSetExpanded(" + flag + ")");
3043
+ // node.debug("nodeSetExpanded(" + flag + ")");
2822
3044
 
2823
3045
  if((node.expanded && flag) || (!node.expanded && !flag)){
2824
3046
  // Nothing to do
2825
- node.debug("nodeSetExpanded(" + flag + "): nothing to do");
3047
+ // node.debug("nodeSetExpanded(" + flag + "): nothing to do");
2826
3048
  return _getResolvedPromise(node);
2827
3049
  }else if(flag && !node.lazy && !node.hasChildren() ){
2828
3050
  // Prevent expanding of empty nodes
2829
- return _getRejectedPromise(node, ["empty"]);
3051
+ // return _getRejectedPromise(node, ["empty"]);
3052
+ return _getResolvedPromise(node);
2830
3053
  }else if( !flag && node.getLevel() < opts.minExpandLevel ) {
2831
3054
  // Prevent collapsing locked levels
2832
3055
  return _getRejectedPromise(node, ["locked"]);
2833
- }else if ( this._triggerNodeEvent("beforeExpand", node, ctx.originalEvent) === false ){
3056
+ }else if ( !noEvents && this._triggerNodeEvent("beforeExpand", node, ctx.originalEvent) === false ){
2834
3057
  // Callback returned false
2835
3058
  return _getRejectedPromise(node, ["rejected"]);
2836
3059
  }
@@ -2857,10 +3080,17 @@ $.extend(Fancytree.prototype,
2857
3080
  }
2858
3081
  // Trigger expand/collapse after expanding
2859
3082
  dfd.done(function(){
2860
- ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
2861
3083
  if( opts.autoScroll && !noAnimation ) {
2862
3084
  // Scroll down to last child, but keep current node visible
2863
- node.getLastChild().scrollIntoView(true, node);
3085
+ node.getLastChild().scrollIntoView(true, node).always(function(){
3086
+ if( !noEvents ) {
3087
+ ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
3088
+ }
3089
+ });
3090
+ } else {
3091
+ if( !noEvents ) {
3092
+ ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx);
3093
+ }
2864
3094
  }
2865
3095
  });
2866
3096
 
@@ -2896,9 +3126,9 @@ $.extend(Fancytree.prototype,
2896
3126
  } else {
2897
3127
  duration = opts.fx.duration || 200;
2898
3128
  easing = opts.fx.easing;
2899
- node.debug("nodeSetExpanded: animate start...");
3129
+ // node.debug("nodeSetExpanded: animate start...");
2900
3130
  $(node.ul).animate(opts.fx, duration, easing, function(){
2901
- node.debug("nodeSetExpanded: animate done");
3131
+ // node.debug("nodeSetExpanded: animate done");
2902
3132
  callback();
2903
3133
  });
2904
3134
  return;
@@ -2910,9 +3140,9 @@ $.extend(Fancytree.prototype,
2910
3140
 
2911
3141
  // Load lazy nodes, if any. Then continue with _afterLoad()
2912
3142
  if(flag && node.lazy && node.hasChildren() === undefined){
2913
- node.debug("nodeSetExpanded: load start...");
2914
- node.lazyLoad().done(function(){
2915
- node.debug("nodeSetExpanded: load done");
3143
+ // node.debug("nodeSetExpanded: load start...");
3144
+ node.load().done(function(){
3145
+ // node.debug("nodeSetExpanded: load done");
2916
3146
  if(dfd.notifyWith){ // requires jQuery 1.6+
2917
3147
  dfd.notifyWith(node, ["loaded"]);
2918
3148
  }
@@ -2921,8 +3151,8 @@ $.extend(Fancytree.prototype,
2921
3151
  _afterLoad(function () { dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); });
2922
3152
  });
2923
3153
  /*
2924
- var source = tree._triggerNodeEvent("lazyload", node, ctx.originalEvent);
2925
- _assert(typeof source !== "boolean", "lazyload event must return source in data.result");
3154
+ var source = tree._triggerNodeEvent("lazyLoad", node, ctx.originalEvent);
3155
+ _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result");
2926
3156
  node.debug("nodeSetExpanded: load start...");
2927
3157
  this._callHook("nodeLoadChildren", ctx, source).done(function(){
2928
3158
  node.debug("nodeSetExpanded: load done");
@@ -2937,15 +3167,15 @@ $.extend(Fancytree.prototype,
2937
3167
  }else{
2938
3168
  _afterLoad(function () { dfd.resolveWith(node); });
2939
3169
  }
2940
- node.debug("nodeSetExpanded: returns");
3170
+ // node.debug("nodeSetExpanded: returns");
2941
3171
  return dfd.promise();
2942
3172
  },
2943
- /**
3173
+ /** Focus ot blur this node.
2944
3174
  * @param {EventData} ctx
2945
3175
  * @param {boolean} [flag=true]
2946
3176
  */
2947
3177
  nodeSetFocus: function(ctx, flag) {
2948
- ctx.node.debug("nodeSetFocus(" + flag + ")");
3178
+ // ctx.node.debug("nodeSetFocus(" + flag + ")");
2949
3179
  var ctx2,
2950
3180
  tree = ctx.tree,
2951
3181
  node = ctx.node;
@@ -2955,7 +3185,7 @@ $.extend(Fancytree.prototype,
2955
3185
  // Blur previous node if any
2956
3186
  if(tree.focusNode){
2957
3187
  if(tree.focusNode === node && flag){
2958
- node.debug("nodeSetFocus(" + flag + "): nothing to do");
3188
+ // node.debug("nodeSetFocus(" + flag + "): nothing to do");
2959
3189
  return;
2960
3190
  }
2961
3191
  ctx2 = $.extend({}, ctx, {node: tree.focusNode});
@@ -2970,7 +3200,8 @@ $.extend(Fancytree.prototype,
2970
3200
  // Note: we pass _calledByNodeSetFocus=true
2971
3201
  this._callHook("treeSetFocus", ctx, true, true);
2972
3202
  }
2973
- this.nodeMakeVisible(ctx);
3203
+ // this.nodeMakeVisible(ctx);
3204
+ node.makeVisible();
2974
3205
  tree.focusNode = node;
2975
3206
  // node.debug("FOCUS...");
2976
3207
  // $(node.span).find(".fancytree-title").focus();
@@ -3032,19 +3263,19 @@ $.extend(Fancytree.prototype,
3032
3263
  * @param details
3033
3264
  */
3034
3265
  nodeSetStatus: function(ctx, status, message, details) {
3035
- var _clearStatusNode, _setStatusNode,
3036
- node = ctx.node,
3037
- tree = ctx.tree,
3038
- cn = ctx.options._classNames;
3266
+ var node = ctx.node,
3267
+ tree = ctx.tree;
3268
+ // cn = ctx.options._classNames;
3039
3269
 
3040
- _clearStatusNode = function() {
3270
+ function _clearStatusNode() {
3271
+ // Remove dedicated dummy node, if any
3041
3272
  var firstChild = ( node.children ? node.children[0] : null );
3042
- if ( firstChild && firstChild.isStatusNode ) {
3273
+ if ( firstChild && firstChild.isStatusNode() ) {
3043
3274
  try{
3044
3275
  // I've seen exceptions here with loadKeyPath...
3045
3276
  if(node.ul){
3046
3277
  node.ul.removeChild(firstChild.li);
3047
- firstChild.li = null; // avoid leaks (issue 215)
3278
+ firstChild.li = null; // avoid leaks (DT issue 215)
3048
3279
  }
3049
3280
  }catch(e){}
3050
3281
  if( node.children.length === 1 ){
@@ -3053,48 +3284,58 @@ $.extend(Fancytree.prototype,
3053
3284
  node.children.shift();
3054
3285
  }
3055
3286
  }
3056
- };
3057
- _setStatusNode = function(data) {
3287
+ }
3288
+ function _setStatusNode(data, type) {
3289
+ // Create/modify the dedicated dummy node for 'loading...' or
3290
+ // 'error!' status. (only called for direct child of the invisible
3291
+ // system root)
3058
3292
  var firstChild = ( node.children ? node.children[0] : null );
3059
- if ( firstChild && firstChild.isStatusNode ) {
3293
+ if ( firstChild && firstChild.isStatusNode() ) {
3060
3294
  $.extend(firstChild, data);
3061
3295
  tree._callHook("nodeRender", firstChild);
3062
3296
  } else {
3063
3297
  data.key = "_statusNode";
3064
3298
  node._setChildren([data]);
3065
- node.children[0].isStatusNode = true;
3299
+ node.children[0].statusNodeType = type;
3066
3300
  tree.render();
3067
3301
  }
3068
3302
  return node.children[0];
3069
- };
3070
- switch(status){
3303
+ }
3304
+
3305
+ switch( status ){
3071
3306
  case "ok":
3072
3307
  _clearStatusNode();
3073
- $(node.span).removeClass(cn.loading);
3074
- $(node.span).removeClass(cn.error);
3308
+ // $(node.span).removeClass(cn.loading).removeClass(cn.error);
3309
+ node._isLoading = false;
3310
+ node._error = null;
3311
+ node.renderStatus();
3075
3312
  break;
3076
3313
  case "loading":
3077
- $(node.span).removeClass(cn.error);
3078
- $(node.span).addClass(cn.loading);
3079
- if(!node.parent){
3314
+ // $(node.span).removeClass(cn.error).addClass(cn.loading);
3315
+ if( !node.parent ) {
3080
3316
  _setStatusNode({
3081
3317
  title: tree.options.strings.loading + (message ? " (" + message + ") " : ""),
3082
3318
  tooltip: details,
3083
3319
  extraClasses: "fancytree-statusnode-wait"
3084
- });
3320
+ }, status);
3085
3321
  }
3322
+ node._isLoading = true;
3323
+ node._error = null;
3324
+ node.renderStatus();
3086
3325
  break;
3087
3326
  case "error":
3088
- $(node.span).removeClass(cn.loading);
3089
- $(node.span).addClass(cn.error);
3327
+ // $(node.span).removeClass(cn.loading).addClass(cn.error);
3090
3328
  _setStatusNode({
3091
3329
  title: tree.options.strings.loadError + (message ? " (" + message + ") " : ""),
3092
3330
  tooltip: details,
3093
3331
  extraClasses: "fancytree-statusnode-error"
3094
- });
3332
+ }, status);
3333
+ node._isLoading = false;
3334
+ node._error = { message: message, details: details };
3335
+ node.renderStatus();
3095
3336
  break;
3096
3337
  default:
3097
- $.error("invalid status " + status);
3338
+ $.error("invalid node status " + status);
3098
3339
  }
3099
3340
  },
3100
3341
  /**
@@ -3140,7 +3381,7 @@ $.extend(Fancytree.prototype,
3140
3381
  },
3141
3382
  /** Parse Fancytree from source, as configured in the options.
3142
3383
  * @param {EventData} ctx
3143
- * @param {object} [source] new source
3384
+ * @param {object} [source] optional new source (use last data otherwise)
3144
3385
  */
3145
3386
  treeLoad: function(ctx, source) {
3146
3387
  var type, $ul,
@@ -3162,6 +3403,8 @@ $.extend(Fancytree.prototype,
3162
3403
  $ul = $container.find(">ul:first");
3163
3404
  $ul.addClass("ui-fancytree-source ui-helper-hidden");
3164
3405
  source = $.ui.fancytree.parseHtml($ul);
3406
+ // allow to init tree.data.foo from <ul data-foo=''>
3407
+ this.data = $.extend(this.data, _getElementDataAsDict($ul));
3165
3408
  break;
3166
3409
  case "json":
3167
3410
  // $().addClass("ui-helper-hidden");
@@ -3193,12 +3436,23 @@ $.extend(Fancytree.prototype,
3193
3436
  });
3194
3437
  return dfd;
3195
3438
  },
3439
+ /** Node was inserted into or removed from the tree.
3440
+ * @param {EventData} ctx
3441
+ * @param {boolean} add
3442
+ * @param {FancytreeNode} node
3443
+ */
3444
+ treeRegisterNode: function(ctx, add, node) {
3445
+ },
3446
+ /** Widget got focus.
3447
+ * @param {EventData} ctx
3448
+ * @param {boolean} [flag=true]
3449
+ */
3196
3450
  treeSetFocus: function(ctx, flag, _calledByNodeSetFocus) {
3197
3451
  flag = (flag !== false);
3198
3452
 
3199
- this.debug("treeSetFocus(" + flag + "), _calledByNodeSetFocus: " + _calledByNodeSetFocus);
3200
- this.debug(" focusNode: " + this.focusNode);
3201
- this.debug(" activeNode: " + this.activeNode);
3453
+ // this.debug("treeSetFocus(" + flag + "), _calledByNodeSetFocus: " + _calledByNodeSetFocus);
3454
+ // this.debug(" focusNode: " + this.focusNode);
3455
+ // this.debug(" activeNode: " + this.activeNode);
3202
3456
  if( flag !== this.hasFocus() ){
3203
3457
  this._hasFocus = flag;
3204
3458
  this.$container.toggleClass("fancytree-treefocus", flag);
@@ -3211,20 +3465,21 @@ $.extend(Fancytree.prototype,
3211
3465
  /* ******************************************************************************
3212
3466
  * jQuery UI widget boilerplate
3213
3467
  */
3468
+
3214
3469
  /**
3215
- * This constructor is not called directly. Use `$(selector).fancytre({})`
3216
- * to initialize the plugin instead.
3217
- *
3218
- * @class ui.fancytree
3219
- * @classdesc The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br>
3220
- * <pre class="sh_javascript sunlight-highlight-javascript">// Access instance methods and members:
3221
- * var tree = $(selector).fancytree("getTree");
3222
- * // Access static members:
3223
- * alert($.ui.fancytree.version);
3470
+ * The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br>
3471
+ * This constructor is not called directly. Use `$(selector).fancytree({})`
3472
+ * to initialize the plugin instead.<br>
3473
+ * <pre class="sh_javascript sunlight-highlight-javascript">// Access widget methods and members:
3474
+ * var tree = $("#tree").fancytree("getTree");
3475
+ * var node = $("#tree").fancytree("getActiveNode", "1234");
3224
3476
  * </pre>
3477
+ *
3478
+ * @mixin Fancytree_Widget
3225
3479
  */
3480
+
3226
3481
  $.widget("ui.fancytree",
3227
- /** @lends ui.fancytree# */
3482
+ /** @lends Fancytree_Widget# */
3228
3483
  {
3229
3484
  /**These options will be used as defaults
3230
3485
  * @type {FancytreeOptions}
@@ -3281,7 +3536,7 @@ $.widget("ui.fancytree",
3281
3536
  error: "fancytree-error"
3282
3537
  },
3283
3538
  // events
3284
- lazyload: null,
3539
+ lazyLoad: null,
3285
3540
  postProcess: null
3286
3541
  },
3287
3542
  /* Set up the widget, Called on first $().fancytree() */
@@ -3466,29 +3721,35 @@ $.widget("ui.fancytree",
3466
3721
  return ( tree._triggerNodeEvent("dblclick", ctx, event) === false ) ? false : tree._callHook("nodeDblclick", ctx);
3467
3722
  }
3468
3723
  // } catch(e) {
3469
- // // var _ = null; // issue 117 // TODO
3724
+ // // var _ = null; // DT issue 117 // TODO
3470
3725
  // $.error(e);
3471
3726
  } finally {
3472
3727
  tree.phase = prevPhase;
3473
3728
  }
3474
3729
  });
3475
3730
  },
3476
- /** @returns {FancytreeNode} the active node or null */
3731
+ /** Return the active node or null.
3732
+ * @returns {FancytreeNode}
3733
+ */
3477
3734
  getActiveNode: function() {
3478
3735
  return this.tree.activeNode;
3479
3736
  },
3480
- /**
3737
+ /** Return the matching node or null.
3481
3738
  * @param {string} key
3482
- * @returns {FancytreeNode} the matching node or null
3739
+ * @returns {FancytreeNode}
3483
3740
  */
3484
3741
  getNodeByKey: function(key) {
3485
3742
  return this.tree.getNodeByKey(key);
3486
3743
  },
3487
- /** @returns {FancytreeNode} the invisible system root node */
3744
+ /** Return the invisible system root node.
3745
+ * @returns {FancytreeNode}
3746
+ */
3488
3747
  getRootNode: function() {
3489
3748
  return this.tree.rootNode;
3490
3749
  },
3491
- /** @returns {Fancytree} the current tree instance */
3750
+ /** Return the current tree instance.
3751
+ * @returns {Fancytree}
3752
+ */
3492
3753
  getTree: function() {
3493
3754
  return this.tree;
3494
3755
  }
@@ -3497,22 +3758,26 @@ $.widget("ui.fancytree",
3497
3758
  // $.ui.fancytree was created by the widget factory. Create a local shortcut:
3498
3759
  FT = $.ui.fancytree;
3499
3760
 
3500
- /*
3501
- * Static members in the `$.ui.fancytree` namespace.
3502
- *
3503
- * @example:
3504
- * alert(""version: " + $.ui.fancytree.version);
3761
+ /**
3762
+ * Static members in the `$.ui.fancytree` namespace.<br>
3763
+ * <br>
3764
+ * <pre class="sh_javascript sunlight-highlight-javascript">// Access static members:
3505
3765
  * var node = $.ui.fancytree.getNode(element);
3766
+ * alert($.ui.fancytree.version);
3767
+ * </pre>
3768
+ *
3769
+ * @mixin Fancytree_Static
3506
3770
  */
3507
3771
  $.extend($.ui.fancytree,
3508
- /** @lends ui.fancytree */
3772
+ /** @lends Fancytree_Static# */
3509
3773
  {
3510
3774
  /** @type {string} */
3511
- version: "2.0.0-6",
3775
+ version: "2.0.0-11", // Set to semver by 'grunt release'
3512
3776
  /** @type {string} */
3513
- buildType: "release",
3777
+ buildType: "production", // Set to 'production' by 'grunt build'
3514
3778
  /** @type {int} */
3515
- debugLevel: 1, // used by $.ui.fancytree.debug() and as default for tree.options.debugLevel
3779
+ debugLevel: 1, // Set to 1 by 'grunt build'
3780
+ // Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel
3516
3781
 
3517
3782
  _nextId: 1,
3518
3783
  _nextNodeKey: 1,
@@ -3528,19 +3793,48 @@ $.extend($.ui.fancytree,
3528
3793
  // http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at
3529
3794
  positionMyOfs: isVersionAtLeast($.ui.version, 1, 9)
3530
3795
  },
3796
+ /** Throw an error if condition fails (debug method).
3797
+ * @param {boolean} cond
3798
+ * @param {string} msg
3799
+ */
3531
3800
  assert: function(cond, msg){
3532
3801
  return _assert(cond, msg);
3533
3802
  },
3803
+ /** Write message to console if debugLevel >= 2
3804
+ * @param {string} msg
3805
+ */
3534
3806
  debug: function(msg){
3535
3807
  /*jshint expr:true */
3536
3808
  ($.ui.fancytree.debugLevel >= 2) && consoleApply("log", arguments);
3537
3809
  },
3810
+ /** Write error message to console.
3811
+ * @param {string} msg
3812
+ */
3538
3813
  error: function(msg){
3539
3814
  consoleApply("error", arguments);
3540
3815
  },
3816
+ /** Convert &lt;, &gt;, &amp;, &quot;, &#39;, &#x2F; to the equivalent entitites.
3817
+ *
3818
+ * @param {string} s
3819
+ * @returns {string}
3820
+ */
3821
+ escapeHtml: function(s){
3822
+ return ("" + s).replace(/[&<>"'\/]/g, function (s) {
3823
+ return ENTITY_MAP[s];
3824
+ });
3825
+ },
3826
+ /** Inverse of escapeHtml().
3827
+ *
3828
+ * @param {string} s
3829
+ * @returns {string}
3830
+ */
3831
+ unescapeHtml: function(s){
3832
+ var e = document.createElement("div");
3833
+ e.innerHTML = s;
3834
+ return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
3835
+ },
3541
3836
  /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event.
3542
3837
  *
3543
- * @static
3544
3838
  * @param {Event} event Mouse event, e.g. click, ...
3545
3839
  * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
3546
3840
  */
@@ -3563,12 +3857,12 @@ $.extend($.ui.fancytree,
3563
3857
  res.type = "title";
3564
3858
  }else if( /\bfancytree-expander\b/.test(tcn) ){
3565
3859
  res.type = (res.node.hasChildren() === false ? "prefix" : "expander");
3566
- }else if( /\bfancytree-checkbox\b/.test(tcn) ){
3860
+ }else if( /\bfancytree-checkbox\b/.test(tcn) || /\bfancytree-radio\b/.test(tcn) ){
3567
3861
  res.type = "checkbox";
3568
3862
  }else if( /\bfancytree-icon\b/.test(tcn) ){
3569
3863
  res.type = "icon";
3570
3864
  }else if( /\bfancytree-node\b/.test(tcn) ){
3571
- // TODO: issue #93 (http://code.google.com/p/fancytree/issues/detail?id=93)
3865
+ // TODO: (http://code.google.com/p/dynatree/issues/detail?id=93)
3572
3866
  // res.type = this._getTypeForOuterNodeEvent(event);
3573
3867
  res.type = "title";
3574
3868
  }
@@ -3612,6 +3906,9 @@ $.extend($.ui.fancytree,
3612
3906
  return null;
3613
3907
  },
3614
3908
  */
3909
+ /** Write message to console if debugLevel >= 1
3910
+ * @param {string} msg
3911
+ */
3615
3912
  info: function(msg){
3616
3913
  /*jshint expr:true */
3617
3914
  ($.ui.fancytree.debugLevel >= 1) && consoleApply("info", arguments);
@@ -3625,13 +3922,12 @@ $.extend($.ui.fancytree,
3625
3922
  parseHtml: function($ul) {
3626
3923
  // TODO: understand this:
3627
3924
  /*jshint validthis:true */
3628
- var $children = $ul.find(">li"),
3629
- extraClasses, i, l, iPos, tmp, classes, className,
3925
+ var extraClasses, i, l, iPos, tmp, tmp2, classes, className,
3926
+ $children = $ul.find(">li"),
3630
3927
  children = [];
3631
- // that = this;
3632
3928
 
3633
3929
  $children.each(function() {
3634
- var allData, jsonData,
3930
+ var allData,
3635
3931
  $li = $(this),
3636
3932
  $liSpan = $li.find(">span:first", this),
3637
3933
  $liA = $liSpan.length ? null : $li.find(">a:first"),
@@ -3685,24 +3981,20 @@ $.extend($.ui.fancytree,
3685
3981
  d.key = tmp;
3686
3982
  }
3687
3983
  // Add <li data-NAME='...'> as node.data.NAME
3688
- // See http://api.jquery.com/data/#data-html5
3689
- allData = $li.data();
3690
- // alert("d: " + JSON.stringify(allData));
3984
+ allData = _getElementDataAsDict($li);
3691
3985
  if(allData && !$.isEmptyObject(allData)) {
3692
- // Special handling for <li data-json='...'>
3693
- jsonData = allData.json;
3694
- delete allData.json;
3695
- $.extend(d.data, allData);
3696
- // If a 'data-json' attribute is present, evaluate and add to node.data
3697
- if(jsonData) {
3698
- // alert("$li.data()" + JSON.stringify(jsonData));
3699
- // <li data-json='...'> is already returned as object
3700
- // see http://api.jquery.com/data/#data-html5
3701
- $.extend(d.data, jsonData);
3986
+ // #56: Allow to set special node.attributes from data-...
3987
+ for(i=0, l=NODE_ATTRS.length; i<l; i++){
3988
+ tmp = NODE_ATTRS[i];
3989
+ tmp2 = allData[tmp];
3990
+ if( tmp2 != null ) {
3991
+ delete allData[tmp];
3992
+ d[tmp] = tmp2;
3993
+ }
3702
3994
  }
3995
+ // All other data-... goes to node.data...
3996
+ $.extend(d.data, allData);
3703
3997
  }
3704
- // that.debug("parse ", d);
3705
- // var childNode = parentTreeNode.addChild(data);
3706
3998
  // Recursive reading of child nodes, if LI tag contains an UL tag
3707
3999
  $ul = $li.find(">ul:first");
3708
4000
  if( $ul.length ) {
@@ -3717,39 +4009,19 @@ $.extend($.ui.fancytree,
3717
4009
  },
3718
4010
  /** Add Fancytree extension definition to the list of globally available extensions.
3719
4011
  *
3720
- * @param {Object} definition
4012
+ * @param {object} definition
3721
4013
  */
3722
4014
  registerExtension: function(definition){
3723
4015
  _assert(definition.name != null, "extensions must have a `name` property.");
3724
4016
  _assert(definition.version != null, "extensions must have a `version` property.");
3725
4017
  $.ui.fancytree._extensions[definition.name] = definition;
3726
4018
  },
4019
+ /** Write warning message to console.
4020
+ * @param {string} msg
4021
+ */
3727
4022
  warn: function(msg){
3728
4023
  consoleApply("warn", arguments);
3729
4024
  }
3730
4025
  });
3731
4026
 
3732
- // Use $.ui.fancytree.debugLevel as default for tree.options.debugLevel
3733
- //$.ui.fancytree.debug($.ui.fancytree.prototype);
3734
- //$.ui.fancytree.prototype.options.debugLevel = $.ui.fancytree.debugLevel;
3735
-
3736
-
3737
- /* *****************************************************************************
3738
- * Register AMD
3739
- */
3740
- // http://stackoverflow.com/questions/10918063/how-to-make-a-jquery-plugin-loadable-with-requirejs
3741
-
3742
- // if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
3743
- // define( "jquery", [], function () { return jQuery; } );
3744
- // }
3745
-
3746
- // TODO: maybe like so:?
3747
- // https://raw.github.com/malsup/blockui/master/jquery.blockUI.js
3748
- /*
3749
- if( typeof define === "function" && define.amd ) {
3750
- define( ["jquery"], function () {
3751
- return jQuery.ui.fancytree;
3752
- });
3753
- }
3754
- */
3755
4027
  }(jQuery, window, document));