diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b63f054..1e584a8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ fancytree-drag-remove class not removed on drop/dragend * [Fixed] #875 ext-dnd5: Unwanted expanding of folder node when a node is dragged before/after it + * [Fixed] #876 `triggerStart: []` does not override the default settings.
+ **NOTE:** Options of type `Array` will now override the default option. + Before, arrays were merged with the default. * [Fixed] ext-ariagrid default actions # 2.29.0 / 2018-06-16 diff --git a/src/jquery.fancytree.js b/src/jquery.fancytree.js index dddbfb56..6a22e9ba 100644 --- a/src/jquery.fancytree.js +++ b/src/jquery.fancytree.js @@ -151,6 +151,62 @@ function isVersionAtLeast(dottedVersion, major, minor, patch){ return true; } + +/** + * Deep-merge a list of objects (but replace array-type options). + * + * jQuery's $.extend(true, ...) method does a deep merge, that also merges Arrays. + * This variant is used to merge extension defaults with user options, and should + * merge objects, but override arrays (for example the `triggerStart: [...]` option + * of ext-edit). Also `null` values are copied over and not skipped. + * + * See issue #876 + * + * Example: + * _simpleDeepMerge({}, o1, o2); + */ + function _simpleDeepMerge() { + var options, name, src, copy, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length; + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !$.isFunction( target ) ) { + target = {}; + } + if ( i === length ) { + throw "need at least two args"; + } + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + // Recurse if we're merging plain objects + // (NOTE: unlike $.extend, we don't merge arrays, but relace them) + if ( copy && jQuery.isPlainObject( copy ) ) { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + // Never move original objects, clone them + target[ name ] = _simpleDeepMerge( clone, copy ); + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + // Return the modified object + return target; +} + + /** Return a wrapper that calls sub.methodName() and exposes * this : tree * this._local : tree.ext.EXTNAME @@ -4911,7 +4967,15 @@ $.widget("ui.fancytree", } // Add extension options as tree.options.EXTENSION // _assert(!this.tree.options[extName], "Extension name must not exist as option name: " + extName); - this.tree.options[extName] = $.extend(true, {}, extension.options, this.tree.options[extName]); + + // console.info("extend " + extName, extension.options, this.tree.options[extName]) + // issue #876: we want to replace custom array-options, not merge them + this.tree.options[extName] = _simpleDeepMerge({}, extension.options, this.tree.options[extName]); + // this.tree.options[extName] = $.extend(true, {}, extension.options, this.tree.options[extName]); + + // console.info("extend " + extName + " =>", this.tree.options[extName]) + // console.info("extend " + extName + " org default =>", extension.options) + // Add a namespace tree.ext.EXTENSION, to hold instance data _assert(this.tree.ext[extName] === undefined, "Extension name must not exist as Fancytree.ext attribute: '" + extName + "'"); // this.tree[extName] = extension;