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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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));