Adding indexmenu version 2024-01-05 (ed06f21).
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
92cc8375f2
commit
f339727d60
766 changed files with 83299 additions and 0 deletions
|
@ -0,0 +1,514 @@
|
|||
/*!
|
||||
*
|
||||
* jquery.fancytree.clones.js
|
||||
* Support faster lookup of nodes by key and shared ref-ids.
|
||||
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
|
||||
*
|
||||
* Copyright (c) 2008-2023, Martin Wendt (https://wwWendt.de)
|
||||
*
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.38.3
|
||||
* @date 2023-02-01T20:52:50Z
|
||||
*/
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(["jquery", "./jquery.fancytree"], factory);
|
||||
} else if (typeof module === "object" && module.exports) {
|
||||
// Node/CommonJS
|
||||
require("./jquery.fancytree");
|
||||
module.exports = factory(require("jquery"));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
})(function ($) {
|
||||
"use strict";
|
||||
|
||||
/*******************************************************************************
|
||||
* Private functions and variables
|
||||
*/
|
||||
|
||||
var _assert = $.ui.fancytree.assert;
|
||||
|
||||
/* Return first occurrence of member from array. */
|
||||
function _removeArrayMember(arr, elem) {
|
||||
// TODO: use Array.indexOf for IE >= 9
|
||||
var i;
|
||||
for (i = arr.length - 1; i >= 0; i--) {
|
||||
if (arr[i] === elem) {
|
||||
arr.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
|
||||
*
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @see http://github.com/garycourt/murmurhash-js
|
||||
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
|
||||
* @see http://sites.google.com/site/murmurhash/
|
||||
*
|
||||
* @param {string} key ASCII only
|
||||
* @param {boolean} [asString=false]
|
||||
* @param {number} seed Positive integer only
|
||||
* @return {number} 32-bit positive integer hash
|
||||
*/
|
||||
function hashMurmur3(key, asString, seed) {
|
||||
/*eslint-disable no-bitwise */
|
||||
var h1b,
|
||||
k1,
|
||||
remainder = key.length & 3,
|
||||
bytes = key.length - remainder,
|
||||
h1 = seed,
|
||||
c1 = 0xcc9e2d51,
|
||||
c2 = 0x1b873593,
|
||||
i = 0;
|
||||
|
||||
while (i < bytes) {
|
||||
k1 =
|
||||
(key.charCodeAt(i) & 0xff) |
|
||||
((key.charCodeAt(++i) & 0xff) << 8) |
|
||||
((key.charCodeAt(++i) & 0xff) << 16) |
|
||||
((key.charCodeAt(++i) & 0xff) << 24);
|
||||
++i;
|
||||
|
||||
k1 =
|
||||
((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 =
|
||||
((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = (h1 << 13) | (h1 >>> 19);
|
||||
h1b =
|
||||
((h1 & 0xffff) * 5 + ((((h1 >>> 16) * 5) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
h1 =
|
||||
(h1b & 0xffff) +
|
||||
0x6b64 +
|
||||
((((h1b >>> 16) + 0xe654) & 0xffff) << 16);
|
||||
}
|
||||
|
||||
k1 = 0;
|
||||
|
||||
switch (remainder) {
|
||||
case 3:
|
||||
k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
|
||||
// fall through
|
||||
case 2:
|
||||
k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
|
||||
// fall through
|
||||
case 1:
|
||||
k1 ^= key.charCodeAt(i) & 0xff;
|
||||
|
||||
k1 =
|
||||
((k1 & 0xffff) * c1 +
|
||||
((((k1 >>> 16) * c1) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 =
|
||||
((k1 & 0xffff) * c2 +
|
||||
((((k1 >>> 16) * c2) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
h1 ^= key.length;
|
||||
|
||||
h1 ^= h1 >>> 16;
|
||||
h1 =
|
||||
((h1 & 0xffff) * 0x85ebca6b +
|
||||
((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
h1 ^= h1 >>> 13;
|
||||
h1 =
|
||||
((h1 & 0xffff) * 0xc2b2ae35 +
|
||||
((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) &
|
||||
0xffffffff;
|
||||
h1 ^= h1 >>> 16;
|
||||
|
||||
if (asString) {
|
||||
// Convert to 8 digit hex string
|
||||
return ("0000000" + (h1 >>> 0).toString(16)).substr(-8);
|
||||
}
|
||||
return h1 >>> 0;
|
||||
/*eslint-enable no-bitwise */
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a unique key for node by calculating the hash of the parents refKey-list.
|
||||
*/
|
||||
function calcUniqueKey(node) {
|
||||
var key,
|
||||
h1,
|
||||
path = $.map(node.getParentList(false, true), function (e) {
|
||||
return e.refKey || e.key;
|
||||
});
|
||||
|
||||
path = path.join("/");
|
||||
// 32-bit has a high probability of collisions, so we pump up to 64-bit
|
||||
// https://security.stackexchange.com/q/209882/207588
|
||||
|
||||
h1 = hashMurmur3(path, true);
|
||||
key = "id_" + h1 + hashMurmur3(h1 + path, true);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* [ext-clones] Return a list of clone-nodes (i.e. same refKey) or null.
|
||||
* @param {boolean} [includeSelf=false]
|
||||
* @returns {FancytreeNode[] | null}
|
||||
*
|
||||
* @alias FancytreeNode#getCloneList
|
||||
* @requires jquery.fancytree.clones.js
|
||||
*/
|
||||
$.ui.fancytree._FancytreeNodeClass.prototype.getCloneList = function (
|
||||
includeSelf
|
||||
) {
|
||||
var key,
|
||||
tree = this.tree,
|
||||
refList = tree.refMap[this.refKey] || null,
|
||||
keyMap = tree.keyMap;
|
||||
|
||||
if (refList) {
|
||||
key = this.key;
|
||||
// Convert key list to node list
|
||||
if (includeSelf) {
|
||||
refList = $.map(refList, function (val) {
|
||||
return keyMap[val];
|
||||
});
|
||||
} else {
|
||||
refList = $.map(refList, function (val) {
|
||||
return val === key ? null : keyMap[val];
|
||||
});
|
||||
if (refList.length < 1) {
|
||||
refList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return refList;
|
||||
};
|
||||
|
||||
/**
|
||||
* [ext-clones] Return true if this node has at least another clone with same refKey.
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @alias FancytreeNode#isClone
|
||||
* @requires jquery.fancytree.clones.js
|
||||
*/
|
||||
$.ui.fancytree._FancytreeNodeClass.prototype.isClone = function () {
|
||||
var refKey = this.refKey || null,
|
||||
refList = (refKey && this.tree.refMap[refKey]) || null;
|
||||
return !!(refList && refList.length > 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* [ext-clones] Update key and/or refKey for an existing node.
|
||||
* @param {string} key
|
||||
* @param {string} refKey
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @alias FancytreeNode#reRegister
|
||||
* @requires jquery.fancytree.clones.js
|
||||
*/
|
||||
$.ui.fancytree._FancytreeNodeClass.prototype.reRegister = function (
|
||||
key,
|
||||
refKey
|
||||
) {
|
||||
key = key == null ? null : "" + key;
|
||||
refKey = refKey == null ? null : "" + refKey;
|
||||
// this.debug("reRegister", key, refKey);
|
||||
|
||||
var tree = this.tree,
|
||||
prevKey = this.key,
|
||||
prevRefKey = this.refKey,
|
||||
keyMap = tree.keyMap,
|
||||
refMap = tree.refMap,
|
||||
refList = refMap[prevRefKey] || null,
|
||||
// curCloneKeys = refList ? node.getCloneList(true),
|
||||
modified = false;
|
||||
|
||||
// Key has changed: update all references
|
||||
if (key != null && key !== this.key) {
|
||||
if (keyMap[key]) {
|
||||
$.error(
|
||||
"[ext-clones] reRegister(" +
|
||||
key +
|
||||
"): already exists: " +
|
||||
this
|
||||
);
|
||||
}
|
||||
// Update keyMap
|
||||
delete keyMap[prevKey];
|
||||
keyMap[key] = this;
|
||||
// Update refMap
|
||||
if (refList) {
|
||||
refMap[prevRefKey] = $.map(refList, function (e) {
|
||||
return e === prevKey ? key : e;
|
||||
});
|
||||
}
|
||||
this.key = key;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// refKey has changed
|
||||
if (refKey != null && refKey !== this.refKey) {
|
||||
// Remove previous refKeys
|
||||
if (refList) {
|
||||
if (refList.length === 1) {
|
||||
delete refMap[prevRefKey];
|
||||
} else {
|
||||
refMap[prevRefKey] = $.map(refList, function (e) {
|
||||
return e === prevKey ? null : e;
|
||||
});
|
||||
}
|
||||
}
|
||||
// Add refKey
|
||||
if (refMap[refKey]) {
|
||||
refMap[refKey].append(key);
|
||||
} else {
|
||||
refMap[refKey] = [this.key];
|
||||
}
|
||||
this.refKey = refKey;
|
||||
modified = true;
|
||||
}
|
||||
return modified;
|
||||
};
|
||||
|
||||
/**
|
||||
* [ext-clones] Define a refKey for an existing node.
|
||||
* @param {string} refKey
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @alias FancytreeNode#setRefKey
|
||||
* @requires jquery.fancytree.clones.js
|
||||
* @since 2.16
|
||||
*/
|
||||
$.ui.fancytree._FancytreeNodeClass.prototype.setRefKey = function (refKey) {
|
||||
return this.reRegister(null, refKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* [ext-clones] Return all nodes with a given refKey (null if not found).
|
||||
* @param {string} refKey
|
||||
* @param {FancytreeNode} [rootNode] optionally restrict results to descendants of this node
|
||||
* @returns {FancytreeNode[] | null}
|
||||
* @alias Fancytree#getNodesByRef
|
||||
* @requires jquery.fancytree.clones.js
|
||||
*/
|
||||
$.ui.fancytree._FancytreeClass.prototype.getNodesByRef = function (
|
||||
refKey,
|
||||
rootNode
|
||||
) {
|
||||
var keyMap = this.keyMap,
|
||||
refList = this.refMap[refKey] || null;
|
||||
|
||||
if (refList) {
|
||||
// Convert key list to node list
|
||||
if (rootNode) {
|
||||
refList = $.map(refList, function (val) {
|
||||
var node = keyMap[val];
|
||||
return node.isDescendantOf(rootNode) ? node : null;
|
||||
});
|
||||
} else {
|
||||
refList = $.map(refList, function (val) {
|
||||
return keyMap[val];
|
||||
});
|
||||
}
|
||||
if (refList.length < 1) {
|
||||
refList = null;
|
||||
}
|
||||
}
|
||||
return refList;
|
||||
};
|
||||
|
||||
/**
|
||||
* [ext-clones] Replace a refKey with a new one.
|
||||
* @param {string} oldRefKey
|
||||
* @param {string} newRefKey
|
||||
* @alias Fancytree#changeRefKey
|
||||
* @requires jquery.fancytree.clones.js
|
||||
*/
|
||||
$.ui.fancytree._FancytreeClass.prototype.changeRefKey = function (
|
||||
oldRefKey,
|
||||
newRefKey
|
||||
) {
|
||||
var i,
|
||||
node,
|
||||
keyMap = this.keyMap,
|
||||
refList = this.refMap[oldRefKey] || null;
|
||||
|
||||
if (refList) {
|
||||
for (i = 0; i < refList.length; i++) {
|
||||
node = keyMap[refList[i]];
|
||||
node.refKey = newRefKey;
|
||||
}
|
||||
delete this.refMap[oldRefKey];
|
||||
this.refMap[newRefKey] = refList;
|
||||
}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Extension code
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "clones",
|
||||
version: "2.38.3",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers
|
||||
highlightClones: false, // set 'fancytree-clone' class on any node that has at least one clone
|
||||
},
|
||||
|
||||
treeCreate: function (ctx) {
|
||||
this._superApply(arguments);
|
||||
ctx.tree.refMap = {};
|
||||
ctx.tree.keyMap = {};
|
||||
},
|
||||
treeInit: function (ctx) {
|
||||
this.$container.addClass("fancytree-ext-clones");
|
||||
_assert(ctx.options.defaultKey == null);
|
||||
// Generate unique / reproducible default keys
|
||||
ctx.options.defaultKey = function (node) {
|
||||
return calcUniqueKey(node);
|
||||
};
|
||||
// The default implementation loads initial data
|
||||
this._superApply(arguments);
|
||||
},
|
||||
treeClear: function (ctx) {
|
||||
ctx.tree.refMap = {};
|
||||
ctx.tree.keyMap = {};
|
||||
return this._superApply(arguments);
|
||||
},
|
||||
treeRegisterNode: function (ctx, add, node) {
|
||||
var refList,
|
||||
len,
|
||||
tree = ctx.tree,
|
||||
keyMap = tree.keyMap,
|
||||
refMap = tree.refMap,
|
||||
key = node.key,
|
||||
refKey = node && node.refKey != null ? "" + node.refKey : null;
|
||||
|
||||
// ctx.tree.debug("clones.treeRegisterNode", add, node);
|
||||
|
||||
if (node.isStatusNode()) {
|
||||
return this._super(ctx, add, node);
|
||||
}
|
||||
|
||||
if (add) {
|
||||
if (keyMap[node.key] != null) {
|
||||
var other = keyMap[node.key],
|
||||
msg =
|
||||
"clones.treeRegisterNode: duplicate key '" +
|
||||
node.key +
|
||||
"': /" +
|
||||
node.getPath(true) +
|
||||
" => " +
|
||||
other.getPath(true);
|
||||
// Sometimes this exception is not visible in the console,
|
||||
// so we also write it:
|
||||
tree.error(msg);
|
||||
$.error(msg);
|
||||
}
|
||||
keyMap[key] = node;
|
||||
|
||||
if (refKey) {
|
||||
refList = refMap[refKey];
|
||||
if (refList) {
|
||||
refList.push(key);
|
||||
if (
|
||||
refList.length === 2 &&
|
||||
ctx.options.clones.highlightClones
|
||||
) {
|
||||
// Mark peer node, if it just became a clone (no need to
|
||||
// mark current node, since it will be rendered later anyway)
|
||||
keyMap[refList[0]].renderStatus();
|
||||
}
|
||||
} else {
|
||||
refMap[refKey] = [key];
|
||||
}
|
||||
// node.debug("clones.treeRegisterNode: add clone =>", refMap[refKey]);
|
||||
}
|
||||
} else {
|
||||
if (keyMap[key] == null) {
|
||||
$.error(
|
||||
"clones.treeRegisterNode: node.key not registered: " +
|
||||
node.key
|
||||
);
|
||||
}
|
||||
delete keyMap[key];
|
||||
if (refKey) {
|
||||
refList = refMap[refKey];
|
||||
// node.debug("clones.treeRegisterNode: remove clone BEFORE =>", refMap[refKey]);
|
||||
if (refList) {
|
||||
len = refList.length;
|
||||
if (len <= 1) {
|
||||
_assert(len === 1);
|
||||
_assert(refList[0] === key);
|
||||
delete refMap[refKey];
|
||||
} else {
|
||||
_removeArrayMember(refList, key);
|
||||
// Unmark peer node, if this was the only clone
|
||||
if (
|
||||
len === 2 &&
|
||||
ctx.options.clones.highlightClones
|
||||
) {
|
||||
// node.debug("clones.treeRegisterNode: last =>", node.getCloneList());
|
||||
keyMap[refList[0]].renderStatus();
|
||||
}
|
||||
}
|
||||
// node.debug("clones.treeRegisterNode: remove clone =>", refMap[refKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._super(ctx, add, node);
|
||||
},
|
||||
nodeRenderStatus: function (ctx) {
|
||||
var $span,
|
||||
res,
|
||||
node = ctx.node;
|
||||
|
||||
res = this._super(ctx);
|
||||
|
||||
if (ctx.options.clones.highlightClones) {
|
||||
$span = $(node[ctx.tree.statusClassPropName]);
|
||||
// Only if span already exists
|
||||
if ($span.length && node.isClone()) {
|
||||
// node.debug("clones.nodeRenderStatus: ", ctx.options.clones.highlightClones);
|
||||
$span.addClass("fancytree-clone");
|
||||
}
|
||||
}
|
||||
return res;
|
||||
},
|
||||
nodeSetActive: function (ctx, flag, callOpts) {
|
||||
var res,
|
||||
scpn = ctx.tree.statusClassPropName,
|
||||
node = ctx.node;
|
||||
|
||||
res = this._superApply(arguments);
|
||||
|
||||
if (ctx.options.clones.highlightActiveClones && node.isClone()) {
|
||||
$.each(node.getCloneList(true), function (idx, n) {
|
||||
// n.debug("clones.nodeSetActive: ", flag !== false);
|
||||
$(n[scpn]).toggleClass(
|
||||
"fancytree-active-clone",
|
||||
flag !== false
|
||||
);
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
});
|
||||
// Value returned by `require('jquery.fancytree..')`
|
||||
return $.ui.fancytree;
|
||||
}); // End of closure
|
Loading…
Add table
Add a link
Reference in a new issue