/*! jQuery Fancytree Plugin - 2.29.0 - 2018-06-16T11:23:53Z * https://github.com/mar10/fancytree * Copyright (c) 2018 Martin Wendt; Licensed MIT */ /*! jQuery UI - v1.12.1 - 2018-05-20 * http://jqueryui.com * Includes: widget.js, position.js, keycode.js, scroll-parent.js, unique-id.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ /* NOTE: Original jQuery UI wrapper was replaced with a simple IIFE. See README-Fancytree.md */ (function( $ ) { $.ui = $.ui || {}; var version = $.ui.version = "1.12.1"; /*! * jQuery UI Widget 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Widget //>>group: Core //>>description: Provides a factory for creating stateful widgets with a common API. //>>docs: http://api.jqueryui.com/jQuery.widget/ //>>demos: http://jqueryui.com/widget/ var widgetUuid = 0; var widgetSlice = Array.prototype.slice; $.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { try { // Only trigger remove when necessary to save time events = $._data( elem, "events" ); if ( events && events.remove ) { $( elem ).triggerHandler( "remove" ); } // Http://bugs.jquery.com/ticket/8235 } catch ( e ) {} } orig( elems ); }; } )( $.cleanData ); $.widget = function( name, base, prototype ) { var existingConstructor, constructor, basePrototype; // ProxiedPrototype allows the provided prototype to remain unmodified // so that it can be used as a mixin for multiple widgets (#8876) var proxiedPrototype = {}; var namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; var fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } if ( $.isArray( prototype ) ) { prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); } // Create selector for plugin $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; $[ namespace ] = $[ namespace ] || {}; existingConstructor = $[ namespace ][ name ]; constructor = $[ namespace ][ name ] = function( options, element ) { // Allow instantiation without "new" keyword if ( !this._createWidget ) { return new constructor( options, element ); } // Allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; // Extend with the existing constructor to carry over any static properties $.extend( constructor, existingConstructor, { version: prototype.version, // Copy the object used to create the prototype in case we need to // redefine the widget later _proto: $.extend( {}, prototype ), // Track widgets that inherit from this widget in case this widget is // redefined after a widget inherits from it _childConstructors: [] } ); basePrototype = new base(); // We need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { if ( !$.isFunction( value ) ) { proxiedPrototype[ prop ] = value; return; } proxiedPrototype[ prop ] = ( function() { function _super() { return base.prototype[ prop ].apply( this, arguments ); } function _superApply( args ) { return base.prototype[ prop ].apply( this, args ); } return function() { var __super = this._super; var __superApply = this._superApply; var returnValue; this._super = _super; this._superApply = _superApply; returnValue = value.apply( this, arguments ); this._super = __super; this._superApply = __superApply; return returnValue; }; } )(); } ); constructor.prototype = $.widget.extend( basePrototype, { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, widgetFullName: fullName } ); // If this widget is being redefined then we need to find all widgets that // are inheriting from it and redefine all of them so that they inherit from // the new version of this widget. We're essentially trying to replace one // level in the prototype chain. if ( existingConstructor ) { $.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype; // Redefine the child widget using the same prototype that was // originally used, but inherit from the new version of the base $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); } ); // Remove the list of existing child constructors from the old constructor // so the old child constructors can be garbage collected delete existingConstructor._childConstructors; } else { base._childConstructors.push( constructor ); } $.widget.bridge( name, constructor ); return constructor; }; $.widget.extend = function( target ) { var input = widgetSlice.call( arguments, 1 ); var inputIndex = 0; var inputLength = input.length; var key; var value; for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { target[ key ] = $.isPlainObject( target[ key ] ) ? $.widget.extend( {}, target[ key ], value ) : // Don't extend strings, arrays, etc. with objects $.widget.extend( {}, value ); // Copy everything else by reference } else { target[ key ] = value; } } } } return target; }; $.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string"; var args = widgetSlice.call( arguments, 1 ); var returnValue = this; if ( isMethodCall ) { // If this is an empty collection, we need to have the instance method // return undefined instead of the jQuery instance if ( !this.length && options === "instance" ) { returnValue = undefined; } else { this.each( function() { var methodValue; var instance = $.data( this, fullName ); if ( options === "instance" ) { returnValue = instance; return false; } if ( !instance ) { return $.error( "cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue && methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } } ); } } else { // Allow multiple hashes to be passed on init if ( args.length ) { options = $.widget.extend.apply( null, [ options ].concat( args ) ); } this.each( function() { var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} ); if ( instance._init ) { instance._init(); } } else { $.data( this, fullName, new object( options, this ) ); } } ); } return returnValue; }; }; $.Widget = function( /* options, element */ ) {}; $.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "
* 'child': append this node as last child of targetNode. * This is the default. To be compatble with the D'n'd * hitMode, we also accept 'over'. * 'firstChild': add this node as first child of targetNode. * 'before': add this node as sibling before targetNode. * 'after': add this node as sibling after targetNode.* @param {function} [map] optional callback(FancytreeNode) to allow modifcations */ moveTo: function(targetNode, mode, map) { if(mode === undefined || mode === "over"){ mode = "child"; } else if ( mode === "firstChild" ) { if( targetNode.children && targetNode.children.length ) { mode = "before"; targetNode = targetNode.children[0]; } else { mode = "child"; } } var pos, prevParent = this.parent, targetParent = (mode === "child") ? targetNode : targetNode.parent; if(this === targetNode){ return; }else if( !this.parent ){ $.error("Cannot move system root"); }else if( targetParent.isDescendantOf(this) ){ $.error("Cannot move a node to its own descendant"); } if( targetParent !== prevParent ) { prevParent.triggerModifyChild("remove", this); } // Unlink this node from current parent if( this.parent.children.length === 1 ) { if( this.parent === targetParent ){ return; // #258 } this.parent.children = this.parent.lazy ? [] : null; this.parent.expanded = false; } else { pos = $.inArray(this, this.parent.children); _assert(pos >= 0, "invalid source parent"); this.parent.children.splice(pos, 1); } // Remove from source DOM parent // if(this.parent.ul){ // this.parent.ul.removeChild(this.li); // } // Insert this node to target parent's child list this.parent = targetParent; if( targetParent.hasChildren() ) { switch(mode) { case "child": // Append to existing target children targetParent.children.push(this); break; case "before": // Insert this node before target node pos = $.inArray(targetNode, targetParent.children); _assert(pos >= 0, "invalid target parent"); targetParent.children.splice(pos, 0, this); break; case "after": // Insert this node after target node pos = $.inArray(targetNode, targetParent.children); _assert(pos >= 0, "invalid target parent"); targetParent.children.splice(pos+1, 0, this); break; default: $.error("Invalid mode " + mode); } } else { targetParent.children = [ this ]; } // Parent has no
// Access widget methods and members: * var tree = $("#tree").fancytree("getTree"); * var node = $("#tree").fancytree("getActiveNode", "1234"); ** * @mixin Fancytree_Widget */ $.widget("ui.fancytree", /** @lends Fancytree_Widget# */ { /**These options will be used as defaults * @type {FancytreeOptions} */ options: { activeVisible: true, ajax: { type: "GET", cache: false, // false: Append random '_' argument to the request url to prevent caching. // timeout: 0, // >0: Make sure we get an ajax error if server is unreachable dataType: "json" // Expect json format and pass json object to callbacks. }, // aria: true, autoActivate: true, autoCollapse: false, autoScroll: false, checkbox: false, clickFolderMode: 4, debugLevel: null, // 0..4 (null: use global setting $.ui.fancytree.debugInfo) disabled: false, // TODO: required anymore? enableAspx: true, escapeTitles: false, extensions: [], // fx: { height: "toggle", duration: 200 }, // toggleEffect: { effect: "drop", options: {direction: "left"}, duration: 200 }, // toggleEffect: { effect: "slide", options: {direction: "up"}, duration: 200 }, //toggleEffect: { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 }, toggleEffect: { effect: "slideToggle", duration: 200 }, //< "toggle" or "slideToggle" to use jQuery instead of jQueryUI for toggleEffect animation generateIds: false, icon: true, idPrefix: "ft_", focusOnSelect: false, keyboard: true, keyPathSeparator: "/", minExpandLevel: 1, quicksearch: false, rtl: false, scrollOfs: {top: 0, bottom: 0}, scrollParent: null, selectMode: 2, strings: { loading: "Loading...", // … would be escaped when escapeTitles is true loadError: "Load error!", moreData: "More...", noData: "No data." }, tabindex: "0", titlesTabbable: false, tooltip: false, _classNames: { node: "fancytree-node", folder: "fancytree-folder", animating: "fancytree-animating", 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", partload: "fancytree-partload", partsel: "fancytree-partsel", radio: "fancytree-radio", // radiogroup: "fancytree-radiogroup", unselectable: "fancytree-unselectable", lastsib: "fancytree-lastsib", loading: "fancytree-loading", error: "fancytree-error", statusNodePrefix: "fancytree-statusnode-" }, // events lazyLoad: null, postProcess: null }, /* Set up the widget, Called on first $().fancytree() */ _create: function() { this.tree = new Fancytree(this); this.$source = this.source || this.element.data("type") === "json" ? this.element : this.element.find(">ul:first"); // Subclass Fancytree instance with all enabled extensions var extension, extName, i, opts = this.options, extensions = opts.extensions, base = this.tree; for(i=0; i
// Access static members: * var node = $.ui.fancytree.getNode(element); * alert($.ui.fancytree.version); ** * @mixin Fancytree_Static */ $.extend($.ui.fancytree, /** @lends Fancytree_Static# */ { /** @type {string} */ version: "2.29.0", // Set to semver by 'grunt release' /** @type {string} */ buildType: "production", // Set to 'production' by 'grunt build' /** @type {int} */ debugLevel: 3, // Set to 3 by 'grunt build' // Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel _nextId: 1, _nextNodeKey: 1, _extensions: {}, // focusTree: null, /** Expose class object as $.ui.fancytree._FancytreeClass */ _FancytreeClass: Fancytree, /** Expose class object as $.ui.fancytree._FancytreeNodeClass */ _FancytreeNodeClass: FancytreeNode, /* Feature checks to provide backwards compatibility */ jquerySupports: { // http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at positionMyOfs: isVersionAtLeast($.ui.version, 1, 9) }, /** Throw an error if condition fails (debug method). * @param {boolean} cond * @param {string} msg */ assert: function(cond, msg){ return _assert(cond, msg); }, /** Create a new Fancytree instance on a target element. * * @param {Element | jQueryObject | string} el Target DOM element or selector * @param {FancytreeOptions} [opts] Fancytree options * @returns {Fancytree} new tree instance * @example * var tree = $.ui.fancytree.createTree("#tree", { * source: {url: "my/webservice"} * }); // Create tree for this matching element * * @since 2.25 */ createTree: function(el, opts){ var tree = $(el).fancytree(opts).fancytree("getTree"); return tree; }, /** Return a function that executes *fn* at most every *timeout* ms. * @param {integer} timeout * @param {function} fn * @param {boolean} [invokeAsap=false] * @param {any} [ctx] */ debounce: function(timeout, fn, invokeAsap, ctx) { var timer; if(arguments.length === 3 && typeof invokeAsap !== "boolean") { ctx = invokeAsap; invokeAsap = false; } return function() { var args = arguments; ctx = ctx || this; invokeAsap && !timer && fn.apply(ctx, args); clearTimeout(timer); timer = setTimeout(function() { invokeAsap || fn.apply(ctx, args); timer = null; }, timeout); }; }, /** Write message to console if debugLevel >= 4 * @param {string} msg */ debug: function(msg){ /*jshint expr:true */ ($.ui.fancytree.debugLevel >= 4) && consoleApply("log", arguments); }, /** Write error message to console if debugLevel >= 1. * @param {string} msg */ error: function(msg){ ($.ui.fancytree.debugLevel >= 1) && consoleApply("error", arguments); }, /** Convert <, >, &, ", ', / to the equivalent entities. * * @param {string} s * @returns {string} */ escapeHtml: function(s){ return ("" + s).replace(REX_HTML, function(s) { return ENTITY_MAP[s]; }); }, /** Make jQuery.position() arguments backwards compatible, i.e. if * jQuery UI version <= 1.8, convert * { my: "left+3 center", at: "left bottom", of: $target } * to * { my: "left center", at: "left bottom", of: $target, offset: "3 0" } * * See http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at * and http://jsfiddle.net/mar10/6xtu9a4e/ * * @param {object} opts * @returns {object} the (potentially modified) original opts hash object */ fixPositionOptions: function(opts) { if( opts.offset || ("" + opts.my + opts.at ).indexOf("%") >= 0 ) { $.error("expected new position syntax (but '%' is not supported)"); } if( ! $.ui.fancytree.jquerySupports.positionMyOfs ) { var // parse 'left+3 center' into ['left+3 center', 'left', '+3', 'center', undefined] myParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.my), atParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.at), // convert to numbers dx = (myParts[2] ? (+myParts[2]) : 0) + (atParts[2] ? (+atParts[2]) : 0), dy = (myParts[4] ? (+myParts[4]) : 0) + (atParts[4] ? (+atParts[4]) : 0); opts = $.extend({}, opts, { // make a copy and overwrite my: myParts[1] + " " + myParts[3], at: atParts[1] + " " + atParts[3] }); if( dx || dy ) { opts.offset = "" + dx + " " + dy; } } return opts; }, /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. * * @param {Event} event Mouse event, e.g. click, ... * @returns {object} Return a {node: FancytreeNode, type: TYPE} object * TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined */ getEventTarget: function(event){ var $target, tree, tcn = event && event.target ? event.target.className : "", res = {node: this.getNode(event.target), type: undefined}; // We use a fast version of $(res.node).hasClass() // See http://jsperf.com/test-for-classname/2 if( /\bfancytree-title\b/.test(tcn) ){ res.type = "title"; }else if( /\bfancytree-expander\b/.test(tcn) ){ res.type = (res.node.hasChildren() === false ? "prefix" : "expander"); // }else if( /\bfancytree-checkbox\b/.test(tcn) || /\bfancytree-radio\b/.test(tcn) ){ }else if( /\bfancytree-checkbox\b/.test(tcn) ){ res.type = "checkbox"; }else if( /\bfancytree(-custom)?-icon\b/.test(tcn) ){ res.type = "icon"; }else if( /\bfancytree-node\b/.test(tcn) ){ // Somewhere near the title res.type = "title"; }else if( event && event.target ) { $target = $(event.target); if( $target.is("ul[role=group]") ) { // #nnn: Clicking right to a node may hit the surrounding UL tree = res.node && res.node.tree; (tree || FT).debug("Ignoring click on outer UL."); res.node = null; }else if( $target.closest(".fancytree-title").length ) { // #228: clicking an embedded element inside a title res.type = "title"; }else if( $target.closest(".fancytree-checkbox").length ) { // E.g.