mirror of
https://github.com/vladmandic/automatic
synced 2026-08-31 01:20:59 +02:00
5cda0aeeb2
Signed-off-by: Vladimir Mandic <mandic00@live.com>
19161 lines
762 KiB
JavaScript
19161 lines
762 KiB
JavaScript
/*
|
|
SD.Next core UI bundle — generated by @vladmandic/build
|
|
*/
|
|
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
}) : x)(function(x) {
|
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
});
|
|
var __commonJS = (cb, mod) => function __require2() {
|
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
|
|
// node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist/jquery.js
|
|
var require_jquery = __commonJS({
|
|
"node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist/jquery.js"(exports, module) {
|
|
(function(global2, factory) {
|
|
"use strict";
|
|
if (typeof module === "object" && typeof module.exports === "object") {
|
|
module.exports = factory(global2, true);
|
|
} else {
|
|
factory(global2);
|
|
}
|
|
})(typeof window !== "undefined" ? window : exports, function(window2, noGlobal) {
|
|
"use strict";
|
|
if (!window2.document) {
|
|
throw new Error("jQuery requires a window with a document");
|
|
}
|
|
var arr = [];
|
|
var getProto = Object.getPrototypeOf;
|
|
var slice = arr.slice;
|
|
var flat = arr.flat ? function(array) {
|
|
return arr.flat.call(array);
|
|
} : function(array) {
|
|
return arr.concat.apply([], array);
|
|
};
|
|
var push = arr.push;
|
|
var indexOf = arr.indexOf;
|
|
var class2type = {};
|
|
var toString = class2type.toString;
|
|
var hasOwn = class2type.hasOwnProperty;
|
|
var fnToString = hasOwn.toString;
|
|
var ObjectFunctionString = fnToString.call(Object);
|
|
var support = {};
|
|
function toType(obj) {
|
|
if (obj == null) {
|
|
return obj + "";
|
|
}
|
|
return typeof obj === "object" ? class2type[toString.call(obj)] || "object" : typeof obj;
|
|
}
|
|
function isWindow(obj) {
|
|
return obj != null && obj === obj.window;
|
|
}
|
|
function isArrayLike(obj) {
|
|
var length = !!obj && obj.length, type = toType(obj);
|
|
if (typeof obj === "function" || isWindow(obj)) {
|
|
return false;
|
|
}
|
|
return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
|
|
}
|
|
var document$1 = window2.document;
|
|
var preservedScriptAttributes = {
|
|
type: true,
|
|
src: true,
|
|
nonce: true,
|
|
noModule: true
|
|
};
|
|
function DOMEval(code, node, doc) {
|
|
doc = doc || document$1;
|
|
var i2, script = doc.createElement("script");
|
|
script.text = code;
|
|
for (i2 in preservedScriptAttributes) {
|
|
if (node && node[i2]) {
|
|
script[i2] = node[i2];
|
|
}
|
|
}
|
|
if (doc.head.appendChild(script).parentNode) {
|
|
script.parentNode.removeChild(script);
|
|
}
|
|
}
|
|
var version = "4.0.0", rhtmlSuffix = /HTML$/i, jQuery3 = function(selector, context) {
|
|
return new jQuery3.fn.init(selector, context);
|
|
};
|
|
jQuery3.fn = jQuery3.prototype = {
|
|
// The current version of jQuery being used
|
|
jquery: version,
|
|
constructor: jQuery3,
|
|
// The default length of a jQuery object is 0
|
|
length: 0,
|
|
toArray: function() {
|
|
return slice.call(this);
|
|
},
|
|
// Get the Nth element in the matched element set OR
|
|
// Get the whole matched element set as a clean array
|
|
get: function(num) {
|
|
if (num == null) {
|
|
return slice.call(this);
|
|
}
|
|
return num < 0 ? this[num + this.length] : this[num];
|
|
},
|
|
// Take an array of elements and push it onto the stack
|
|
// (returning the new matched element set)
|
|
pushStack: function(elems) {
|
|
var ret = jQuery3.merge(this.constructor(), elems);
|
|
ret.prevObject = this;
|
|
return ret;
|
|
},
|
|
// Execute a callback for every element in the matched set.
|
|
each: function(callback) {
|
|
return jQuery3.each(this, callback);
|
|
},
|
|
map: function(callback) {
|
|
return this.pushStack(jQuery3.map(this, function(elem, i2) {
|
|
return callback.call(elem, i2, elem);
|
|
}));
|
|
},
|
|
slice: function() {
|
|
return this.pushStack(slice.apply(this, arguments));
|
|
},
|
|
first: function() {
|
|
return this.eq(0);
|
|
},
|
|
last: function() {
|
|
return this.eq(-1);
|
|
},
|
|
even: function() {
|
|
return this.pushStack(jQuery3.grep(this, function(_elem, i2) {
|
|
return (i2 + 1) % 2;
|
|
}));
|
|
},
|
|
odd: function() {
|
|
return this.pushStack(jQuery3.grep(this, function(_elem, i2) {
|
|
return i2 % 2;
|
|
}));
|
|
},
|
|
eq: function(i2) {
|
|
var len = this.length, j = +i2 + (i2 < 0 ? len : 0);
|
|
return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
|
|
},
|
|
end: function() {
|
|
return this.prevObject || this.constructor();
|
|
}
|
|
};
|
|
jQuery3.extend = jQuery3.fn.extend = function() {
|
|
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i2 = 1, length = arguments.length, deep = false;
|
|
if (typeof target === "boolean") {
|
|
deep = target;
|
|
target = arguments[i2] || {};
|
|
i2++;
|
|
}
|
|
if (typeof target !== "object" && typeof target !== "function") {
|
|
target = {};
|
|
}
|
|
if (i2 === length) {
|
|
target = this;
|
|
i2--;
|
|
}
|
|
for (; i2 < length; i2++) {
|
|
if ((options = arguments[i2]) != null) {
|
|
for (name in options) {
|
|
copy = options[name];
|
|
if (name === "__proto__" || target === copy) {
|
|
continue;
|
|
}
|
|
if (deep && copy && (jQuery3.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
|
|
src = target[name];
|
|
if (copyIsArray && !Array.isArray(src)) {
|
|
clone = [];
|
|
} else if (!copyIsArray && !jQuery3.isPlainObject(src)) {
|
|
clone = {};
|
|
} else {
|
|
clone = src;
|
|
}
|
|
copyIsArray = false;
|
|
target[name] = jQuery3.extend(deep, clone, copy);
|
|
} else if (copy !== void 0) {
|
|
target[name] = copy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
};
|
|
jQuery3.extend({
|
|
// Unique for each copy of jQuery on the page
|
|
expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
|
|
// Assume jQuery is ready without the ready module
|
|
isReady: true,
|
|
error: function(msg) {
|
|
throw new Error(msg);
|
|
},
|
|
noop: function() {
|
|
},
|
|
isPlainObject: function(obj) {
|
|
var proto, Ctor;
|
|
if (!obj || toString.call(obj) !== "[object Object]") {
|
|
return false;
|
|
}
|
|
proto = getProto(obj);
|
|
if (!proto) {
|
|
return true;
|
|
}
|
|
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
|
|
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
|
|
},
|
|
isEmptyObject: function(obj) {
|
|
var name;
|
|
for (name in obj) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
// Evaluates a script in a provided context; falls back to the global one
|
|
// if not specified.
|
|
globalEval: function(code, options, doc) {
|
|
DOMEval(code, { nonce: options && options.nonce }, doc);
|
|
},
|
|
each: function(obj, callback) {
|
|
var length, i2 = 0;
|
|
if (isArrayLike(obj)) {
|
|
length = obj.length;
|
|
for (; i2 < length; i2++) {
|
|
if (callback.call(obj[i2], i2, obj[i2]) === false) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (i2 in obj) {
|
|
if (callback.call(obj[i2], i2, obj[i2]) === false) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
},
|
|
// Retrieve the text value of an array of DOM nodes
|
|
text: function(elem) {
|
|
var node, ret = "", i2 = 0, nodeType = elem.nodeType;
|
|
if (!nodeType) {
|
|
while (node = elem[i2++]) {
|
|
ret += jQuery3.text(node);
|
|
}
|
|
}
|
|
if (nodeType === 1 || nodeType === 11) {
|
|
return elem.textContent;
|
|
}
|
|
if (nodeType === 9) {
|
|
return elem.documentElement.textContent;
|
|
}
|
|
if (nodeType === 3 || nodeType === 4) {
|
|
return elem.nodeValue;
|
|
}
|
|
return ret;
|
|
},
|
|
// results is for internal usage only
|
|
makeArray: function(arr2, results) {
|
|
var ret = results || [];
|
|
if (arr2 != null) {
|
|
if (isArrayLike(Object(arr2))) {
|
|
jQuery3.merge(
|
|
ret,
|
|
typeof arr2 === "string" ? [arr2] : arr2
|
|
);
|
|
} else {
|
|
push.call(ret, arr2);
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
inArray: function(elem, arr2, i2) {
|
|
return arr2 == null ? -1 : indexOf.call(arr2, elem, i2);
|
|
},
|
|
isXMLDoc: function(elem) {
|
|
var namespace = elem && elem.namespaceURI, docElem = elem && (elem.ownerDocument || elem).documentElement;
|
|
return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML");
|
|
},
|
|
// Note: an element does not contain itself
|
|
contains: function(a, b) {
|
|
var bup = b && b.parentNode;
|
|
return a === bup || !!(bup && bup.nodeType === 1 && // Support: IE 9 - 11+
|
|
// IE doesn't have `contains` on SVG.
|
|
(a.contains ? a.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
|
|
},
|
|
merge: function(first, second) {
|
|
var len = +second.length, j = 0, i2 = first.length;
|
|
for (; j < len; j++) {
|
|
first[i2++] = second[j];
|
|
}
|
|
first.length = i2;
|
|
return first;
|
|
},
|
|
grep: function(elems, callback, invert) {
|
|
var callbackInverse, matches2 = [], i2 = 0, length = elems.length, callbackExpect = !invert;
|
|
for (; i2 < length; i2++) {
|
|
callbackInverse = !callback(elems[i2], i2);
|
|
if (callbackInverse !== callbackExpect) {
|
|
matches2.push(elems[i2]);
|
|
}
|
|
}
|
|
return matches2;
|
|
},
|
|
// arg is for internal usage only
|
|
map: function(elems, callback, arg) {
|
|
var length, value, i2 = 0, ret = [];
|
|
if (isArrayLike(elems)) {
|
|
length = elems.length;
|
|
for (; i2 < length; i2++) {
|
|
value = callback(elems[i2], i2, arg);
|
|
if (value != null) {
|
|
ret.push(value);
|
|
}
|
|
}
|
|
} else {
|
|
for (i2 in elems) {
|
|
value = callback(elems[i2], i2, arg);
|
|
if (value != null) {
|
|
ret.push(value);
|
|
}
|
|
}
|
|
}
|
|
return flat(ret);
|
|
},
|
|
// A global GUID counter for objects
|
|
guid: 1,
|
|
// jQuery.support is not used in Core but other projects attach their
|
|
// properties to it so it needs to exist.
|
|
support
|
|
});
|
|
if (typeof Symbol === "function") {
|
|
jQuery3.fn[Symbol.iterator] = arr[Symbol.iterator];
|
|
}
|
|
jQuery3.each(
|
|
"Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),
|
|
function(_i, name) {
|
|
class2type["[object " + name + "]"] = name.toLowerCase();
|
|
}
|
|
);
|
|
function nodeName(elem, name) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
|
}
|
|
var pop = arr.pop;
|
|
var whitespace = "[\\x20\\t\\r\\n\\f]";
|
|
var isIE = document$1.documentMode;
|
|
var rbuggyQSA = isIE && new RegExp(
|
|
// Support: IE 9 - 11+
|
|
// IE's :disabled selector does not pick up the children of disabled fieldsets
|
|
":enabled|:disabled|\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + `*(?:''|"")`
|
|
);
|
|
var rtrimCSS = new RegExp(
|
|
"^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
|
|
"g"
|
|
);
|
|
var identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+";
|
|
var rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*");
|
|
var rdescend = new RegExp(whitespace + "|>");
|
|
var rsibling = /[+~]/;
|
|
var documentElement$1 = document$1.documentElement;
|
|
var matches = documentElement$1.matches || documentElement$1.msMatchesSelector;
|
|
function createCache() {
|
|
var keys = [];
|
|
function cache(key, value) {
|
|
if (keys.push(key + " ") > jQuery3.expr.cacheLength) {
|
|
delete cache[keys.shift()];
|
|
}
|
|
return cache[key + " "] = value;
|
|
}
|
|
return cache;
|
|
}
|
|
function testContext(context) {
|
|
return context && typeof context.getElementsByTagName !== "undefined" && context;
|
|
}
|
|
var attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2)
|
|
"*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
|
|
`*(?:'((?:\\\\.|[^\\\\'])*)'|"((?:\\\\.|[^\\\\"])*)"|(` + identifier + "))|)" + whitespace + "*\\]";
|
|
var pseudos = ":(" + identifier + `)(?:\\((('((?:\\\\.|[^\\\\'])*)'|"((?:\\\\.|[^\\\\"])*)")|((?:\\\\.|[^\\\\()[\\]]|` + attributes + ")*)|.*)\\)|)";
|
|
var filterMatchExpr = {
|
|
ID: new RegExp("^#(" + identifier + ")"),
|
|
CLASS: new RegExp("^\\.(" + identifier + ")"),
|
|
TAG: new RegExp("^(" + identifier + "|[*])"),
|
|
ATTR: new RegExp("^" + attributes),
|
|
PSEUDO: new RegExp("^" + pseudos),
|
|
CHILD: new RegExp(
|
|
"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)",
|
|
"i"
|
|
)
|
|
};
|
|
var rpseudo = new RegExp(pseudos);
|
|
var runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), funescape = function(escape2, nonHex) {
|
|
var high = "0x" + escape2.slice(1) - 65536;
|
|
if (nonHex) {
|
|
return nonHex;
|
|
}
|
|
return high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
|
|
};
|
|
function unescapeSelector(sel) {
|
|
return sel.replace(runescape, funescape);
|
|
}
|
|
function selectorError(msg) {
|
|
jQuery3.error("Syntax error, unrecognized expression: " + msg);
|
|
}
|
|
var rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*");
|
|
var tokenCache = createCache();
|
|
function tokenize(selector, parseOnly) {
|
|
var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
|
|
if (cached) {
|
|
return parseOnly ? 0 : cached.slice(0);
|
|
}
|
|
soFar = selector;
|
|
groups = [];
|
|
preFilters = jQuery3.expr.preFilter;
|
|
while (soFar) {
|
|
if (!matched || (match = rcomma.exec(soFar))) {
|
|
if (match) {
|
|
soFar = soFar.slice(match[0].length) || soFar;
|
|
}
|
|
groups.push(tokens = []);
|
|
}
|
|
matched = false;
|
|
if (match = rleadingCombinator.exec(soFar)) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
// Cast descendant combinators to space
|
|
type: match[0].replace(rtrimCSS, " ")
|
|
});
|
|
soFar = soFar.slice(matched.length);
|
|
}
|
|
for (type in filterMatchExpr) {
|
|
if ((match = jQuery3.expr.match[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
type,
|
|
matches: match
|
|
});
|
|
soFar = soFar.slice(matched.length);
|
|
}
|
|
}
|
|
if (!matched) {
|
|
break;
|
|
}
|
|
}
|
|
if (parseOnly) {
|
|
return soFar.length;
|
|
}
|
|
return soFar ? selectorError(selector) : (
|
|
// Cache the tokens
|
|
tokenCache(selector, groups).slice(0)
|
|
);
|
|
}
|
|
var preFilter = {
|
|
ATTR: function(match) {
|
|
match[1] = unescapeSelector(match[1]);
|
|
match[3] = unescapeSelector(match[3] || match[4] || match[5] || "");
|
|
if (match[2] === "~=") {
|
|
match[3] = " " + match[3] + " ";
|
|
}
|
|
return match.slice(0, 4);
|
|
},
|
|
CHILD: function(match) {
|
|
match[1] = match[1].toLowerCase();
|
|
if (match[1].slice(0, 3) === "nth") {
|
|
if (!match[3]) {
|
|
selectorError(match[0]);
|
|
}
|
|
match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
|
|
match[5] = +(match[7] + match[8] || match[3] === "odd");
|
|
} else if (match[3]) {
|
|
selectorError(match[0]);
|
|
}
|
|
return match;
|
|
},
|
|
PSEUDO: function(match) {
|
|
var excess, unquoted = !match[6] && match[2];
|
|
if (filterMatchExpr.CHILD.test(match[0])) {
|
|
return null;
|
|
}
|
|
if (match[3]) {
|
|
match[2] = match[4] || match[5] || "";
|
|
} else if (unquoted && rpseudo.test(unquoted) && // Get excess from tokenize (recursively)
|
|
(excess = tokenize(unquoted, true)) && // advance to the next closing parenthesis
|
|
(excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
|
|
match[0] = match[0].slice(0, excess);
|
|
match[2] = unquoted.slice(0, excess);
|
|
}
|
|
return match.slice(0, 3);
|
|
}
|
|
};
|
|
function toSelector(tokens) {
|
|
var i2 = 0, len = tokens.length, selector = "";
|
|
for (; i2 < len; i2++) {
|
|
selector += tokens[i2].value;
|
|
}
|
|
return selector;
|
|
}
|
|
function access(elems, fn, key, value, chainable, emptyGet, raw) {
|
|
var i2 = 0, len = elems.length, bulk = key == null;
|
|
if (toType(key) === "object") {
|
|
chainable = true;
|
|
for (i2 in key) {
|
|
access(elems, fn, i2, key[i2], true, emptyGet, raw);
|
|
}
|
|
} else if (value !== void 0) {
|
|
chainable = true;
|
|
if (typeof value !== "function") {
|
|
raw = true;
|
|
}
|
|
if (bulk) {
|
|
if (raw) {
|
|
fn.call(elems, value);
|
|
fn = null;
|
|
} else {
|
|
bulk = fn;
|
|
fn = function(elem, _key, value2) {
|
|
return bulk.call(jQuery3(elem), value2);
|
|
};
|
|
}
|
|
}
|
|
if (fn) {
|
|
for (; i2 < len; i2++) {
|
|
fn(
|
|
elems[i2],
|
|
key,
|
|
raw ? value : value.call(elems[i2], i2, fn(elems[i2], key))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
if (chainable) {
|
|
return elems;
|
|
}
|
|
if (bulk) {
|
|
return fn.call(elems);
|
|
}
|
|
return len ? fn(elems[0], key) : emptyGet;
|
|
}
|
|
var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
|
jQuery3.fn.extend({
|
|
attr: function(name, value) {
|
|
return access(this, jQuery3.attr, name, value, arguments.length > 1);
|
|
},
|
|
removeAttr: function(name) {
|
|
return this.each(function() {
|
|
jQuery3.removeAttr(this, name);
|
|
});
|
|
}
|
|
});
|
|
jQuery3.extend({
|
|
attr: function(elem, name, value) {
|
|
var ret, hooks, nType = elem.nodeType;
|
|
if (nType === 3 || nType === 8 || nType === 2) {
|
|
return;
|
|
}
|
|
if (typeof elem.getAttribute === "undefined") {
|
|
return jQuery3.prop(elem, name, value);
|
|
}
|
|
if (nType !== 1 || !jQuery3.isXMLDoc(elem)) {
|
|
hooks = jQuery3.attrHooks[name.toLowerCase()];
|
|
}
|
|
if (value !== void 0) {
|
|
if (value === null || // For compat with previous handling of boolean attributes,
|
|
// remove when `false` passed. For ARIA attributes -
|
|
// many of which recognize a `"false"` value - continue to
|
|
// set the `"false"` value as jQuery <4 did.
|
|
value === false && name.toLowerCase().indexOf("aria-") !== 0) {
|
|
jQuery3.removeAttr(elem, name);
|
|
return;
|
|
}
|
|
if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) {
|
|
return ret;
|
|
}
|
|
elem.setAttribute(name, value);
|
|
return value;
|
|
}
|
|
if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
|
|
return ret;
|
|
}
|
|
ret = elem.getAttribute(name);
|
|
return ret == null ? void 0 : ret;
|
|
},
|
|
attrHooks: {},
|
|
removeAttr: function(elem, value) {
|
|
var name, i2 = 0, attrNames = value && value.match(rnothtmlwhite);
|
|
if (attrNames && elem.nodeType === 1) {
|
|
while (name = attrNames[i2++]) {
|
|
elem.removeAttribute(name);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (isIE) {
|
|
jQuery3.attrHooks.type = {
|
|
set: function(elem, value) {
|
|
if (value === "radio" && nodeName(elem, "input")) {
|
|
var val = elem.value;
|
|
elem.setAttribute("type", value);
|
|
if (val) {
|
|
elem.value = val;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
|
|
function fcssescape(ch, asCodePoint) {
|
|
if (asCodePoint) {
|
|
if (ch === "\0") {
|
|
return "\uFFFD";
|
|
}
|
|
return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
|
|
}
|
|
return "\\" + ch;
|
|
}
|
|
jQuery3.escapeSelector = function(sel) {
|
|
return (sel + "").replace(rcssescape, fcssescape);
|
|
};
|
|
var sort = arr.sort;
|
|
var splice = arr.splice;
|
|
var hasDuplicate;
|
|
function sortOrder(a, b) {
|
|
if (a === b) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
|
|
if (compare) {
|
|
return compare;
|
|
}
|
|
compare = (a.ownerDocument || a) == (b.ownerDocument || b) ? a.compareDocumentPosition(b) : (
|
|
// Otherwise we know they are disconnected
|
|
1
|
|
);
|
|
if (compare & 1) {
|
|
if (a == document$1 || a.ownerDocument == document$1 && jQuery3.contains(document$1, a)) {
|
|
return -1;
|
|
}
|
|
if (b == document$1 || b.ownerDocument == document$1 && jQuery3.contains(document$1, b)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return compare & 4 ? -1 : 1;
|
|
}
|
|
jQuery3.uniqueSort = function(results) {
|
|
var elem, duplicates = [], j = 0, i2 = 0;
|
|
hasDuplicate = false;
|
|
sort.call(results, sortOrder);
|
|
if (hasDuplicate) {
|
|
while (elem = results[i2++]) {
|
|
if (elem === results[i2]) {
|
|
j = duplicates.push(i2);
|
|
}
|
|
}
|
|
while (j--) {
|
|
splice.call(results, duplicates[j], 1);
|
|
}
|
|
}
|
|
return results;
|
|
};
|
|
jQuery3.fn.uniqueSort = function() {
|
|
return this.pushStack(jQuery3.uniqueSort(slice.apply(this)));
|
|
};
|
|
var i, outermostContext, document2, documentElement, documentIsHTML, dirruns = 0, done = 0, classCache = createCache(), compilerCache = createCache(), nonnativeSelectorCache = createCache(), rwhitespace = new RegExp(whitespace + "+", "g"), ridentifier = new RegExp("^" + identifier + "$"), matchExpr = jQuery3.extend({
|
|
// For use in libraries implementing .is()
|
|
// We use this for POS matching in `select`
|
|
needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
|
|
}, filterMatchExpr), rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rquickExpr$1 = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, unloadHandler = function() {
|
|
setDocument();
|
|
}, inDisabledFieldset = addCombinator(
|
|
function(elem) {
|
|
return elem.disabled === true && nodeName(elem, "fieldset");
|
|
},
|
|
{ dir: "parentNode", next: "legend" }
|
|
);
|
|
function find(selector, context, results, seed) {
|
|
var m, i2, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, nodeType = context ? context.nodeType : 9;
|
|
results = results || [];
|
|
if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {
|
|
return results;
|
|
}
|
|
if (!seed) {
|
|
setDocument(context);
|
|
context = context || document2;
|
|
if (documentIsHTML) {
|
|
if (nodeType !== 11 && (match = rquickExpr$1.exec(selector))) {
|
|
if (m = match[1]) {
|
|
if (nodeType === 9) {
|
|
if (elem = context.getElementById(m)) {
|
|
push.call(results, elem);
|
|
}
|
|
return results;
|
|
} else {
|
|
if (newContext && (elem = newContext.getElementById(m)) && jQuery3.contains(context, elem)) {
|
|
push.call(results, elem);
|
|
return results;
|
|
}
|
|
}
|
|
} else if (match[2]) {
|
|
push.apply(results, context.getElementsByTagName(selector));
|
|
return results;
|
|
} else if ((m = match[3]) && context.getElementsByClassName) {
|
|
push.apply(results, context.getElementsByClassName(m));
|
|
return results;
|
|
}
|
|
}
|
|
if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
|
|
newSelector = selector;
|
|
newContext = context;
|
|
if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) {
|
|
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
|
|
if (newContext != context || isIE) {
|
|
if (nid = context.getAttribute("id")) {
|
|
nid = jQuery3.escapeSelector(nid);
|
|
} else {
|
|
context.setAttribute("id", nid = jQuery3.expando);
|
|
}
|
|
}
|
|
groups = tokenize(selector);
|
|
i2 = groups.length;
|
|
while (i2--) {
|
|
groups[i2] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i2]);
|
|
}
|
|
newSelector = groups.join(",");
|
|
}
|
|
try {
|
|
push.apply(
|
|
results,
|
|
newContext.querySelectorAll(newSelector)
|
|
);
|
|
return results;
|
|
} catch (qsaError) {
|
|
nonnativeSelectorCache(selector, true);
|
|
} finally {
|
|
if (nid === jQuery3.expando) {
|
|
context.removeAttribute("id");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return select(selector.replace(rtrimCSS, "$1"), context, results, seed);
|
|
}
|
|
function markFunction(fn) {
|
|
fn[jQuery3.expando] = true;
|
|
return fn;
|
|
}
|
|
function createInputPseudo(type) {
|
|
return function(elem) {
|
|
return nodeName(elem, "input") && elem.type === type;
|
|
};
|
|
}
|
|
function createButtonPseudo(type) {
|
|
return function(elem) {
|
|
return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type;
|
|
};
|
|
}
|
|
function createDisabledPseudo(disabled) {
|
|
return function(elem) {
|
|
if ("form" in elem) {
|
|
if (elem.parentNode && elem.disabled === false) {
|
|
if ("label" in elem) {
|
|
if ("label" in elem.parentNode) {
|
|
return elem.parentNode.disabled === disabled;
|
|
} else {
|
|
return elem.disabled === disabled;
|
|
}
|
|
}
|
|
return elem.isDisabled === disabled || // Where there is no isDisabled, check manually
|
|
elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled;
|
|
}
|
|
return elem.disabled === disabled;
|
|
} else if ("label" in elem) {
|
|
return elem.disabled === disabled;
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
function createPositionalPseudo(fn) {
|
|
return markFunction(function(argument) {
|
|
argument = +argument;
|
|
return markFunction(function(seed, matches2) {
|
|
var j, matchIndexes = fn([], seed.length, argument), i2 = matchIndexes.length;
|
|
while (i2--) {
|
|
if (seed[j = matchIndexes[i2]]) {
|
|
seed[j] = !(matches2[j] = seed[j]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function setDocument(node) {
|
|
var subWindow, doc = node ? node.ownerDocument || node : document$1;
|
|
if (doc == document2 || doc.nodeType !== 9) {
|
|
return;
|
|
}
|
|
document2 = doc;
|
|
documentElement = document2.documentElement;
|
|
documentIsHTML = !jQuery3.isXMLDoc(document2);
|
|
if (isIE && document$1 != document2 && (subWindow = document2.defaultView) && subWindow.top !== subWindow) {
|
|
subWindow.addEventListener("unload", unloadHandler);
|
|
}
|
|
}
|
|
find.matches = function(expr, elements) {
|
|
return find(expr, null, null, elements);
|
|
};
|
|
find.matchesSelector = function(elem, expr) {
|
|
setDocument(elem);
|
|
if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) {
|
|
try {
|
|
return matches.call(elem, expr);
|
|
} catch (e) {
|
|
nonnativeSelectorCache(expr, true);
|
|
}
|
|
}
|
|
return find(expr, document2, null, [elem]).length > 0;
|
|
};
|
|
jQuery3.expr = {
|
|
// Can be adjusted by the user
|
|
cacheLength: 50,
|
|
createPseudo: markFunction,
|
|
match: matchExpr,
|
|
find: {
|
|
ID: function(id, context) {
|
|
if (typeof context.getElementById !== "undefined" && documentIsHTML) {
|
|
var elem = context.getElementById(id);
|
|
return elem ? [elem] : [];
|
|
}
|
|
},
|
|
TAG: function(tag, context) {
|
|
if (typeof context.getElementsByTagName !== "undefined") {
|
|
return context.getElementsByTagName(tag);
|
|
} else {
|
|
return context.querySelectorAll(tag);
|
|
}
|
|
},
|
|
CLASS: function(className, context) {
|
|
if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) {
|
|
return context.getElementsByClassName(className);
|
|
}
|
|
}
|
|
},
|
|
relative: {
|
|
">": { dir: "parentNode", first: true },
|
|
" ": { dir: "parentNode" },
|
|
"+": { dir: "previousSibling", first: true },
|
|
"~": { dir: "previousSibling" }
|
|
},
|
|
preFilter,
|
|
filter: {
|
|
ID: function(id) {
|
|
var attrId = unescapeSelector(id);
|
|
return function(elem) {
|
|
return elem.getAttribute("id") === attrId;
|
|
};
|
|
},
|
|
TAG: function(nodeNameSelector) {
|
|
var expectedNodeName = unescapeSelector(nodeNameSelector).toLowerCase();
|
|
return nodeNameSelector === "*" ? function() {
|
|
return true;
|
|
} : function(elem) {
|
|
return nodeName(elem, expectedNodeName);
|
|
};
|
|
},
|
|
CLASS: function(className) {
|
|
var pattern = classCache[className + " "];
|
|
return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem) {
|
|
return pattern.test(
|
|
typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || ""
|
|
);
|
|
});
|
|
},
|
|
ATTR: function(name, operator, check) {
|
|
return function(elem) {
|
|
var result = jQuery3.attr(elem, name);
|
|
if (result == null) {
|
|
return operator === "!=";
|
|
}
|
|
if (!operator) {
|
|
return true;
|
|
}
|
|
result += "";
|
|
if (operator === "=") {
|
|
return result === check;
|
|
}
|
|
if (operator === "!=") {
|
|
return result !== check;
|
|
}
|
|
if (operator === "^=") {
|
|
return check && result.indexOf(check) === 0;
|
|
}
|
|
if (operator === "*=") {
|
|
return check && result.indexOf(check) > -1;
|
|
}
|
|
if (operator === "$=") {
|
|
return check && result.slice(-check.length) === check;
|
|
}
|
|
if (operator === "~=") {
|
|
return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1;
|
|
}
|
|
if (operator === "|=") {
|
|
return result === check || result.slice(0, check.length + 1) === check + "-";
|
|
}
|
|
return false;
|
|
};
|
|
},
|
|
CHILD: function(type, what, _argument, first, last) {
|
|
var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type";
|
|
return first === 1 && last === 0 ? (
|
|
// Shortcut for :nth-*(n)
|
|
function(elem) {
|
|
return !!elem.parentNode;
|
|
}
|
|
) : function(elem, _context, xml) {
|
|
var cache, outerCache, node, nodeIndex, start, dir2 = simple !== forward ? "nextSibling" : "previousSibling", parent2 = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false;
|
|
if (parent2) {
|
|
if (simple) {
|
|
while (dir2) {
|
|
node = elem;
|
|
while (node = node[dir2]) {
|
|
if (ofType ? nodeName(node, name) : node.nodeType === 1) {
|
|
return false;
|
|
}
|
|
}
|
|
start = dir2 = type === "only" && !start && "nextSibling";
|
|
}
|
|
return true;
|
|
}
|
|
start = [forward ? parent2.firstChild : parent2.lastChild];
|
|
if (forward && useCache) {
|
|
outerCache = parent2[jQuery3.expando] || (parent2[jQuery3.expando] = {});
|
|
cache = outerCache[type] || [];
|
|
nodeIndex = cache[0] === dirruns && cache[1];
|
|
diff = nodeIndex && cache[2];
|
|
node = nodeIndex && parent2.childNodes[nodeIndex];
|
|
while (node = ++nodeIndex && node && node[dir2] || // Fallback to seeking `elem` from the start
|
|
(diff = nodeIndex = 0) || start.pop()) {
|
|
if (node.nodeType === 1 && ++diff && node === elem) {
|
|
outerCache[type] = [dirruns, nodeIndex, diff];
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (useCache) {
|
|
outerCache = elem[jQuery3.expando] || (elem[jQuery3.expando] = {});
|
|
cache = outerCache[type] || [];
|
|
nodeIndex = cache[0] === dirruns && cache[1];
|
|
diff = nodeIndex;
|
|
}
|
|
if (diff === false) {
|
|
while (node = ++nodeIndex && node && node[dir2] || (diff = nodeIndex = 0) || start.pop()) {
|
|
if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) {
|
|
if (useCache) {
|
|
outerCache = node[jQuery3.expando] || (node[jQuery3.expando] = {});
|
|
outerCache[type] = [dirruns, diff];
|
|
}
|
|
if (node === elem) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
diff -= last;
|
|
return diff === first || diff % first === 0 && diff / first >= 0;
|
|
}
|
|
};
|
|
},
|
|
PSEUDO: function(pseudo, argument) {
|
|
var fn = jQuery3.expr.pseudos[pseudo] || jQuery3.expr.setFilters[pseudo.toLowerCase()] || selectorError("unsupported pseudo: " + pseudo);
|
|
if (fn[jQuery3.expando]) {
|
|
return fn(argument);
|
|
}
|
|
return fn;
|
|
}
|
|
},
|
|
pseudos: {
|
|
// Potentially complex pseudos
|
|
not: markFunction(function(selector) {
|
|
var input = [], results = [], matcher = compile(selector.replace(rtrimCSS, "$1"));
|
|
return matcher[jQuery3.expando] ? markFunction(function(seed, matches2, _context, xml) {
|
|
var elem, unmatched = matcher(seed, null, xml, []), i2 = seed.length;
|
|
while (i2--) {
|
|
if (elem = unmatched[i2]) {
|
|
seed[i2] = !(matches2[i2] = elem);
|
|
}
|
|
}
|
|
}) : function(elem, _context, xml) {
|
|
input[0] = elem;
|
|
matcher(input, null, xml, results);
|
|
input[0] = null;
|
|
return !results.pop();
|
|
};
|
|
}),
|
|
has: markFunction(function(selector) {
|
|
return function(elem) {
|
|
return find(selector, elem).length > 0;
|
|
};
|
|
}),
|
|
contains: markFunction(function(text) {
|
|
text = unescapeSelector(text);
|
|
return function(elem) {
|
|
return (elem.textContent || jQuery3.text(elem)).indexOf(text) > -1;
|
|
};
|
|
}),
|
|
// "Whether an element is represented by a :lang() selector
|
|
// is based solely on the element's language value
|
|
// being equal to the identifier C,
|
|
// or beginning with the identifier C immediately followed by "-".
|
|
// The matching of C against the element's language value is performed case-insensitively.
|
|
// The identifier C does not have to be a valid language name."
|
|
// https://www.w3.org/TR/selectors/#lang-pseudo
|
|
lang: markFunction(function(lang) {
|
|
if (!ridentifier.test(lang || "")) {
|
|
selectorError("unsupported lang: " + lang);
|
|
}
|
|
lang = unescapeSelector(lang).toLowerCase();
|
|
return function(elem) {
|
|
var elemLang;
|
|
do {
|
|
if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {
|
|
elemLang = elemLang.toLowerCase();
|
|
return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
|
|
}
|
|
} while ((elem = elem.parentNode) && elem.nodeType === 1);
|
|
return false;
|
|
};
|
|
}),
|
|
// Miscellaneous
|
|
target: function(elem) {
|
|
var hash3 = window2.location && window2.location.hash;
|
|
return hash3 && hash3.slice(1) === elem.id;
|
|
},
|
|
root: function(elem) {
|
|
return elem === documentElement;
|
|
},
|
|
focus: function(elem) {
|
|
return elem === document2.activeElement && document2.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex);
|
|
},
|
|
// Boolean properties
|
|
enabled: createDisabledPseudo(false),
|
|
disabled: createDisabledPseudo(true),
|
|
checked: function(elem) {
|
|
return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected;
|
|
},
|
|
selected: function(elem) {
|
|
if (isIE && elem.parentNode) {
|
|
elem.parentNode.selectedIndex;
|
|
}
|
|
return elem.selected === true;
|
|
},
|
|
// Contents
|
|
empty: function(elem) {
|
|
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
|
|
if (elem.nodeType < 6) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
parent: function(elem) {
|
|
return !jQuery3.expr.pseudos.empty(elem);
|
|
},
|
|
// Element/input types
|
|
header: function(elem) {
|
|
return rheader.test(elem.nodeName);
|
|
},
|
|
input: function(elem) {
|
|
return rinputs.test(elem.nodeName);
|
|
},
|
|
button: function(elem) {
|
|
return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button");
|
|
},
|
|
text: function(elem) {
|
|
return nodeName(elem, "input") && elem.type === "text";
|
|
},
|
|
// Position-in-collection
|
|
first: createPositionalPseudo(function() {
|
|
return [0];
|
|
}),
|
|
last: createPositionalPseudo(function(_matchIndexes, length) {
|
|
return [length - 1];
|
|
}),
|
|
eq: createPositionalPseudo(function(_matchIndexes, length, argument) {
|
|
return [argument < 0 ? argument + length : argument];
|
|
}),
|
|
even: createPositionalPseudo(function(matchIndexes, length) {
|
|
var i2 = 0;
|
|
for (; i2 < length; i2 += 2) {
|
|
matchIndexes.push(i2);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
odd: createPositionalPseudo(function(matchIndexes, length) {
|
|
var i2 = 1;
|
|
for (; i2 < length; i2 += 2) {
|
|
matchIndexes.push(i2);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
lt: createPositionalPseudo(function(matchIndexes, length, argument) {
|
|
var i2;
|
|
if (argument < 0) {
|
|
i2 = argument + length;
|
|
} else if (argument > length) {
|
|
i2 = length;
|
|
} else {
|
|
i2 = argument;
|
|
}
|
|
for (; --i2 >= 0; ) {
|
|
matchIndexes.push(i2);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
gt: createPositionalPseudo(function(matchIndexes, length, argument) {
|
|
var i2 = argument < 0 ? argument + length : argument;
|
|
for (; ++i2 < length; ) {
|
|
matchIndexes.push(i2);
|
|
}
|
|
return matchIndexes;
|
|
})
|
|
}
|
|
};
|
|
jQuery3.expr.pseudos.nth = jQuery3.expr.pseudos.eq;
|
|
for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
|
|
jQuery3.expr.pseudos[i] = createInputPseudo(i);
|
|
}
|
|
for (i in { submit: true, reset: true }) {
|
|
jQuery3.expr.pseudos[i] = createButtonPseudo(i);
|
|
}
|
|
function setFilters() {
|
|
}
|
|
setFilters.prototype = jQuery3.expr.pseudos;
|
|
jQuery3.expr.setFilters = new setFilters();
|
|
function addCombinator(matcher, combinator, base) {
|
|
var dir2 = combinator.dir, skip = combinator.next, key = skip || dir2, checkNonElements = base && key === "parentNode", doneName = done++;
|
|
return combinator.first ? (
|
|
// Check against closest ancestor/preceding element
|
|
function(elem, context, xml) {
|
|
while (elem = elem[dir2]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
return matcher(elem, context, xml);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
) : (
|
|
// Check against all ancestor/preceding elements
|
|
function(elem, context, xml) {
|
|
var oldCache, outerCache, newCache = [dirruns, doneName];
|
|
if (xml) {
|
|
while (elem = elem[dir2]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
if (matcher(elem, context, xml)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while (elem = elem[dir2]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
outerCache = elem[jQuery3.expando] || (elem[jQuery3.expando] = {});
|
|
if (skip && nodeName(elem, skip)) {
|
|
elem = elem[dir2] || elem;
|
|
} else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) {
|
|
return newCache[2] = oldCache[2];
|
|
} else {
|
|
outerCache[key] = newCache;
|
|
if (newCache[2] = matcher(elem, context, xml)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
function elementMatcher(matchers) {
|
|
return matchers.length > 1 ? function(elem, context, xml) {
|
|
var i2 = matchers.length;
|
|
while (i2--) {
|
|
if (!matchers[i2](elem, context, xml)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} : matchers[0];
|
|
}
|
|
function multipleContexts(selector, contexts, results) {
|
|
var i2 = 0, len = contexts.length;
|
|
for (; i2 < len; i2++) {
|
|
find(selector, contexts[i2], results);
|
|
}
|
|
return results;
|
|
}
|
|
function condense(unmatched, map, filter, context, xml) {
|
|
var elem, newUnmatched = [], i2 = 0, len = unmatched.length, mapped = map != null;
|
|
for (; i2 < len; i2++) {
|
|
if (elem = unmatched[i2]) {
|
|
if (!filter || filter(elem, context, xml)) {
|
|
newUnmatched.push(elem);
|
|
if (mapped) {
|
|
map.push(i2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return newUnmatched;
|
|
}
|
|
function setMatcher(preFilter2, selector, matcher, postFilter, postFinder, postSelector) {
|
|
if (postFilter && !postFilter[jQuery3.expando]) {
|
|
postFilter = setMatcher(postFilter);
|
|
}
|
|
if (postFinder && !postFinder[jQuery3.expando]) {
|
|
postFinder = setMatcher(postFinder, postSelector);
|
|
}
|
|
return markFunction(function(seed, results, context, xml) {
|
|
var temp, i2, elem, matcherOut, preMap = [], postMap = [], preexisting = results.length, elems = seed || multipleContexts(
|
|
selector || "*",
|
|
context.nodeType ? [context] : context,
|
|
[]
|
|
), matcherIn = preFilter2 && (seed || !selector) ? condense(elems, preMap, preFilter2, context, xml) : elems;
|
|
if (matcher) {
|
|
matcherOut = postFinder || (seed ? preFilter2 : preexisting || postFilter) ? (
|
|
// ...intermediate processing is necessary
|
|
[]
|
|
) : (
|
|
// ...otherwise use results directly
|
|
results
|
|
);
|
|
matcher(matcherIn, matcherOut, context, xml);
|
|
} else {
|
|
matcherOut = matcherIn;
|
|
}
|
|
if (postFilter) {
|
|
temp = condense(matcherOut, postMap);
|
|
postFilter(temp, [], context, xml);
|
|
i2 = temp.length;
|
|
while (i2--) {
|
|
if (elem = temp[i2]) {
|
|
matcherOut[postMap[i2]] = !(matcherIn[postMap[i2]] = elem);
|
|
}
|
|
}
|
|
}
|
|
if (seed) {
|
|
if (postFinder || preFilter2) {
|
|
if (postFinder) {
|
|
temp = [];
|
|
i2 = matcherOut.length;
|
|
while (i2--) {
|
|
if (elem = matcherOut[i2]) {
|
|
temp.push(matcherIn[i2] = elem);
|
|
}
|
|
}
|
|
postFinder(null, matcherOut = [], temp, xml);
|
|
}
|
|
i2 = matcherOut.length;
|
|
while (i2--) {
|
|
if ((elem = matcherOut[i2]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i2]) > -1) {
|
|
seed[temp] = !(results[temp] = elem);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
matcherOut = condense(
|
|
matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut
|
|
);
|
|
if (postFinder) {
|
|
postFinder(null, results, matcherOut, xml);
|
|
} else {
|
|
push.apply(results, matcherOut);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function matcherFromTokens(tokens) {
|
|
var checkContext, matcher, j, len = tokens.length, leadingRelative = jQuery3.expr.relative[tokens[0].type], implicitRelative = leadingRelative || jQuery3.expr.relative[" "], i2 = leadingRelative ? 1 : 0, matchContext = addCombinator(function(elem) {
|
|
return elem === checkContext;
|
|
}, implicitRelative, true), matchAnyContext = addCombinator(function(elem) {
|
|
return indexOf.call(checkContext, elem) > -1;
|
|
}, implicitRelative, true), matchers = [function(elem, context, xml) {
|
|
var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
|
|
checkContext = null;
|
|
return ret;
|
|
}];
|
|
for (; i2 < len; i2++) {
|
|
if (matcher = jQuery3.expr.relative[tokens[i2].type]) {
|
|
matchers = [addCombinator(elementMatcher(matchers), matcher)];
|
|
} else {
|
|
matcher = jQuery3.expr.filter[tokens[i2].type].apply(null, tokens[i2].matches);
|
|
if (matcher[jQuery3.expando]) {
|
|
j = ++i2;
|
|
for (; j < len; j++) {
|
|
if (jQuery3.expr.relative[tokens[j].type]) {
|
|
break;
|
|
}
|
|
}
|
|
return setMatcher(
|
|
i2 > 1 && elementMatcher(matchers),
|
|
i2 > 1 && toSelector(
|
|
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
|
|
tokens.slice(0, i2 - 1).concat({ value: tokens[i2 - 2].type === " " ? "*" : "" })
|
|
).replace(rtrimCSS, "$1"),
|
|
matcher,
|
|
i2 < j && matcherFromTokens(tokens.slice(i2, j)),
|
|
j < len && matcherFromTokens(tokens = tokens.slice(j)),
|
|
j < len && toSelector(tokens)
|
|
);
|
|
}
|
|
matchers.push(matcher);
|
|
}
|
|
}
|
|
return elementMatcher(matchers);
|
|
}
|
|
function matcherFromGroupMatchers(elementMatchers, setMatchers) {
|
|
var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function(seed, context, xml, results, outermost) {
|
|
var elem, j, matcher, matchedCount = 0, i2 = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, elems = seed || byElement && jQuery3.expr.find.TAG("*", outermost), dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1;
|
|
if (outermost) {
|
|
outermostContext = context == document2 || context || outermost;
|
|
}
|
|
for (; (elem = elems[i2]) != null; i2++) {
|
|
if (byElement && elem) {
|
|
j = 0;
|
|
if (!context && elem.ownerDocument != document2) {
|
|
setDocument(elem);
|
|
xml = !documentIsHTML;
|
|
}
|
|
while (matcher = elementMatchers[j++]) {
|
|
if (matcher(elem, context || document2, xml)) {
|
|
push.call(results, elem);
|
|
break;
|
|
}
|
|
}
|
|
if (outermost) {
|
|
dirruns = dirrunsUnique;
|
|
}
|
|
}
|
|
if (bySet) {
|
|
if (elem = !matcher && elem) {
|
|
matchedCount--;
|
|
}
|
|
if (seed) {
|
|
unmatched.push(elem);
|
|
}
|
|
}
|
|
}
|
|
matchedCount += i2;
|
|
if (bySet && i2 !== matchedCount) {
|
|
j = 0;
|
|
while (matcher = setMatchers[j++]) {
|
|
matcher(unmatched, setMatched, context, xml);
|
|
}
|
|
if (seed) {
|
|
if (matchedCount > 0) {
|
|
while (i2--) {
|
|
if (!(unmatched[i2] || setMatched[i2])) {
|
|
setMatched[i2] = pop.call(results);
|
|
}
|
|
}
|
|
}
|
|
setMatched = condense(setMatched);
|
|
}
|
|
push.apply(results, setMatched);
|
|
if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) {
|
|
jQuery3.uniqueSort(results);
|
|
}
|
|
}
|
|
if (outermost) {
|
|
dirruns = dirrunsUnique;
|
|
outermostContext = contextBackup;
|
|
}
|
|
return unmatched;
|
|
};
|
|
return bySet ? markFunction(superMatcher) : superMatcher;
|
|
}
|
|
function compile(selector, match) {
|
|
var i2, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + " "];
|
|
if (!cached) {
|
|
if (!match) {
|
|
match = tokenize(selector);
|
|
}
|
|
i2 = match.length;
|
|
while (i2--) {
|
|
cached = matcherFromTokens(match[i2]);
|
|
if (cached[jQuery3.expando]) {
|
|
setMatchers.push(cached);
|
|
} else {
|
|
elementMatchers.push(cached);
|
|
}
|
|
}
|
|
cached = compilerCache(
|
|
selector,
|
|
matcherFromGroupMatchers(elementMatchers, setMatchers)
|
|
);
|
|
cached.selector = selector;
|
|
}
|
|
return cached;
|
|
}
|
|
function select(selector, context, results, seed) {
|
|
var i2, tokens, token2, type, find2, compiled = typeof selector === "function" && selector, match = !seed && tokenize(selector = compiled.selector || selector);
|
|
results = results || [];
|
|
if (match.length === 1) {
|
|
tokens = match[0] = match[0].slice(0);
|
|
if (tokens.length > 2 && (token2 = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && jQuery3.expr.relative[tokens[1].type]) {
|
|
context = (jQuery3.expr.find.ID(
|
|
unescapeSelector(token2.matches[0]),
|
|
context
|
|
) || [])[0];
|
|
if (!context) {
|
|
return results;
|
|
} else if (compiled) {
|
|
context = context.parentNode;
|
|
}
|
|
selector = selector.slice(tokens.shift().value.length);
|
|
}
|
|
i2 = matchExpr.needsContext.test(selector) ? 0 : tokens.length;
|
|
while (i2--) {
|
|
token2 = tokens[i2];
|
|
if (jQuery3.expr.relative[type = token2.type]) {
|
|
break;
|
|
}
|
|
if (find2 = jQuery3.expr.find[type]) {
|
|
if (seed = find2(
|
|
unescapeSelector(token2.matches[0]),
|
|
rsibling.test(tokens[0].type) && testContext(context.parentNode) || context
|
|
)) {
|
|
tokens.splice(i2, 1);
|
|
selector = seed.length && toSelector(tokens);
|
|
if (!selector) {
|
|
push.apply(results, seed);
|
|
return results;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(compiled || compile(selector, match))(
|
|
seed,
|
|
context,
|
|
!documentIsHTML,
|
|
results,
|
|
!context || rsibling.test(selector) && testContext(context.parentNode) || context
|
|
);
|
|
return results;
|
|
}
|
|
setDocument();
|
|
jQuery3.find = find;
|
|
find.compile = compile;
|
|
find.select = select;
|
|
find.setDocument = setDocument;
|
|
find.tokenize = tokenize;
|
|
function dir(elem, dir2, until) {
|
|
var matched = [], truncate = until !== void 0;
|
|
while ((elem = elem[dir2]) && elem.nodeType !== 9) {
|
|
if (elem.nodeType === 1) {
|
|
if (truncate && jQuery3(elem).is(until)) {
|
|
break;
|
|
}
|
|
matched.push(elem);
|
|
}
|
|
}
|
|
return matched;
|
|
}
|
|
function siblings(n, elem) {
|
|
var matched = [];
|
|
for (; n; n = n.nextSibling) {
|
|
if (n.nodeType === 1 && n !== elem) {
|
|
matched.push(n);
|
|
}
|
|
}
|
|
return matched;
|
|
}
|
|
var rneedsContext = jQuery3.expr.match.needsContext;
|
|
var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
|
|
function isObviousHtml(input) {
|
|
return input[0] === "<" && input[input.length - 1] === ">" && input.length >= 3;
|
|
}
|
|
function winnow(elements, qualifier, not) {
|
|
if (typeof qualifier === "function") {
|
|
return jQuery3.grep(elements, function(elem, i2) {
|
|
return !!qualifier.call(elem, i2, elem) !== not;
|
|
});
|
|
}
|
|
if (qualifier.nodeType) {
|
|
return jQuery3.grep(elements, function(elem) {
|
|
return elem === qualifier !== not;
|
|
});
|
|
}
|
|
if (typeof qualifier !== "string") {
|
|
return jQuery3.grep(elements, function(elem) {
|
|
return indexOf.call(qualifier, elem) > -1 !== not;
|
|
});
|
|
}
|
|
return jQuery3.filter(qualifier, elements, not);
|
|
}
|
|
jQuery3.filter = function(expr, elems, not) {
|
|
var elem = elems[0];
|
|
if (not) {
|
|
expr = ":not(" + expr + ")";
|
|
}
|
|
if (elems.length === 1 && elem.nodeType === 1) {
|
|
return jQuery3.find.matchesSelector(elem, expr) ? [elem] : [];
|
|
}
|
|
return jQuery3.find.matches(expr, jQuery3.grep(elems, function(elem2) {
|
|
return elem2.nodeType === 1;
|
|
}));
|
|
};
|
|
jQuery3.fn.extend({
|
|
find: function(selector) {
|
|
var i2, ret, len = this.length, self2 = this;
|
|
if (typeof selector !== "string") {
|
|
return this.pushStack(jQuery3(selector).filter(function() {
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
if (jQuery3.contains(self2[i2], this)) {
|
|
return true;
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
ret = this.pushStack([]);
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
jQuery3.find(selector, self2[i2], ret);
|
|
}
|
|
return len > 1 ? jQuery3.uniqueSort(ret) : ret;
|
|
},
|
|
filter: function(selector) {
|
|
return this.pushStack(winnow(this, selector || [], false));
|
|
},
|
|
not: function(selector) {
|
|
return this.pushStack(winnow(this, selector || [], true));
|
|
},
|
|
is: function(selector) {
|
|
return !!winnow(
|
|
this,
|
|
// If this is a positional/relative selector, check membership in the returned set
|
|
// so $("p:first").is("p:last") won't return true for a doc with two "p".
|
|
typeof selector === "string" && rneedsContext.test(selector) ? jQuery3(selector) : selector || [],
|
|
false
|
|
).length;
|
|
}
|
|
});
|
|
var rootjQuery, rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery3.fn.init = function(selector, context) {
|
|
var match, elem;
|
|
if (!selector) {
|
|
return this;
|
|
}
|
|
if (selector.nodeType) {
|
|
this[0] = selector;
|
|
this.length = 1;
|
|
return this;
|
|
} else if (typeof selector === "function") {
|
|
return rootjQuery.ready !== void 0 ? rootjQuery.ready(selector) : (
|
|
// Execute immediately if ready is not present
|
|
selector(jQuery3)
|
|
);
|
|
} else {
|
|
match = selector + "";
|
|
if (isObviousHtml(match)) {
|
|
match = [null, selector, null];
|
|
} else if (typeof selector === "string") {
|
|
match = rquickExpr.exec(selector);
|
|
} else {
|
|
return jQuery3.makeArray(selector, this);
|
|
}
|
|
if (match && (match[1] || !context)) {
|
|
if (match[1]) {
|
|
context = context instanceof jQuery3 ? context[0] : context;
|
|
jQuery3.merge(this, jQuery3.parseHTML(
|
|
match[1],
|
|
context && context.nodeType ? context.ownerDocument || context : document$1,
|
|
true
|
|
));
|
|
if (rsingleTag.test(match[1]) && jQuery3.isPlainObject(context)) {
|
|
for (match in context) {
|
|
if (typeof this[match] === "function") {
|
|
this[match](context[match]);
|
|
} else {
|
|
this.attr(match, context[match]);
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
} else {
|
|
elem = document$1.getElementById(match[2]);
|
|
if (elem) {
|
|
this[0] = elem;
|
|
this.length = 1;
|
|
}
|
|
return this;
|
|
}
|
|
} else if (!context || context.jquery) {
|
|
return (context || rootjQuery).find(selector);
|
|
} else {
|
|
return this.constructor(context).find(selector);
|
|
}
|
|
}
|
|
};
|
|
init.prototype = jQuery3.fn;
|
|
rootjQuery = jQuery3(document$1);
|
|
var rparentsprev = /^(?:parents|prev(?:Until|All))/, guaranteedUnique = {
|
|
children: true,
|
|
contents: true,
|
|
next: true,
|
|
prev: true
|
|
};
|
|
jQuery3.fn.extend({
|
|
has: function(target) {
|
|
var targets = jQuery3(target, this), l = targets.length;
|
|
return this.filter(function() {
|
|
var i2 = 0;
|
|
for (; i2 < l; i2++) {
|
|
if (jQuery3.contains(this, targets[i2])) {
|
|
return true;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
closest: function(selectors, context) {
|
|
var cur, i2 = 0, l = this.length, matched = [], targets = typeof selectors !== "string" && jQuery3(selectors);
|
|
if (!rneedsContext.test(selectors)) {
|
|
for (; i2 < l; i2++) {
|
|
for (cur = this[i2]; cur && cur !== context; cur = cur.parentNode) {
|
|
if (cur.nodeType < 11 && (targets ? targets.index(cur) > -1 : (
|
|
// Don't pass non-elements to jQuery#find
|
|
cur.nodeType === 1 && jQuery3.find.matchesSelector(cur, selectors)
|
|
))) {
|
|
matched.push(cur);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this.pushStack(matched.length > 1 ? jQuery3.uniqueSort(matched) : matched);
|
|
},
|
|
// Determine the position of an element within the set
|
|
index: function(elem) {
|
|
if (!elem) {
|
|
return this[0] && this[0].parentNode ? this.first().prevAll().length : -1;
|
|
}
|
|
if (typeof elem === "string") {
|
|
return indexOf.call(jQuery3(elem), this[0]);
|
|
}
|
|
return indexOf.call(
|
|
this,
|
|
// If it receives a jQuery object, the first element is used
|
|
elem.jquery ? elem[0] : elem
|
|
);
|
|
},
|
|
add: function(selector, context) {
|
|
return this.pushStack(
|
|
jQuery3.uniqueSort(
|
|
jQuery3.merge(this.get(), jQuery3(selector, context))
|
|
)
|
|
);
|
|
},
|
|
addBack: function(selector) {
|
|
return this.add(
|
|
selector == null ? this.prevObject : this.prevObject.filter(selector)
|
|
);
|
|
}
|
|
});
|
|
function sibling(cur, dir2) {
|
|
while ((cur = cur[dir2]) && cur.nodeType !== 1) {
|
|
}
|
|
return cur;
|
|
}
|
|
jQuery3.each({
|
|
parent: function(elem) {
|
|
var parent2 = elem.parentNode;
|
|
return parent2 && parent2.nodeType !== 11 ? parent2 : null;
|
|
},
|
|
parents: function(elem) {
|
|
return dir(elem, "parentNode");
|
|
},
|
|
parentsUntil: function(elem, _i, until) {
|
|
return dir(elem, "parentNode", until);
|
|
},
|
|
next: function(elem) {
|
|
return sibling(elem, "nextSibling");
|
|
},
|
|
prev: function(elem) {
|
|
return sibling(elem, "previousSibling");
|
|
},
|
|
nextAll: function(elem) {
|
|
return dir(elem, "nextSibling");
|
|
},
|
|
prevAll: function(elem) {
|
|
return dir(elem, "previousSibling");
|
|
},
|
|
nextUntil: function(elem, _i, until) {
|
|
return dir(elem, "nextSibling", until);
|
|
},
|
|
prevUntil: function(elem, _i, until) {
|
|
return dir(elem, "previousSibling", until);
|
|
},
|
|
siblings: function(elem) {
|
|
return siblings((elem.parentNode || {}).firstChild, elem);
|
|
},
|
|
children: function(elem) {
|
|
return siblings(elem.firstChild);
|
|
},
|
|
contents: function(elem) {
|
|
if (elem.contentDocument != null && // Support: IE 11+
|
|
// <object> elements with no `data` attribute has an object
|
|
// `contentDocument` with a `null` prototype.
|
|
getProto(elem.contentDocument)) {
|
|
return elem.contentDocument;
|
|
}
|
|
if (nodeName(elem, "template")) {
|
|
elem = elem.content || elem;
|
|
}
|
|
return jQuery3.merge([], elem.childNodes);
|
|
}
|
|
}, function(name, fn) {
|
|
jQuery3.fn[name] = function(until, selector) {
|
|
var matched = jQuery3.map(this, fn, until);
|
|
if (name.slice(-5) !== "Until") {
|
|
selector = until;
|
|
}
|
|
if (selector && typeof selector === "string") {
|
|
matched = jQuery3.filter(selector, matched);
|
|
}
|
|
if (this.length > 1) {
|
|
if (!guaranteedUnique[name]) {
|
|
jQuery3.uniqueSort(matched);
|
|
}
|
|
if (rparentsprev.test(name)) {
|
|
matched.reverse();
|
|
}
|
|
}
|
|
return this.pushStack(matched);
|
|
};
|
|
});
|
|
function createOptions(options) {
|
|
var object = {};
|
|
jQuery3.each(options.match(rnothtmlwhite) || [], function(_, flag) {
|
|
object[flag] = true;
|
|
});
|
|
return object;
|
|
}
|
|
jQuery3.Callbacks = function(options) {
|
|
options = typeof options === "string" ? createOptions(options) : jQuery3.extend({}, options);
|
|
var firing, memory, fired, locked, list = [], queue = [], firingIndex = -1, fire = function() {
|
|
locked = locked || options.once;
|
|
fired = firing = true;
|
|
for (; queue.length; firingIndex = -1) {
|
|
memory = queue.shift();
|
|
while (++firingIndex < list.length) {
|
|
if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) {
|
|
firingIndex = list.length;
|
|
memory = false;
|
|
}
|
|
}
|
|
}
|
|
if (!options.memory) {
|
|
memory = false;
|
|
}
|
|
firing = false;
|
|
if (locked) {
|
|
if (memory) {
|
|
list = [];
|
|
} else {
|
|
list = "";
|
|
}
|
|
}
|
|
}, self2 = {
|
|
// Add a callback or a collection of callbacks to the list
|
|
add: function() {
|
|
if (list) {
|
|
if (memory && !firing) {
|
|
firingIndex = list.length - 1;
|
|
queue.push(memory);
|
|
}
|
|
(function add2(args) {
|
|
jQuery3.each(args, function(_, arg) {
|
|
if (typeof arg === "function") {
|
|
if (!options.unique || !self2.has(arg)) {
|
|
list.push(arg);
|
|
}
|
|
} else if (arg && arg.length && toType(arg) !== "string") {
|
|
add2(arg);
|
|
}
|
|
});
|
|
})(arguments);
|
|
if (memory && !firing) {
|
|
fire();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
// Remove a callback from the list
|
|
remove: function() {
|
|
jQuery3.each(arguments, function(_, arg) {
|
|
var index;
|
|
while ((index = jQuery3.inArray(arg, list, index)) > -1) {
|
|
list.splice(index, 1);
|
|
if (index <= firingIndex) {
|
|
firingIndex--;
|
|
}
|
|
}
|
|
});
|
|
return this;
|
|
},
|
|
// Check if a given callback is in the list.
|
|
// If no argument is given, return whether or not list has callbacks attached.
|
|
has: function(fn) {
|
|
return fn ? jQuery3.inArray(fn, list) > -1 : list.length > 0;
|
|
},
|
|
// Remove all callbacks from the list
|
|
empty: function() {
|
|
if (list) {
|
|
list = [];
|
|
}
|
|
return this;
|
|
},
|
|
// Disable .fire and .add
|
|
// Abort any current/pending executions
|
|
// Clear all callbacks and values
|
|
disable: function() {
|
|
locked = queue = [];
|
|
list = memory = "";
|
|
return this;
|
|
},
|
|
disabled: function() {
|
|
return !list;
|
|
},
|
|
// Disable .fire
|
|
// Also disable .add unless we have memory (since it would have no effect)
|
|
// Abort any pending executions
|
|
lock: function() {
|
|
locked = queue = [];
|
|
if (!memory && !firing) {
|
|
list = memory = "";
|
|
}
|
|
return this;
|
|
},
|
|
locked: function() {
|
|
return !!locked;
|
|
},
|
|
// Call all callbacks with the given context and arguments
|
|
fireWith: function(context, args) {
|
|
if (!locked) {
|
|
args = args || [];
|
|
args = [context, args.slice ? args.slice() : args];
|
|
queue.push(args);
|
|
if (!firing) {
|
|
fire();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
// Call all the callbacks with the given arguments
|
|
fire: function() {
|
|
self2.fireWith(this, arguments);
|
|
return this;
|
|
},
|
|
// To know if the callbacks have already been called at least once
|
|
fired: function() {
|
|
return !!fired;
|
|
}
|
|
};
|
|
return self2;
|
|
};
|
|
function Identity(v) {
|
|
return v;
|
|
}
|
|
function Thrower(ex) {
|
|
throw ex;
|
|
}
|
|
function adoptValue(value, resolve, reject, noValue) {
|
|
var method;
|
|
try {
|
|
if (value && typeof (method = value.promise) === "function") {
|
|
method.call(value).done(resolve).fail(reject);
|
|
} else if (value && typeof (method = value.then) === "function") {
|
|
method.call(value, resolve, reject);
|
|
} else {
|
|
resolve.apply(void 0, [value].slice(noValue));
|
|
}
|
|
} catch (value2) {
|
|
reject(value2);
|
|
}
|
|
}
|
|
jQuery3.extend({
|
|
Deferred: function(func) {
|
|
var tuples = [
|
|
// action, add listener, callbacks,
|
|
// ... .then handlers, argument index, [final state]
|
|
[
|
|
"notify",
|
|
"progress",
|
|
jQuery3.Callbacks("memory"),
|
|
jQuery3.Callbacks("memory"),
|
|
2
|
|
],
|
|
[
|
|
"resolve",
|
|
"done",
|
|
jQuery3.Callbacks("once memory"),
|
|
jQuery3.Callbacks("once memory"),
|
|
0,
|
|
"resolved"
|
|
],
|
|
[
|
|
"reject",
|
|
"fail",
|
|
jQuery3.Callbacks("once memory"),
|
|
jQuery3.Callbacks("once memory"),
|
|
1,
|
|
"rejected"
|
|
]
|
|
], state = "pending", promise = {
|
|
state: function() {
|
|
return state;
|
|
},
|
|
always: function() {
|
|
deferred.done(arguments).fail(arguments);
|
|
return this;
|
|
},
|
|
catch: function(fn) {
|
|
return promise.then(null, fn);
|
|
},
|
|
// Keep pipe for back-compat
|
|
pipe: function() {
|
|
var fns = arguments;
|
|
return jQuery3.Deferred(function(newDefer) {
|
|
jQuery3.each(tuples, function(_i, tuple) {
|
|
var fn = typeof fns[tuple[4]] === "function" && fns[tuple[4]];
|
|
deferred[tuple[1]](function() {
|
|
var returned = fn && fn.apply(this, arguments);
|
|
if (returned && typeof returned.promise === "function") {
|
|
returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject);
|
|
} else {
|
|
newDefer[tuple[0] + "With"](
|
|
this,
|
|
fn ? [returned] : arguments
|
|
);
|
|
}
|
|
});
|
|
});
|
|
fns = null;
|
|
}).promise();
|
|
},
|
|
then: function(onFulfilled, onRejected, onProgress) {
|
|
var maxDepth = 0;
|
|
function resolve(depth, deferred2, handler, special) {
|
|
return function() {
|
|
var that = this, args = arguments, mightThrow = function() {
|
|
var returned, then;
|
|
if (depth < maxDepth) {
|
|
return;
|
|
}
|
|
returned = handler.apply(that, args);
|
|
if (returned === deferred2.promise()) {
|
|
throw new TypeError("Thenable self-resolution");
|
|
}
|
|
then = returned && // Support: Promises/A+ section 2.3.4
|
|
// https://promisesaplus.com/#point-64
|
|
// Only check objects and functions for thenability
|
|
(typeof returned === "object" || typeof returned === "function") && returned.then;
|
|
if (typeof then === "function") {
|
|
if (special) {
|
|
then.call(
|
|
returned,
|
|
resolve(maxDepth, deferred2, Identity, special),
|
|
resolve(maxDepth, deferred2, Thrower, special)
|
|
);
|
|
} else {
|
|
maxDepth++;
|
|
then.call(
|
|
returned,
|
|
resolve(maxDepth, deferred2, Identity, special),
|
|
resolve(maxDepth, deferred2, Thrower, special),
|
|
resolve(
|
|
maxDepth,
|
|
deferred2,
|
|
Identity,
|
|
deferred2.notifyWith
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
if (handler !== Identity) {
|
|
that = void 0;
|
|
args = [returned];
|
|
}
|
|
(special || deferred2.resolveWith)(that, args);
|
|
}
|
|
}, process2 = special ? mightThrow : function() {
|
|
try {
|
|
mightThrow();
|
|
} catch (e) {
|
|
if (jQuery3.Deferred.exceptionHook) {
|
|
jQuery3.Deferred.exceptionHook(
|
|
e,
|
|
process2.error
|
|
);
|
|
}
|
|
if (depth + 1 >= maxDepth) {
|
|
if (handler !== Thrower) {
|
|
that = void 0;
|
|
args = [e];
|
|
}
|
|
deferred2.rejectWith(that, args);
|
|
}
|
|
}
|
|
};
|
|
if (depth) {
|
|
process2();
|
|
} else {
|
|
if (jQuery3.Deferred.getErrorHook) {
|
|
process2.error = jQuery3.Deferred.getErrorHook();
|
|
}
|
|
window2.setTimeout(process2);
|
|
}
|
|
};
|
|
}
|
|
return jQuery3.Deferred(function(newDefer) {
|
|
tuples[0][3].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
typeof onProgress === "function" ? onProgress : Identity,
|
|
newDefer.notifyWith
|
|
)
|
|
);
|
|
tuples[1][3].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
typeof onFulfilled === "function" ? onFulfilled : Identity
|
|
)
|
|
);
|
|
tuples[2][3].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
typeof onRejected === "function" ? onRejected : Thrower
|
|
)
|
|
);
|
|
}).promise();
|
|
},
|
|
// Get a promise for this deferred
|
|
// If obj is provided, the promise aspect is added to the object
|
|
promise: function(obj) {
|
|
return obj != null ? jQuery3.extend(obj, promise) : promise;
|
|
}
|
|
}, deferred = {};
|
|
jQuery3.each(tuples, function(i2, tuple) {
|
|
var list = tuple[2], stateString = tuple[5];
|
|
promise[tuple[1]] = list.add;
|
|
if (stateString) {
|
|
list.add(
|
|
function() {
|
|
state = stateString;
|
|
},
|
|
// rejected_callbacks.disable
|
|
// fulfilled_callbacks.disable
|
|
tuples[3 - i2][2].disable,
|
|
// rejected_handlers.disable
|
|
// fulfilled_handlers.disable
|
|
tuples[3 - i2][3].disable,
|
|
// progress_callbacks.lock
|
|
tuples[0][2].lock,
|
|
// progress_handlers.lock
|
|
tuples[0][3].lock
|
|
);
|
|
}
|
|
list.add(tuple[3].fire);
|
|
deferred[tuple[0]] = function() {
|
|
deferred[tuple[0] + "With"](this === deferred ? void 0 : this, arguments);
|
|
return this;
|
|
};
|
|
deferred[tuple[0] + "With"] = list.fireWith;
|
|
});
|
|
promise.promise(deferred);
|
|
if (func) {
|
|
func.call(deferred, deferred);
|
|
}
|
|
return deferred;
|
|
},
|
|
// Deferred helper
|
|
when: function(singleValue) {
|
|
var remaining = arguments.length, i2 = remaining, resolveContexts = Array(i2), resolveValues = slice.call(arguments), primary = jQuery3.Deferred(), updateFunc = function(i3) {
|
|
return function(value) {
|
|
resolveContexts[i3] = this;
|
|
resolveValues[i3] = arguments.length > 1 ? slice.call(arguments) : value;
|
|
if (!--remaining) {
|
|
primary.resolveWith(resolveContexts, resolveValues);
|
|
}
|
|
};
|
|
};
|
|
if (remaining <= 1) {
|
|
adoptValue(
|
|
singleValue,
|
|
primary.done(updateFunc(i2)).resolve,
|
|
primary.reject,
|
|
!remaining
|
|
);
|
|
if (primary.state() === "pending" || typeof (resolveValues[i2] && resolveValues[i2].then) === "function") {
|
|
return primary.then();
|
|
}
|
|
}
|
|
while (i2--) {
|
|
adoptValue(resolveValues[i2], updateFunc(i2), primary.reject);
|
|
}
|
|
return primary.promise();
|
|
}
|
|
});
|
|
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
|
|
jQuery3.Deferred.exceptionHook = function(error2, asyncError) {
|
|
if (error2 && rerrorNames.test(error2.name)) {
|
|
window2.console.warn(
|
|
"jQuery.Deferred exception",
|
|
error2,
|
|
asyncError
|
|
);
|
|
}
|
|
};
|
|
jQuery3.readyException = function(error2) {
|
|
window2.setTimeout(function() {
|
|
throw error2;
|
|
});
|
|
};
|
|
var readyList = jQuery3.Deferred();
|
|
jQuery3.fn.ready = function(fn) {
|
|
readyList.then(fn).catch(function(error2) {
|
|
jQuery3.readyException(error2);
|
|
});
|
|
return this;
|
|
};
|
|
jQuery3.extend({
|
|
// Is the DOM ready to be used? Set to true once it occurs.
|
|
isReady: false,
|
|
// A counter to track how many items to wait for before
|
|
// the ready event fires. See trac-6781
|
|
readyWait: 1,
|
|
// Handle when the DOM is ready
|
|
ready: function(wait) {
|
|
if (wait === true ? --jQuery3.readyWait : jQuery3.isReady) {
|
|
return;
|
|
}
|
|
jQuery3.isReady = true;
|
|
if (wait !== true && --jQuery3.readyWait > 0) {
|
|
return;
|
|
}
|
|
readyList.resolveWith(document$1, [jQuery3]);
|
|
}
|
|
});
|
|
jQuery3.ready.then = readyList.then;
|
|
function completed() {
|
|
document$1.removeEventListener("DOMContentLoaded", completed);
|
|
window2.removeEventListener("load", completed);
|
|
jQuery3.ready();
|
|
}
|
|
if (document$1.readyState !== "loading") {
|
|
window2.setTimeout(jQuery3.ready);
|
|
} else {
|
|
document$1.addEventListener("DOMContentLoaded", completed);
|
|
window2.addEventListener("load", completed);
|
|
}
|
|
var rdashAlpha = /-([a-z])/g;
|
|
function fcamelCase(_all, letter) {
|
|
return letter.toUpperCase();
|
|
}
|
|
function camelCase(string) {
|
|
return string.replace(rdashAlpha, fcamelCase);
|
|
}
|
|
function acceptData(owner) {
|
|
return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType;
|
|
}
|
|
function Data() {
|
|
this.expando = jQuery3.expando + Data.uid++;
|
|
}
|
|
Data.uid = 1;
|
|
Data.prototype = {
|
|
cache: function(owner) {
|
|
var value = owner[this.expando];
|
|
if (!value) {
|
|
value = /* @__PURE__ */ Object.create(null);
|
|
if (acceptData(owner)) {
|
|
if (owner.nodeType) {
|
|
owner[this.expando] = value;
|
|
} else {
|
|
Object.defineProperty(owner, this.expando, {
|
|
value,
|
|
configurable: true
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
set: function(owner, data, value) {
|
|
var prop, cache = this.cache(owner);
|
|
if (typeof data === "string") {
|
|
cache[camelCase(data)] = value;
|
|
} else {
|
|
for (prop in data) {
|
|
cache[camelCase(prop)] = data[prop];
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
get: function(owner, key) {
|
|
return key === void 0 ? this.cache(owner) : (
|
|
// Always use camelCase key (gh-2257)
|
|
owner[this.expando] && owner[this.expando][camelCase(key)]
|
|
);
|
|
},
|
|
access: function(owner, key, value) {
|
|
if (key === void 0 || key && typeof key === "string" && value === void 0) {
|
|
return this.get(owner, key);
|
|
}
|
|
this.set(owner, key, value);
|
|
return value !== void 0 ? value : key;
|
|
},
|
|
remove: function(owner, key) {
|
|
var i2, cache = owner[this.expando];
|
|
if (cache === void 0) {
|
|
return;
|
|
}
|
|
if (key !== void 0) {
|
|
if (Array.isArray(key)) {
|
|
key = key.map(camelCase);
|
|
} else {
|
|
key = camelCase(key);
|
|
key = key in cache ? [key] : key.match(rnothtmlwhite) || [];
|
|
}
|
|
i2 = key.length;
|
|
while (i2--) {
|
|
delete cache[key[i2]];
|
|
}
|
|
}
|
|
if (key === void 0 || jQuery3.isEmptyObject(cache)) {
|
|
if (owner.nodeType) {
|
|
owner[this.expando] = void 0;
|
|
} else {
|
|
delete owner[this.expando];
|
|
}
|
|
}
|
|
},
|
|
hasData: function(owner) {
|
|
var cache = owner[this.expando];
|
|
return cache !== void 0 && !jQuery3.isEmptyObject(cache);
|
|
}
|
|
};
|
|
var dataPriv = new Data();
|
|
var dataUser = new Data();
|
|
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g;
|
|
function getData(data) {
|
|
if (data === "true") {
|
|
return true;
|
|
}
|
|
if (data === "false") {
|
|
return false;
|
|
}
|
|
if (data === "null") {
|
|
return null;
|
|
}
|
|
if (data === +data + "") {
|
|
return +data;
|
|
}
|
|
if (rbrace.test(data)) {
|
|
return JSON.parse(data);
|
|
}
|
|
return data;
|
|
}
|
|
function dataAttr(elem, key, data) {
|
|
var name;
|
|
if (data === void 0 && elem.nodeType === 1) {
|
|
name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase();
|
|
data = elem.getAttribute(name);
|
|
if (typeof data === "string") {
|
|
try {
|
|
data = getData(data);
|
|
} catch (e) {
|
|
}
|
|
dataUser.set(elem, key, data);
|
|
} else {
|
|
data = void 0;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
jQuery3.extend({
|
|
hasData: function(elem) {
|
|
return dataUser.hasData(elem) || dataPriv.hasData(elem);
|
|
},
|
|
data: function(elem, name, data) {
|
|
return dataUser.access(elem, name, data);
|
|
},
|
|
removeData: function(elem, name) {
|
|
dataUser.remove(elem, name);
|
|
},
|
|
// TODO: Now that all calls to _data and _removeData have been replaced
|
|
// with direct calls to dataPriv methods, these can be deprecated.
|
|
_data: function(elem, name, data) {
|
|
return dataPriv.access(elem, name, data);
|
|
},
|
|
_removeData: function(elem, name) {
|
|
dataPriv.remove(elem, name);
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
data: function(key, value) {
|
|
var i2, name, data, elem = this[0], attrs = elem && elem.attributes;
|
|
if (key === void 0) {
|
|
if (this.length) {
|
|
data = dataUser.get(elem);
|
|
if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) {
|
|
i2 = attrs.length;
|
|
while (i2--) {
|
|
if (attrs[i2]) {
|
|
name = attrs[i2].name;
|
|
if (name.indexOf("data-") === 0) {
|
|
name = camelCase(name.slice(5));
|
|
dataAttr(elem, name, data[name]);
|
|
}
|
|
}
|
|
}
|
|
dataPriv.set(elem, "hasDataAttrs", true);
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
if (typeof key === "object") {
|
|
return this.each(function() {
|
|
dataUser.set(this, key);
|
|
});
|
|
}
|
|
return access(this, function(value2) {
|
|
var data2;
|
|
if (elem && value2 === void 0) {
|
|
data2 = dataUser.get(elem, key);
|
|
if (data2 !== void 0) {
|
|
return data2;
|
|
}
|
|
data2 = dataAttr(elem, key);
|
|
if (data2 !== void 0) {
|
|
return data2;
|
|
}
|
|
return;
|
|
}
|
|
this.each(function() {
|
|
dataUser.set(this, key, value2);
|
|
});
|
|
}, null, value, arguments.length > 1, null, true);
|
|
},
|
|
removeData: function(key) {
|
|
return this.each(function() {
|
|
dataUser.remove(this, key);
|
|
});
|
|
}
|
|
});
|
|
jQuery3.extend({
|
|
queue: function(elem, type, data) {
|
|
var queue;
|
|
if (elem) {
|
|
type = (type || "fx") + "queue";
|
|
queue = dataPriv.get(elem, type);
|
|
if (data) {
|
|
if (!queue || Array.isArray(data)) {
|
|
queue = dataPriv.set(elem, type, jQuery3.makeArray(data));
|
|
} else {
|
|
queue.push(data);
|
|
}
|
|
}
|
|
return queue || [];
|
|
}
|
|
},
|
|
dequeue: function(elem, type) {
|
|
type = type || "fx";
|
|
var queue = jQuery3.queue(elem, type), startLength = queue.length, fn = queue.shift(), hooks = jQuery3._queueHooks(elem, type), next = function() {
|
|
jQuery3.dequeue(elem, type);
|
|
};
|
|
if (fn === "inprogress") {
|
|
fn = queue.shift();
|
|
startLength--;
|
|
}
|
|
if (fn) {
|
|
if (type === "fx") {
|
|
queue.unshift("inprogress");
|
|
}
|
|
delete hooks.stop;
|
|
fn.call(elem, next, hooks);
|
|
}
|
|
if (!startLength && hooks) {
|
|
hooks.empty.fire();
|
|
}
|
|
},
|
|
// Not public - generate a queueHooks object, or return the current one
|
|
_queueHooks: function(elem, type) {
|
|
var key = type + "queueHooks";
|
|
return dataPriv.get(elem, key) || dataPriv.set(elem, key, {
|
|
empty: jQuery3.Callbacks("once memory").add(function() {
|
|
dataPriv.remove(elem, [type + "queue", key]);
|
|
})
|
|
});
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
queue: function(type, data) {
|
|
var setter = 2;
|
|
if (typeof type !== "string") {
|
|
data = type;
|
|
type = "fx";
|
|
setter--;
|
|
}
|
|
if (arguments.length < setter) {
|
|
return jQuery3.queue(this[0], type);
|
|
}
|
|
return data === void 0 ? this : this.each(function() {
|
|
var queue = jQuery3.queue(this, type, data);
|
|
jQuery3._queueHooks(this, type);
|
|
if (type === "fx" && queue[0] !== "inprogress") {
|
|
jQuery3.dequeue(this, type);
|
|
}
|
|
});
|
|
},
|
|
dequeue: function(type) {
|
|
return this.each(function() {
|
|
jQuery3.dequeue(this, type);
|
|
});
|
|
},
|
|
clearQueue: function(type) {
|
|
return this.queue(type || "fx", []);
|
|
},
|
|
// Get a promise resolved when queues of a certain type
|
|
// are emptied (fx is the type by default)
|
|
promise: function(type, obj) {
|
|
var tmp, count = 1, defer = jQuery3.Deferred(), elements = this, i2 = this.length, resolve = function() {
|
|
if (!--count) {
|
|
defer.resolveWith(elements, [elements]);
|
|
}
|
|
};
|
|
if (typeof type !== "string") {
|
|
obj = type;
|
|
type = void 0;
|
|
}
|
|
type = type || "fx";
|
|
while (i2--) {
|
|
tmp = dataPriv.get(elements[i2], type + "queueHooks");
|
|
if (tmp && tmp.empty) {
|
|
count++;
|
|
tmp.empty.add(resolve);
|
|
}
|
|
}
|
|
resolve();
|
|
return defer.promise(obj);
|
|
}
|
|
});
|
|
var pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
|
|
var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i");
|
|
var cssExpand = ["Top", "Right", "Bottom", "Left"];
|
|
function isHiddenWithinTree(elem, el2) {
|
|
elem = el2 || elem;
|
|
return elem.style.display === "none" || elem.style.display === "" && jQuery3.css(elem, "display") === "none";
|
|
}
|
|
var ralphaStart = /^[a-z]/, rautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;
|
|
function isAutoPx(prop) {
|
|
return ralphaStart.test(prop) && rautoPx.test(prop[0].toUpperCase() + prop.slice(1));
|
|
}
|
|
function adjustCSS(elem, prop, valueParts, tween) {
|
|
var adjusted, scale, maxIterations = 20, currentValue = tween ? function() {
|
|
return tween.cur();
|
|
} : function() {
|
|
return jQuery3.css(elem, prop, "");
|
|
}, initial = currentValue(), unit = valueParts && valueParts[3] || (isAutoPx(prop) ? "px" : ""), initialInUnit = elem.nodeType && (!isAutoPx(prop) || unit !== "px" && +initial) && rcssNum.exec(jQuery3.css(elem, prop));
|
|
if (initialInUnit && initialInUnit[3] !== unit) {
|
|
initial = initial / 2;
|
|
unit = unit || initialInUnit[3];
|
|
initialInUnit = +initial || 1;
|
|
while (maxIterations--) {
|
|
jQuery3.style(elem, prop, initialInUnit + unit);
|
|
if ((1 - scale) * (1 - (scale = currentValue() / initial || 0.5)) <= 0) {
|
|
maxIterations = 0;
|
|
}
|
|
initialInUnit = initialInUnit / scale;
|
|
}
|
|
initialInUnit = initialInUnit * 2;
|
|
jQuery3.style(elem, prop, initialInUnit + unit);
|
|
valueParts = valueParts || [];
|
|
}
|
|
if (valueParts) {
|
|
initialInUnit = +initialInUnit || +initial || 0;
|
|
adjusted = valueParts[1] ? initialInUnit + (valueParts[1] + 1) * valueParts[2] : +valueParts[2];
|
|
if (tween) {
|
|
tween.unit = unit;
|
|
tween.start = initialInUnit;
|
|
tween.end = adjusted;
|
|
}
|
|
}
|
|
return adjusted;
|
|
}
|
|
var rmsPrefix = /^-ms-/;
|
|
function cssCamelCase(string) {
|
|
return camelCase(string.replace(rmsPrefix, "ms-"));
|
|
}
|
|
var defaultDisplayMap = {};
|
|
function getDefaultDisplay(elem) {
|
|
var temp, doc = elem.ownerDocument, nodeName2 = elem.nodeName, display = defaultDisplayMap[nodeName2];
|
|
if (display) {
|
|
return display;
|
|
}
|
|
temp = doc.body.appendChild(doc.createElement(nodeName2));
|
|
display = jQuery3.css(temp, "display");
|
|
temp.parentNode.removeChild(temp);
|
|
if (display === "none") {
|
|
display = "block";
|
|
}
|
|
defaultDisplayMap[nodeName2] = display;
|
|
return display;
|
|
}
|
|
function showHide(elements, show) {
|
|
var display, elem, values = [], index = 0, length = elements.length;
|
|
for (; index < length; index++) {
|
|
elem = elements[index];
|
|
if (!elem.style) {
|
|
continue;
|
|
}
|
|
display = elem.style.display;
|
|
if (show) {
|
|
if (display === "none") {
|
|
values[index] = dataPriv.get(elem, "display") || null;
|
|
if (!values[index]) {
|
|
elem.style.display = "";
|
|
}
|
|
}
|
|
if (elem.style.display === "" && isHiddenWithinTree(elem)) {
|
|
values[index] = getDefaultDisplay(elem);
|
|
}
|
|
} else {
|
|
if (display !== "none") {
|
|
values[index] = "none";
|
|
dataPriv.set(elem, "display", display);
|
|
}
|
|
}
|
|
}
|
|
for (index = 0; index < length; index++) {
|
|
if (values[index] != null) {
|
|
elements[index].style.display = values[index];
|
|
}
|
|
}
|
|
return elements;
|
|
}
|
|
jQuery3.fn.extend({
|
|
show: function() {
|
|
return showHide(this, true);
|
|
},
|
|
hide: function() {
|
|
return showHide(this);
|
|
},
|
|
toggle: function(state) {
|
|
if (typeof state === "boolean") {
|
|
return state ? this.show() : this.hide();
|
|
}
|
|
return this.each(function() {
|
|
if (isHiddenWithinTree(this)) {
|
|
jQuery3(this).show();
|
|
} else {
|
|
jQuery3(this).hide();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
var isAttached = function(elem) {
|
|
return jQuery3.contains(elem.ownerDocument, elem) || elem.getRootNode(composed) === elem.ownerDocument;
|
|
}, composed = { composed: true };
|
|
if (!documentElement$1.getRootNode) {
|
|
isAttached = function(elem) {
|
|
return jQuery3.contains(elem.ownerDocument, elem);
|
|
};
|
|
}
|
|
var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i;
|
|
var wrapMap = {
|
|
// Table parts need to be wrapped with `<table>` or they're
|
|
// stripped to their contents when put in a div.
|
|
// XHTML parsers do not magically insert elements in the
|
|
// same way that tag soup parsers do, so we cannot shorten
|
|
// this by omitting <tbody> or other required elements.
|
|
thead: ["table"],
|
|
col: ["colgroup", "table"],
|
|
tr: ["tbody", "table"],
|
|
td: ["tr", "tbody", "table"]
|
|
};
|
|
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
|
wrapMap.th = wrapMap.td;
|
|
function getAll(context, tag) {
|
|
var ret;
|
|
if (typeof context.getElementsByTagName !== "undefined") {
|
|
ret = arr.slice.call(context.getElementsByTagName(tag || "*"));
|
|
} else if (typeof context.querySelectorAll !== "undefined") {
|
|
ret = context.querySelectorAll(tag || "*");
|
|
} else {
|
|
ret = [];
|
|
}
|
|
if (tag === void 0 || tag && nodeName(context, tag)) {
|
|
return jQuery3.merge([context], ret);
|
|
}
|
|
return ret;
|
|
}
|
|
var rscriptType = /^$|^module$|\/(?:java|ecma)script/i;
|
|
function setGlobalEval(elems, refElements) {
|
|
var i2 = 0, l = elems.length;
|
|
for (; i2 < l; i2++) {
|
|
dataPriv.set(
|
|
elems[i2],
|
|
"globalEval",
|
|
!refElements || dataPriv.get(refElements[i2], "globalEval")
|
|
);
|
|
}
|
|
}
|
|
var rhtml = /<|&#?\w+;/;
|
|
function buildFragment(elems, context, scripts, selection, ignored) {
|
|
var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i2 = 0, l = elems.length;
|
|
for (; i2 < l; i2++) {
|
|
elem = elems[i2];
|
|
if (elem || elem === 0) {
|
|
if (toType(elem) === "object" && (elem.nodeType || isArrayLike(elem))) {
|
|
jQuery3.merge(nodes, elem.nodeType ? [elem] : elem);
|
|
} else if (!rhtml.test(elem)) {
|
|
nodes.push(context.createTextNode(elem));
|
|
} else {
|
|
tmp = tmp || fragment.appendChild(context.createElement("div"));
|
|
tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
|
|
wrap = wrapMap[tag] || arr;
|
|
j = wrap.length;
|
|
while (--j > -1) {
|
|
tmp = tmp.appendChild(context.createElement(wrap[j]));
|
|
}
|
|
tmp.innerHTML = jQuery3.htmlPrefilter(elem);
|
|
jQuery3.merge(nodes, tmp.childNodes);
|
|
tmp = fragment.firstChild;
|
|
tmp.textContent = "";
|
|
}
|
|
}
|
|
}
|
|
fragment.textContent = "";
|
|
i2 = 0;
|
|
while (elem = nodes[i2++]) {
|
|
if (selection && jQuery3.inArray(elem, selection) > -1) {
|
|
if (ignored) {
|
|
ignored.push(elem);
|
|
}
|
|
continue;
|
|
}
|
|
attached = isAttached(elem);
|
|
tmp = getAll(fragment.appendChild(elem), "script");
|
|
if (attached) {
|
|
setGlobalEval(tmp);
|
|
}
|
|
if (scripts) {
|
|
j = 0;
|
|
while (elem = tmp[j++]) {
|
|
if (rscriptType.test(elem.type || "")) {
|
|
scripts.push(elem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return fragment;
|
|
}
|
|
function disableScript(elem) {
|
|
elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
|
|
return elem;
|
|
}
|
|
function restoreScript(elem) {
|
|
if ((elem.type || "").slice(0, 5) === "true/") {
|
|
elem.type = elem.type.slice(5);
|
|
} else {
|
|
elem.removeAttribute("type");
|
|
}
|
|
return elem;
|
|
}
|
|
function domManip(collection, args, callback, ignored) {
|
|
args = flat(args);
|
|
var fragment, first, scripts, hasScripts, node, doc, i2 = 0, l = collection.length, iNoClone = l - 1, value = args[0], valueIsFunction = typeof value === "function";
|
|
if (valueIsFunction) {
|
|
return collection.each(function(index) {
|
|
var self2 = collection.eq(index);
|
|
args[0] = value.call(this, index, self2.html());
|
|
domManip(self2, args, callback, ignored);
|
|
});
|
|
}
|
|
if (l) {
|
|
fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
|
|
first = fragment.firstChild;
|
|
if (fragment.childNodes.length === 1) {
|
|
fragment = first;
|
|
}
|
|
if (first || ignored) {
|
|
scripts = jQuery3.map(getAll(fragment, "script"), disableScript);
|
|
hasScripts = scripts.length;
|
|
for (; i2 < l; i2++) {
|
|
node = fragment;
|
|
if (i2 !== iNoClone) {
|
|
node = jQuery3.clone(node, true, true);
|
|
if (hasScripts) {
|
|
jQuery3.merge(scripts, getAll(node, "script"));
|
|
}
|
|
}
|
|
callback.call(collection[i2], node, i2);
|
|
}
|
|
if (hasScripts) {
|
|
doc = scripts[scripts.length - 1].ownerDocument;
|
|
jQuery3.map(scripts, restoreScript);
|
|
for (i2 = 0; i2 < hasScripts; i2++) {
|
|
node = scripts[i2];
|
|
if (rscriptType.test(node.type || "") && !dataPriv.get(node, "globalEval") && jQuery3.contains(doc, node)) {
|
|
if (node.src && (node.type || "").toLowerCase() !== "module") {
|
|
if (jQuery3._evalUrl && !node.noModule) {
|
|
jQuery3._evalUrl(node.src, {
|
|
nonce: node.nonce,
|
|
crossOrigin: node.crossOrigin
|
|
}, doc);
|
|
}
|
|
} else {
|
|
DOMEval(node.textContent, node, doc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return collection;
|
|
}
|
|
var rcheckableType = /^(?:checkbox|radio)$/i;
|
|
var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
|
|
function returnTrue() {
|
|
return true;
|
|
}
|
|
function returnFalse() {
|
|
return false;
|
|
}
|
|
function on(elem, types, selector, data, fn, one) {
|
|
var origFn, type;
|
|
if (typeof types === "object") {
|
|
if (typeof selector !== "string") {
|
|
data = data || selector;
|
|
selector = void 0;
|
|
}
|
|
for (type in types) {
|
|
on(elem, type, selector, data, types[type], one);
|
|
}
|
|
return elem;
|
|
}
|
|
if (data == null && fn == null) {
|
|
fn = selector;
|
|
data = selector = void 0;
|
|
} else if (fn == null) {
|
|
if (typeof selector === "string") {
|
|
fn = data;
|
|
data = void 0;
|
|
} else {
|
|
fn = data;
|
|
data = selector;
|
|
selector = void 0;
|
|
}
|
|
}
|
|
if (fn === false) {
|
|
fn = returnFalse;
|
|
} else if (!fn) {
|
|
return elem;
|
|
}
|
|
if (one === 1) {
|
|
origFn = fn;
|
|
fn = function(event2) {
|
|
jQuery3().off(event2);
|
|
return origFn.apply(this, arguments);
|
|
};
|
|
fn.guid = origFn.guid || (origFn.guid = jQuery3.guid++);
|
|
}
|
|
return elem.each(function() {
|
|
jQuery3.event.add(this, types, fn, data, selector);
|
|
});
|
|
}
|
|
jQuery3.event = {
|
|
add: function(elem, types, handler, data, selector) {
|
|
var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.get(elem);
|
|
if (!acceptData(elem)) {
|
|
return;
|
|
}
|
|
if (handler.handler) {
|
|
handleObjIn = handler;
|
|
handler = handleObjIn.handler;
|
|
selector = handleObjIn.selector;
|
|
}
|
|
if (selector) {
|
|
jQuery3.find.matchesSelector(documentElement$1, selector);
|
|
}
|
|
if (!handler.guid) {
|
|
handler.guid = jQuery3.guid++;
|
|
}
|
|
if (!(events = elemData.events)) {
|
|
events = elemData.events = /* @__PURE__ */ Object.create(null);
|
|
}
|
|
if (!(eventHandle = elemData.handle)) {
|
|
eventHandle = elemData.handle = function(e) {
|
|
return typeof jQuery3 !== "undefined" && jQuery3.event.triggered !== e.type ? jQuery3.event.dispatch.apply(elem, arguments) : void 0;
|
|
};
|
|
}
|
|
types = (types || "").match(rnothtmlwhite) || [""];
|
|
t = types.length;
|
|
while (t--) {
|
|
tmp = rtypenamespace.exec(types[t]) || [];
|
|
type = origType = tmp[1];
|
|
namespaces = (tmp[2] || "").split(".").sort();
|
|
if (!type) {
|
|
continue;
|
|
}
|
|
special = jQuery3.event.special[type] || {};
|
|
type = (selector ? special.delegateType : special.bindType) || type;
|
|
special = jQuery3.event.special[type] || {};
|
|
handleObj = jQuery3.extend({
|
|
type,
|
|
origType,
|
|
data,
|
|
handler,
|
|
guid: handler.guid,
|
|
selector,
|
|
needsContext: selector && jQuery3.expr.match.needsContext.test(selector),
|
|
namespace: namespaces.join(".")
|
|
}, handleObjIn);
|
|
if (!(handlers = events[type])) {
|
|
handlers = events[type] = [];
|
|
handlers.delegateCount = 0;
|
|
if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {
|
|
if (elem.addEventListener) {
|
|
elem.addEventListener(type, eventHandle);
|
|
}
|
|
}
|
|
}
|
|
if (special.add) {
|
|
special.add.call(elem, handleObj);
|
|
if (!handleObj.handler.guid) {
|
|
handleObj.handler.guid = handler.guid;
|
|
}
|
|
}
|
|
if (selector) {
|
|
handlers.splice(handlers.delegateCount++, 0, handleObj);
|
|
} else {
|
|
handlers.push(handleObj);
|
|
}
|
|
}
|
|
},
|
|
// Detach an event or set of events from an element
|
|
remove: function(elem, types, handler, selector, mappedTypes) {
|
|
var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.hasData(elem) && dataPriv.get(elem);
|
|
if (!elemData || !(events = elemData.events)) {
|
|
return;
|
|
}
|
|
types = (types || "").match(rnothtmlwhite) || [""];
|
|
t = types.length;
|
|
while (t--) {
|
|
tmp = rtypenamespace.exec(types[t]) || [];
|
|
type = origType = tmp[1];
|
|
namespaces = (tmp[2] || "").split(".").sort();
|
|
if (!type) {
|
|
for (type in events) {
|
|
jQuery3.event.remove(elem, type + types[t], handler, selector, true);
|
|
}
|
|
continue;
|
|
}
|
|
special = jQuery3.event.special[type] || {};
|
|
type = (selector ? special.delegateType : special.bindType) || type;
|
|
handlers = events[type] || [];
|
|
tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
|
|
origCount = j = handlers.length;
|
|
while (j--) {
|
|
handleObj = handlers[j];
|
|
if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) {
|
|
handlers.splice(j, 1);
|
|
if (handleObj.selector) {
|
|
handlers.delegateCount--;
|
|
}
|
|
if (special.remove) {
|
|
special.remove.call(elem, handleObj);
|
|
}
|
|
}
|
|
}
|
|
if (origCount && !handlers.length) {
|
|
if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) {
|
|
jQuery3.removeEvent(elem, type, elemData.handle);
|
|
}
|
|
delete events[type];
|
|
}
|
|
}
|
|
if (jQuery3.isEmptyObject(events)) {
|
|
dataPriv.remove(elem, "handle events");
|
|
}
|
|
},
|
|
dispatch: function(nativeEvent) {
|
|
var i2, j, ret, matched, handleObj, handlerQueue, args = new Array(arguments.length), event2 = jQuery3.event.fix(nativeEvent), handlers = (dataPriv.get(this, "events") || /* @__PURE__ */ Object.create(null))[event2.type] || [], special = jQuery3.event.special[event2.type] || {};
|
|
args[0] = event2;
|
|
for (i2 = 1; i2 < arguments.length; i2++) {
|
|
args[i2] = arguments[i2];
|
|
}
|
|
event2.delegateTarget = this;
|
|
if (special.preDispatch && special.preDispatch.call(this, event2) === false) {
|
|
return;
|
|
}
|
|
handlerQueue = jQuery3.event.handlers.call(this, event2, handlers);
|
|
i2 = 0;
|
|
while ((matched = handlerQueue[i2++]) && !event2.isPropagationStopped()) {
|
|
event2.currentTarget = matched.elem;
|
|
j = 0;
|
|
while ((handleObj = matched.handlers[j++]) && !event2.isImmediatePropagationStopped()) {
|
|
if (!event2.rnamespace || handleObj.namespace === false || event2.rnamespace.test(handleObj.namespace)) {
|
|
event2.handleObj = handleObj;
|
|
event2.data = handleObj.data;
|
|
ret = ((jQuery3.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);
|
|
if (ret !== void 0) {
|
|
if ((event2.result = ret) === false) {
|
|
event2.preventDefault();
|
|
event2.stopPropagation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (special.postDispatch) {
|
|
special.postDispatch.call(this, event2);
|
|
}
|
|
return event2.result;
|
|
},
|
|
handlers: function(event2, handlers) {
|
|
var i2, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event2.target;
|
|
if (delegateCount && // Support: Firefox <=42 - 66+
|
|
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
|
|
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
|
|
// Support: IE 11+
|
|
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
|
|
!(event2.type === "click" && event2.button >= 1)) {
|
|
for (; cur !== this; cur = cur.parentNode || this) {
|
|
if (cur.nodeType === 1 && !(event2.type === "click" && cur.disabled === true)) {
|
|
matchedHandlers = [];
|
|
matchedSelectors = {};
|
|
for (i2 = 0; i2 < delegateCount; i2++) {
|
|
handleObj = handlers[i2];
|
|
sel = handleObj.selector + " ";
|
|
if (matchedSelectors[sel] === void 0) {
|
|
matchedSelectors[sel] = handleObj.needsContext ? jQuery3(sel, this).index(cur) > -1 : jQuery3.find(sel, this, null, [cur]).length;
|
|
}
|
|
if (matchedSelectors[sel]) {
|
|
matchedHandlers.push(handleObj);
|
|
}
|
|
}
|
|
if (matchedHandlers.length) {
|
|
handlerQueue.push({ elem: cur, handlers: matchedHandlers });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cur = this;
|
|
if (delegateCount < handlers.length) {
|
|
handlerQueue.push({ elem: cur, handlers: handlers.slice(delegateCount) });
|
|
}
|
|
return handlerQueue;
|
|
},
|
|
addProp: function(name, hook) {
|
|
Object.defineProperty(jQuery3.Event.prototype, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
get: typeof hook === "function" ? function() {
|
|
if (this.originalEvent) {
|
|
return hook(this.originalEvent);
|
|
}
|
|
} : function() {
|
|
if (this.originalEvent) {
|
|
return this.originalEvent[name];
|
|
}
|
|
},
|
|
set: function(value) {
|
|
Object.defineProperty(this, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value
|
|
});
|
|
}
|
|
});
|
|
},
|
|
fix: function(originalEvent) {
|
|
return originalEvent[jQuery3.expando] ? originalEvent : new jQuery3.Event(originalEvent);
|
|
},
|
|
special: jQuery3.extend(/* @__PURE__ */ Object.create(null), {
|
|
load: {
|
|
// Prevent triggered image.load events from bubbling to window.load
|
|
noBubble: true
|
|
},
|
|
click: {
|
|
// Utilize native event to ensure correct state for checkable inputs
|
|
setup: function(data) {
|
|
var el2 = this || data;
|
|
if (rcheckableType.test(el2.type) && el2.click && nodeName(el2, "input")) {
|
|
leverageNative(el2, "click", true);
|
|
}
|
|
return false;
|
|
},
|
|
trigger: function(data) {
|
|
var el2 = this || data;
|
|
if (rcheckableType.test(el2.type) && el2.click && nodeName(el2, "input")) {
|
|
leverageNative(el2, "click");
|
|
}
|
|
return true;
|
|
},
|
|
// For cross-browser consistency, suppress native .click() on links
|
|
// Also prevent it if we're currently inside a leveraged native-event stack
|
|
_default: function(event2) {
|
|
var target = event2.target;
|
|
return rcheckableType.test(target.type) && target.click && nodeName(target, "input") && dataPriv.get(target, "click") || nodeName(target, "a");
|
|
}
|
|
},
|
|
beforeunload: {
|
|
postDispatch: function(event2) {
|
|
if (event2.result !== void 0) {
|
|
event2.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
})
|
|
};
|
|
function leverageNative(el2, type, isSetup) {
|
|
if (!isSetup) {
|
|
if (dataPriv.get(el2, type) === void 0) {
|
|
jQuery3.event.add(el2, type, returnTrue);
|
|
}
|
|
return;
|
|
}
|
|
dataPriv.set(el2, type, false);
|
|
jQuery3.event.add(el2, type, {
|
|
namespace: false,
|
|
handler: function(event2) {
|
|
var result, saved = dataPriv.get(this, type);
|
|
if (event2.isTrigger & 1 && this[type]) {
|
|
if (!saved.length) {
|
|
saved = slice.call(arguments);
|
|
dataPriv.set(this, type, saved);
|
|
this[type]();
|
|
result = dataPriv.get(this, type);
|
|
dataPriv.set(this, type, false);
|
|
if (saved !== result) {
|
|
event2.stopImmediatePropagation();
|
|
event2.preventDefault();
|
|
return result && result.value;
|
|
}
|
|
} else if ((jQuery3.event.special[type] || {}).delegateType) {
|
|
event2.stopPropagation();
|
|
}
|
|
} else if (saved.length) {
|
|
dataPriv.set(this, type, {
|
|
value: jQuery3.event.trigger(
|
|
saved[0],
|
|
saved.slice(1),
|
|
this
|
|
)
|
|
});
|
|
event2.stopPropagation();
|
|
event2.isImmediatePropagationStopped = returnTrue;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
jQuery3.removeEvent = function(elem, type, handle) {
|
|
if (elem.removeEventListener) {
|
|
elem.removeEventListener(type, handle);
|
|
}
|
|
};
|
|
jQuery3.Event = function(src, props) {
|
|
if (!(this instanceof jQuery3.Event)) {
|
|
return new jQuery3.Event(src, props);
|
|
}
|
|
if (src && src.type) {
|
|
this.originalEvent = src;
|
|
this.type = src.type;
|
|
this.isDefaultPrevented = src.defaultPrevented ? returnTrue : returnFalse;
|
|
this.target = src.target;
|
|
this.currentTarget = src.currentTarget;
|
|
this.relatedTarget = src.relatedTarget;
|
|
} else {
|
|
this.type = src;
|
|
}
|
|
if (props) {
|
|
jQuery3.extend(this, props);
|
|
}
|
|
this.timeStamp = src && src.timeStamp || Date.now();
|
|
this[jQuery3.expando] = true;
|
|
};
|
|
jQuery3.Event.prototype = {
|
|
constructor: jQuery3.Event,
|
|
isDefaultPrevented: returnFalse,
|
|
isPropagationStopped: returnFalse,
|
|
isImmediatePropagationStopped: returnFalse,
|
|
isSimulated: false,
|
|
preventDefault: function() {
|
|
var e = this.originalEvent;
|
|
this.isDefaultPrevented = returnTrue;
|
|
if (e && !this.isSimulated) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
stopPropagation: function() {
|
|
var e = this.originalEvent;
|
|
this.isPropagationStopped = returnTrue;
|
|
if (e && !this.isSimulated) {
|
|
e.stopPropagation();
|
|
}
|
|
},
|
|
stopImmediatePropagation: function() {
|
|
var e = this.originalEvent;
|
|
this.isImmediatePropagationStopped = returnTrue;
|
|
if (e && !this.isSimulated) {
|
|
e.stopImmediatePropagation();
|
|
}
|
|
this.stopPropagation();
|
|
}
|
|
};
|
|
jQuery3.each({
|
|
altKey: true,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
changedTouches: true,
|
|
ctrlKey: true,
|
|
detail: true,
|
|
eventPhase: true,
|
|
metaKey: true,
|
|
pageX: true,
|
|
pageY: true,
|
|
shiftKey: true,
|
|
view: true,
|
|
"char": true,
|
|
code: true,
|
|
charCode: true,
|
|
key: true,
|
|
keyCode: true,
|
|
button: true,
|
|
buttons: true,
|
|
clientX: true,
|
|
clientY: true,
|
|
offsetX: true,
|
|
offsetY: true,
|
|
pointerId: true,
|
|
pointerType: true,
|
|
screenX: true,
|
|
screenY: true,
|
|
targetTouches: true,
|
|
toElement: true,
|
|
touches: true,
|
|
which: true
|
|
}, jQuery3.event.addProp);
|
|
jQuery3.each({ focus: "focusin", blur: "focusout" }, function(type, delegateType) {
|
|
function focusMappedHandler(nativeEvent) {
|
|
var event2 = jQuery3.event.fix(nativeEvent);
|
|
event2.type = nativeEvent.type === "focusin" ? "focus" : "blur";
|
|
event2.isSimulated = true;
|
|
if (event2.target === event2.currentTarget) {
|
|
dataPriv.get(this, "handle")(event2);
|
|
}
|
|
}
|
|
jQuery3.event.special[type] = {
|
|
// Utilize native event if possible so blur/focus sequence is correct
|
|
setup: function() {
|
|
leverageNative(this, type, true);
|
|
if (isIE) {
|
|
this.addEventListener(delegateType, focusMappedHandler);
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
trigger: function() {
|
|
leverageNative(this, type);
|
|
return true;
|
|
},
|
|
teardown: function() {
|
|
if (isIE) {
|
|
this.removeEventListener(delegateType, focusMappedHandler);
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
// Suppress native focus or blur if we're currently inside
|
|
// a leveraged native-event stack
|
|
_default: function(event2) {
|
|
return dataPriv.get(event2.target, type);
|
|
},
|
|
delegateType
|
|
};
|
|
});
|
|
jQuery3.each({
|
|
mouseenter: "mouseover",
|
|
mouseleave: "mouseout",
|
|
pointerenter: "pointerover",
|
|
pointerleave: "pointerout"
|
|
}, function(orig, fix) {
|
|
jQuery3.event.special[orig] = {
|
|
delegateType: fix,
|
|
bindType: fix,
|
|
handle: function(event2) {
|
|
var ret, target = this, related = event2.relatedTarget, handleObj = event2.handleObj;
|
|
if (!related || related !== target && !jQuery3.contains(target, related)) {
|
|
event2.type = handleObj.origType;
|
|
ret = handleObj.handler.apply(this, arguments);
|
|
event2.type = fix;
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
});
|
|
jQuery3.fn.extend({
|
|
on: function(types, selector, data, fn) {
|
|
return on(this, types, selector, data, fn);
|
|
},
|
|
one: function(types, selector, data, fn) {
|
|
return on(this, types, selector, data, fn, 1);
|
|
},
|
|
off: function(types, selector, fn) {
|
|
var handleObj, type;
|
|
if (types && types.preventDefault && types.handleObj) {
|
|
handleObj = types.handleObj;
|
|
jQuery3(types.delegateTarget).off(
|
|
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
|
|
handleObj.selector,
|
|
handleObj.handler
|
|
);
|
|
return this;
|
|
}
|
|
if (typeof types === "object") {
|
|
for (type in types) {
|
|
this.off(type, selector, types[type]);
|
|
}
|
|
return this;
|
|
}
|
|
if (selector === false || typeof selector === "function") {
|
|
fn = selector;
|
|
selector = void 0;
|
|
}
|
|
if (fn === false) {
|
|
fn = returnFalse;
|
|
}
|
|
return this.each(function() {
|
|
jQuery3.event.remove(this, types, fn, selector);
|
|
});
|
|
}
|
|
});
|
|
var rnoInnerhtml = /<script|<style|<link/i;
|
|
function manipulationTarget(elem, content) {
|
|
if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) {
|
|
return jQuery3(elem).children("tbody")[0] || elem;
|
|
}
|
|
return elem;
|
|
}
|
|
function cloneCopyEvent(src, dest) {
|
|
var type, i2, l, events = dataPriv.get(src, "events");
|
|
if (dest.nodeType !== 1) {
|
|
return;
|
|
}
|
|
if (events) {
|
|
dataPriv.remove(dest, "handle events");
|
|
for (type in events) {
|
|
for (i2 = 0, l = events[type].length; i2 < l; i2++) {
|
|
jQuery3.event.add(dest, type, events[type][i2]);
|
|
}
|
|
}
|
|
}
|
|
if (dataUser.hasData(src)) {
|
|
dataUser.set(dest, jQuery3.extend({}, dataUser.get(src)));
|
|
}
|
|
}
|
|
function remove(elem, selector, keepData) {
|
|
var node, nodes = selector ? jQuery3.filter(selector, elem) : elem, i2 = 0;
|
|
for (; (node = nodes[i2]) != null; i2++) {
|
|
if (!keepData && node.nodeType === 1) {
|
|
jQuery3.cleanData(getAll(node));
|
|
}
|
|
if (node.parentNode) {
|
|
if (keepData && isAttached(node)) {
|
|
setGlobalEval(getAll(node, "script"));
|
|
}
|
|
node.parentNode.removeChild(node);
|
|
}
|
|
}
|
|
return elem;
|
|
}
|
|
jQuery3.extend({
|
|
htmlPrefilter: function(html) {
|
|
return html;
|
|
},
|
|
clone: function(elem, dataAndEvents, deepDataAndEvents) {
|
|
var i2, l, srcElements, destElements, clone = elem.cloneNode(true), inPage = isAttached(elem);
|
|
if (isIE && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery3.isXMLDoc(elem)) {
|
|
destElements = getAll(clone);
|
|
srcElements = getAll(elem);
|
|
for (i2 = 0, l = srcElements.length; i2 < l; i2++) {
|
|
if (nodeName(destElements[i2], "textarea")) {
|
|
destElements[i2].defaultValue = srcElements[i2].defaultValue;
|
|
}
|
|
}
|
|
}
|
|
if (dataAndEvents) {
|
|
if (deepDataAndEvents) {
|
|
srcElements = srcElements || getAll(elem);
|
|
destElements = destElements || getAll(clone);
|
|
for (i2 = 0, l = srcElements.length; i2 < l; i2++) {
|
|
cloneCopyEvent(srcElements[i2], destElements[i2]);
|
|
}
|
|
} else {
|
|
cloneCopyEvent(elem, clone);
|
|
}
|
|
}
|
|
destElements = getAll(clone, "script");
|
|
if (destElements.length > 0) {
|
|
setGlobalEval(destElements, !inPage && getAll(elem, "script"));
|
|
}
|
|
return clone;
|
|
},
|
|
cleanData: function(elems) {
|
|
var data, elem, type, special = jQuery3.event.special, i2 = 0;
|
|
for (; (elem = elems[i2]) !== void 0; i2++) {
|
|
if (acceptData(elem)) {
|
|
if (data = elem[dataPriv.expando]) {
|
|
if (data.events) {
|
|
for (type in data.events) {
|
|
if (special[type]) {
|
|
jQuery3.event.remove(elem, type);
|
|
} else {
|
|
jQuery3.removeEvent(elem, type, data.handle);
|
|
}
|
|
}
|
|
}
|
|
elem[dataPriv.expando] = void 0;
|
|
}
|
|
if (elem[dataUser.expando]) {
|
|
elem[dataUser.expando] = void 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
detach: function(selector) {
|
|
return remove(this, selector, true);
|
|
},
|
|
remove: function(selector) {
|
|
return remove(this, selector);
|
|
},
|
|
text: function(value) {
|
|
return access(this, function(value2) {
|
|
return value2 === void 0 ? jQuery3.text(this) : this.empty().each(function() {
|
|
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
|
|
this.textContent = value2;
|
|
}
|
|
});
|
|
}, null, value, arguments.length);
|
|
},
|
|
append: function() {
|
|
return domManip(this, arguments, function(elem) {
|
|
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
|
|
var target = manipulationTarget(this, elem);
|
|
target.appendChild(elem);
|
|
}
|
|
});
|
|
},
|
|
prepend: function() {
|
|
return domManip(this, arguments, function(elem) {
|
|
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
|
|
var target = manipulationTarget(this, elem);
|
|
target.insertBefore(elem, target.firstChild);
|
|
}
|
|
});
|
|
},
|
|
before: function() {
|
|
return domManip(this, arguments, function(elem) {
|
|
if (this.parentNode) {
|
|
this.parentNode.insertBefore(elem, this);
|
|
}
|
|
});
|
|
},
|
|
after: function() {
|
|
return domManip(this, arguments, function(elem) {
|
|
if (this.parentNode) {
|
|
this.parentNode.insertBefore(elem, this.nextSibling);
|
|
}
|
|
});
|
|
},
|
|
empty: function() {
|
|
var elem, i2 = 0;
|
|
for (; (elem = this[i2]) != null; i2++) {
|
|
if (elem.nodeType === 1) {
|
|
jQuery3.cleanData(getAll(elem, false));
|
|
elem.textContent = "";
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
clone: function(dataAndEvents, deepDataAndEvents) {
|
|
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
|
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
|
return this.map(function() {
|
|
return jQuery3.clone(this, dataAndEvents, deepDataAndEvents);
|
|
});
|
|
},
|
|
html: function(value) {
|
|
return access(this, function(value2) {
|
|
var elem = this[0] || {}, i2 = 0, l = this.length;
|
|
if (value2 === void 0 && elem.nodeType === 1) {
|
|
return elem.innerHTML;
|
|
}
|
|
if (typeof value2 === "string" && !rnoInnerhtml.test(value2) && !wrapMap[(rtagName.exec(value2) || ["", ""])[1].toLowerCase()]) {
|
|
value2 = jQuery3.htmlPrefilter(value2);
|
|
try {
|
|
for (; i2 < l; i2++) {
|
|
elem = this[i2] || {};
|
|
if (elem.nodeType === 1) {
|
|
jQuery3.cleanData(getAll(elem, false));
|
|
elem.innerHTML = value2;
|
|
}
|
|
}
|
|
elem = 0;
|
|
} catch (e) {
|
|
}
|
|
}
|
|
if (elem) {
|
|
this.empty().append(value2);
|
|
}
|
|
}, null, value, arguments.length);
|
|
},
|
|
replaceWith: function() {
|
|
var ignored = [];
|
|
return domManip(this, arguments, function(elem) {
|
|
var parent2 = this.parentNode;
|
|
if (jQuery3.inArray(this, ignored) < 0) {
|
|
jQuery3.cleanData(getAll(this));
|
|
if (parent2) {
|
|
parent2.replaceChild(elem, this);
|
|
}
|
|
}
|
|
}, ignored);
|
|
}
|
|
});
|
|
jQuery3.each({
|
|
appendTo: "append",
|
|
prependTo: "prepend",
|
|
insertBefore: "before",
|
|
insertAfter: "after",
|
|
replaceAll: "replaceWith"
|
|
}, function(name, original) {
|
|
jQuery3.fn[name] = function(selector) {
|
|
var elems, ret = [], insert = jQuery3(selector), last = insert.length - 1, i2 = 0;
|
|
for (; i2 <= last; i2++) {
|
|
elems = i2 === last ? this : this.clone(true);
|
|
jQuery3(insert[i2])[original](elems);
|
|
push.apply(ret, elems);
|
|
}
|
|
return this.pushStack(ret);
|
|
};
|
|
});
|
|
var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
|
|
var rcustomProp = /^--/;
|
|
function getStyles(elem) {
|
|
var view = elem.ownerDocument.defaultView;
|
|
if (!view) {
|
|
view = window2;
|
|
}
|
|
return view.getComputedStyle(elem);
|
|
}
|
|
function swap(elem, options, callback) {
|
|
var ret, name, old = {};
|
|
for (name in options) {
|
|
old[name] = elem.style[name];
|
|
elem.style[name] = options[name];
|
|
}
|
|
ret = callback.call(elem);
|
|
for (name in options) {
|
|
elem.style[name] = old[name];
|
|
}
|
|
return ret;
|
|
}
|
|
function curCSS(elem, name, computed) {
|
|
var ret, isCustomProp = rcustomProp.test(name);
|
|
computed = computed || getStyles(elem);
|
|
if (computed) {
|
|
ret = computed.getPropertyValue(name) || computed[name];
|
|
if (isCustomProp && ret) {
|
|
ret = ret.replace(rtrimCSS, "$1") || void 0;
|
|
}
|
|
if (ret === "" && !isAttached(elem)) {
|
|
ret = jQuery3.style(elem, name);
|
|
}
|
|
}
|
|
return ret !== void 0 ? (
|
|
// Support: IE <=9 - 11+
|
|
// IE returns zIndex value as an integer.
|
|
ret + ""
|
|
) : ret;
|
|
}
|
|
var cssPrefixes = ["Webkit", "Moz", "ms"], emptyStyle = document$1.createElement("div").style;
|
|
function vendorPropName(name) {
|
|
var capName = name[0].toUpperCase() + name.slice(1), i2 = cssPrefixes.length;
|
|
while (i2--) {
|
|
name = cssPrefixes[i2] + capName;
|
|
if (name in emptyStyle) {
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
function finalPropName(name) {
|
|
if (name in emptyStyle) {
|
|
return name;
|
|
}
|
|
return vendorPropName(name) || name;
|
|
}
|
|
var reliableTrDimensionsVal, reliableColDimensionsVal, table = document$1.createElement("table");
|
|
function computeTableStyleTests() {
|
|
if (
|
|
// This is a singleton, we need to execute it only once
|
|
!table || // Finish early in limited (non-browser) environments
|
|
!table.style
|
|
) {
|
|
return;
|
|
}
|
|
var trStyle, col = document$1.createElement("col"), tr = document$1.createElement("tr"), td = document$1.createElement("td");
|
|
table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate;border-spacing:0";
|
|
tr.style.cssText = "box-sizing:content-box;border:1px solid;height:1px";
|
|
td.style.cssText = "height:9px;width:9px;padding:0";
|
|
col.span = 2;
|
|
documentElement$1.appendChild(table).appendChild(col).parentNode.appendChild(tr).appendChild(td).parentNode.appendChild(td.cloneNode(true));
|
|
if (table.offsetWidth === 0) {
|
|
documentElement$1.removeChild(table);
|
|
return;
|
|
}
|
|
trStyle = window2.getComputedStyle(tr);
|
|
reliableColDimensionsVal = isIE || Math.round(
|
|
parseFloat(
|
|
window2.getComputedStyle(col).width
|
|
)
|
|
) === 18;
|
|
reliableTrDimensionsVal = Math.round(parseFloat(trStyle.height) + parseFloat(trStyle.borderTopWidth) + parseFloat(trStyle.borderBottomWidth)) === tr.offsetHeight;
|
|
documentElement$1.removeChild(table);
|
|
table = null;
|
|
}
|
|
jQuery3.extend(support, {
|
|
reliableTrDimensions: function() {
|
|
computeTableStyleTests();
|
|
return reliableTrDimensionsVal;
|
|
},
|
|
reliableColDimensions: function() {
|
|
computeTableStyleTests();
|
|
return reliableColDimensionsVal;
|
|
}
|
|
});
|
|
var cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = {
|
|
letterSpacing: "0",
|
|
fontWeight: "400"
|
|
};
|
|
function setPositiveNumber(_elem, value, subtract) {
|
|
var matches2 = rcssNum.exec(value);
|
|
return matches2 ? (
|
|
// Guard against undefined "subtract", e.g., when used as in cssHooks
|
|
Math.max(0, matches2[2] - (subtract || 0)) + (matches2[3] || "px")
|
|
) : value;
|
|
}
|
|
function boxModelAdjustment(elem, dimension, box, isBorderBox, styles, computedVal) {
|
|
var i2 = dimension === "width" ? 1 : 0, extra = 0, delta = 0, marginDelta = 0;
|
|
if (box === (isBorderBox ? "border" : "content")) {
|
|
return 0;
|
|
}
|
|
for (; i2 < 4; i2 += 2) {
|
|
if (box === "margin") {
|
|
marginDelta += jQuery3.css(elem, box + cssExpand[i2], true, styles);
|
|
}
|
|
if (!isBorderBox) {
|
|
delta += jQuery3.css(elem, "padding" + cssExpand[i2], true, styles);
|
|
if (box !== "padding") {
|
|
delta += jQuery3.css(elem, "border" + cssExpand[i2] + "Width", true, styles);
|
|
} else {
|
|
extra += jQuery3.css(elem, "border" + cssExpand[i2] + "Width", true, styles);
|
|
}
|
|
} else {
|
|
if (box === "content") {
|
|
delta -= jQuery3.css(elem, "padding" + cssExpand[i2], true, styles);
|
|
}
|
|
if (box !== "margin") {
|
|
delta -= jQuery3.css(elem, "border" + cssExpand[i2] + "Width", true, styles);
|
|
}
|
|
}
|
|
}
|
|
if (!isBorderBox && computedVal >= 0) {
|
|
delta += Math.max(0, Math.ceil(
|
|
elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - 0.5
|
|
// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
|
|
// Use an explicit zero to avoid NaN (gh-3964)
|
|
)) || 0;
|
|
}
|
|
return delta + marginDelta;
|
|
}
|
|
function getWidthOrHeight(elem, dimension, extra) {
|
|
var styles = getStyles(elem), boxSizingNeeded = isIE || extra, isBorderBox = boxSizingNeeded && jQuery3.css(elem, "boxSizing", false, styles) === "border-box", valueIsBorderBox = isBorderBox, val = curCSS(elem, dimension, styles), offsetProp = "offset" + dimension[0].toUpperCase() + dimension.slice(1);
|
|
if (rnumnonpx.test(val)) {
|
|
if (!extra) {
|
|
return val;
|
|
}
|
|
val = "auto";
|
|
}
|
|
if (
|
|
// Fall back to offsetWidth/offsetHeight when value is "auto"
|
|
// This happens for inline elements with no explicit setting (gh-3571)
|
|
(val === "auto" || // Support: IE 9 - 11+
|
|
// Use offsetWidth/offsetHeight for when box sizing is unreliable.
|
|
// In those cases, the computed value can be trusted to be border-box.
|
|
isIE && isBorderBox || !support.reliableColDimensions() && nodeName(elem, "col") || !support.reliableTrDimensions() && nodeName(elem, "tr")) && // Make sure the element is visible & connected
|
|
elem.getClientRects().length
|
|
) {
|
|
isBorderBox = jQuery3.css(elem, "boxSizing", false, styles) === "border-box";
|
|
valueIsBorderBox = offsetProp in elem;
|
|
if (valueIsBorderBox) {
|
|
val = elem[offsetProp];
|
|
}
|
|
}
|
|
val = parseFloat(val) || 0;
|
|
return val + boxModelAdjustment(
|
|
elem,
|
|
dimension,
|
|
extra || (isBorderBox ? "border" : "content"),
|
|
valueIsBorderBox,
|
|
styles,
|
|
// Provide the current computed size to request scroll gutter calculation (gh-3589)
|
|
val
|
|
) + "px";
|
|
}
|
|
jQuery3.extend({
|
|
// Add in style property hooks for overriding the default
|
|
// behavior of getting and setting a style property
|
|
cssHooks: {},
|
|
// Get and set the style property on a DOM Node
|
|
style: function(elem, name, value, extra) {
|
|
if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) {
|
|
return;
|
|
}
|
|
var ret, type, hooks, origName = cssCamelCase(name), isCustomProp = rcustomProp.test(name), style = elem.style;
|
|
if (!isCustomProp) {
|
|
name = finalPropName(origName);
|
|
}
|
|
hooks = jQuery3.cssHooks[name] || jQuery3.cssHooks[origName];
|
|
if (value !== void 0) {
|
|
type = typeof value;
|
|
if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) {
|
|
value = adjustCSS(elem, name, ret);
|
|
type = "number";
|
|
}
|
|
if (value == null || value !== value) {
|
|
return;
|
|
}
|
|
if (type === "number") {
|
|
value += ret && ret[3] || (isAutoPx(origName) ? "px" : "");
|
|
}
|
|
if (isIE && value === "" && name.indexOf("background") === 0) {
|
|
style[name] = "inherit";
|
|
}
|
|
if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== void 0) {
|
|
if (isCustomProp) {
|
|
style.setProperty(name, value);
|
|
} else {
|
|
style[name] = value;
|
|
}
|
|
}
|
|
} else {
|
|
if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== void 0) {
|
|
return ret;
|
|
}
|
|
return style[name];
|
|
}
|
|
},
|
|
css: function(elem, name, extra, styles) {
|
|
var val, num, hooks, origName = cssCamelCase(name), isCustomProp = rcustomProp.test(name);
|
|
if (!isCustomProp) {
|
|
name = finalPropName(origName);
|
|
}
|
|
hooks = jQuery3.cssHooks[name] || jQuery3.cssHooks[origName];
|
|
if (hooks && "get" in hooks) {
|
|
val = hooks.get(elem, true, extra);
|
|
}
|
|
if (val === void 0) {
|
|
val = curCSS(elem, name, styles);
|
|
}
|
|
if (val === "normal" && name in cssNormalTransform) {
|
|
val = cssNormalTransform[name];
|
|
}
|
|
if (extra === "" || extra) {
|
|
num = parseFloat(val);
|
|
return extra === true || isFinite(num) ? num || 0 : val;
|
|
}
|
|
return val;
|
|
}
|
|
});
|
|
jQuery3.each(["height", "width"], function(_i, dimension) {
|
|
jQuery3.cssHooks[dimension] = {
|
|
get: function(elem, computed, extra) {
|
|
if (computed) {
|
|
return jQuery3.css(elem, "display") === "none" ? swap(elem, cssShow, function() {
|
|
return getWidthOrHeight(elem, dimension, extra);
|
|
}) : getWidthOrHeight(elem, dimension, extra);
|
|
}
|
|
},
|
|
set: function(elem, value, extra) {
|
|
var matches2, styles = getStyles(elem), isBorderBox = extra && jQuery3.css(elem, "boxSizing", false, styles) === "border-box", subtract = extra ? boxModelAdjustment(
|
|
elem,
|
|
dimension,
|
|
extra,
|
|
isBorderBox,
|
|
styles
|
|
) : 0;
|
|
if (subtract && (matches2 = rcssNum.exec(value)) && (matches2[3] || "px") !== "px") {
|
|
elem.style[dimension] = value;
|
|
value = jQuery3.css(elem, dimension);
|
|
}
|
|
return setPositiveNumber(elem, value, subtract);
|
|
}
|
|
};
|
|
});
|
|
jQuery3.each({
|
|
margin: "",
|
|
padding: "",
|
|
border: "Width"
|
|
}, function(prefix, suffix) {
|
|
jQuery3.cssHooks[prefix + suffix] = {
|
|
expand: function(value) {
|
|
var i2 = 0, expanded = {}, parts = typeof value === "string" ? value.split(" ") : [value];
|
|
for (; i2 < 4; i2++) {
|
|
expanded[prefix + cssExpand[i2] + suffix] = parts[i2] || parts[i2 - 2] || parts[0];
|
|
}
|
|
return expanded;
|
|
}
|
|
};
|
|
if (prefix !== "margin") {
|
|
jQuery3.cssHooks[prefix + suffix].set = setPositiveNumber;
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
css: function(name, value) {
|
|
return access(this, function(elem, name2, value2) {
|
|
var styles, len, map = {}, i2 = 0;
|
|
if (Array.isArray(name2)) {
|
|
styles = getStyles(elem);
|
|
len = name2.length;
|
|
for (; i2 < len; i2++) {
|
|
map[name2[i2]] = jQuery3.css(elem, name2[i2], false, styles);
|
|
}
|
|
return map;
|
|
}
|
|
return value2 !== void 0 ? jQuery3.style(elem, name2, value2) : jQuery3.css(elem, name2);
|
|
}, name, value, arguments.length > 1);
|
|
}
|
|
});
|
|
function Tween(elem, options, prop, end, easing) {
|
|
return new Tween.prototype.init(elem, options, prop, end, easing);
|
|
}
|
|
jQuery3.Tween = Tween;
|
|
Tween.prototype = {
|
|
constructor: Tween,
|
|
init: function(elem, options, prop, end, easing, unit) {
|
|
this.elem = elem;
|
|
this.prop = prop;
|
|
this.easing = easing || jQuery3.easing._default;
|
|
this.options = options;
|
|
this.start = this.now = this.cur();
|
|
this.end = end;
|
|
this.unit = unit || (isAutoPx(prop) ? "px" : "");
|
|
},
|
|
cur: function() {
|
|
var hooks = Tween.propHooks[this.prop];
|
|
return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this);
|
|
},
|
|
run: function(percent) {
|
|
var eased, hooks = Tween.propHooks[this.prop];
|
|
if (this.options.duration) {
|
|
this.pos = eased = jQuery3.easing[this.easing](
|
|
percent,
|
|
this.options.duration * percent,
|
|
0,
|
|
1,
|
|
this.options.duration
|
|
);
|
|
} else {
|
|
this.pos = eased = percent;
|
|
}
|
|
this.now = (this.end - this.start) * eased + this.start;
|
|
if (this.options.step) {
|
|
this.options.step.call(this.elem, this.now, this);
|
|
}
|
|
if (hooks && hooks.set) {
|
|
hooks.set(this);
|
|
} else {
|
|
Tween.propHooks._default.set(this);
|
|
}
|
|
return this;
|
|
}
|
|
};
|
|
Tween.prototype.init.prototype = Tween.prototype;
|
|
Tween.propHooks = {
|
|
_default: {
|
|
get: function(tween) {
|
|
var result;
|
|
if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) {
|
|
return tween.elem[tween.prop];
|
|
}
|
|
result = jQuery3.css(tween.elem, tween.prop, "");
|
|
return !result || result === "auto" ? 0 : result;
|
|
},
|
|
set: function(tween) {
|
|
if (jQuery3.fx.step[tween.prop]) {
|
|
jQuery3.fx.step[tween.prop](tween);
|
|
} else if (tween.elem.nodeType === 1 && (jQuery3.cssHooks[tween.prop] || tween.elem.style[finalPropName(tween.prop)] != null)) {
|
|
jQuery3.style(tween.elem, tween.prop, tween.now + tween.unit);
|
|
} else {
|
|
tween.elem[tween.prop] = tween.now;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
jQuery3.easing = {
|
|
linear: function(p) {
|
|
return p;
|
|
},
|
|
swing: function(p) {
|
|
return 0.5 - Math.cos(p * Math.PI) / 2;
|
|
},
|
|
_default: "swing"
|
|
};
|
|
jQuery3.fx = Tween.prototype.init;
|
|
jQuery3.fx.step = {};
|
|
var fxNow, inProgress, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/;
|
|
function schedule2() {
|
|
if (inProgress) {
|
|
if (document$1.hidden === false && window2.requestAnimationFrame) {
|
|
window2.requestAnimationFrame(schedule2);
|
|
} else {
|
|
window2.setTimeout(schedule2, 13);
|
|
}
|
|
jQuery3.fx.tick();
|
|
}
|
|
}
|
|
function createFxNow() {
|
|
window2.setTimeout(function() {
|
|
fxNow = void 0;
|
|
});
|
|
return fxNow = Date.now();
|
|
}
|
|
function genFx(type, includeWidth) {
|
|
var which, i2 = 0, attrs = { height: type };
|
|
includeWidth = includeWidth ? 1 : 0;
|
|
for (; i2 < 4; i2 += 2 - includeWidth) {
|
|
which = cssExpand[i2];
|
|
attrs["margin" + which] = attrs["padding" + which] = type;
|
|
}
|
|
if (includeWidth) {
|
|
attrs.opacity = attrs.width = type;
|
|
}
|
|
return attrs;
|
|
}
|
|
function createTween(value, prop, animation) {
|
|
var tween, collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), index = 0, length = collection.length;
|
|
for (; index < length; index++) {
|
|
if (tween = collection[index].call(animation, prop, value)) {
|
|
return tween;
|
|
}
|
|
}
|
|
}
|
|
function defaultPrefilter(elem, props, opts2) {
|
|
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, isBox = "width" in props || "height" in props, anim = this, orig = {}, style = elem.style, hidden = elem.nodeType && isHiddenWithinTree(elem), dataShow = dataPriv.get(elem, "fxshow");
|
|
if (!opts2.queue) {
|
|
hooks = jQuery3._queueHooks(elem, "fx");
|
|
if (hooks.unqueued == null) {
|
|
hooks.unqueued = 0;
|
|
oldfire = hooks.empty.fire;
|
|
hooks.empty.fire = function() {
|
|
if (!hooks.unqueued) {
|
|
oldfire();
|
|
}
|
|
};
|
|
}
|
|
hooks.unqueued++;
|
|
anim.always(function() {
|
|
anim.always(function() {
|
|
hooks.unqueued--;
|
|
if (!jQuery3.queue(elem, "fx").length) {
|
|
hooks.empty.fire();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
for (prop in props) {
|
|
value = props[prop];
|
|
if (rfxtypes.test(value)) {
|
|
delete props[prop];
|
|
toggle = toggle || value === "toggle";
|
|
if (value === (hidden ? "hide" : "show")) {
|
|
if (value === "show" && dataShow && dataShow[prop] !== void 0) {
|
|
hidden = true;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
orig[prop] = dataShow && dataShow[prop] || jQuery3.style(elem, prop);
|
|
}
|
|
}
|
|
propTween = !jQuery3.isEmptyObject(props);
|
|
if (!propTween && jQuery3.isEmptyObject(orig)) {
|
|
return;
|
|
}
|
|
if (isBox && elem.nodeType === 1) {
|
|
opts2.overflow = [style.overflow, style.overflowX, style.overflowY];
|
|
restoreDisplay = dataShow && dataShow.display;
|
|
if (restoreDisplay == null) {
|
|
restoreDisplay = dataPriv.get(elem, "display");
|
|
}
|
|
display = jQuery3.css(elem, "display");
|
|
if (display === "none") {
|
|
if (restoreDisplay) {
|
|
display = restoreDisplay;
|
|
} else {
|
|
showHide([elem], true);
|
|
restoreDisplay = elem.style.display || restoreDisplay;
|
|
display = jQuery3.css(elem, "display");
|
|
showHide([elem]);
|
|
}
|
|
}
|
|
if (display === "inline" || display === "inline-block" && restoreDisplay != null) {
|
|
if (jQuery3.css(elem, "float") === "none") {
|
|
if (!propTween) {
|
|
anim.done(function() {
|
|
style.display = restoreDisplay;
|
|
});
|
|
if (restoreDisplay == null) {
|
|
display = style.display;
|
|
restoreDisplay = display === "none" ? "" : display;
|
|
}
|
|
}
|
|
style.display = "inline-block";
|
|
}
|
|
}
|
|
}
|
|
if (opts2.overflow) {
|
|
style.overflow = "hidden";
|
|
anim.always(function() {
|
|
style.overflow = opts2.overflow[0];
|
|
style.overflowX = opts2.overflow[1];
|
|
style.overflowY = opts2.overflow[2];
|
|
});
|
|
}
|
|
propTween = false;
|
|
for (prop in orig) {
|
|
if (!propTween) {
|
|
if (dataShow) {
|
|
if ("hidden" in dataShow) {
|
|
hidden = dataShow.hidden;
|
|
}
|
|
} else {
|
|
dataShow = dataPriv.set(elem, "fxshow", { display: restoreDisplay });
|
|
}
|
|
if (toggle) {
|
|
dataShow.hidden = !hidden;
|
|
}
|
|
if (hidden) {
|
|
showHide([elem], true);
|
|
}
|
|
anim.done(function() {
|
|
if (!hidden) {
|
|
showHide([elem]);
|
|
}
|
|
dataPriv.remove(elem, "fxshow");
|
|
for (prop in orig) {
|
|
jQuery3.style(elem, prop, orig[prop]);
|
|
}
|
|
});
|
|
}
|
|
propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
|
|
if (!(prop in dataShow)) {
|
|
dataShow[prop] = propTween.start;
|
|
if (hidden) {
|
|
propTween.end = propTween.start;
|
|
propTween.start = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function propFilter(props, specialEasing) {
|
|
var index, name, easing, value, hooks;
|
|
for (index in props) {
|
|
name = cssCamelCase(index);
|
|
easing = specialEasing[name];
|
|
value = props[index];
|
|
if (Array.isArray(value)) {
|
|
easing = value[1];
|
|
value = props[index] = value[0];
|
|
}
|
|
if (index !== name) {
|
|
props[name] = value;
|
|
delete props[index];
|
|
}
|
|
hooks = jQuery3.cssHooks[name];
|
|
if (hooks && "expand" in hooks) {
|
|
value = hooks.expand(value);
|
|
delete props[name];
|
|
for (index in value) {
|
|
if (!(index in props)) {
|
|
props[index] = value[index];
|
|
specialEasing[index] = easing;
|
|
}
|
|
}
|
|
} else {
|
|
specialEasing[name] = easing;
|
|
}
|
|
}
|
|
}
|
|
function Animation(elem, properties, options) {
|
|
var result, stopped, index = 0, length = Animation.prefilters.length, deferred = jQuery3.Deferred().always(function() {
|
|
delete tick.elem;
|
|
}), tick = function() {
|
|
if (stopped) {
|
|
return false;
|
|
}
|
|
var currentTime = fxNow || createFxNow(), remaining = Math.max(0, animation.startTime + animation.duration - currentTime), percent = 1 - (remaining / animation.duration || 0), index2 = 0, length2 = animation.tweens.length;
|
|
for (; index2 < length2; index2++) {
|
|
animation.tweens[index2].run(percent);
|
|
}
|
|
deferred.notifyWith(elem, [animation, percent, remaining]);
|
|
if (percent < 1 && length2) {
|
|
return remaining;
|
|
}
|
|
if (!length2) {
|
|
deferred.notifyWith(elem, [animation, 1, 0]);
|
|
}
|
|
deferred.resolveWith(elem, [animation]);
|
|
return false;
|
|
}, animation = deferred.promise({
|
|
elem,
|
|
props: jQuery3.extend({}, properties),
|
|
opts: jQuery3.extend(true, {
|
|
specialEasing: {},
|
|
easing: jQuery3.easing._default
|
|
}, options),
|
|
originalProperties: properties,
|
|
originalOptions: options,
|
|
startTime: fxNow || createFxNow(),
|
|
duration: options.duration,
|
|
tweens: [],
|
|
createTween: function(prop, end) {
|
|
var tween = jQuery3.Tween(
|
|
elem,
|
|
animation.opts,
|
|
prop,
|
|
end,
|
|
animation.opts.specialEasing[prop] || animation.opts.easing
|
|
);
|
|
animation.tweens.push(tween);
|
|
return tween;
|
|
},
|
|
stop: function(gotoEnd) {
|
|
var index2 = 0, length2 = gotoEnd ? animation.tweens.length : 0;
|
|
if (stopped) {
|
|
return this;
|
|
}
|
|
stopped = true;
|
|
for (; index2 < length2; index2++) {
|
|
animation.tweens[index2].run(1);
|
|
}
|
|
if (gotoEnd) {
|
|
deferred.notifyWith(elem, [animation, 1, 0]);
|
|
deferred.resolveWith(elem, [animation, gotoEnd]);
|
|
} else {
|
|
deferred.rejectWith(elem, [animation, gotoEnd]);
|
|
}
|
|
return this;
|
|
}
|
|
}), props = animation.props;
|
|
propFilter(props, animation.opts.specialEasing);
|
|
for (; index < length; index++) {
|
|
result = Animation.prefilters[index].call(animation, elem, props, animation.opts);
|
|
if (result) {
|
|
if (typeof result.stop === "function") {
|
|
jQuery3._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
jQuery3.map(props, createTween, animation);
|
|
if (typeof animation.opts.start === "function") {
|
|
animation.opts.start.call(elem, animation);
|
|
}
|
|
animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);
|
|
jQuery3.fx.timer(
|
|
jQuery3.extend(tick, {
|
|
elem,
|
|
anim: animation,
|
|
queue: animation.opts.queue
|
|
})
|
|
);
|
|
return animation;
|
|
}
|
|
jQuery3.Animation = jQuery3.extend(Animation, {
|
|
tweeners: {
|
|
"*": [function(prop, value) {
|
|
var tween = this.createTween(prop, value);
|
|
adjustCSS(tween.elem, prop, rcssNum.exec(value), tween);
|
|
return tween;
|
|
}]
|
|
},
|
|
tweener: function(props, callback) {
|
|
if (typeof props === "function") {
|
|
callback = props;
|
|
props = ["*"];
|
|
} else {
|
|
props = props.match(rnothtmlwhite);
|
|
}
|
|
var prop, index = 0, length = props.length;
|
|
for (; index < length; index++) {
|
|
prop = props[index];
|
|
Animation.tweeners[prop] = Animation.tweeners[prop] || [];
|
|
Animation.tweeners[prop].unshift(callback);
|
|
}
|
|
},
|
|
prefilters: [defaultPrefilter],
|
|
prefilter: function(callback, prepend) {
|
|
if (prepend) {
|
|
Animation.prefilters.unshift(callback);
|
|
} else {
|
|
Animation.prefilters.push(callback);
|
|
}
|
|
}
|
|
});
|
|
jQuery3.speed = function(speed, easing, fn) {
|
|
var opt = speed && typeof speed === "object" ? jQuery3.extend({}, speed) : {
|
|
complete: fn || easing || typeof speed === "function" && speed,
|
|
duration: speed,
|
|
easing: fn && easing || easing && typeof easing !== "function" && easing
|
|
};
|
|
if (jQuery3.fx.off) {
|
|
opt.duration = 0;
|
|
} else {
|
|
if (typeof opt.duration !== "number") {
|
|
if (opt.duration in jQuery3.fx.speeds) {
|
|
opt.duration = jQuery3.fx.speeds[opt.duration];
|
|
} else {
|
|
opt.duration = jQuery3.fx.speeds._default;
|
|
}
|
|
}
|
|
}
|
|
if (opt.queue == null || opt.queue === true) {
|
|
opt.queue = "fx";
|
|
}
|
|
opt.old = opt.complete;
|
|
opt.complete = function() {
|
|
if (typeof opt.old === "function") {
|
|
opt.old.call(this);
|
|
}
|
|
if (opt.queue) {
|
|
jQuery3.dequeue(this, opt.queue);
|
|
}
|
|
};
|
|
return opt;
|
|
};
|
|
jQuery3.fn.extend({
|
|
fadeTo: function(speed, to, easing, callback) {
|
|
return this.filter(isHiddenWithinTree).css("opacity", 0).show().end().animate({ opacity: to }, speed, easing, callback);
|
|
},
|
|
animate: function(prop, speed, easing, callback) {
|
|
var empty = jQuery3.isEmptyObject(prop), optall = jQuery3.speed(speed, easing, callback), doAnimation = function() {
|
|
var anim = Animation(this, jQuery3.extend({}, prop), optall);
|
|
if (empty || dataPriv.get(this, "finish")) {
|
|
anim.stop(true);
|
|
}
|
|
};
|
|
doAnimation.finish = doAnimation;
|
|
return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation);
|
|
},
|
|
stop: function(type, clearQueue, gotoEnd) {
|
|
var stopQueue = function(hooks) {
|
|
var stop = hooks.stop;
|
|
delete hooks.stop;
|
|
stop(gotoEnd);
|
|
};
|
|
if (typeof type !== "string") {
|
|
gotoEnd = clearQueue;
|
|
clearQueue = type;
|
|
type = void 0;
|
|
}
|
|
if (clearQueue) {
|
|
this.queue(type || "fx", []);
|
|
}
|
|
return this.each(function() {
|
|
var dequeue = true, index = type != null && type + "queueHooks", timers2 = jQuery3.timers, data = dataPriv.get(this);
|
|
if (index) {
|
|
if (data[index] && data[index].stop) {
|
|
stopQueue(data[index]);
|
|
}
|
|
} else {
|
|
for (index in data) {
|
|
if (data[index] && data[index].stop && rrun.test(index)) {
|
|
stopQueue(data[index]);
|
|
}
|
|
}
|
|
}
|
|
for (index = timers2.length; index--; ) {
|
|
if (timers2[index].elem === this && (type == null || timers2[index].queue === type)) {
|
|
timers2[index].anim.stop(gotoEnd);
|
|
dequeue = false;
|
|
timers2.splice(index, 1);
|
|
}
|
|
}
|
|
if (dequeue || !gotoEnd) {
|
|
jQuery3.dequeue(this, type);
|
|
}
|
|
});
|
|
},
|
|
finish: function(type) {
|
|
if (type !== false) {
|
|
type = type || "fx";
|
|
}
|
|
return this.each(function() {
|
|
var index, data = dataPriv.get(this), queue = data[type + "queue"], hooks = data[type + "queueHooks"], timers2 = jQuery3.timers, length = queue ? queue.length : 0;
|
|
data.finish = true;
|
|
jQuery3.queue(this, type, []);
|
|
if (hooks && hooks.stop) {
|
|
hooks.stop.call(this, true);
|
|
}
|
|
for (index = timers2.length; index--; ) {
|
|
if (timers2[index].elem === this && timers2[index].queue === type) {
|
|
timers2[index].anim.stop(true);
|
|
timers2.splice(index, 1);
|
|
}
|
|
}
|
|
for (index = 0; index < length; index++) {
|
|
if (queue[index] && queue[index].finish) {
|
|
queue[index].finish.call(this);
|
|
}
|
|
}
|
|
delete data.finish;
|
|
});
|
|
}
|
|
});
|
|
jQuery3.each(["toggle", "show", "hide"], function(_i, name) {
|
|
var cssFn = jQuery3.fn[name];
|
|
jQuery3.fn[name] = function(speed, easing, callback) {
|
|
return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback);
|
|
};
|
|
});
|
|
jQuery3.each({
|
|
slideDown: genFx("show"),
|
|
slideUp: genFx("hide"),
|
|
slideToggle: genFx("toggle"),
|
|
fadeIn: { opacity: "show" },
|
|
fadeOut: { opacity: "hide" },
|
|
fadeToggle: { opacity: "toggle" }
|
|
}, function(name, props) {
|
|
jQuery3.fn[name] = function(speed, easing, callback) {
|
|
return this.animate(props, speed, easing, callback);
|
|
};
|
|
});
|
|
jQuery3.timers = [];
|
|
jQuery3.fx.tick = function() {
|
|
var timer2, i2 = 0, timers2 = jQuery3.timers;
|
|
fxNow = Date.now();
|
|
for (; i2 < timers2.length; i2++) {
|
|
timer2 = timers2[i2];
|
|
if (!timer2() && timers2[i2] === timer2) {
|
|
timers2.splice(i2--, 1);
|
|
}
|
|
}
|
|
if (!timers2.length) {
|
|
jQuery3.fx.stop();
|
|
}
|
|
fxNow = void 0;
|
|
};
|
|
jQuery3.fx.timer = function(timer2) {
|
|
jQuery3.timers.push(timer2);
|
|
jQuery3.fx.start();
|
|
};
|
|
jQuery3.fx.start = function() {
|
|
if (inProgress) {
|
|
return;
|
|
}
|
|
inProgress = true;
|
|
schedule2();
|
|
};
|
|
jQuery3.fx.stop = function() {
|
|
inProgress = null;
|
|
};
|
|
jQuery3.fx.speeds = {
|
|
slow: 600,
|
|
fast: 200,
|
|
// Default speed
|
|
_default: 400
|
|
};
|
|
jQuery3.fn.delay = function(time, type) {
|
|
time = jQuery3.fx ? jQuery3.fx.speeds[time] || time : time;
|
|
type = type || "fx";
|
|
return this.queue(type, function(next, hooks) {
|
|
var timeout = window2.setTimeout(next, time);
|
|
hooks.stop = function() {
|
|
window2.clearTimeout(timeout);
|
|
};
|
|
});
|
|
};
|
|
var rfocusable = /^(?:input|select|textarea|button)$/i, rclickable = /^(?:a|area)$/i;
|
|
jQuery3.fn.extend({
|
|
prop: function(name, value) {
|
|
return access(this, jQuery3.prop, name, value, arguments.length > 1);
|
|
},
|
|
removeProp: function(name) {
|
|
return this.each(function() {
|
|
delete this[jQuery3.propFix[name] || name];
|
|
});
|
|
}
|
|
});
|
|
jQuery3.extend({
|
|
prop: function(elem, name, value) {
|
|
var ret, hooks, nType = elem.nodeType;
|
|
if (nType === 3 || nType === 8 || nType === 2) {
|
|
return;
|
|
}
|
|
if (nType !== 1 || !jQuery3.isXMLDoc(elem)) {
|
|
name = jQuery3.propFix[name] || name;
|
|
hooks = jQuery3.propHooks[name];
|
|
}
|
|
if (value !== void 0) {
|
|
if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) {
|
|
return ret;
|
|
}
|
|
return elem[name] = value;
|
|
}
|
|
if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
|
|
return ret;
|
|
}
|
|
return elem[name];
|
|
},
|
|
propHooks: {
|
|
tabIndex: {
|
|
get: function(elem) {
|
|
var tabindex = elem.getAttribute("tabindex");
|
|
if (tabindex) {
|
|
return parseInt(tabindex, 10);
|
|
}
|
|
if (rfocusable.test(elem.nodeName) || // href-less anchor's `tabIndex` property value is `0` and
|
|
// the `tabindex` attribute value: `null`. We want `-1`.
|
|
rclickable.test(elem.nodeName) && elem.href) {
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
},
|
|
propFix: {
|
|
"for": "htmlFor",
|
|
"class": "className"
|
|
}
|
|
});
|
|
if (isIE) {
|
|
jQuery3.propHooks.selected = {
|
|
get: function(elem) {
|
|
var parent2 = elem.parentNode;
|
|
if (parent2 && parent2.parentNode) {
|
|
parent2.parentNode.selectedIndex;
|
|
}
|
|
return null;
|
|
},
|
|
set: function(elem) {
|
|
var parent2 = elem.parentNode;
|
|
if (parent2) {
|
|
parent2.selectedIndex;
|
|
if (parent2.parentNode) {
|
|
parent2.parentNode.selectedIndex;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
jQuery3.each([
|
|
"tabIndex",
|
|
"readOnly",
|
|
"maxLength",
|
|
"cellSpacing",
|
|
"cellPadding",
|
|
"rowSpan",
|
|
"colSpan",
|
|
"useMap",
|
|
"frameBorder",
|
|
"contentEditable"
|
|
], function() {
|
|
jQuery3.propFix[this.toLowerCase()] = this;
|
|
});
|
|
function stripAndCollapse(value) {
|
|
var tokens = value.match(rnothtmlwhite) || [];
|
|
return tokens.join(" ");
|
|
}
|
|
function getClass(elem) {
|
|
return elem.getAttribute && elem.getAttribute("class") || "";
|
|
}
|
|
function classesToArray(value) {
|
|
if (Array.isArray(value)) {
|
|
return value;
|
|
}
|
|
if (typeof value === "string") {
|
|
return value.match(rnothtmlwhite) || [];
|
|
}
|
|
return [];
|
|
}
|
|
jQuery3.fn.extend({
|
|
addClass: function(value) {
|
|
var classNames, cur, curValue, className, i2, finalValue;
|
|
if (typeof value === "function") {
|
|
return this.each(function(j) {
|
|
jQuery3(this).addClass(value.call(this, j, getClass(this)));
|
|
});
|
|
}
|
|
classNames = classesToArray(value);
|
|
if (classNames.length) {
|
|
return this.each(function() {
|
|
curValue = getClass(this);
|
|
cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
|
|
if (cur) {
|
|
for (i2 = 0; i2 < classNames.length; i2++) {
|
|
className = classNames[i2];
|
|
if (cur.indexOf(" " + className + " ") < 0) {
|
|
cur += className + " ";
|
|
}
|
|
}
|
|
finalValue = stripAndCollapse(cur);
|
|
if (curValue !== finalValue) {
|
|
this.setAttribute("class", finalValue);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
removeClass: function(value) {
|
|
var classNames, cur, curValue, className, i2, finalValue;
|
|
if (typeof value === "function") {
|
|
return this.each(function(j) {
|
|
jQuery3(this).removeClass(value.call(this, j, getClass(this)));
|
|
});
|
|
}
|
|
if (!arguments.length) {
|
|
return this.attr("class", "");
|
|
}
|
|
classNames = classesToArray(value);
|
|
if (classNames.length) {
|
|
return this.each(function() {
|
|
curValue = getClass(this);
|
|
cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
|
|
if (cur) {
|
|
for (i2 = 0; i2 < classNames.length; i2++) {
|
|
className = classNames[i2];
|
|
while (cur.indexOf(" " + className + " ") > -1) {
|
|
cur = cur.replace(" " + className + " ", " ");
|
|
}
|
|
}
|
|
finalValue = stripAndCollapse(cur);
|
|
if (curValue !== finalValue) {
|
|
this.setAttribute("class", finalValue);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
toggleClass: function(value, stateVal) {
|
|
var classNames, className, i2, self2;
|
|
if (typeof value === "function") {
|
|
return this.each(function(i3) {
|
|
jQuery3(this).toggleClass(
|
|
value.call(this, i3, getClass(this), stateVal),
|
|
stateVal
|
|
);
|
|
});
|
|
}
|
|
if (typeof stateVal === "boolean") {
|
|
return stateVal ? this.addClass(value) : this.removeClass(value);
|
|
}
|
|
classNames = classesToArray(value);
|
|
if (classNames.length) {
|
|
return this.each(function() {
|
|
self2 = jQuery3(this);
|
|
for (i2 = 0; i2 < classNames.length; i2++) {
|
|
className = classNames[i2];
|
|
if (self2.hasClass(className)) {
|
|
self2.removeClass(className);
|
|
} else {
|
|
self2.addClass(className);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
hasClass: function(selector) {
|
|
var className, elem, i2 = 0;
|
|
className = " " + selector + " ";
|
|
while (elem = this[i2++]) {
|
|
if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
val: function(value) {
|
|
var hooks, ret, valueIsFunction, elem = this[0];
|
|
if (!arguments.length) {
|
|
if (elem) {
|
|
hooks = jQuery3.valHooks[elem.type] || jQuery3.valHooks[elem.nodeName.toLowerCase()];
|
|
if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== void 0) {
|
|
return ret;
|
|
}
|
|
ret = elem.value;
|
|
return ret == null ? "" : ret;
|
|
}
|
|
return;
|
|
}
|
|
valueIsFunction = typeof value === "function";
|
|
return this.each(function(i2) {
|
|
var val;
|
|
if (this.nodeType !== 1) {
|
|
return;
|
|
}
|
|
if (valueIsFunction) {
|
|
val = value.call(this, i2, jQuery3(this).val());
|
|
} else {
|
|
val = value;
|
|
}
|
|
if (val == null) {
|
|
val = "";
|
|
} else if (typeof val === "number") {
|
|
val += "";
|
|
} else if (Array.isArray(val)) {
|
|
val = jQuery3.map(val, function(value2) {
|
|
return value2 == null ? "" : value2 + "";
|
|
});
|
|
}
|
|
hooks = jQuery3.valHooks[this.type] || jQuery3.valHooks[this.nodeName.toLowerCase()];
|
|
if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === void 0) {
|
|
this.value = val;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
jQuery3.extend({
|
|
valHooks: {
|
|
select: {
|
|
get: function(elem) {
|
|
var value, option, i2, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one", values = one ? null : [], max = one ? index + 1 : options.length;
|
|
if (index < 0) {
|
|
i2 = max;
|
|
} else {
|
|
i2 = one ? index : 0;
|
|
}
|
|
for (; i2 < max; i2++) {
|
|
option = options[i2];
|
|
if (option.selected && // Don't return options that are disabled or in a disabled optgroup
|
|
!option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) {
|
|
value = jQuery3(option).val();
|
|
if (one) {
|
|
return value;
|
|
}
|
|
values.push(value);
|
|
}
|
|
}
|
|
return values;
|
|
},
|
|
set: function(elem, value) {
|
|
var optionSet, option, options = elem.options, values = jQuery3.makeArray(value), i2 = options.length;
|
|
while (i2--) {
|
|
option = options[i2];
|
|
if (option.selected = jQuery3.inArray(jQuery3(option).val(), values) > -1) {
|
|
optionSet = true;
|
|
}
|
|
}
|
|
if (!optionSet) {
|
|
elem.selectedIndex = -1;
|
|
}
|
|
return values;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (isIE) {
|
|
jQuery3.valHooks.option = {
|
|
get: function(elem) {
|
|
var val = elem.getAttribute("value");
|
|
return val != null ? val : (
|
|
// Support: IE <=10 - 11+
|
|
// option.text throws exceptions (trac-14686, trac-14858)
|
|
// Strip and collapse whitespace
|
|
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
|
stripAndCollapse(jQuery3.text(elem))
|
|
);
|
|
}
|
|
};
|
|
}
|
|
jQuery3.each(["radio", "checkbox"], function() {
|
|
jQuery3.valHooks[this] = {
|
|
set: function(elem, value) {
|
|
if (Array.isArray(value)) {
|
|
return elem.checked = jQuery3.inArray(jQuery3(elem).val(), value) > -1;
|
|
}
|
|
}
|
|
};
|
|
});
|
|
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, stopPropagationCallback = function(e) {
|
|
e.stopPropagation();
|
|
};
|
|
jQuery3.extend(jQuery3.event, {
|
|
trigger: function(event2, data, elem, onlyHandlers) {
|
|
var i2, cur, tmp, bubbleType, ontype, handle, special, lastElement, eventPath = [elem || document$1], type = hasOwn.call(event2, "type") ? event2.type : event2, namespaces = hasOwn.call(event2, "namespace") ? event2.namespace.split(".") : [];
|
|
cur = lastElement = tmp = elem = elem || document$1;
|
|
if (elem.nodeType === 3 || elem.nodeType === 8) {
|
|
return;
|
|
}
|
|
if (rfocusMorph.test(type + jQuery3.event.triggered)) {
|
|
return;
|
|
}
|
|
if (type.indexOf(".") > -1) {
|
|
namespaces = type.split(".");
|
|
type = namespaces.shift();
|
|
namespaces.sort();
|
|
}
|
|
ontype = type.indexOf(":") < 0 && "on" + type;
|
|
event2 = event2[jQuery3.expando] ? event2 : new jQuery3.Event(type, typeof event2 === "object" && event2);
|
|
event2.isTrigger = onlyHandlers ? 2 : 3;
|
|
event2.namespace = namespaces.join(".");
|
|
event2.rnamespace = event2.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
|
|
event2.result = void 0;
|
|
if (!event2.target) {
|
|
event2.target = elem;
|
|
}
|
|
data = data == null ? [event2] : jQuery3.makeArray(data, [event2]);
|
|
special = jQuery3.event.special[type] || {};
|
|
if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) {
|
|
return;
|
|
}
|
|
if (!onlyHandlers && !special.noBubble && !isWindow(elem)) {
|
|
bubbleType = special.delegateType || type;
|
|
if (!rfocusMorph.test(bubbleType + type)) {
|
|
cur = cur.parentNode;
|
|
}
|
|
for (; cur; cur = cur.parentNode) {
|
|
eventPath.push(cur);
|
|
tmp = cur;
|
|
}
|
|
if (tmp === (elem.ownerDocument || document$1)) {
|
|
eventPath.push(tmp.defaultView || tmp.parentWindow || window2);
|
|
}
|
|
}
|
|
i2 = 0;
|
|
while ((cur = eventPath[i2++]) && !event2.isPropagationStopped()) {
|
|
lastElement = cur;
|
|
event2.type = i2 > 1 ? bubbleType : special.bindType || type;
|
|
handle = (dataPriv.get(cur, "events") || /* @__PURE__ */ Object.create(null))[event2.type] && dataPriv.get(cur, "handle");
|
|
if (handle) {
|
|
handle.apply(cur, data);
|
|
}
|
|
handle = ontype && cur[ontype];
|
|
if (handle && handle.apply && acceptData(cur)) {
|
|
event2.result = handle.apply(cur, data);
|
|
if (event2.result === false) {
|
|
event2.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
event2.type = type;
|
|
if (!onlyHandlers && !event2.isDefaultPrevented()) {
|
|
if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) {
|
|
if (ontype && typeof elem[type] === "function" && !isWindow(elem)) {
|
|
tmp = elem[ontype];
|
|
if (tmp) {
|
|
elem[ontype] = null;
|
|
}
|
|
jQuery3.event.triggered = type;
|
|
if (event2.isPropagationStopped()) {
|
|
lastElement.addEventListener(type, stopPropagationCallback);
|
|
}
|
|
elem[type]();
|
|
if (event2.isPropagationStopped()) {
|
|
lastElement.removeEventListener(type, stopPropagationCallback);
|
|
}
|
|
jQuery3.event.triggered = void 0;
|
|
if (tmp) {
|
|
elem[ontype] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return event2.result;
|
|
},
|
|
// Piggyback on a donor event to simulate a different one
|
|
// Used only for `focus(in | out)` events
|
|
simulate: function(type, elem, event2) {
|
|
var e = jQuery3.extend(
|
|
new jQuery3.Event(),
|
|
event2,
|
|
{
|
|
type,
|
|
isSimulated: true
|
|
}
|
|
);
|
|
jQuery3.event.trigger(e, null, elem);
|
|
}
|
|
});
|
|
jQuery3.fn.extend({
|
|
trigger: function(type, data) {
|
|
return this.each(function() {
|
|
jQuery3.event.trigger(type, data, this);
|
|
});
|
|
},
|
|
triggerHandler: function(type, data) {
|
|
var elem = this[0];
|
|
if (elem) {
|
|
return jQuery3.event.trigger(type, data, elem, true);
|
|
}
|
|
}
|
|
});
|
|
var location2 = window2.location;
|
|
var nonce = { guid: Date.now() };
|
|
var rquery = /\?/;
|
|
jQuery3.parseXML = function(data) {
|
|
var xml, parserErrorElem;
|
|
if (!data || typeof data !== "string") {
|
|
return null;
|
|
}
|
|
try {
|
|
xml = new window2.DOMParser().parseFromString(data, "text/xml");
|
|
} catch (e) {
|
|
}
|
|
parserErrorElem = xml && xml.getElementsByTagName("parsererror")[0];
|
|
if (!xml || parserErrorElem) {
|
|
jQuery3.error("Invalid XML: " + (parserErrorElem ? jQuery3.map(parserErrorElem.childNodes, function(el2) {
|
|
return el2.textContent;
|
|
}).join("\n") : data));
|
|
}
|
|
return xml;
|
|
};
|
|
var rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i;
|
|
function buildParams(prefix, obj, traditional, add2) {
|
|
var name;
|
|
if (Array.isArray(obj)) {
|
|
jQuery3.each(obj, function(i2, v) {
|
|
if (traditional || rbracket.test(prefix)) {
|
|
add2(prefix, v);
|
|
} else {
|
|
buildParams(
|
|
prefix + "[" + (typeof v === "object" && v != null ? i2 : "") + "]",
|
|
v,
|
|
traditional,
|
|
add2
|
|
);
|
|
}
|
|
});
|
|
} else if (!traditional && toType(obj) === "object") {
|
|
for (name in obj) {
|
|
buildParams(prefix + "[" + name + "]", obj[name], traditional, add2);
|
|
}
|
|
} else {
|
|
add2(prefix, obj);
|
|
}
|
|
}
|
|
jQuery3.param = function(a, traditional) {
|
|
var prefix, s = [], add2 = function(key, valueOrFunction) {
|
|
var value = typeof valueOrFunction === "function" ? valueOrFunction() : valueOrFunction;
|
|
s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
|
|
};
|
|
if (a == null) {
|
|
return "";
|
|
}
|
|
if (Array.isArray(a) || a.jquery && !jQuery3.isPlainObject(a)) {
|
|
jQuery3.each(a, function() {
|
|
add2(this.name, this.value);
|
|
});
|
|
} else {
|
|
for (prefix in a) {
|
|
buildParams(prefix, a[prefix], traditional, add2);
|
|
}
|
|
}
|
|
return s.join("&");
|
|
};
|
|
jQuery3.fn.extend({
|
|
serialize: function() {
|
|
return jQuery3.param(this.serializeArray());
|
|
},
|
|
serializeArray: function() {
|
|
return this.map(function() {
|
|
var elements = jQuery3.prop(this, "elements");
|
|
return elements ? jQuery3.makeArray(elements) : this;
|
|
}).filter(function() {
|
|
var type = this.type;
|
|
return this.name && !jQuery3(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type));
|
|
}).map(function(_i, elem) {
|
|
var val = jQuery3(this).val();
|
|
if (val == null) {
|
|
return null;
|
|
}
|
|
if (Array.isArray(val)) {
|
|
return jQuery3.map(val, function(val2) {
|
|
return { name: elem.name, value: val2.replace(rCRLF, "\r\n") };
|
|
});
|
|
}
|
|
return { name: elem.name, value: val.replace(rCRLF, "\r\n") };
|
|
}).get();
|
|
}
|
|
});
|
|
var r20 = /%20/g, rhash = /#.*$/, rantiCache = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, prefilters = {}, transports = {}, allTypes = "*/".concat("*"), originAnchor = document$1.createElement("a");
|
|
originAnchor.href = location2.href;
|
|
function addToPrefiltersOrTransports(structure) {
|
|
return function(dataTypeExpression, func) {
|
|
if (typeof dataTypeExpression !== "string") {
|
|
func = dataTypeExpression;
|
|
dataTypeExpression = "*";
|
|
}
|
|
var dataType, i2 = 0, dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || [];
|
|
if (typeof func === "function") {
|
|
while (dataType = dataTypes[i2++]) {
|
|
if (dataType[0] === "+") {
|
|
dataType = dataType.slice(1) || "*";
|
|
(structure[dataType] = structure[dataType] || []).unshift(func);
|
|
} else {
|
|
(structure[dataType] = structure[dataType] || []).push(func);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
|
|
var inspected = {}, seekingTransport = structure === transports;
|
|
function inspect(dataType) {
|
|
var selected;
|
|
inspected[dataType] = true;
|
|
jQuery3.each(structure[dataType] || [], function(_, prefilterOrFactory) {
|
|
var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
|
|
if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
|
|
options.dataTypes.unshift(dataTypeOrTransport);
|
|
inspect(dataTypeOrTransport);
|
|
return false;
|
|
} else if (seekingTransport) {
|
|
return !(selected = dataTypeOrTransport);
|
|
}
|
|
});
|
|
return selected;
|
|
}
|
|
return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
|
|
}
|
|
function ajaxExtend(target, src) {
|
|
var key, deep, flatOptions = jQuery3.ajaxSettings.flatOptions || {};
|
|
for (key in src) {
|
|
if (src[key] !== void 0) {
|
|
(flatOptions[key] ? target : deep || (deep = {}))[key] = src[key];
|
|
}
|
|
}
|
|
if (deep) {
|
|
jQuery3.extend(true, target, deep);
|
|
}
|
|
return target;
|
|
}
|
|
function ajaxHandleResponses(s, jqXHR, responses) {
|
|
var ct, type, finalDataType, firstDataType, contents = s.contents, dataTypes = s.dataTypes;
|
|
while (dataTypes[0] === "*") {
|
|
dataTypes.shift();
|
|
if (ct === void 0) {
|
|
ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
|
|
}
|
|
}
|
|
if (ct) {
|
|
for (type in contents) {
|
|
if (contents[type] && contents[type].test(ct)) {
|
|
dataTypes.unshift(type);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (dataTypes[0] in responses) {
|
|
finalDataType = dataTypes[0];
|
|
} else {
|
|
for (type in responses) {
|
|
if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
|
|
finalDataType = type;
|
|
break;
|
|
}
|
|
if (!firstDataType) {
|
|
firstDataType = type;
|
|
}
|
|
}
|
|
finalDataType = finalDataType || firstDataType;
|
|
}
|
|
if (finalDataType) {
|
|
if (finalDataType !== dataTypes[0]) {
|
|
dataTypes.unshift(finalDataType);
|
|
}
|
|
return responses[finalDataType];
|
|
}
|
|
}
|
|
function ajaxConvert(s, response, jqXHR, isSuccess) {
|
|
var conv2, current, conv, tmp, prev, converters = {}, dataTypes = s.dataTypes.slice();
|
|
if (dataTypes[1]) {
|
|
for (conv in s.converters) {
|
|
converters[conv.toLowerCase()] = s.converters[conv];
|
|
}
|
|
}
|
|
current = dataTypes.shift();
|
|
while (current) {
|
|
if (s.responseFields[current]) {
|
|
jqXHR[s.responseFields[current]] = response;
|
|
}
|
|
if (!prev && isSuccess && s.dataFilter) {
|
|
response = s.dataFilter(response, s.dataType);
|
|
}
|
|
prev = current;
|
|
current = dataTypes.shift();
|
|
if (current) {
|
|
if (current === "*") {
|
|
current = prev;
|
|
} else if (prev !== "*" && prev !== current) {
|
|
conv = converters[prev + " " + current] || converters["* " + current];
|
|
if (!conv) {
|
|
for (conv2 in converters) {
|
|
tmp = conv2.split(" ");
|
|
if (tmp[1] === current) {
|
|
conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]];
|
|
if (conv) {
|
|
if (conv === true) {
|
|
conv = converters[conv2];
|
|
} else if (converters[conv2] !== true) {
|
|
current = tmp[0];
|
|
dataTypes.unshift(tmp[1]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (conv !== true) {
|
|
if (conv && s.throws) {
|
|
response = conv(response);
|
|
} else {
|
|
try {
|
|
response = conv(response);
|
|
} catch (e) {
|
|
return {
|
|
state: "parsererror",
|
|
error: conv ? e : "No conversion from " + prev + " to " + current
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return { state: "success", data: response };
|
|
}
|
|
jQuery3.extend({
|
|
// Counter for holding the number of active queries
|
|
active: 0,
|
|
// Last-Modified header cache for next request
|
|
lastModified: {},
|
|
etag: {},
|
|
ajaxSettings: {
|
|
url: location2.href,
|
|
type: "GET",
|
|
isLocal: rlocalProtocol.test(location2.protocol),
|
|
global: true,
|
|
processData: true,
|
|
async: true,
|
|
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
|
/*
|
|
timeout: 0,
|
|
data: null,
|
|
dataType: null,
|
|
username: null,
|
|
password: null,
|
|
cache: null,
|
|
throws: false,
|
|
traditional: false,
|
|
headers: {},
|
|
*/
|
|
accepts: {
|
|
"*": allTypes,
|
|
text: "text/plain",
|
|
html: "text/html",
|
|
xml: "application/xml, text/xml",
|
|
json: "application/json, text/javascript"
|
|
},
|
|
contents: {
|
|
xml: /\bxml\b/,
|
|
html: /\bhtml/,
|
|
json: /\bjson\b/
|
|
},
|
|
responseFields: {
|
|
xml: "responseXML",
|
|
text: "responseText",
|
|
json: "responseJSON"
|
|
},
|
|
// Data converters
|
|
// Keys separate source (or catchall "*") and destination types with a single space
|
|
converters: {
|
|
// Convert anything to text
|
|
"* text": String,
|
|
// Text to html (true = no transformation)
|
|
"text html": true,
|
|
// Evaluate text as a json expression
|
|
"text json": JSON.parse,
|
|
// Parse text as xml
|
|
"text xml": jQuery3.parseXML
|
|
},
|
|
// For options that shouldn't be deep extended:
|
|
// you can add your own custom options here if
|
|
// and when you create one that shouldn't be
|
|
// deep extended (see ajaxExtend)
|
|
flatOptions: {
|
|
url: true,
|
|
context: true
|
|
}
|
|
},
|
|
// Creates a full fledged settings object into target
|
|
// with both ajaxSettings and settings fields.
|
|
// If target is omitted, writes into ajaxSettings.
|
|
ajaxSetup: function(target, settings) {
|
|
return settings ? (
|
|
// Building a settings object
|
|
ajaxExtend(ajaxExtend(target, jQuery3.ajaxSettings), settings)
|
|
) : (
|
|
// Extending ajaxSettings
|
|
ajaxExtend(jQuery3.ajaxSettings, target)
|
|
);
|
|
},
|
|
ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
|
|
ajaxTransport: addToPrefiltersOrTransports(transports),
|
|
// Main method
|
|
ajax: function(url2, options) {
|
|
if (typeof url2 === "object") {
|
|
options = url2;
|
|
url2 = void 0;
|
|
}
|
|
options = options || {};
|
|
var transport, cacheURL, responseHeadersString, responseHeaders, timeoutTimer, urlAnchor, completed2, fireGlobals, i2, uncached, s = jQuery3.ajaxSetup({}, options), callbackContext = s.context || s, globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery3(callbackContext) : jQuery3.event, deferred = jQuery3.Deferred(), completeDeferred = jQuery3.Callbacks("once memory"), statusCode = s.statusCode || {}, requestHeaders = {}, requestHeadersNames = {}, strAbort = "canceled", jqXHR = {
|
|
readyState: 0,
|
|
// Builds headers hashtable if needed
|
|
getResponseHeader: function(key) {
|
|
var match;
|
|
if (completed2) {
|
|
if (!responseHeaders) {
|
|
responseHeaders = {};
|
|
while (match = rheaders.exec(responseHeadersString)) {
|
|
responseHeaders[match[1].toLowerCase() + " "] = (responseHeaders[match[1].toLowerCase() + " "] || []).concat(match[2]);
|
|
}
|
|
}
|
|
match = responseHeaders[key.toLowerCase() + " "];
|
|
}
|
|
return match == null ? null : match.join(", ");
|
|
},
|
|
// Raw string
|
|
getAllResponseHeaders: function() {
|
|
return completed2 ? responseHeadersString : null;
|
|
},
|
|
// Caches the header
|
|
setRequestHeader: function(name, value) {
|
|
if (completed2 == null) {
|
|
name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name;
|
|
requestHeaders[name] = value;
|
|
}
|
|
return this;
|
|
},
|
|
// Overrides response content-type header
|
|
overrideMimeType: function(type) {
|
|
if (completed2 == null) {
|
|
s.mimeType = type;
|
|
}
|
|
return this;
|
|
},
|
|
// Status-dependent callbacks
|
|
statusCode: function(map) {
|
|
var code;
|
|
if (map) {
|
|
if (completed2) {
|
|
jqXHR.always(map[jqXHR.status]);
|
|
} else {
|
|
for (code in map) {
|
|
statusCode[code] = [statusCode[code], map[code]];
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
// Cancel the request
|
|
abort: function(statusText) {
|
|
var finalText = statusText || strAbort;
|
|
if (transport) {
|
|
transport.abort(finalText);
|
|
}
|
|
done2(0, finalText);
|
|
return this;
|
|
}
|
|
};
|
|
deferred.promise(jqXHR);
|
|
s.url = ((url2 || s.url || location2.href) + "").replace(rprotocol, location2.protocol + "//");
|
|
s.type = options.method || options.type || s.method || s.type;
|
|
s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""];
|
|
if (s.crossDomain == null) {
|
|
urlAnchor = document$1.createElement("a");
|
|
try {
|
|
urlAnchor.href = s.url;
|
|
urlAnchor.href = urlAnchor.href;
|
|
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
|
|
} catch (e) {
|
|
s.crossDomain = true;
|
|
}
|
|
}
|
|
inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
|
|
if (s.data && s.processData && typeof s.data !== "string") {
|
|
s.data = jQuery3.param(s.data, s.traditional);
|
|
}
|
|
if (completed2) {
|
|
return jqXHR;
|
|
}
|
|
fireGlobals = jQuery3.event && s.global;
|
|
if (fireGlobals && jQuery3.active++ === 0) {
|
|
jQuery3.event.trigger("ajaxStart");
|
|
}
|
|
s.type = s.type.toUpperCase();
|
|
s.hasContent = !rnoContent.test(s.type);
|
|
cacheURL = s.url.replace(rhash, "");
|
|
if (!s.hasContent) {
|
|
uncached = s.url.slice(cacheURL.length);
|
|
if (s.data && (s.processData || typeof s.data === "string")) {
|
|
cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data;
|
|
delete s.data;
|
|
}
|
|
if (s.cache === false) {
|
|
cacheURL = cacheURL.replace(rantiCache, "$1");
|
|
uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce.guid++ + uncached;
|
|
}
|
|
s.url = cacheURL + uncached;
|
|
} else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) {
|
|
s.data = s.data.replace(r20, "+");
|
|
}
|
|
if (s.ifModified) {
|
|
if (jQuery3.lastModified[cacheURL]) {
|
|
jqXHR.setRequestHeader("If-Modified-Since", jQuery3.lastModified[cacheURL]);
|
|
}
|
|
if (jQuery3.etag[cacheURL]) {
|
|
jqXHR.setRequestHeader("If-None-Match", jQuery3.etag[cacheURL]);
|
|
}
|
|
}
|
|
if (s.data && s.hasContent && s.contentType !== false || options.contentType) {
|
|
jqXHR.setRequestHeader("Content-Type", s.contentType);
|
|
}
|
|
jqXHR.setRequestHeader(
|
|
"Accept",
|
|
s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]
|
|
);
|
|
for (i2 in s.headers) {
|
|
jqXHR.setRequestHeader(i2, s.headers[i2]);
|
|
}
|
|
if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed2)) {
|
|
return jqXHR.abort();
|
|
}
|
|
strAbort = "abort";
|
|
completeDeferred.add(s.complete);
|
|
jqXHR.done(s.success);
|
|
jqXHR.fail(s.error);
|
|
transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
|
|
if (!transport) {
|
|
done2(-1, "No Transport");
|
|
} else {
|
|
jqXHR.readyState = 1;
|
|
if (fireGlobals) {
|
|
globalEventContext.trigger("ajaxSend", [jqXHR, s]);
|
|
}
|
|
if (completed2) {
|
|
return jqXHR;
|
|
}
|
|
if (s.async && s.timeout > 0) {
|
|
timeoutTimer = window2.setTimeout(function() {
|
|
jqXHR.abort("timeout");
|
|
}, s.timeout);
|
|
}
|
|
try {
|
|
completed2 = false;
|
|
transport.send(requestHeaders, done2);
|
|
} catch (e) {
|
|
if (completed2) {
|
|
throw e;
|
|
}
|
|
done2(-1, e);
|
|
}
|
|
}
|
|
function done2(status, nativeStatusText, responses, headers) {
|
|
var isSuccess, success, error2, response, modified, statusText = nativeStatusText;
|
|
if (completed2) {
|
|
return;
|
|
}
|
|
completed2 = true;
|
|
if (timeoutTimer) {
|
|
window2.clearTimeout(timeoutTimer);
|
|
}
|
|
transport = void 0;
|
|
responseHeadersString = headers || "";
|
|
jqXHR.readyState = status > 0 ? 4 : 0;
|
|
isSuccess = status >= 200 && status < 300 || status === 304;
|
|
if (responses) {
|
|
response = ajaxHandleResponses(s, jqXHR, responses);
|
|
}
|
|
if (!isSuccess && jQuery3.inArray("script", s.dataTypes) > -1 && jQuery3.inArray("json", s.dataTypes) < 0) {
|
|
s.converters["text script"] = function() {
|
|
};
|
|
}
|
|
response = ajaxConvert(s, response, jqXHR, isSuccess);
|
|
if (isSuccess) {
|
|
if (s.ifModified) {
|
|
modified = jqXHR.getResponseHeader("Last-Modified");
|
|
if (modified) {
|
|
jQuery3.lastModified[cacheURL] = modified;
|
|
}
|
|
modified = jqXHR.getResponseHeader("etag");
|
|
if (modified) {
|
|
jQuery3.etag[cacheURL] = modified;
|
|
}
|
|
}
|
|
if (status === 204 || s.type === "HEAD") {
|
|
statusText = "nocontent";
|
|
} else if (status === 304) {
|
|
statusText = "notmodified";
|
|
} else {
|
|
statusText = response.state;
|
|
success = response.data;
|
|
error2 = response.error;
|
|
isSuccess = !error2;
|
|
}
|
|
} else {
|
|
error2 = statusText;
|
|
if (status || !statusText) {
|
|
statusText = "error";
|
|
if (status < 0) {
|
|
status = 0;
|
|
}
|
|
}
|
|
}
|
|
jqXHR.status = status;
|
|
jqXHR.statusText = (nativeStatusText || statusText) + "";
|
|
if (isSuccess) {
|
|
deferred.resolveWith(callbackContext, [success, statusText, jqXHR]);
|
|
} else {
|
|
deferred.rejectWith(callbackContext, [jqXHR, statusText, error2]);
|
|
}
|
|
jqXHR.statusCode(statusCode);
|
|
statusCode = void 0;
|
|
if (fireGlobals) {
|
|
globalEventContext.trigger(
|
|
isSuccess ? "ajaxSuccess" : "ajaxError",
|
|
[jqXHR, s, isSuccess ? success : error2]
|
|
);
|
|
}
|
|
completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
|
|
if (fireGlobals) {
|
|
globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
|
|
if (!--jQuery3.active) {
|
|
jQuery3.event.trigger("ajaxStop");
|
|
}
|
|
}
|
|
}
|
|
return jqXHR;
|
|
},
|
|
getJSON: function(url2, data, callback) {
|
|
return jQuery3.get(url2, data, callback, "json");
|
|
},
|
|
getScript: function(url2, callback) {
|
|
return jQuery3.get(url2, void 0, callback, "script");
|
|
}
|
|
});
|
|
jQuery3.each(["get", "post"], function(_i, method) {
|
|
jQuery3[method] = function(url2, data, callback, type) {
|
|
if (typeof data === "function" || data === null) {
|
|
type = type || callback;
|
|
callback = data;
|
|
data = void 0;
|
|
}
|
|
return jQuery3.ajax(jQuery3.extend({
|
|
url: url2,
|
|
type: method,
|
|
dataType: type,
|
|
data,
|
|
success: callback
|
|
}, jQuery3.isPlainObject(url2) && url2));
|
|
};
|
|
});
|
|
jQuery3.ajaxPrefilter(function(s) {
|
|
var i2;
|
|
for (i2 in s.headers) {
|
|
if (i2.toLowerCase() === "content-type") {
|
|
s.contentType = s.headers[i2] || "";
|
|
}
|
|
}
|
|
});
|
|
jQuery3._evalUrl = function(url2, options, doc) {
|
|
return jQuery3.ajax({
|
|
url: url2,
|
|
// Make this explicit, since user can override this through ajaxSetup (trac-11264)
|
|
type: "GET",
|
|
dataType: "script",
|
|
cache: true,
|
|
async: false,
|
|
global: false,
|
|
scriptAttrs: options.crossOrigin ? { "crossOrigin": options.crossOrigin } : void 0,
|
|
// Only evaluate the response if it is successful (gh-4126)
|
|
// dataFilter is not invoked for failure responses, so using it instead
|
|
// of the default converter is kludgy but it works.
|
|
converters: {
|
|
"text script": function() {
|
|
}
|
|
},
|
|
dataFilter: function(response) {
|
|
jQuery3.globalEval(response, options, doc);
|
|
}
|
|
});
|
|
};
|
|
jQuery3.fn.extend({
|
|
wrapAll: function(html) {
|
|
var wrap;
|
|
if (this[0]) {
|
|
if (typeof html === "function") {
|
|
html = html.call(this[0]);
|
|
}
|
|
wrap = jQuery3(html, this[0].ownerDocument).eq(0).clone(true);
|
|
if (this[0].parentNode) {
|
|
wrap.insertBefore(this[0]);
|
|
}
|
|
wrap.map(function() {
|
|
var elem = this;
|
|
while (elem.firstElementChild) {
|
|
elem = elem.firstElementChild;
|
|
}
|
|
return elem;
|
|
}).append(this);
|
|
}
|
|
return this;
|
|
},
|
|
wrapInner: function(html) {
|
|
if (typeof html === "function") {
|
|
return this.each(function(i2) {
|
|
jQuery3(this).wrapInner(html.call(this, i2));
|
|
});
|
|
}
|
|
return this.each(function() {
|
|
var self2 = jQuery3(this), contents = self2.contents();
|
|
if (contents.length) {
|
|
contents.wrapAll(html);
|
|
} else {
|
|
self2.append(html);
|
|
}
|
|
});
|
|
},
|
|
wrap: function(html) {
|
|
var htmlIsFunction = typeof html === "function";
|
|
return this.each(function(i2) {
|
|
jQuery3(this).wrapAll(htmlIsFunction ? html.call(this, i2) : html);
|
|
});
|
|
},
|
|
unwrap: function(selector) {
|
|
this.parent(selector).not("body").each(function() {
|
|
jQuery3(this).replaceWith(this.childNodes);
|
|
});
|
|
return this;
|
|
}
|
|
});
|
|
jQuery3.expr.pseudos.hidden = function(elem) {
|
|
return !jQuery3.expr.pseudos.visible(elem);
|
|
};
|
|
jQuery3.expr.pseudos.visible = function(elem) {
|
|
return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
|
|
};
|
|
jQuery3.ajaxSettings.xhr = function() {
|
|
return new window2.XMLHttpRequest();
|
|
};
|
|
var xhrSuccessStatus = {
|
|
// File protocol always yields status code 0, assume 200
|
|
0: 200
|
|
};
|
|
jQuery3.ajaxTransport(function(options) {
|
|
var callback;
|
|
return {
|
|
send: function(headers, complete) {
|
|
var i2, xhr = options.xhr();
|
|
xhr.open(
|
|
options.type,
|
|
options.url,
|
|
options.async,
|
|
options.username,
|
|
options.password
|
|
);
|
|
if (options.xhrFields) {
|
|
for (i2 in options.xhrFields) {
|
|
xhr[i2] = options.xhrFields[i2];
|
|
}
|
|
}
|
|
if (options.mimeType && xhr.overrideMimeType) {
|
|
xhr.overrideMimeType(options.mimeType);
|
|
}
|
|
if (!options.crossDomain && !headers["X-Requested-With"]) {
|
|
headers["X-Requested-With"] = "XMLHttpRequest";
|
|
}
|
|
for (i2 in headers) {
|
|
xhr.setRequestHeader(i2, headers[i2]);
|
|
}
|
|
callback = function(type) {
|
|
return function() {
|
|
if (callback) {
|
|
callback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = null;
|
|
if (type === "abort") {
|
|
xhr.abort();
|
|
} else if (type === "error") {
|
|
complete(
|
|
// File: protocol always yields status 0; see trac-8605, trac-14207
|
|
xhr.status,
|
|
xhr.statusText
|
|
);
|
|
} else {
|
|
complete(
|
|
xhrSuccessStatus[xhr.status] || xhr.status,
|
|
xhr.statusText,
|
|
// For XHR2 non-text, let the caller handle it (gh-2498)
|
|
(xhr.responseType || "text") === "text" ? { text: xhr.responseText } : { binary: xhr.response },
|
|
xhr.getAllResponseHeaders()
|
|
);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
xhr.onload = callback();
|
|
xhr.onabort = xhr.onerror = xhr.ontimeout = callback("error");
|
|
callback = callback("abort");
|
|
try {
|
|
xhr.send(options.hasContent && options.data || null);
|
|
} catch (e) {
|
|
if (callback) {
|
|
throw e;
|
|
}
|
|
}
|
|
},
|
|
abort: function() {
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
});
|
|
function canUseScriptTag(s) {
|
|
return s.scriptAttrs || !s.headers && (s.crossDomain || // When dealing with JSONP (`s.dataTypes` include "json" then)
|
|
// don't use a script tag so that error responses still may have
|
|
// `responseJSON` set. Continue using a script tag for JSONP requests that:
|
|
// * are cross-domain as AJAX requests won't work without a CORS setup
|
|
// * have `scriptAttrs` set as that's a script-only functionality
|
|
// Note that this means JSONP requests violate strict CSP script-src settings.
|
|
// A proper solution is to migrate from using JSONP to a CORS setup.
|
|
s.async && jQuery3.inArray("json", s.dataTypes) < 0);
|
|
}
|
|
jQuery3.ajaxSetup({
|
|
accepts: {
|
|
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
|
|
},
|
|
converters: {
|
|
"text script": function(text) {
|
|
jQuery3.globalEval(text);
|
|
return text;
|
|
}
|
|
}
|
|
});
|
|
jQuery3.ajaxPrefilter("script", function(s) {
|
|
if (s.cache === void 0) {
|
|
s.cache = false;
|
|
}
|
|
if (canUseScriptTag(s)) {
|
|
s.type = "GET";
|
|
}
|
|
});
|
|
jQuery3.ajaxTransport("script", function(s) {
|
|
if (canUseScriptTag(s)) {
|
|
var script, callback;
|
|
return {
|
|
send: function(_, complete) {
|
|
script = jQuery3("<script>").attr(s.scriptAttrs || {}).prop({ charset: s.scriptCharset, src: s.url }).on("load error", callback = function(evt) {
|
|
script.remove();
|
|
callback = null;
|
|
if (evt) {
|
|
complete(evt.type === "error" ? 404 : 200, evt.type);
|
|
}
|
|
});
|
|
document$1.head.appendChild(script[0]);
|
|
},
|
|
abort: function() {
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
var oldCallbacks = [], rjsonp = /(=)\?(?=&|$)|\?\?/;
|
|
jQuery3.ajaxSetup({
|
|
jsonp: "callback",
|
|
jsonpCallback: function() {
|
|
var callback = oldCallbacks.pop() || jQuery3.expando + "_" + nonce.guid++;
|
|
this[callback] = true;
|
|
return callback;
|
|
}
|
|
});
|
|
jQuery3.ajaxPrefilter("jsonp", function(s, originalSettings, jqXHR) {
|
|
var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0 && rjsonp.test(s.data) && "data");
|
|
callbackName = s.jsonpCallback = typeof s.jsonpCallback === "function" ? s.jsonpCallback() : s.jsonpCallback;
|
|
if (jsonProp) {
|
|
s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
|
|
} else if (s.jsonp !== false) {
|
|
s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
|
|
}
|
|
s.converters["script json"] = function() {
|
|
if (!responseContainer) {
|
|
jQuery3.error(callbackName + " was not called");
|
|
}
|
|
return responseContainer[0];
|
|
};
|
|
s.dataTypes[0] = "json";
|
|
overwritten = window2[callbackName];
|
|
window2[callbackName] = function() {
|
|
responseContainer = arguments;
|
|
};
|
|
jqXHR.always(function() {
|
|
if (overwritten === void 0) {
|
|
jQuery3(window2).removeProp(callbackName);
|
|
} else {
|
|
window2[callbackName] = overwritten;
|
|
}
|
|
if (s[callbackName]) {
|
|
s.jsonpCallback = originalSettings.jsonpCallback;
|
|
oldCallbacks.push(callbackName);
|
|
}
|
|
if (responseContainer && typeof overwritten === "function") {
|
|
overwritten(responseContainer[0]);
|
|
}
|
|
responseContainer = overwritten = void 0;
|
|
});
|
|
return "script";
|
|
});
|
|
jQuery3.ajaxPrefilter(function(s, origOptions) {
|
|
if (typeof s.data !== "string" && !jQuery3.isPlainObject(s.data) && !Array.isArray(s.data) && // Don't disable data processing if explicitly set by the user.
|
|
!("processData" in origOptions)) {
|
|
s.processData = false;
|
|
}
|
|
if (s.data instanceof window2.FormData) {
|
|
s.contentType = false;
|
|
}
|
|
});
|
|
jQuery3.parseHTML = function(data, context, keepScripts) {
|
|
if (typeof data !== "string" && !isObviousHtml(data + "")) {
|
|
return [];
|
|
}
|
|
if (typeof context === "boolean") {
|
|
keepScripts = context;
|
|
context = false;
|
|
}
|
|
var parsed, scripts;
|
|
if (!context) {
|
|
context = new window2.DOMParser().parseFromString("", "text/html");
|
|
}
|
|
parsed = rsingleTag.exec(data);
|
|
scripts = !keepScripts && [];
|
|
if (parsed) {
|
|
return [context.createElement(parsed[1])];
|
|
}
|
|
parsed = buildFragment([data], context, scripts);
|
|
if (scripts && scripts.length) {
|
|
jQuery3(scripts).remove();
|
|
}
|
|
return jQuery3.merge([], parsed.childNodes);
|
|
};
|
|
jQuery3.fn.load = function(url2, params, callback) {
|
|
var selector, type, response, self2 = this, off = url2.indexOf(" ");
|
|
if (off > -1) {
|
|
selector = stripAndCollapse(url2.slice(off));
|
|
url2 = url2.slice(0, off);
|
|
}
|
|
if (typeof params === "function") {
|
|
callback = params;
|
|
params = void 0;
|
|
} else if (params && typeof params === "object") {
|
|
type = "POST";
|
|
}
|
|
if (self2.length > 0) {
|
|
jQuery3.ajax({
|
|
url: url2,
|
|
// If "type" variable is undefined, then "GET" method will be used.
|
|
// Make value of this field explicit since
|
|
// user can override it through ajaxSetup method
|
|
type: type || "GET",
|
|
dataType: "html",
|
|
data: params
|
|
}).done(function(responseText) {
|
|
response = arguments;
|
|
self2.html(selector ? (
|
|
// If a selector was specified, locate the right elements in a dummy div
|
|
// Exclude scripts to avoid IE 'Permission Denied' errors
|
|
jQuery3("<div>").append(jQuery3.parseHTML(responseText)).find(selector)
|
|
) : (
|
|
// Otherwise use the full result
|
|
responseText
|
|
));
|
|
}).always(callback && function(jqXHR, status) {
|
|
self2.each(function() {
|
|
callback.apply(this, response || [jqXHR.responseText, status, jqXHR]);
|
|
});
|
|
});
|
|
}
|
|
return this;
|
|
};
|
|
jQuery3.expr.pseudos.animated = function(elem) {
|
|
return jQuery3.grep(jQuery3.timers, function(fn) {
|
|
return elem === fn.elem;
|
|
}).length;
|
|
};
|
|
jQuery3.offset = {
|
|
setOffset: function(elem, options, i2) {
|
|
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = jQuery3.css(elem, "position"), curElem = jQuery3(elem), props = {};
|
|
if (position === "static") {
|
|
elem.style.position = "relative";
|
|
}
|
|
curOffset = curElem.offset();
|
|
curCSSTop = jQuery3.css(elem, "top");
|
|
curCSSLeft = jQuery3.css(elem, "left");
|
|
calculatePosition = (position === "absolute" || position === "fixed") && (curCSSTop + curCSSLeft).indexOf("auto") > -1;
|
|
if (calculatePosition) {
|
|
curPosition = curElem.position();
|
|
curTop = curPosition.top;
|
|
curLeft = curPosition.left;
|
|
} else {
|
|
curTop = parseFloat(curCSSTop) || 0;
|
|
curLeft = parseFloat(curCSSLeft) || 0;
|
|
}
|
|
if (typeof options === "function") {
|
|
options = options.call(elem, i2, jQuery3.extend({}, curOffset));
|
|
}
|
|
if (options.top != null) {
|
|
props.top = options.top - curOffset.top + curTop;
|
|
}
|
|
if (options.left != null) {
|
|
props.left = options.left - curOffset.left + curLeft;
|
|
}
|
|
if ("using" in options) {
|
|
options.using.call(elem, props);
|
|
} else {
|
|
curElem.css(props);
|
|
}
|
|
}
|
|
};
|
|
jQuery3.fn.extend({
|
|
// offset() relates an element's border box to the document origin
|
|
offset: function(options) {
|
|
if (arguments.length) {
|
|
return options === void 0 ? this : this.each(function(i2) {
|
|
jQuery3.offset.setOffset(this, options, i2);
|
|
});
|
|
}
|
|
var rect, win, elem = this[0];
|
|
if (!elem) {
|
|
return;
|
|
}
|
|
if (!elem.getClientRects().length) {
|
|
return { top: 0, left: 0 };
|
|
}
|
|
rect = elem.getBoundingClientRect();
|
|
win = elem.ownerDocument.defaultView;
|
|
return {
|
|
top: rect.top + win.pageYOffset,
|
|
left: rect.left + win.pageXOffset
|
|
};
|
|
},
|
|
// position() relates an element's margin box to its offset parent's padding box
|
|
// This corresponds to the behavior of CSS absolute positioning
|
|
position: function() {
|
|
if (!this[0]) {
|
|
return;
|
|
}
|
|
var offsetParent, offset, doc, elem = this[0], parentOffset = { top: 0, left: 0 };
|
|
if (jQuery3.css(elem, "position") === "fixed") {
|
|
offset = elem.getBoundingClientRect();
|
|
} else {
|
|
offset = this.offset();
|
|
doc = elem.ownerDocument;
|
|
offsetParent = elem.offsetParent || doc.documentElement;
|
|
while (offsetParent && offsetParent !== doc.documentElement && jQuery3.css(offsetParent, "position") === "static") {
|
|
offsetParent = offsetParent.offsetParent || doc.documentElement;
|
|
}
|
|
if (offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 && jQuery3.css(offsetParent, "position") !== "static") {
|
|
parentOffset = jQuery3(offsetParent).offset();
|
|
parentOffset.top += jQuery3.css(offsetParent, "borderTopWidth", true);
|
|
parentOffset.left += jQuery3.css(offsetParent, "borderLeftWidth", true);
|
|
}
|
|
}
|
|
return {
|
|
top: offset.top - parentOffset.top - jQuery3.css(elem, "marginTop", true),
|
|
left: offset.left - parentOffset.left - jQuery3.css(elem, "marginLeft", true)
|
|
};
|
|
},
|
|
// This method will return documentElement in the following cases:
|
|
// 1) For the element inside the iframe without offsetParent, this method will return
|
|
// documentElement of the parent window
|
|
// 2) For the hidden or detached element
|
|
// 3) For body or html element, i.e. in case of the html node - it will return itself
|
|
//
|
|
// but those exceptions were never presented as a real life use-cases
|
|
// and might be considered as more preferable results.
|
|
//
|
|
// This logic, however, is not guaranteed and can change at any point in the future
|
|
offsetParent: function() {
|
|
return this.map(function() {
|
|
var offsetParent = this.offsetParent;
|
|
while (offsetParent && jQuery3.css(offsetParent, "position") === "static") {
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
return offsetParent || documentElement$1;
|
|
});
|
|
}
|
|
});
|
|
jQuery3.each({ scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function(method, prop) {
|
|
var top = "pageYOffset" === prop;
|
|
jQuery3.fn[method] = function(val) {
|
|
return access(this, function(elem, method2, val2) {
|
|
var win;
|
|
if (isWindow(elem)) {
|
|
win = elem;
|
|
} else if (elem.nodeType === 9) {
|
|
win = elem.defaultView;
|
|
}
|
|
if (val2 === void 0) {
|
|
return win ? win[prop] : elem[method2];
|
|
}
|
|
if (win) {
|
|
win.scrollTo(
|
|
!top ? val2 : win.pageXOffset,
|
|
top ? val2 : win.pageYOffset
|
|
);
|
|
} else {
|
|
elem[method2] = val2;
|
|
}
|
|
}, method, val, arguments.length);
|
|
};
|
|
});
|
|
jQuery3.each({ Height: "height", Width: "width" }, function(name, type) {
|
|
jQuery3.each({
|
|
padding: "inner" + name,
|
|
content: type,
|
|
"": "outer" + name
|
|
}, function(defaultExtra, funcName) {
|
|
jQuery3.fn[funcName] = function(margin, value) {
|
|
var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"), extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
|
|
return access(this, function(elem, type2, value2) {
|
|
var doc;
|
|
if (isWindow(elem)) {
|
|
return funcName.indexOf("outer") === 0 ? elem["inner" + name] : elem.document.documentElement["client" + name];
|
|
}
|
|
if (elem.nodeType === 9) {
|
|
doc = elem.documentElement;
|
|
return Math.max(
|
|
elem.body["scroll" + name],
|
|
doc["scroll" + name],
|
|
elem.body["offset" + name],
|
|
doc["offset" + name],
|
|
doc["client" + name]
|
|
);
|
|
}
|
|
return value2 === void 0 ? (
|
|
// Get width or height on the element, requesting but not forcing parseFloat
|
|
jQuery3.css(elem, type2, extra)
|
|
) : (
|
|
// Set width or height on the element
|
|
jQuery3.style(elem, type2, value2, extra)
|
|
);
|
|
}, type, chainable ? margin : void 0, chainable);
|
|
};
|
|
});
|
|
});
|
|
jQuery3.each([
|
|
"ajaxStart",
|
|
"ajaxStop",
|
|
"ajaxComplete",
|
|
"ajaxError",
|
|
"ajaxSuccess",
|
|
"ajaxSend"
|
|
], function(_i, type) {
|
|
jQuery3.fn[type] = function(fn) {
|
|
return this.on(type, fn);
|
|
};
|
|
});
|
|
jQuery3.fn.extend({
|
|
bind: function(types, data, fn) {
|
|
return this.on(types, null, data, fn);
|
|
},
|
|
unbind: function(types, fn) {
|
|
return this.off(types, null, fn);
|
|
},
|
|
delegate: function(selector, types, data, fn) {
|
|
return this.on(types, selector, data, fn);
|
|
},
|
|
undelegate: function(selector, types, fn) {
|
|
return arguments.length === 1 ? this.off(selector, "**") : this.off(types, selector || "**", fn);
|
|
},
|
|
hover: function(fnOver, fnOut) {
|
|
return this.on("mouseenter", fnOver).on("mouseleave", fnOut || fnOver);
|
|
}
|
|
});
|
|
jQuery3.each(
|
|
"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),
|
|
function(_i, name) {
|
|
jQuery3.fn[name] = function(data, fn) {
|
|
return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
|
|
};
|
|
}
|
|
);
|
|
jQuery3.proxy = function(fn, context) {
|
|
var tmp, args, proxy;
|
|
if (typeof context === "string") {
|
|
tmp = fn[context];
|
|
context = fn;
|
|
fn = tmp;
|
|
}
|
|
if (typeof fn !== "function") {
|
|
return void 0;
|
|
}
|
|
args = slice.call(arguments, 2);
|
|
proxy = function() {
|
|
return fn.apply(context || this, args.concat(slice.call(arguments)));
|
|
};
|
|
proxy.guid = fn.guid = fn.guid || jQuery3.guid++;
|
|
return proxy;
|
|
};
|
|
jQuery3.holdReady = function(hold) {
|
|
if (hold) {
|
|
jQuery3.readyWait++;
|
|
} else {
|
|
jQuery3.ready(true);
|
|
}
|
|
};
|
|
jQuery3.expr[":"] = jQuery3.expr.filters = jQuery3.expr.pseudos;
|
|
if (typeof define === "function" && define.amd) {
|
|
define("jquery", [], function() {
|
|
return jQuery3;
|
|
});
|
|
}
|
|
var _jQuery = window2.jQuery, _$ = window2.$;
|
|
jQuery3.noConflict = function(deep) {
|
|
if (window2.$ === jQuery3) {
|
|
window2.$ = _$;
|
|
}
|
|
if (deep && window2.jQuery === jQuery3) {
|
|
window2.jQuery = _jQuery;
|
|
}
|
|
return jQuery3;
|
|
};
|
|
if (typeof noGlobal === "undefined") {
|
|
window2.jQuery = window2.$ = jQuery3;
|
|
}
|
|
return jQuery3;
|
|
});
|
|
}
|
|
});
|
|
|
|
// ui/js/iframeResizer.js
|
|
var require_iframeResizer = __commonJS({
|
|
"ui/js/iframeResizer.js"(exports, module) {
|
|
"use strict";
|
|
(function(undefined2) {
|
|
if (typeof window === "undefined") return;
|
|
var count = 0, logEnabled = false, hiddenCheckEnabled = false, msgHeader = "message", msgHeaderLen = msgHeader.length, msgId = "[iFrameSizer]", msgIdLen = msgId.length, pagePosition = null, requestAnimationFrame2 = window.requestAnimationFrame, resetRequiredMethods = Object.freeze({
|
|
max: 1,
|
|
scroll: 1,
|
|
bodyScroll: 1,
|
|
documentElementScroll: 1
|
|
}), settings = {}, timer2 = null, defaults = Object.freeze({
|
|
autoResize: true,
|
|
bodyBackground: null,
|
|
bodyMargin: null,
|
|
bodyMarginV1: 8,
|
|
bodyPadding: null,
|
|
checkOrigin: true,
|
|
inPageLinks: false,
|
|
enablePublicMethods: true,
|
|
heightCalculationMethod: "bodyOffset",
|
|
id: "iFrameResizer",
|
|
interval: 32,
|
|
log: false,
|
|
maxHeight: Infinity,
|
|
maxWidth: Infinity,
|
|
minHeight: 0,
|
|
minWidth: 0,
|
|
mouseEvents: true,
|
|
resizeFrom: "parent",
|
|
scrolling: false,
|
|
sizeHeight: true,
|
|
sizeWidth: false,
|
|
warningTimeout: 5e3,
|
|
tolerance: 0,
|
|
widthCalculationMethod: "scroll",
|
|
onClose: function() {
|
|
return true;
|
|
},
|
|
onClosed: function() {
|
|
},
|
|
onInit: function() {
|
|
},
|
|
onMessage: function() {
|
|
warn("onMessage function not defined");
|
|
},
|
|
onMouseEnter: function() {
|
|
},
|
|
onMouseLeave: function() {
|
|
},
|
|
onResized: function() {
|
|
},
|
|
onScroll: function() {
|
|
return true;
|
|
}
|
|
});
|
|
function getMutationObserver() {
|
|
return window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
|
|
}
|
|
function addEventListener2(el2, evt, func) {
|
|
el2.addEventListener(evt, func, false);
|
|
}
|
|
function removeEventListener(el2, evt, func) {
|
|
el2.removeEventListener(evt, func, false);
|
|
}
|
|
function setupRequestAnimationFrame() {
|
|
var vendors = ["moz", "webkit", "o", "ms"];
|
|
var x;
|
|
for (x = 0; x < vendors.length && !requestAnimationFrame2; x += 1) {
|
|
requestAnimationFrame2 = window[vendors[x] + "RequestAnimationFrame"];
|
|
}
|
|
if (requestAnimationFrame2) {
|
|
requestAnimationFrame2 = requestAnimationFrame2.bind(window);
|
|
} else {
|
|
log2("setup", "RequestAnimationFrame not supported");
|
|
}
|
|
}
|
|
function getMyID(iframeId) {
|
|
var retStr = "Host page: " + iframeId;
|
|
if (window.top !== window.self) {
|
|
retStr = window.parentIFrame && window.parentIFrame.getId ? window.parentIFrame.getId() + ": " + iframeId : "Nested host page: " + iframeId;
|
|
}
|
|
return retStr;
|
|
}
|
|
function formatLogHeader(iframeId) {
|
|
return msgId + "[" + getMyID(iframeId) + "]";
|
|
}
|
|
function isLogEnabled(iframeId) {
|
|
return settings[iframeId] ? settings[iframeId].log : logEnabled;
|
|
}
|
|
function log2(iframeId, msg) {
|
|
output("log", iframeId, msg, isLogEnabled(iframeId));
|
|
}
|
|
function info(iframeId, msg) {
|
|
output("info", iframeId, msg, isLogEnabled(iframeId));
|
|
}
|
|
function warn(iframeId, msg) {
|
|
output("warn", iframeId, msg, true);
|
|
}
|
|
function output(type, iframeId, msg, enabled) {
|
|
if (true === enabled && "object" === typeof window.console) {
|
|
console[type](formatLogHeader(iframeId), msg);
|
|
}
|
|
}
|
|
function iFrameListener(event2) {
|
|
function resizeIFrame() {
|
|
function resize() {
|
|
setSize(messageData);
|
|
setPagePosition(iframeId);
|
|
on("onResized", messageData);
|
|
}
|
|
ensureInRange("Height");
|
|
ensureInRange("Width");
|
|
syncResize(resize, messageData, "init");
|
|
}
|
|
function processMsg() {
|
|
var data = msg.slice(msgIdLen).split(":");
|
|
var height = data[1] ? parseInt(data[1], 10) : 0;
|
|
var iframe = settings[data[0]] && settings[data[0]].iframe;
|
|
var compStyle = getComputedStyle(iframe);
|
|
return {
|
|
iframe,
|
|
id: data[0],
|
|
height: height + getPaddingEnds(compStyle) + getBorderEnds(compStyle),
|
|
width: data[2],
|
|
type: data[3]
|
|
};
|
|
}
|
|
function getPaddingEnds(compStyle) {
|
|
if (compStyle.boxSizing !== "border-box") {
|
|
return 0;
|
|
}
|
|
var top = compStyle.paddingTop ? parseInt(compStyle.paddingTop, 10) : 0;
|
|
var bot = compStyle.paddingBottom ? parseInt(compStyle.paddingBottom, 10) : 0;
|
|
return top + bot;
|
|
}
|
|
function getBorderEnds(compStyle) {
|
|
if (compStyle.boxSizing !== "border-box") {
|
|
return 0;
|
|
}
|
|
var top = compStyle.borderTopWidth ? parseInt(compStyle.borderTopWidth, 10) : 0;
|
|
var bot = compStyle.borderBottomWidth ? parseInt(compStyle.borderBottomWidth, 10) : 0;
|
|
return top + bot;
|
|
}
|
|
function ensureInRange(Dimension) {
|
|
var max = Number(settings[iframeId]["max" + Dimension]), min = Number(settings[iframeId]["min" + Dimension]), dimension = Dimension.toLowerCase(), size = Number(messageData[dimension]);
|
|
log2(iframeId, "Checking " + dimension + " is in range " + min + "-" + max);
|
|
if (size < min) {
|
|
size = min;
|
|
log2(iframeId, "Set " + dimension + " to min value");
|
|
}
|
|
if (size > max) {
|
|
size = max;
|
|
log2(iframeId, "Set " + dimension + " to max value");
|
|
}
|
|
messageData[dimension] = "" + size;
|
|
}
|
|
function isMessageFromIFrame() {
|
|
function checkAllowedOrigin() {
|
|
function checkList() {
|
|
var i = 0, retCode = false;
|
|
log2(
|
|
iframeId,
|
|
"Checking connection is from allowed list of origins: " + checkOrigin
|
|
);
|
|
for (; i < checkOrigin.length; i++) {
|
|
if (checkOrigin[i] === origin) {
|
|
retCode = true;
|
|
break;
|
|
}
|
|
}
|
|
return retCode;
|
|
}
|
|
function checkSingle() {
|
|
var remoteHost = settings[iframeId] && settings[iframeId].remoteHost;
|
|
log2(iframeId, "Checking connection is from: " + remoteHost);
|
|
return origin === remoteHost;
|
|
}
|
|
return checkOrigin.constructor === Array ? checkList() : checkSingle();
|
|
}
|
|
var origin = event2.origin, checkOrigin = settings[iframeId] && settings[iframeId].checkOrigin;
|
|
if (checkOrigin && "" + origin !== "null" && !checkAllowedOrigin()) {
|
|
throw new Error(
|
|
"Unexpected message received from: " + origin + " for " + messageData.iframe.id + ". Message was: " + event2.data + ". This error can be disabled by setting the checkOrigin: false option or by providing of array of trusted domains."
|
|
);
|
|
}
|
|
return true;
|
|
}
|
|
function isMessageForUs() {
|
|
return msgId === ("" + msg).slice(0, msgIdLen) && msg.slice(msgIdLen).split(":")[0] in settings;
|
|
}
|
|
function isMessageFromMetaParent() {
|
|
var retCode = messageData.type in { true: 1, false: 1, undefined: 1 };
|
|
if (retCode) {
|
|
log2(iframeId, "Ignoring init message from meta parent page");
|
|
}
|
|
return retCode;
|
|
}
|
|
function getMsgBody(offset) {
|
|
return msg.slice(msg.indexOf(":") + msgHeaderLen + offset);
|
|
}
|
|
function forwardMsgFromIFrame(msgBody) {
|
|
log2(
|
|
iframeId,
|
|
"onMessage passed: {iframe: " + messageData.iframe.id + ", message: " + msgBody + "}"
|
|
);
|
|
on("onMessage", {
|
|
iframe: messageData.iframe,
|
|
message: JSON.parse(msgBody)
|
|
});
|
|
log2(iframeId, "--");
|
|
}
|
|
function getPageInfo() {
|
|
var bodyPosition = document.body.getBoundingClientRect(), iFramePosition = messageData.iframe.getBoundingClientRect();
|
|
return JSON.stringify({
|
|
iframeHeight: iFramePosition.height,
|
|
iframeWidth: iFramePosition.width,
|
|
clientHeight: Math.max(
|
|
document.documentElement.clientHeight,
|
|
window.innerHeight || 0
|
|
),
|
|
clientWidth: Math.max(
|
|
document.documentElement.clientWidth,
|
|
window.innerWidth || 0
|
|
),
|
|
offsetTop: parseInt(iFramePosition.top - bodyPosition.top, 10),
|
|
offsetLeft: parseInt(iFramePosition.left - bodyPosition.left, 10),
|
|
scrollTop: window.pageYOffset,
|
|
scrollLeft: window.pageXOffset,
|
|
documentHeight: document.documentElement.clientHeight,
|
|
documentWidth: document.documentElement.clientWidth,
|
|
windowHeight: window.innerHeight,
|
|
windowWidth: window.innerWidth
|
|
});
|
|
}
|
|
function sendPageInfoToIframe(iframe, iframeId2) {
|
|
function debouncedTrigger() {
|
|
trigger("Send Page Info", "pageInfo:" + getPageInfo(), iframe, iframeId2);
|
|
}
|
|
debounceFrameEvents(debouncedTrigger, 32, iframeId2);
|
|
}
|
|
function startPageInfoMonitor() {
|
|
function setListener(type, func) {
|
|
function sendPageInfo() {
|
|
if (settings[id]) {
|
|
sendPageInfoToIframe(settings[id].iframe, id);
|
|
} else {
|
|
stop();
|
|
}
|
|
}
|
|
;
|
|
["scroll", "resize"].forEach(function(evt) {
|
|
log2(id, type + evt + " listener for sendPageInfo");
|
|
func(window, evt, sendPageInfo);
|
|
});
|
|
}
|
|
function stop() {
|
|
setListener("Remove ", removeEventListener);
|
|
}
|
|
function start() {
|
|
setListener("Add ", addEventListener2);
|
|
}
|
|
var id = iframeId;
|
|
start();
|
|
if (settings[id]) {
|
|
settings[id].stopPageInfo = stop;
|
|
}
|
|
}
|
|
function stopPageInfoMonitor() {
|
|
if (settings[iframeId] && settings[iframeId].stopPageInfo) {
|
|
settings[iframeId].stopPageInfo();
|
|
delete settings[iframeId].stopPageInfo;
|
|
}
|
|
}
|
|
function checkIFrameExists() {
|
|
var retBool = true;
|
|
if (null === messageData.iframe) {
|
|
warn(iframeId, "IFrame (" + messageData.id + ") not found");
|
|
retBool = false;
|
|
}
|
|
return retBool;
|
|
}
|
|
function getElementPosition(target) {
|
|
var iFramePosition = target.getBoundingClientRect();
|
|
getPagePosition(iframeId);
|
|
return {
|
|
x: Math.floor(Number(iFramePosition.left) + Number(pagePosition.x)),
|
|
y: Math.floor(Number(iFramePosition.top) + Number(pagePosition.y))
|
|
};
|
|
}
|
|
function scrollRequestFromChild(addOffset) {
|
|
function reposition() {
|
|
pagePosition = newPosition;
|
|
scrollTo();
|
|
log2(iframeId, "--");
|
|
}
|
|
function calcOffset() {
|
|
return {
|
|
x: Number(messageData.width) + offset.x,
|
|
y: Number(messageData.height) + offset.y
|
|
};
|
|
}
|
|
function scrollParent() {
|
|
if (window.parentIFrame) {
|
|
window.parentIFrame["scrollTo" + (addOffset ? "Offset" : "")](
|
|
newPosition.x,
|
|
newPosition.y
|
|
);
|
|
} else {
|
|
warn(
|
|
iframeId,
|
|
"Unable to scroll to requested position, window.parentIFrame not found"
|
|
);
|
|
}
|
|
}
|
|
var offset = addOffset ? getElementPosition(messageData.iframe) : { x: 0, y: 0 }, newPosition = calcOffset();
|
|
log2(
|
|
iframeId,
|
|
"Reposition requested from iFrame (offset x:" + offset.x + " y:" + offset.y + ")"
|
|
);
|
|
if (window.top === window.self) {
|
|
reposition();
|
|
} else {
|
|
scrollParent();
|
|
}
|
|
}
|
|
function scrollTo() {
|
|
if (false === on("onScroll", pagePosition)) {
|
|
unsetPagePosition();
|
|
} else {
|
|
setPagePosition(iframeId);
|
|
}
|
|
}
|
|
function findTarget(location2) {
|
|
function jumpToTarget() {
|
|
var jumpPosition = getElementPosition(target);
|
|
log2(
|
|
iframeId,
|
|
"Moving to in page link (#" + hash3 + ") at x: " + jumpPosition.x + " y: " + jumpPosition.y
|
|
);
|
|
pagePosition = {
|
|
x: jumpPosition.x,
|
|
y: jumpPosition.y
|
|
};
|
|
scrollTo();
|
|
log2(iframeId, "--");
|
|
}
|
|
function jumpToParent() {
|
|
if (window.parentIFrame) {
|
|
window.parentIFrame.moveToAnchor(hash3);
|
|
} else {
|
|
log2(
|
|
iframeId,
|
|
"In page link #" + hash3 + " not found and window.parentIFrame not found"
|
|
);
|
|
}
|
|
}
|
|
var hash3 = location2.split("#")[1] || "", hashData = decodeURIComponent(hash3), target = document.getElementById(hashData) || document.getElementsByName(hashData)[0];
|
|
if (target) {
|
|
jumpToTarget();
|
|
} else if (window.top === window.self) {
|
|
log2(iframeId, "In page link #" + hash3 + " not found");
|
|
} else {
|
|
jumpToParent();
|
|
}
|
|
}
|
|
function onMouse(event3) {
|
|
var mousePos = {};
|
|
if (Number(messageData.width) === 0 && Number(messageData.height) === 0) {
|
|
var data = getMsgBody(9).split(":");
|
|
mousePos = {
|
|
x: data[1],
|
|
y: data[0]
|
|
};
|
|
} else {
|
|
mousePos = {
|
|
x: messageData.width,
|
|
y: messageData.height
|
|
};
|
|
}
|
|
on(event3, {
|
|
iframe: messageData.iframe,
|
|
screenX: Number(mousePos.x),
|
|
screenY: Number(mousePos.y),
|
|
type: messageData.type
|
|
});
|
|
}
|
|
function on(funcName, val) {
|
|
return chkEvent(iframeId, funcName, val);
|
|
}
|
|
function actionMsg() {
|
|
if (settings[iframeId] && settings[iframeId].firstRun) firstRun();
|
|
switch (messageData.type) {
|
|
case "close": {
|
|
closeIFrame(messageData.iframe);
|
|
break;
|
|
}
|
|
case "message": {
|
|
forwardMsgFromIFrame(getMsgBody(6));
|
|
break;
|
|
}
|
|
case "mouseenter": {
|
|
onMouse("onMouseEnter");
|
|
break;
|
|
}
|
|
case "mouseleave": {
|
|
onMouse("onMouseLeave");
|
|
break;
|
|
}
|
|
case "autoResize": {
|
|
settings[iframeId].autoResize = JSON.parse(getMsgBody(9));
|
|
break;
|
|
}
|
|
case "scrollTo": {
|
|
scrollRequestFromChild(false);
|
|
break;
|
|
}
|
|
case "scrollToOffset": {
|
|
scrollRequestFromChild(true);
|
|
break;
|
|
}
|
|
case "pageInfo": {
|
|
sendPageInfoToIframe(
|
|
settings[iframeId] && settings[iframeId].iframe,
|
|
iframeId
|
|
);
|
|
startPageInfoMonitor();
|
|
break;
|
|
}
|
|
case "pageInfoStop": {
|
|
stopPageInfoMonitor();
|
|
break;
|
|
}
|
|
case "inPageLink": {
|
|
findTarget(getMsgBody(9));
|
|
break;
|
|
}
|
|
case "reset": {
|
|
resetIFrame(messageData);
|
|
break;
|
|
}
|
|
case "init": {
|
|
resizeIFrame();
|
|
on("onInit", messageData.iframe);
|
|
break;
|
|
}
|
|
default: {
|
|
if (Number(messageData.width) === 0 && Number(messageData.height) === 0) {
|
|
warn(
|
|
"Unsupported message received (" + messageData.type + "), this is likely due to the iframe containing a later version of iframe-resizer than the parent page"
|
|
);
|
|
} else {
|
|
resizeIFrame();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function hasSettings(iframeId2) {
|
|
var retBool = true;
|
|
if (!settings[iframeId2]) {
|
|
retBool = false;
|
|
warn(
|
|
messageData.type + " No settings for " + iframeId2 + ". Message was: " + msg
|
|
);
|
|
}
|
|
return retBool;
|
|
}
|
|
function iFrameReadyMsgReceived() {
|
|
for (var iframeId2 in settings) {
|
|
trigger(
|
|
"iFrame requested init",
|
|
createOutgoingMsg(iframeId2),
|
|
settings[iframeId2].iframe,
|
|
iframeId2
|
|
);
|
|
}
|
|
}
|
|
function firstRun() {
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].firstRun = false;
|
|
}
|
|
}
|
|
var msg = event2.data, messageData = {}, iframeId = null;
|
|
if ("[iFrameResizerChild]Ready" === msg) {
|
|
iFrameReadyMsgReceived();
|
|
} else if (isMessageForUs()) {
|
|
messageData = processMsg();
|
|
iframeId = messageData.id;
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].loaded = true;
|
|
}
|
|
if (!isMessageFromMetaParent() && hasSettings(iframeId)) {
|
|
log2(iframeId, "Received: " + msg);
|
|
if (checkIFrameExists() && isMessageFromIFrame()) {
|
|
actionMsg();
|
|
}
|
|
}
|
|
} else {
|
|
info(iframeId, "Ignored: " + msg);
|
|
}
|
|
}
|
|
function chkEvent(iframeId, funcName, val) {
|
|
var func = null, retVal = null;
|
|
if (settings[iframeId]) {
|
|
func = settings[iframeId][funcName];
|
|
if ("function" === typeof func) {
|
|
retVal = func(val);
|
|
} else {
|
|
throw new TypeError(
|
|
funcName + " on iFrame[" + iframeId + "] is not a function"
|
|
);
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
function removeIframeListeners(iframe) {
|
|
var iframeId = iframe.id;
|
|
delete settings[iframeId];
|
|
}
|
|
function closeIFrame(iframe) {
|
|
var iframeId = iframe.id;
|
|
if (chkEvent(iframeId, "onClose", iframeId) === false) {
|
|
log2(iframeId, "Close iframe cancelled by onClose event");
|
|
return;
|
|
}
|
|
log2(iframeId, "Removing iFrame: " + iframeId);
|
|
try {
|
|
if (iframe.parentNode) {
|
|
iframe.parentNode.removeChild(iframe);
|
|
}
|
|
} catch (error2) {
|
|
warn(error2);
|
|
}
|
|
chkEvent(iframeId, "onClosed", iframeId);
|
|
log2(iframeId, "--");
|
|
removeIframeListeners(iframe);
|
|
}
|
|
function getPagePosition(iframeId) {
|
|
if (null === pagePosition) {
|
|
pagePosition = {
|
|
x: window.pageXOffset === undefined2 ? document.documentElement.scrollLeft : window.pageXOffset,
|
|
y: window.pageYOffset === undefined2 ? document.documentElement.scrollTop : window.pageYOffset
|
|
};
|
|
log2(
|
|
iframeId,
|
|
"Get page position: " + pagePosition.x + "," + pagePosition.y
|
|
);
|
|
}
|
|
}
|
|
function setPagePosition(iframeId) {
|
|
if (null !== pagePosition) {
|
|
window.scrollTo(pagePosition.x, pagePosition.y);
|
|
log2(
|
|
iframeId,
|
|
"Set page position: " + pagePosition.x + "," + pagePosition.y
|
|
);
|
|
unsetPagePosition();
|
|
}
|
|
}
|
|
function unsetPagePosition() {
|
|
pagePosition = null;
|
|
}
|
|
function resetIFrame(messageData) {
|
|
function reset() {
|
|
setSize(messageData);
|
|
trigger("reset", "reset", messageData.iframe, messageData.id);
|
|
}
|
|
log2(
|
|
messageData.id,
|
|
"Size reset requested by " + ("init" === messageData.type ? "host page" : "iFrame")
|
|
);
|
|
getPagePosition(messageData.id);
|
|
syncResize(reset, messageData, "reset");
|
|
}
|
|
function setSize(messageData) {
|
|
function setDimension(dimension) {
|
|
if (!messageData.id) {
|
|
log2("undefined", "messageData id not set");
|
|
return;
|
|
}
|
|
messageData.iframe.style[dimension] = messageData[dimension] + "px";
|
|
log2(
|
|
messageData.id,
|
|
"IFrame (" + iframeId + ") " + dimension + " set to " + messageData[dimension] + "px"
|
|
);
|
|
}
|
|
function chkZero(dimension) {
|
|
if (!hiddenCheckEnabled && "0" === messageData[dimension]) {
|
|
hiddenCheckEnabled = true;
|
|
log2(iframeId, "Hidden iFrame detected, creating visibility listener");
|
|
fixHiddenIFrames();
|
|
}
|
|
}
|
|
function processDimension(dimension) {
|
|
setDimension(dimension);
|
|
chkZero(dimension);
|
|
}
|
|
var iframeId = messageData.iframe.id;
|
|
if (settings[iframeId]) {
|
|
if (settings[iframeId].sizeHeight) {
|
|
processDimension("height");
|
|
}
|
|
if (settings[iframeId].sizeWidth) {
|
|
processDimension("width");
|
|
}
|
|
}
|
|
}
|
|
function syncResize(func, messageData, doNotSync) {
|
|
if (doNotSync !== messageData.type && requestAnimationFrame2 && // including check for jasmine because had trouble getting spy to work in unit test using requestAnimationFrame
|
|
!window.jasmine) {
|
|
log2(messageData.id, "Requesting animation frame");
|
|
requestAnimationFrame2(func);
|
|
} else {
|
|
func();
|
|
}
|
|
}
|
|
function trigger(calleeMsg, msg, iframe, id, noResponseWarning) {
|
|
function postMessageToIFrame() {
|
|
var target = settings[id] && settings[id].targetOrigin;
|
|
log2(
|
|
id,
|
|
"[" + calleeMsg + "] Sending msg to iframe[" + id + "] (" + msg + ") targetOrigin: " + target
|
|
);
|
|
iframe.contentWindow.postMessage(msgId + msg, target);
|
|
}
|
|
function iFrameNotFound() {
|
|
warn(id, "[" + calleeMsg + "] IFrame(" + id + ") not found");
|
|
}
|
|
function chkAndSend() {
|
|
if (iframe && "contentWindow" in iframe && null !== iframe.contentWindow) {
|
|
postMessageToIFrame();
|
|
} else {
|
|
iFrameNotFound();
|
|
}
|
|
}
|
|
function warnOnNoResponse() {
|
|
function warning() {
|
|
if (settings[id] && !settings[id].loaded && !errorShown) {
|
|
errorShown = true;
|
|
warn(
|
|
id,
|
|
"IFrame has not responded within " + settings[id].warningTimeout / 1e3 + " seconds. Check iFrameResizer.contentWindow.js has been loaded in iFrame. This message can be ignored if everything is working, or you can set the warningTimeout option to a higher value or zero to suppress this warning."
|
|
);
|
|
}
|
|
}
|
|
if (!!noResponseWarning && settings[id] && !!settings[id].warningTimeout) {
|
|
settings[id].msgTimeout = setTimeout(
|
|
warning,
|
|
settings[id].warningTimeout
|
|
);
|
|
}
|
|
}
|
|
var errorShown = false;
|
|
id = id || iframe.id;
|
|
if (settings[id]) {
|
|
chkAndSend();
|
|
warnOnNoResponse();
|
|
}
|
|
}
|
|
function createOutgoingMsg(iframeId) {
|
|
return iframeId + ":" + settings[iframeId].bodyMarginV1 + ":" + settings[iframeId].sizeWidth + ":" + settings[iframeId].log + ":" + settings[iframeId].interval + ":" + settings[iframeId].enablePublicMethods + ":" + settings[iframeId].autoResize + ":" + settings[iframeId].bodyMargin + ":" + settings[iframeId].heightCalculationMethod + ":" + settings[iframeId].bodyBackground + ":" + settings[iframeId].bodyPadding + ":" + settings[iframeId].tolerance + ":" + settings[iframeId].inPageLinks + ":" + settings[iframeId].resizeFrom + ":" + settings[iframeId].widthCalculationMethod + ":" + settings[iframeId].mouseEvents;
|
|
}
|
|
function isNumber(value) {
|
|
return typeof value === "number";
|
|
}
|
|
function setupIFrame(iframe, options) {
|
|
function setLimits() {
|
|
function addStyle(style) {
|
|
var styleValue = settings[iframeId][style];
|
|
if (Infinity !== styleValue && 0 !== styleValue) {
|
|
iframe.style[style] = isNumber(styleValue) ? styleValue + "px" : styleValue;
|
|
log2(iframeId, "Set " + style + " = " + iframe.style[style]);
|
|
}
|
|
}
|
|
function chkMinMax(dimension) {
|
|
if (settings[iframeId]["min" + dimension] > settings[iframeId]["max" + dimension]) {
|
|
throw new Error(
|
|
"Value for min" + dimension + " can not be greater than max" + dimension
|
|
);
|
|
}
|
|
}
|
|
chkMinMax("Height");
|
|
chkMinMax("Width");
|
|
addStyle("maxHeight");
|
|
addStyle("minHeight");
|
|
addStyle("maxWidth");
|
|
addStyle("minWidth");
|
|
}
|
|
function newId() {
|
|
var id = options && options.id || defaults.id + count++;
|
|
if (null !== document.getElementById(id)) {
|
|
id += count++;
|
|
}
|
|
return id;
|
|
}
|
|
function ensureHasId(iframeId2) {
|
|
if (typeof iframeId2 !== "string") {
|
|
throw new TypeError("Invaild id for iFrame. Expected String");
|
|
}
|
|
if ("" === iframeId2) {
|
|
iframe.id = iframeId2 = newId();
|
|
logEnabled = (options || {}).log;
|
|
log2(
|
|
iframeId2,
|
|
"Added missing iframe ID: " + iframeId2 + " (" + iframe.src + ")"
|
|
);
|
|
}
|
|
return iframeId2;
|
|
}
|
|
function setScrolling() {
|
|
log2(
|
|
iframeId,
|
|
"IFrame scrolling " + (settings[iframeId] && settings[iframeId].scrolling ? "enabled" : "disabled") + " for " + iframeId
|
|
);
|
|
iframe.style.overflow = false === (settings[iframeId] && settings[iframeId].scrolling) ? "hidden" : "auto";
|
|
switch (settings[iframeId] && settings[iframeId].scrolling) {
|
|
case "omit": {
|
|
break;
|
|
}
|
|
case true: {
|
|
iframe.scrolling = "yes";
|
|
break;
|
|
}
|
|
case false: {
|
|
iframe.scrolling = "no";
|
|
break;
|
|
}
|
|
default: {
|
|
iframe.scrolling = settings[iframeId] ? settings[iframeId].scrolling : "no";
|
|
}
|
|
}
|
|
}
|
|
function setupBodyMarginValues() {
|
|
if ("number" === typeof (settings[iframeId] && settings[iframeId].bodyMargin) || "0" === (settings[iframeId] && settings[iframeId].bodyMargin)) {
|
|
settings[iframeId].bodyMarginV1 = settings[iframeId].bodyMargin;
|
|
settings[iframeId].bodyMargin = "" + settings[iframeId].bodyMargin + "px";
|
|
}
|
|
}
|
|
function checkReset() {
|
|
var firstRun = settings[iframeId] && settings[iframeId].firstRun, resetRequertMethod = settings[iframeId] && settings[iframeId].heightCalculationMethod in resetRequiredMethods;
|
|
if (!firstRun && resetRequertMethod) {
|
|
resetIFrame({ iframe, height: 0, width: 0, type: "init" });
|
|
}
|
|
}
|
|
function setupIFrameObject() {
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].iframe.iFrameResizer = {
|
|
close: closeIFrame.bind(null, settings[iframeId].iframe),
|
|
removeListeners: removeIframeListeners.bind(
|
|
null,
|
|
settings[iframeId].iframe
|
|
),
|
|
resize: trigger.bind(
|
|
null,
|
|
"Window resize",
|
|
"resize",
|
|
settings[iframeId].iframe
|
|
),
|
|
moveToAnchor: function(anchor) {
|
|
trigger(
|
|
"Move to anchor",
|
|
"moveToAnchor:" + anchor,
|
|
settings[iframeId].iframe,
|
|
iframeId
|
|
);
|
|
},
|
|
sendMessage: function(message) {
|
|
message = JSON.stringify(message);
|
|
trigger(
|
|
"Send Message",
|
|
"message:" + message,
|
|
settings[iframeId].iframe,
|
|
iframeId
|
|
);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
function init(msg) {
|
|
function iFrameLoaded() {
|
|
trigger("iFrame.onload", msg, iframe, undefined2, true);
|
|
checkReset();
|
|
}
|
|
function createDestroyObserver(MutationObserver3) {
|
|
if (!iframe.parentNode) {
|
|
return;
|
|
}
|
|
var destroyObserver = new MutationObserver3(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
var removedNodes = Array.prototype.slice.call(mutation.removedNodes);
|
|
removedNodes.forEach(function(removedNode) {
|
|
if (removedNode === iframe) {
|
|
closeIFrame(iframe);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
destroyObserver.observe(iframe.parentNode, {
|
|
childList: true
|
|
});
|
|
}
|
|
var MutationObserver2 = getMutationObserver();
|
|
if (MutationObserver2) {
|
|
createDestroyObserver(MutationObserver2);
|
|
}
|
|
addEventListener2(iframe, "load", iFrameLoaded);
|
|
trigger("init", msg, iframe, undefined2, true);
|
|
}
|
|
function checkOptions(options2) {
|
|
if ("object" !== typeof options2) {
|
|
throw new TypeError("Options is not an object");
|
|
}
|
|
}
|
|
function copyOptions(options2) {
|
|
for (var option in defaults) {
|
|
if (Object.prototype.hasOwnProperty.call(defaults, option)) {
|
|
settings[iframeId][option] = Object.prototype.hasOwnProperty.call(
|
|
options2,
|
|
option
|
|
) ? options2[option] : defaults[option];
|
|
}
|
|
}
|
|
}
|
|
function getTargetOrigin(remoteHost) {
|
|
return "" === remoteHost || null !== remoteHost.match(/^(about:blank|javascript:|file:\/\/)/) ? "*" : remoteHost;
|
|
}
|
|
function deprecate(key) {
|
|
var splitName = key.split("Callback");
|
|
if (splitName.length === 2) {
|
|
var name = "on" + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1);
|
|
this[name] = this[key];
|
|
delete this[key];
|
|
warn(
|
|
iframeId,
|
|
"Deprecated: '" + key + "' has been renamed '" + name + "'. The old method will be removed in the next major version."
|
|
);
|
|
}
|
|
}
|
|
function processOptions(options2) {
|
|
options2 = options2 || {};
|
|
settings[iframeId] = /* @__PURE__ */ Object.create(null);
|
|
settings[iframeId].iframe = iframe;
|
|
settings[iframeId].firstRun = true;
|
|
settings[iframeId].remoteHost = iframe.src && iframe.src.split("/").slice(0, 3).join("/");
|
|
checkOptions(options2);
|
|
Object.keys(options2).forEach(deprecate, options2);
|
|
copyOptions(options2);
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].targetOrigin = true === settings[iframeId].checkOrigin ? getTargetOrigin(settings[iframeId].remoteHost) : "*";
|
|
}
|
|
}
|
|
function beenHere() {
|
|
return iframeId in settings && "iFrameResizer" in iframe;
|
|
}
|
|
var iframeId = ensureHasId(iframe.id);
|
|
if (beenHere()) {
|
|
warn(iframeId, "Ignored iFrame, already setup.");
|
|
} else {
|
|
processOptions(options);
|
|
setScrolling();
|
|
setLimits();
|
|
setupBodyMarginValues();
|
|
init(createOutgoingMsg(iframeId));
|
|
setupIFrameObject();
|
|
}
|
|
}
|
|
function debounce(fn, time) {
|
|
if (null === timer2) {
|
|
timer2 = setTimeout(function() {
|
|
timer2 = null;
|
|
fn();
|
|
}, time);
|
|
}
|
|
}
|
|
var frameTimer = {};
|
|
function debounceFrameEvents(fn, time, frameId) {
|
|
if (!frameTimer[frameId]) {
|
|
frameTimer[frameId] = setTimeout(function() {
|
|
frameTimer[frameId] = null;
|
|
fn();
|
|
}, time);
|
|
}
|
|
}
|
|
function fixHiddenIFrames() {
|
|
function checkIFrames() {
|
|
function checkIFrame(settingId) {
|
|
function chkDimension(dimension) {
|
|
return "0px" === (settings[settingId] && settings[settingId].iframe.style[dimension]);
|
|
}
|
|
function isVisible2(el2) {
|
|
return null !== el2.offsetParent;
|
|
}
|
|
if (settings[settingId] && isVisible2(settings[settingId].iframe) && (chkDimension("height") || chkDimension("width"))) {
|
|
trigger(
|
|
"Visibility change",
|
|
"resize",
|
|
settings[settingId].iframe,
|
|
settingId
|
|
);
|
|
}
|
|
}
|
|
Object.keys(settings).forEach(function(key) {
|
|
checkIFrame(key);
|
|
});
|
|
}
|
|
function mutationObserved(mutations) {
|
|
log2(
|
|
"window",
|
|
"Mutation observed: " + mutations[0].target + " " + mutations[0].type
|
|
);
|
|
debounce(checkIFrames, 16);
|
|
}
|
|
function createMutationObserver() {
|
|
var target = document.querySelector("body"), config = {
|
|
attributes: true,
|
|
attributeOldValue: false,
|
|
characterData: true,
|
|
characterDataOldValue: false,
|
|
childList: true,
|
|
subtree: true
|
|
}, observer = new MutationObserver2(mutationObserved);
|
|
observer.observe(target, config);
|
|
}
|
|
var MutationObserver2 = getMutationObserver();
|
|
if (MutationObserver2) {
|
|
createMutationObserver();
|
|
}
|
|
}
|
|
function resizeIFrames(event2) {
|
|
function resize() {
|
|
sendTriggerMsg("Window " + event2, "resize");
|
|
}
|
|
log2("window", "Trigger event: " + event2);
|
|
debounce(resize, 16);
|
|
}
|
|
function tabVisible() {
|
|
function resize() {
|
|
sendTriggerMsg("Tab Visible", "resize");
|
|
}
|
|
if ("hidden" !== document.visibilityState) {
|
|
log2("document", "Trigger event: Visibility change");
|
|
debounce(resize, 16);
|
|
}
|
|
}
|
|
function sendTriggerMsg(eventName, event2) {
|
|
function isIFrameResizeEnabled(iframeId) {
|
|
return settings[iframeId] && "parent" === settings[iframeId].resizeFrom && settings[iframeId].autoResize && !settings[iframeId].firstRun;
|
|
}
|
|
Object.keys(settings).forEach(function(iframeId) {
|
|
if (isIFrameResizeEnabled(iframeId)) {
|
|
trigger(eventName, event2, settings[iframeId].iframe, iframeId);
|
|
}
|
|
});
|
|
}
|
|
function setupEventListeners() {
|
|
addEventListener2(window, "message", iFrameListener);
|
|
addEventListener2(window, "resize", function() {
|
|
resizeIFrames("resize");
|
|
});
|
|
addEventListener2(document, "visibilitychange", tabVisible);
|
|
addEventListener2(document, "-webkit-visibilitychange", tabVisible);
|
|
}
|
|
function factory() {
|
|
function init(options, element) {
|
|
function chkType() {
|
|
if (!element.tagName) {
|
|
throw new TypeError("Object is not a valid DOM element");
|
|
} else if ("IFRAME" !== element.tagName.toUpperCase()) {
|
|
throw new TypeError(
|
|
"Expected <IFRAME> tag, found <" + element.tagName + ">"
|
|
);
|
|
}
|
|
}
|
|
if (element) {
|
|
chkType();
|
|
setupIFrame(element, options);
|
|
iFrames.push(element);
|
|
}
|
|
}
|
|
function warnDeprecatedOptions(options) {
|
|
if (options && options.enablePublicMethods) {
|
|
warn(
|
|
"enablePublicMethods option has been removed, public methods are now always available in the iFrame"
|
|
);
|
|
}
|
|
}
|
|
var iFrames;
|
|
setupRequestAnimationFrame();
|
|
setupEventListeners();
|
|
return function iFrameResizeF(options, target) {
|
|
iFrames = [];
|
|
warnDeprecatedOptions(options);
|
|
switch (typeof target) {
|
|
case "undefined":
|
|
case "string": {
|
|
Array.prototype.forEach.call(
|
|
document.querySelectorAll(target || "iframe"),
|
|
init.bind(undefined2, options)
|
|
);
|
|
break;
|
|
}
|
|
case "object": {
|
|
init(options, target);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new TypeError("Unexpected data type (" + typeof target + ")");
|
|
}
|
|
}
|
|
return iFrames;
|
|
};
|
|
}
|
|
function createJQueryPublicMethod($2) {
|
|
if (!$2.fn) {
|
|
info("", "Unable to bind to jQuery, it is not fully loaded.");
|
|
} else if (!$2.fn.iFrameResize) {
|
|
$2.fn.iFrameResize = function $iFrameResizeF(options) {
|
|
function init(index, element) {
|
|
setupIFrame(element, options);
|
|
}
|
|
return this.filter("iframe").each(init).end();
|
|
};
|
|
}
|
|
}
|
|
if (window.jQuery !== undefined2) {
|
|
createJQueryPublicMethod(window.jQuery);
|
|
}
|
|
if (typeof define === "function" && define.amd) {
|
|
define([], factory);
|
|
} else if (typeof module === "object" && typeof module.exports === "object") {
|
|
module.exports = factory();
|
|
}
|
|
window.iFrameResize = window.iFrameResize || factory();
|
|
})();
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/exifr@7.1.3/node_modules/exifr/dist/full.umd.js
|
|
var require_full_umd = __commonJS({
|
|
"node_modules/.pnpm/exifr@7.1.3/node_modules/exifr/dist/full.umd.js"(exports, module) {
|
|
!(function(e, t) {
|
|
"object" == typeof exports && "undefined" != typeof module ? t(exports) : "function" == typeof define && define.amd ? define("exifr", ["exports"], t) : t((e = "undefined" != typeof globalThis ? globalThis : e || self).exifr = {});
|
|
})(exports, (function(e) {
|
|
"use strict";
|
|
var t = "undefined" != typeof self ? self : global;
|
|
const i = "undefined" != typeof navigator, n = i && "undefined" == typeof HTMLImageElement, s = !("undefined" == typeof global || "undefined" == typeof process || !process.versions || !process.versions.node), r = t.Buffer, a = t.BigInt, o = !!r, l = (e2) => e2;
|
|
function h(e2, t2 = l) {
|
|
if (s) try {
|
|
return "function" == typeof __require ? Promise.resolve(t2(__require(e2))) : import(
|
|
/* webpackIgnore: true */
|
|
e2
|
|
).then(t2);
|
|
} catch (t3) {
|
|
console.warn(`Couldn't load ${e2}`);
|
|
}
|
|
}
|
|
let u = t.fetch;
|
|
const c = (e2) => u = e2;
|
|
if (!t.fetch) {
|
|
const e2 = h("http", ((e3) => e3)), t2 = h("https", ((e3) => e3)), i2 = (n2, { headers: s2 } = {}) => new Promise((async (r2, a2) => {
|
|
let { port: o2, hostname: l2, pathname: h2, protocol: u2, search: c2 } = new URL(n2);
|
|
const f2 = { method: "GET", hostname: l2, path: encodeURI(h2) + c2, headers: s2 };
|
|
"" !== o2 && (f2.port = Number(o2));
|
|
const d2 = ("https:" === u2 ? await t2 : await e2).request(f2, ((e3) => {
|
|
if (301 === e3.statusCode || 302 === e3.statusCode) {
|
|
let t3 = new URL(e3.headers.location, n2).toString();
|
|
return i2(t3, { headers: s2 }).then(r2).catch(a2);
|
|
}
|
|
r2({ status: e3.statusCode, arrayBuffer: () => new Promise(((t3) => {
|
|
let i3 = [];
|
|
e3.on("data", ((e4) => i3.push(e4))), e3.on("end", (() => t3(Buffer.concat(i3))));
|
|
})) });
|
|
}));
|
|
d2.on("error", a2), d2.end();
|
|
}));
|
|
c(i2);
|
|
}
|
|
function f(e2, t2, i2) {
|
|
return t2 in e2 ? Object.defineProperty(e2, t2, { value: i2, enumerable: true, configurable: true, writable: true }) : e2[t2] = i2, e2;
|
|
}
|
|
const d = (e2) => g(e2) ? void 0 : e2, p = (e2) => void 0 !== e2;
|
|
function g(e2) {
|
|
return void 0 === e2 || (e2 instanceof Map ? 0 === e2.size : 0 === Object.values(e2).filter(p).length);
|
|
}
|
|
function m(e2) {
|
|
let t2 = new Error(e2);
|
|
throw delete t2.stack, t2;
|
|
}
|
|
function S(e2) {
|
|
return "" === (e2 = (function(e3) {
|
|
for (; e3.endsWith("\0"); ) e3 = e3.slice(0, -1);
|
|
return e3;
|
|
})(e2).trim()) ? void 0 : e2;
|
|
}
|
|
function C(e2) {
|
|
let t2 = (function(e3) {
|
|
let t3 = 0;
|
|
return e3.ifd0.enabled && (t3 += 1024), e3.exif.enabled && (t3 += 2048), e3.makerNote && (t3 += 2048), e3.userComment && (t3 += 1024), e3.gps.enabled && (t3 += 512), e3.interop.enabled && (t3 += 100), e3.ifd1.enabled && (t3 += 1024), t3 + 2048;
|
|
})(e2);
|
|
return e2.jfif.enabled && (t2 += 50), e2.xmp.enabled && (t2 += 2e4), e2.iptc.enabled && (t2 += 14e3), e2.icc.enabled && (t2 += 6e3), t2;
|
|
}
|
|
const y = (e2) => String.fromCharCode.apply(null, e2), b = "undefined" != typeof TextDecoder ? new TextDecoder("utf-8") : void 0;
|
|
function P(e2) {
|
|
return b ? b.decode(e2) : o ? Buffer.from(e2).toString("utf8") : decodeURIComponent(escape(y(e2)));
|
|
}
|
|
class I {
|
|
static from(e2, t2) {
|
|
return e2 instanceof this && e2.le === t2 ? e2 : new I(e2, void 0, void 0, t2);
|
|
}
|
|
constructor(e2, t2 = 0, i2, n2) {
|
|
if ("boolean" == typeof n2 && (this.le = n2), Array.isArray(e2) && (e2 = new Uint8Array(e2)), 0 === e2) this.byteOffset = 0, this.byteLength = 0;
|
|
else if (e2 instanceof ArrayBuffer) {
|
|
void 0 === i2 && (i2 = e2.byteLength - t2);
|
|
let n3 = new DataView(e2, t2, i2);
|
|
this._swapDataView(n3);
|
|
} else if (e2 instanceof Uint8Array || e2 instanceof DataView || e2 instanceof I) {
|
|
void 0 === i2 && (i2 = e2.byteLength - t2), (t2 += e2.byteOffset) + i2 > e2.byteOffset + e2.byteLength && m("Creating view outside of available memory in ArrayBuffer");
|
|
let n3 = new DataView(e2.buffer, t2, i2);
|
|
this._swapDataView(n3);
|
|
} else if ("number" == typeof e2) {
|
|
let t3 = new DataView(new ArrayBuffer(e2));
|
|
this._swapDataView(t3);
|
|
} else m("Invalid input argument for BufferView: " + e2);
|
|
}
|
|
_swapArrayBuffer(e2) {
|
|
this._swapDataView(new DataView(e2));
|
|
}
|
|
_swapBuffer(e2) {
|
|
this._swapDataView(new DataView(e2.buffer, e2.byteOffset, e2.byteLength));
|
|
}
|
|
_swapDataView(e2) {
|
|
this.dataView = e2, this.buffer = e2.buffer, this.byteOffset = e2.byteOffset, this.byteLength = e2.byteLength;
|
|
}
|
|
_lengthToEnd(e2) {
|
|
return this.byteLength - e2;
|
|
}
|
|
set(e2, t2, i2 = I) {
|
|
return e2 instanceof DataView || e2 instanceof I ? e2 = new Uint8Array(e2.buffer, e2.byteOffset, e2.byteLength) : e2 instanceof ArrayBuffer && (e2 = new Uint8Array(e2)), e2 instanceof Uint8Array || m("BufferView.set(): Invalid data argument."), this.toUint8().set(e2, t2), new i2(this, t2, e2.byteLength);
|
|
}
|
|
subarray(e2, t2) {
|
|
return t2 = t2 || this._lengthToEnd(e2), new I(this, e2, t2);
|
|
}
|
|
toUint8() {
|
|
return new Uint8Array(this.buffer, this.byteOffset, this.byteLength);
|
|
}
|
|
getUint8Array(e2, t2) {
|
|
return new Uint8Array(this.buffer, this.byteOffset + e2, t2);
|
|
}
|
|
getString(e2 = 0, t2 = this.byteLength) {
|
|
return P(this.getUint8Array(e2, t2));
|
|
}
|
|
getLatin1String(e2 = 0, t2 = this.byteLength) {
|
|
let i2 = this.getUint8Array(e2, t2);
|
|
return y(i2);
|
|
}
|
|
getUnicodeString(e2 = 0, t2 = this.byteLength) {
|
|
const i2 = [];
|
|
for (let n2 = 0; n2 < t2 && e2 + n2 < this.byteLength; n2 += 2) i2.push(this.getUint16(e2 + n2));
|
|
return y(i2);
|
|
}
|
|
getInt8(e2) {
|
|
return this.dataView.getInt8(e2);
|
|
}
|
|
getUint8(e2) {
|
|
return this.dataView.getUint8(e2);
|
|
}
|
|
getInt16(e2, t2 = this.le) {
|
|
return this.dataView.getInt16(e2, t2);
|
|
}
|
|
getInt32(e2, t2 = this.le) {
|
|
return this.dataView.getInt32(e2, t2);
|
|
}
|
|
getUint16(e2, t2 = this.le) {
|
|
return this.dataView.getUint16(e2, t2);
|
|
}
|
|
getUint32(e2, t2 = this.le) {
|
|
return this.dataView.getUint32(e2, t2);
|
|
}
|
|
getFloat32(e2, t2 = this.le) {
|
|
return this.dataView.getFloat32(e2, t2);
|
|
}
|
|
getFloat64(e2, t2 = this.le) {
|
|
return this.dataView.getFloat64(e2, t2);
|
|
}
|
|
getFloat(e2, t2 = this.le) {
|
|
return this.dataView.getFloat32(e2, t2);
|
|
}
|
|
getDouble(e2, t2 = this.le) {
|
|
return this.dataView.getFloat64(e2, t2);
|
|
}
|
|
getUintBytes(e2, t2, i2) {
|
|
switch (t2) {
|
|
case 1:
|
|
return this.getUint8(e2, i2);
|
|
case 2:
|
|
return this.getUint16(e2, i2);
|
|
case 4:
|
|
return this.getUint32(e2, i2);
|
|
case 8:
|
|
return this.getUint64 && this.getUint64(e2, i2);
|
|
}
|
|
}
|
|
getUint(e2, t2, i2) {
|
|
switch (t2) {
|
|
case 8:
|
|
return this.getUint8(e2, i2);
|
|
case 16:
|
|
return this.getUint16(e2, i2);
|
|
case 32:
|
|
return this.getUint32(e2, i2);
|
|
case 64:
|
|
return this.getUint64 && this.getUint64(e2, i2);
|
|
}
|
|
}
|
|
toString(e2) {
|
|
return this.dataView.toString(e2, this.constructor.name);
|
|
}
|
|
ensureChunk() {
|
|
}
|
|
}
|
|
function k(e2, t2) {
|
|
m(`${e2} '${t2}' was not loaded, try using full build of exifr.`);
|
|
}
|
|
class w extends Map {
|
|
constructor(e2) {
|
|
super(), this.kind = e2;
|
|
}
|
|
get(e2, t2) {
|
|
return this.has(e2) || k(this.kind, e2), t2 && (e2 in t2 || (function(e3, t3) {
|
|
m(`Unknown ${e3} '${t3}'.`);
|
|
})(this.kind, e2), t2[e2].enabled || k(this.kind, e2)), super.get(e2);
|
|
}
|
|
keyList() {
|
|
return Array.from(this.keys());
|
|
}
|
|
}
|
|
var T = new w("file parser"), A = new w("segment parser"), D = new w("file reader");
|
|
const O = "Invalid input argument";
|
|
function x(e2, t2) {
|
|
return "string" == typeof e2 ? v(e2, t2) : i && !n && e2 instanceof HTMLImageElement ? v(e2.src, t2) : e2 instanceof Uint8Array || e2 instanceof ArrayBuffer || e2 instanceof DataView ? new I(e2) : i && e2 instanceof Blob ? M(e2, t2, "blob", U) : void m(O);
|
|
}
|
|
function v(e2, t2) {
|
|
return (n2 = e2).startsWith("data:") || n2.length > 1e4 ? R(e2, t2, "base64") : s && e2.includes("://") ? M(e2, t2, "url", L) : s ? R(e2, t2, "fs") : i ? M(e2, t2, "url", L) : void m(O);
|
|
var n2;
|
|
}
|
|
async function M(e2, t2, i2, n2) {
|
|
return D.has(i2) ? R(e2, t2, i2) : n2 ? (async function(e3, t3) {
|
|
let i3 = await t3(e3);
|
|
return new I(i3);
|
|
})(e2, n2) : void m(`Parser ${i2} is not loaded`);
|
|
}
|
|
async function R(e2, t2, i2) {
|
|
let n2 = new (D.get(i2))(e2, t2);
|
|
return await n2.read(), n2;
|
|
}
|
|
const L = (e2) => u(e2).then(((e3) => e3.arrayBuffer())), U = (e2) => new Promise(((t2, i2) => {
|
|
let n2 = new FileReader();
|
|
n2.onloadend = () => t2(n2.result || new ArrayBuffer()), n2.onerror = i2, n2.readAsArrayBuffer(e2);
|
|
}));
|
|
class F extends Map {
|
|
get tagKeys() {
|
|
return this.allKeys || (this.allKeys = Array.from(this.keys())), this.allKeys;
|
|
}
|
|
get tagValues() {
|
|
return this.allValues || (this.allValues = Array.from(this.values())), this.allValues;
|
|
}
|
|
}
|
|
function B(e2, t2, i2) {
|
|
let n2 = new F();
|
|
for (let [e3, t3] of i2) n2.set(e3, t3);
|
|
if (Array.isArray(t2)) for (let i3 of t2) e2.set(i3, n2);
|
|
else e2.set(t2, n2);
|
|
return n2;
|
|
}
|
|
function E(e2, t2, i2) {
|
|
let n2, s2 = e2.get(t2);
|
|
for (n2 of i2) s2.set(n2[0], n2[1]);
|
|
}
|
|
const N = /* @__PURE__ */ new Map(), G = /* @__PURE__ */ new Map(), V = /* @__PURE__ */ new Map(), z = 37500, H = 37510, j = 700, W = 33723, K2 = 34675, X = 34665, _ = 34853, Y = 40965, $2 = ["chunked", "firstChunkSize", "firstChunkSizeNode", "firstChunkSizeBrowser", "chunkSize", "chunkLimit"], J = ["jfif", "xmp", "icc", "iptc", "ihdr"], q = ["tiff", ...J], Q = ["ifd0", "ifd1", "exif", "gps", "interop"], Z = [...q, ...Q], ee = ["makerNote", "userComment"], te = ["translateKeys", "translateValues", "reviveValues", "multiSegment"], ie = [...te, "sanitize", "mergeOutput", "silentErrors"];
|
|
class ne {
|
|
get translate() {
|
|
return this.translateKeys || this.translateValues || this.reviveValues;
|
|
}
|
|
}
|
|
class se extends ne {
|
|
get needed() {
|
|
return this.enabled || this.deps.size > 0;
|
|
}
|
|
constructor(e2, t2, i2, n2) {
|
|
if (super(), f(this, "enabled", false), f(this, "skip", /* @__PURE__ */ new Set()), f(this, "pick", /* @__PURE__ */ new Set()), f(this, "deps", /* @__PURE__ */ new Set()), f(this, "translateKeys", false), f(this, "translateValues", false), f(this, "reviveValues", false), this.key = e2, this.enabled = t2, this.parse = this.enabled, this.applyInheritables(n2), this.canBeFiltered = Q.includes(e2), this.canBeFiltered && (this.dict = N.get(e2)), void 0 !== i2) if (Array.isArray(i2)) this.parse = this.enabled = true, this.canBeFiltered && i2.length > 0 && this.translateTagSet(i2, this.pick);
|
|
else if ("object" == typeof i2) {
|
|
if (this.enabled = true, this.parse = false !== i2.parse, this.canBeFiltered) {
|
|
let { pick: e3, skip: t3 } = i2;
|
|
e3 && e3.length > 0 && this.translateTagSet(e3, this.pick), t3 && t3.length > 0 && this.translateTagSet(t3, this.skip);
|
|
}
|
|
this.applyInheritables(i2);
|
|
} else true === i2 || false === i2 ? this.parse = this.enabled = i2 : m(`Invalid options argument: ${i2}`);
|
|
}
|
|
applyInheritables(e2) {
|
|
let t2, i2;
|
|
for (t2 of te) i2 = e2[t2], void 0 !== i2 && (this[t2] = i2);
|
|
}
|
|
translateTagSet(e2, t2) {
|
|
if (this.dict) {
|
|
let i2, n2, { tagKeys: s2, tagValues: r2 } = this.dict;
|
|
for (i2 of e2) "string" == typeof i2 ? (n2 = r2.indexOf(i2), -1 === n2 && (n2 = s2.indexOf(Number(i2))), -1 !== n2 && t2.add(Number(s2[n2]))) : t2.add(i2);
|
|
} else for (let i2 of e2) t2.add(i2);
|
|
}
|
|
finalizeFilters() {
|
|
!this.enabled && this.deps.size > 0 ? (this.enabled = true, ue(this.pick, this.deps)) : this.enabled && this.pick.size > 0 && ue(this.pick, this.deps);
|
|
}
|
|
}
|
|
var re = { jfif: false, tiff: true, xmp: false, icc: false, iptc: false, ifd0: true, ifd1: false, exif: true, gps: true, interop: false, ihdr: void 0, makerNote: false, userComment: false, multiSegment: false, skip: [], pick: [], translateKeys: true, translateValues: true, reviveValues: true, sanitize: true, mergeOutput: true, silentErrors: true, chunked: true, firstChunkSize: void 0, firstChunkSizeNode: 512, firstChunkSizeBrowser: 65536, chunkSize: 65536, chunkLimit: 5 }, ae = /* @__PURE__ */ new Map();
|
|
class oe extends ne {
|
|
static useCached(e2) {
|
|
let t2 = ae.get(e2);
|
|
return void 0 !== t2 || (t2 = new this(e2), ae.set(e2, t2)), t2;
|
|
}
|
|
constructor(e2) {
|
|
super(), true === e2 ? this.setupFromTrue() : void 0 === e2 ? this.setupFromUndefined() : Array.isArray(e2) ? this.setupFromArray(e2) : "object" == typeof e2 ? this.setupFromObject(e2) : m(`Invalid options argument ${e2}`), void 0 === this.firstChunkSize && (this.firstChunkSize = i ? this.firstChunkSizeBrowser : this.firstChunkSizeNode), this.mergeOutput && (this.ifd1.enabled = false), this.filterNestedSegmentTags(), this.traverseTiffDependencyTree(), this.checkLoadedPlugins();
|
|
}
|
|
setupFromUndefined() {
|
|
let e2;
|
|
for (e2 of $2) this[e2] = re[e2];
|
|
for (e2 of ie) this[e2] = re[e2];
|
|
for (e2 of ee) this[e2] = re[e2];
|
|
for (e2 of Z) this[e2] = new se(e2, re[e2], void 0, this);
|
|
}
|
|
setupFromTrue() {
|
|
let e2;
|
|
for (e2 of $2) this[e2] = re[e2];
|
|
for (e2 of ie) this[e2] = re[e2];
|
|
for (e2 of ee) this[e2] = true;
|
|
for (e2 of Z) this[e2] = new se(e2, true, void 0, this);
|
|
}
|
|
setupFromArray(e2) {
|
|
let t2;
|
|
for (t2 of $2) this[t2] = re[t2];
|
|
for (t2 of ie) this[t2] = re[t2];
|
|
for (t2 of ee) this[t2] = re[t2];
|
|
for (t2 of Z) this[t2] = new se(t2, false, void 0, this);
|
|
this.setupGlobalFilters(e2, void 0, Q);
|
|
}
|
|
setupFromObject(e2) {
|
|
let t2;
|
|
for (t2 of (Q.ifd0 = Q.ifd0 || Q.image, Q.ifd1 = Q.ifd1 || Q.thumbnail, Object.assign(this, e2), $2)) this[t2] = he(e2[t2], re[t2]);
|
|
for (t2 of ie) this[t2] = he(e2[t2], re[t2]);
|
|
for (t2 of ee) this[t2] = he(e2[t2], re[t2]);
|
|
for (t2 of q) this[t2] = new se(t2, re[t2], e2[t2], this);
|
|
for (t2 of Q) this[t2] = new se(t2, re[t2], e2[t2], this.tiff);
|
|
this.setupGlobalFilters(e2.pick, e2.skip, Q, Z), true === e2.tiff ? this.batchEnableWithBool(Q, true) : false === e2.tiff ? this.batchEnableWithUserValue(Q, e2) : Array.isArray(e2.tiff) ? this.setupGlobalFilters(e2.tiff, void 0, Q) : "object" == typeof e2.tiff && this.setupGlobalFilters(e2.tiff.pick, e2.tiff.skip, Q);
|
|
}
|
|
batchEnableWithBool(e2, t2) {
|
|
for (let i2 of e2) this[i2].enabled = t2;
|
|
}
|
|
batchEnableWithUserValue(e2, t2) {
|
|
for (let i2 of e2) {
|
|
let e3 = t2[i2];
|
|
this[i2].enabled = false !== e3 && void 0 !== e3;
|
|
}
|
|
}
|
|
setupGlobalFilters(e2, t2, i2, n2 = i2) {
|
|
if (e2 && e2.length) {
|
|
for (let e3 of n2) this[e3].enabled = false;
|
|
let t3 = le(e2, i2);
|
|
for (let [e3, i3] of t3) ue(this[e3].pick, i3), this[e3].enabled = true;
|
|
} else if (t2 && t2.length) {
|
|
let e3 = le(t2, i2);
|
|
for (let [t3, i3] of e3) ue(this[t3].skip, i3);
|
|
}
|
|
}
|
|
filterNestedSegmentTags() {
|
|
let { ifd0: e2, exif: t2, xmp: i2, iptc: n2, icc: s2 } = this;
|
|
this.makerNote ? t2.deps.add(z) : t2.skip.add(z), this.userComment ? t2.deps.add(H) : t2.skip.add(H), i2.enabled || e2.skip.add(j), n2.enabled || e2.skip.add(W), s2.enabled || e2.skip.add(K2);
|
|
}
|
|
traverseTiffDependencyTree() {
|
|
let { ifd0: e2, exif: t2, gps: i2, interop: n2 } = this;
|
|
n2.needed && (t2.deps.add(Y), e2.deps.add(Y)), t2.needed && e2.deps.add(X), i2.needed && e2.deps.add(_), this.tiff.enabled = Q.some(((e3) => true === this[e3].enabled)) || this.makerNote || this.userComment;
|
|
for (let e3 of Q) this[e3].finalizeFilters();
|
|
}
|
|
get onlyTiff() {
|
|
return !J.map(((e2) => this[e2].enabled)).some(((e2) => true === e2)) && this.tiff.enabled;
|
|
}
|
|
checkLoadedPlugins() {
|
|
for (let e2 of q) this[e2].enabled && !A.has(e2) && k("segment parser", e2);
|
|
}
|
|
}
|
|
function le(e2, t2) {
|
|
let i2, n2, s2, r2, a2 = [];
|
|
for (s2 of t2) {
|
|
for (r2 of (i2 = N.get(s2), n2 = [], i2)) (e2.includes(r2[0]) || e2.includes(r2[1])) && n2.push(r2[0]);
|
|
n2.length && a2.push([s2, n2]);
|
|
}
|
|
return a2;
|
|
}
|
|
function he(e2, t2) {
|
|
return void 0 !== e2 ? e2 : void 0 !== t2 ? t2 : void 0;
|
|
}
|
|
function ue(e2, t2) {
|
|
for (let i2 of t2) e2.add(i2);
|
|
}
|
|
f(oe, "default", re);
|
|
class ce {
|
|
constructor(e2) {
|
|
f(this, "parsers", {}), f(this, "output", {}), f(this, "errors", []), f(this, "pushToErrors", ((e3) => this.errors.push(e3))), this.options = oe.useCached(e2);
|
|
}
|
|
async read(e2) {
|
|
this.file = await x(e2, this.options);
|
|
}
|
|
setup() {
|
|
if (this.fileParser) return;
|
|
let { file: e2 } = this, t2 = e2.getUint16(0);
|
|
for (let [i2, n2] of T) if (n2.canHandle(e2, t2)) return this.fileParser = new n2(this.options, this.file, this.parsers), e2[i2] = true;
|
|
this.file.close && this.file.close(), m("Unknown file format");
|
|
}
|
|
async parse() {
|
|
let { output: e2, errors: t2 } = this;
|
|
return this.setup(), this.options.silentErrors ? (await this.executeParsers().catch(this.pushToErrors), t2.push(...this.fileParser.errors)) : await this.executeParsers(), this.file.close && this.file.close(), this.options.silentErrors && t2.length > 0 && (e2.errors = t2), d(e2);
|
|
}
|
|
async executeParsers() {
|
|
let { output: e2 } = this;
|
|
await this.fileParser.parse();
|
|
let t2 = Object.values(this.parsers).map((async (t3) => {
|
|
let i2 = await t3.parse();
|
|
t3.assignToOutput(e2, i2);
|
|
}));
|
|
this.options.silentErrors && (t2 = t2.map(((e3) => e3.catch(this.pushToErrors)))), await Promise.all(t2);
|
|
}
|
|
async extractThumbnail() {
|
|
this.setup();
|
|
let { options: e2, file: t2 } = this, i2 = A.get("tiff", e2);
|
|
var n2;
|
|
if (t2.tiff ? n2 = { start: 0, type: "tiff" } : t2.jpeg && (n2 = await this.fileParser.getOrFindSegment("tiff")), void 0 === n2) return;
|
|
let s2 = await this.fileParser.ensureSegmentChunk(n2), r2 = this.parsers.tiff = new i2(s2, e2, t2), a2 = await r2.extractThumbnail();
|
|
return t2.close && t2.close(), a2;
|
|
}
|
|
}
|
|
async function fe(e2, t2) {
|
|
let i2 = new ce(t2);
|
|
return await i2.read(e2), i2.parse();
|
|
}
|
|
var de = Object.freeze({ __proto__: null, parse: fe, Exifr: ce, fileParsers: T, segmentParsers: A, fileReaders: D, tagKeys: N, tagValues: G, tagRevivers: V, createDictionary: B, extendDictionary: E, fetchUrlAsArrayBuffer: L, readBlobAsArrayBuffer: U, chunkedProps: $2, otherSegments: J, segments: q, tiffBlocks: Q, segmentsAndBlocks: Z, tiffExtractables: ee, inheritables: te, allFormatters: ie, Options: oe });
|
|
class pe {
|
|
constructor(e2, t2, i2) {
|
|
f(this, "errors", []), f(this, "ensureSegmentChunk", (async (e3) => {
|
|
let t3 = e3.start, i3 = e3.size || 65536;
|
|
if (this.file.chunked) if (this.file.available(t3, i3)) e3.chunk = this.file.subarray(t3, i3);
|
|
else try {
|
|
e3.chunk = await this.file.readChunk(t3, i3);
|
|
} catch (t4) {
|
|
m(`Couldn't read segment: ${JSON.stringify(e3)}. ${t4.message}`);
|
|
}
|
|
else this.file.byteLength > t3 + i3 ? e3.chunk = this.file.subarray(t3, i3) : void 0 === e3.size ? e3.chunk = this.file.subarray(t3) : m("Segment unreachable: " + JSON.stringify(e3));
|
|
return e3.chunk;
|
|
})), this.extendOptions && this.extendOptions(e2), this.options = e2, this.file = t2, this.parsers = i2;
|
|
}
|
|
injectSegment(e2, t2) {
|
|
this.options[e2].enabled && this.createParser(e2, t2);
|
|
}
|
|
createParser(e2, t2) {
|
|
let i2 = new (A.get(e2))(t2, this.options, this.file);
|
|
return this.parsers[e2] = i2;
|
|
}
|
|
createParsers(e2) {
|
|
for (let t2 of e2) {
|
|
let { type: e3, chunk: i2 } = t2, n2 = this.options[e3];
|
|
if (n2 && n2.enabled) {
|
|
let t3 = this.parsers[e3];
|
|
t3 && t3.append || t3 || this.createParser(e3, i2);
|
|
}
|
|
}
|
|
}
|
|
async readSegments(e2) {
|
|
let t2 = e2.map(this.ensureSegmentChunk);
|
|
await Promise.all(t2);
|
|
}
|
|
}
|
|
class ge {
|
|
static findPosition(e2, t2) {
|
|
let i2 = e2.getUint16(t2 + 2) + 2, n2 = "function" == typeof this.headerLength ? this.headerLength(e2, t2, i2) : this.headerLength, s2 = t2 + n2, r2 = i2 - n2;
|
|
return { offset: t2, length: i2, headerLength: n2, start: s2, size: r2, end: s2 + r2 };
|
|
}
|
|
static parse(e2, t2 = {}) {
|
|
return new this(e2, new oe({ [this.type]: t2 }), e2).parse();
|
|
}
|
|
normalizeInput(e2) {
|
|
return e2 instanceof I ? e2 : new I(e2);
|
|
}
|
|
constructor(e2, t2 = {}, i2) {
|
|
f(this, "errors", []), f(this, "raw", /* @__PURE__ */ new Map()), f(this, "handleError", ((e3) => {
|
|
if (!this.options.silentErrors) throw e3;
|
|
this.errors.push(e3.message);
|
|
})), this.chunk = this.normalizeInput(e2), this.file = i2, this.type = this.constructor.type, this.globalOptions = this.options = t2, this.localOptions = t2[this.type], this.canTranslate = this.localOptions && this.localOptions.translate;
|
|
}
|
|
translate() {
|
|
this.canTranslate && (this.translated = this.translateBlock(this.raw, this.type));
|
|
}
|
|
get output() {
|
|
return this.translated ? this.translated : this.raw ? Object.fromEntries(this.raw) : void 0;
|
|
}
|
|
translateBlock(e2, t2) {
|
|
let i2 = V.get(t2), n2 = G.get(t2), s2 = N.get(t2), r2 = this.options[t2], a2 = r2.reviveValues && !!i2, o2 = r2.translateValues && !!n2, l2 = r2.translateKeys && !!s2, h2 = {};
|
|
for (let [t3, r3] of e2) a2 && i2.has(t3) ? r3 = i2.get(t3)(r3) : o2 && n2.has(t3) && (r3 = this.translateValue(r3, n2.get(t3))), l2 && s2.has(t3) && (t3 = s2.get(t3) || t3), h2[t3] = r3;
|
|
return h2;
|
|
}
|
|
translateValue(e2, t2) {
|
|
return t2[e2] || t2.DEFAULT || e2;
|
|
}
|
|
assignToOutput(e2, t2) {
|
|
this.assignObjectToOutput(e2, this.constructor.type, t2);
|
|
}
|
|
assignObjectToOutput(e2, t2, i2) {
|
|
if (this.globalOptions.mergeOutput) return Object.assign(e2, i2);
|
|
e2[t2] ? Object.assign(e2[t2], i2) : e2[t2] = i2;
|
|
}
|
|
}
|
|
f(ge, "headerLength", 4), f(ge, "type", void 0), f(ge, "multiSegment", false), f(ge, "canHandle", (() => false));
|
|
function me(e2) {
|
|
return 192 === e2 || 194 === e2 || 196 === e2 || 219 === e2 || 221 === e2 || 218 === e2 || 254 === e2;
|
|
}
|
|
function Se(e2) {
|
|
return e2 >= 224 && e2 <= 239;
|
|
}
|
|
function Ce(e2, t2, i2) {
|
|
for (let [n2, s2] of A) if (s2.canHandle(e2, t2, i2)) return n2;
|
|
}
|
|
class ye extends pe {
|
|
constructor(...e2) {
|
|
super(...e2), f(this, "appSegments", []), f(this, "jpegSegments", []), f(this, "unknownSegments", []);
|
|
}
|
|
static canHandle(e2, t2) {
|
|
return 65496 === t2;
|
|
}
|
|
async parse() {
|
|
await this.findAppSegments(), await this.readSegments(this.appSegments), this.mergeMultiSegments(), this.createParsers(this.mergedAppSegments || this.appSegments);
|
|
}
|
|
setupSegmentFinderArgs(e2) {
|
|
true === e2 ? (this.findAll = true, this.wanted = new Set(A.keyList())) : (e2 = void 0 === e2 ? A.keyList().filter(((e3) => this.options[e3].enabled)) : e2.filter(((e3) => this.options[e3].enabled && A.has(e3))), this.findAll = false, this.remaining = new Set(e2), this.wanted = new Set(e2)), this.unfinishedMultiSegment = false;
|
|
}
|
|
async findAppSegments(e2 = 0, t2) {
|
|
this.setupSegmentFinderArgs(t2);
|
|
let { file: i2, findAll: n2, wanted: s2, remaining: r2 } = this;
|
|
if (!n2 && this.file.chunked && (n2 = Array.from(s2).some(((e3) => {
|
|
let t3 = A.get(e3), i3 = this.options[e3];
|
|
return t3.multiSegment && i3.multiSegment;
|
|
})), n2 && await this.file.readWhole()), e2 = this.findAppSegmentsInRange(e2, i2.byteLength), !this.options.onlyTiff && i2.chunked) {
|
|
let t3 = false;
|
|
for (; r2.size > 0 && !t3 && (i2.canReadNextChunk || this.unfinishedMultiSegment); ) {
|
|
let { nextChunkOffset: n3 } = i2, s3 = this.appSegments.some(((e3) => !this.file.available(e3.offset || e3.start, e3.length || e3.size)));
|
|
if (t3 = e2 > n3 && !s3 ? !await i2.readNextChunk(e2) : !await i2.readNextChunk(n3), void 0 === (e2 = this.findAppSegmentsInRange(e2, i2.byteLength))) return;
|
|
}
|
|
}
|
|
}
|
|
findAppSegmentsInRange(e2, t2) {
|
|
t2 -= 2;
|
|
let i2, n2, s2, r2, a2, o2, { file: l2, findAll: h2, wanted: u2, remaining: c2, options: f2 } = this;
|
|
for (; e2 < t2; e2++) if (255 === l2.getUint8(e2)) {
|
|
if (i2 = l2.getUint8(e2 + 1), Se(i2)) {
|
|
if (n2 = l2.getUint16(e2 + 2), s2 = Ce(l2, e2, n2), s2 && u2.has(s2) && (r2 = A.get(s2), a2 = r2.findPosition(l2, e2), o2 = f2[s2], a2.type = s2, this.appSegments.push(a2), !h2 && (r2.multiSegment && o2.multiSegment ? (this.unfinishedMultiSegment = a2.chunkNumber < a2.chunkCount, this.unfinishedMultiSegment || c2.delete(s2)) : c2.delete(s2), 0 === c2.size))) break;
|
|
f2.recordUnknownSegments && (a2 = ge.findPosition(l2, e2), a2.marker = i2, this.unknownSegments.push(a2)), e2 += n2 + 1;
|
|
} else if (me(i2)) {
|
|
if (n2 = l2.getUint16(e2 + 2), 218 === i2 && false !== f2.stopAfterSos) return;
|
|
f2.recordJpegSegments && this.jpegSegments.push({ offset: e2, length: n2, marker: i2 }), e2 += n2 + 1;
|
|
}
|
|
}
|
|
return e2;
|
|
}
|
|
mergeMultiSegments() {
|
|
if (!this.appSegments.some(((e3) => e3.multiSegment))) return;
|
|
let e2 = (function(e3, t2) {
|
|
let i2, n2, s2, r2 = /* @__PURE__ */ new Map();
|
|
for (let a2 = 0; a2 < e3.length; a2++) i2 = e3[a2], n2 = i2[t2], r2.has(n2) ? s2 = r2.get(n2) : r2.set(n2, s2 = []), s2.push(i2);
|
|
return Array.from(r2);
|
|
})(this.appSegments, "type");
|
|
this.mergedAppSegments = e2.map((([e3, t2]) => {
|
|
let i2 = A.get(e3, this.options);
|
|
if (i2.handleMultiSegments) {
|
|
return { type: e3, chunk: i2.handleMultiSegments(t2) };
|
|
}
|
|
return t2[0];
|
|
}));
|
|
}
|
|
getSegment(e2) {
|
|
return this.appSegments.find(((t2) => t2.type === e2));
|
|
}
|
|
async getOrFindSegment(e2) {
|
|
let t2 = this.getSegment(e2);
|
|
return void 0 === t2 && (await this.findAppSegments(0, [e2]), t2 = this.getSegment(e2)), t2;
|
|
}
|
|
}
|
|
f(ye, "type", "jpeg"), T.set("jpeg", ye);
|
|
const be = [void 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4];
|
|
class Pe extends ge {
|
|
parseHeader() {
|
|
var e2 = this.chunk.getUint16();
|
|
18761 === e2 ? this.le = true : 19789 === e2 && (this.le = false), this.chunk.le = this.le, this.headerParsed = true;
|
|
}
|
|
parseTags(e2, t2, i2 = /* @__PURE__ */ new Map()) {
|
|
let { pick: n2, skip: s2 } = this.options[t2];
|
|
n2 = new Set(n2);
|
|
let r2 = n2.size > 0, a2 = 0 === s2.size, o2 = this.chunk.getUint16(e2);
|
|
e2 += 2;
|
|
for (let l2 = 0; l2 < o2; l2++) {
|
|
let o3 = this.chunk.getUint16(e2);
|
|
if (r2) {
|
|
if (n2.has(o3) && (i2.set(o3, this.parseTag(e2, o3, t2)), n2.delete(o3), 0 === n2.size)) break;
|
|
} else !a2 && s2.has(o3) || i2.set(o3, this.parseTag(e2, o3, t2));
|
|
e2 += 12;
|
|
}
|
|
return i2;
|
|
}
|
|
parseTag(e2, t2, i2) {
|
|
let { chunk: n2 } = this, s2 = n2.getUint16(e2 + 2), r2 = n2.getUint32(e2 + 4), a2 = be[s2];
|
|
if (a2 * r2 <= 4 ? e2 += 8 : e2 = n2.getUint32(e2 + 8), (s2 < 1 || s2 > 13) && m(`Invalid TIFF value type. block: ${i2.toUpperCase()}, tag: ${t2.toString(16)}, type: ${s2}, offset ${e2}`), e2 > n2.byteLength && m(`Invalid TIFF value offset. block: ${i2.toUpperCase()}, tag: ${t2.toString(16)}, type: ${s2}, offset ${e2} is outside of chunk size ${n2.byteLength}`), 1 === s2) return n2.getUint8Array(e2, r2);
|
|
if (2 === s2) return S(n2.getString(e2, r2));
|
|
if (7 === s2) return n2.getUint8Array(e2, r2);
|
|
if (1 === r2) return this.parseTagValue(s2, e2);
|
|
{
|
|
let t3 = new ((function(e3) {
|
|
switch (e3) {
|
|
case 1:
|
|
return Uint8Array;
|
|
case 3:
|
|
return Uint16Array;
|
|
case 4:
|
|
return Uint32Array;
|
|
case 5:
|
|
return Array;
|
|
case 6:
|
|
return Int8Array;
|
|
case 8:
|
|
return Int16Array;
|
|
case 9:
|
|
return Int32Array;
|
|
case 10:
|
|
return Array;
|
|
case 11:
|
|
return Float32Array;
|
|
case 12:
|
|
return Float64Array;
|
|
default:
|
|
return Array;
|
|
}
|
|
})(s2))(r2), i3 = a2;
|
|
for (let n3 = 0; n3 < r2; n3++) t3[n3] = this.parseTagValue(s2, e2), e2 += i3;
|
|
return t3;
|
|
}
|
|
}
|
|
parseTagValue(e2, t2) {
|
|
let { chunk: i2 } = this;
|
|
switch (e2) {
|
|
case 1:
|
|
return i2.getUint8(t2);
|
|
case 3:
|
|
return i2.getUint16(t2);
|
|
case 4:
|
|
return i2.getUint32(t2);
|
|
case 5:
|
|
return i2.getUint32(t2) / i2.getUint32(t2 + 4);
|
|
case 6:
|
|
return i2.getInt8(t2);
|
|
case 8:
|
|
return i2.getInt16(t2);
|
|
case 9:
|
|
return i2.getInt32(t2);
|
|
case 10:
|
|
return i2.getInt32(t2) / i2.getInt32(t2 + 4);
|
|
case 11:
|
|
return i2.getFloat(t2);
|
|
case 12:
|
|
return i2.getDouble(t2);
|
|
case 13:
|
|
return i2.getUint32(t2);
|
|
default:
|
|
m(`Invalid tiff type ${e2}`);
|
|
}
|
|
}
|
|
}
|
|
class Ie extends Pe {
|
|
static canHandle(e2, t2) {
|
|
return 225 === e2.getUint8(t2 + 1) && 1165519206 === e2.getUint32(t2 + 4) && 0 === e2.getUint16(t2 + 8);
|
|
}
|
|
async parse() {
|
|
this.parseHeader();
|
|
let { options: e2 } = this;
|
|
return e2.ifd0.enabled && await this.parseIfd0Block(), e2.exif.enabled && await this.safeParse("parseExifBlock"), e2.gps.enabled && await this.safeParse("parseGpsBlock"), e2.interop.enabled && await this.safeParse("parseInteropBlock"), e2.ifd1.enabled && await this.safeParse("parseThumbnailBlock"), this.createOutput();
|
|
}
|
|
safeParse(e2) {
|
|
let t2 = this[e2]();
|
|
return void 0 !== t2.catch && (t2 = t2.catch(this.handleError)), t2;
|
|
}
|
|
findIfd0Offset() {
|
|
void 0 === this.ifd0Offset && (this.ifd0Offset = this.chunk.getUint32(4));
|
|
}
|
|
findIfd1Offset() {
|
|
if (void 0 === this.ifd1Offset) {
|
|
this.findIfd0Offset();
|
|
let e2 = this.chunk.getUint16(this.ifd0Offset), t2 = this.ifd0Offset + 2 + 12 * e2;
|
|
this.ifd1Offset = this.chunk.getUint32(t2);
|
|
}
|
|
}
|
|
parseBlock(e2, t2) {
|
|
let i2 = /* @__PURE__ */ new Map();
|
|
return this[t2] = i2, this.parseTags(e2, t2, i2), i2;
|
|
}
|
|
async parseIfd0Block() {
|
|
if (this.ifd0) return;
|
|
let { file: e2 } = this;
|
|
this.findIfd0Offset(), this.ifd0Offset < 8 && m("Malformed EXIF data"), !e2.chunked && this.ifd0Offset > e2.byteLength && m(`IFD0 offset points to outside of file.
|
|
this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e2.byteLength}`), e2.tiff && await e2.ensureChunk(this.ifd0Offset, C(this.options));
|
|
let t2 = this.parseBlock(this.ifd0Offset, "ifd0");
|
|
return 0 !== t2.size ? (this.exifOffset = t2.get(X), this.interopOffset = t2.get(Y), this.gpsOffset = t2.get(_), this.xmp = t2.get(j), this.iptc = t2.get(W), this.icc = t2.get(K2), this.options.sanitize && (t2.delete(X), t2.delete(Y), t2.delete(_), t2.delete(j), t2.delete(W), t2.delete(K2)), t2) : void 0;
|
|
}
|
|
async parseExifBlock() {
|
|
if (this.exif) return;
|
|
if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.exifOffset) return;
|
|
this.file.tiff && await this.file.ensureChunk(this.exifOffset, C(this.options));
|
|
let e2 = this.parseBlock(this.exifOffset, "exif");
|
|
return this.interopOffset || (this.interopOffset = e2.get(Y)), this.makerNote = e2.get(z), this.userComment = e2.get(H), this.options.sanitize && (e2.delete(Y), e2.delete(z), e2.delete(H)), this.unpack(e2, 41728), this.unpack(e2, 41729), e2;
|
|
}
|
|
unpack(e2, t2) {
|
|
let i2 = e2.get(t2);
|
|
i2 && 1 === i2.length && e2.set(t2, i2[0]);
|
|
}
|
|
async parseGpsBlock() {
|
|
if (this.gps) return;
|
|
if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.gpsOffset) return;
|
|
let e2 = this.parseBlock(this.gpsOffset, "gps");
|
|
return e2 && e2.has(2) && e2.has(4) && (e2.set("latitude", ke(...e2.get(2), e2.get(1))), e2.set("longitude", ke(...e2.get(4), e2.get(3)))), e2;
|
|
}
|
|
async parseInteropBlock() {
|
|
if (!this.interop && (this.ifd0 || await this.parseIfd0Block(), void 0 !== this.interopOffset || this.exif || await this.parseExifBlock(), void 0 !== this.interopOffset)) return this.parseBlock(this.interopOffset, "interop");
|
|
}
|
|
async parseThumbnailBlock(e2 = false) {
|
|
if (!this.ifd1 && !this.ifd1Parsed && (!this.options.mergeOutput || e2)) return this.findIfd1Offset(), this.ifd1Offset > 0 && (this.parseBlock(this.ifd1Offset, "ifd1"), this.ifd1Parsed = true), this.ifd1;
|
|
}
|
|
async extractThumbnail() {
|
|
if (this.headerParsed || this.parseHeader(), this.ifd1Parsed || await this.parseThumbnailBlock(true), void 0 === this.ifd1) return;
|
|
let e2 = this.ifd1.get(513), t2 = this.ifd1.get(514);
|
|
return this.chunk.getUint8Array(e2, t2);
|
|
}
|
|
get image() {
|
|
return this.ifd0;
|
|
}
|
|
get thumbnail() {
|
|
return this.ifd1;
|
|
}
|
|
createOutput() {
|
|
let e2, t2, i2, n2 = {};
|
|
for (t2 of Q) if (e2 = this[t2], !g(e2)) if (i2 = this.canTranslate ? this.translateBlock(e2, t2) : Object.fromEntries(e2), this.options.mergeOutput) {
|
|
if ("ifd1" === t2) continue;
|
|
Object.assign(n2, i2);
|
|
} else n2[t2] = i2;
|
|
return this.makerNote && (n2.makerNote = this.makerNote), this.userComment && (n2.userComment = this.userComment), n2;
|
|
}
|
|
assignToOutput(e2, t2) {
|
|
if (this.globalOptions.mergeOutput) Object.assign(e2, t2);
|
|
else for (let [i2, n2] of Object.entries(t2)) this.assignObjectToOutput(e2, i2, n2);
|
|
}
|
|
}
|
|
function ke(e2, t2, i2, n2) {
|
|
var s2 = e2 + t2 / 60 + i2 / 3600;
|
|
return "S" !== n2 && "W" !== n2 || (s2 *= -1), s2;
|
|
}
|
|
f(Ie, "type", "tiff"), f(Ie, "headerLength", 10), A.set("tiff", Ie);
|
|
var we = Object.freeze({ __proto__: null, default: de, Exifr: ce, fileParsers: T, segmentParsers: A, fileReaders: D, tagKeys: N, tagValues: G, tagRevivers: V, createDictionary: B, extendDictionary: E, fetchUrlAsArrayBuffer: L, readBlobAsArrayBuffer: U, chunkedProps: $2, otherSegments: J, segments: q, tiffBlocks: Q, segmentsAndBlocks: Z, tiffExtractables: ee, inheritables: te, allFormatters: ie, Options: oe, parse: fe });
|
|
const Te = { ifd0: false, ifd1: false, exif: false, gps: false, interop: false, sanitize: false, reviveValues: true, translateKeys: false, translateValues: false, mergeOutput: false }, Ae = Object.assign({}, Te, { firstChunkSize: 4e4, gps: [1, 2, 3, 4] });
|
|
async function De(e2) {
|
|
let t2 = new ce(Ae);
|
|
await t2.read(e2);
|
|
let i2 = await t2.parse();
|
|
if (i2 && i2.gps) {
|
|
let { latitude: e3, longitude: t3 } = i2.gps;
|
|
return { latitude: e3, longitude: t3 };
|
|
}
|
|
}
|
|
const Oe = Object.assign({}, Te, { tiff: false, ifd1: true, mergeOutput: false });
|
|
async function xe(e2) {
|
|
let t2 = new ce(Oe);
|
|
await t2.read(e2);
|
|
let i2 = await t2.extractThumbnail();
|
|
return i2 && o ? r.from(i2) : i2;
|
|
}
|
|
async function ve(e2) {
|
|
let t2 = await this.thumbnail(e2);
|
|
if (void 0 !== t2) {
|
|
let e3 = new Blob([t2]);
|
|
return URL.createObjectURL(e3);
|
|
}
|
|
}
|
|
const Me = Object.assign({}, Te, { firstChunkSize: 4e4, ifd0: [274] });
|
|
async function Re(e2) {
|
|
let t2 = new ce(Me);
|
|
await t2.read(e2);
|
|
let i2 = await t2.parse();
|
|
if (i2 && i2.ifd0) return i2.ifd0[274];
|
|
}
|
|
const Le = Object.freeze({ 1: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 0, rad: 0 }, 2: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 0, rad: 0 }, 3: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 4: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 5: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 90, rad: 90 * Math.PI / 180 }, 6: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 90, rad: 90 * Math.PI / 180 }, 7: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 270, rad: 270 * Math.PI / 180 }, 8: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 270, rad: 270 * Math.PI / 180 } });
|
|
if (e.rotateCanvas = true, e.rotateCss = true, "object" == typeof navigator) {
|
|
let t2 = navigator.userAgent;
|
|
if (t2.includes("iPad") || t2.includes("iPhone")) {
|
|
let i2 = t2.match(/OS (\d+)_(\d+)/);
|
|
if (i2) {
|
|
let [, t3, n2] = i2, s2 = Number(t3) + 0.1 * Number(n2);
|
|
e.rotateCanvas = s2 < 13.4, e.rotateCss = false;
|
|
}
|
|
} else if (t2.includes("OS X 10")) {
|
|
let [, i2] = t2.match(/OS X 10[_.](\d+)/);
|
|
e.rotateCanvas = e.rotateCss = Number(i2) < 15;
|
|
}
|
|
if (t2.includes("Chrome/")) {
|
|
let [, i2] = t2.match(/Chrome\/(\d+)/);
|
|
e.rotateCanvas = e.rotateCss = Number(i2) < 81;
|
|
} else if (t2.includes("Firefox/")) {
|
|
let [, i2] = t2.match(/Firefox\/(\d+)/);
|
|
e.rotateCanvas = e.rotateCss = Number(i2) < 77;
|
|
}
|
|
}
|
|
async function Ue(t2) {
|
|
let i2 = await Re(t2);
|
|
return Object.assign({ canvas: e.rotateCanvas, css: e.rotateCss }, Le[i2]);
|
|
}
|
|
class Fe extends I {
|
|
constructor(...e2) {
|
|
super(...e2), f(this, "ranges", new Be()), 0 !== this.byteLength && this.ranges.add(0, this.byteLength);
|
|
}
|
|
_tryExtend(e2, t2, i2) {
|
|
if (0 === e2 && 0 === this.byteLength && i2) {
|
|
let e3 = new DataView(i2.buffer || i2, i2.byteOffset, i2.byteLength);
|
|
this._swapDataView(e3);
|
|
} else {
|
|
let i3 = e2 + t2;
|
|
if (i3 > this.byteLength) {
|
|
let { dataView: e3 } = this._extend(i3);
|
|
this._swapDataView(e3);
|
|
}
|
|
}
|
|
}
|
|
_extend(e2) {
|
|
let t2;
|
|
t2 = o ? r.allocUnsafe(e2) : new Uint8Array(e2);
|
|
let i2 = new DataView(t2.buffer, t2.byteOffset, t2.byteLength);
|
|
return t2.set(new Uint8Array(this.buffer, this.byteOffset, this.byteLength), 0), { uintView: t2, dataView: i2 };
|
|
}
|
|
subarray(e2, t2, i2 = false) {
|
|
return t2 = t2 || this._lengthToEnd(e2), i2 && this._tryExtend(e2, t2), this.ranges.add(e2, t2), super.subarray(e2, t2);
|
|
}
|
|
set(e2, t2, i2 = false) {
|
|
i2 && this._tryExtend(t2, e2.byteLength, e2);
|
|
let n2 = super.set(e2, t2);
|
|
return this.ranges.add(t2, n2.byteLength), n2;
|
|
}
|
|
async ensureChunk(e2, t2) {
|
|
this.chunked && (this.ranges.available(e2, t2) || await this.readChunk(e2, t2));
|
|
}
|
|
available(e2, t2) {
|
|
return this.ranges.available(e2, t2);
|
|
}
|
|
}
|
|
class Be {
|
|
constructor() {
|
|
f(this, "list", []);
|
|
}
|
|
get length() {
|
|
return this.list.length;
|
|
}
|
|
add(e2, t2, i2 = 0) {
|
|
let n2 = e2 + t2, s2 = this.list.filter(((t3) => Ee(e2, t3.offset, n2) || Ee(e2, t3.end, n2)));
|
|
if (s2.length > 0) {
|
|
e2 = Math.min(e2, ...s2.map(((e3) => e3.offset))), n2 = Math.max(n2, ...s2.map(((e3) => e3.end))), t2 = n2 - e2;
|
|
let i3 = s2.shift();
|
|
i3.offset = e2, i3.length = t2, i3.end = n2, this.list = this.list.filter(((e3) => !s2.includes(e3)));
|
|
} else this.list.push({ offset: e2, length: t2, end: n2 });
|
|
}
|
|
available(e2, t2) {
|
|
let i2 = e2 + t2;
|
|
return this.list.some(((t3) => t3.offset <= e2 && i2 <= t3.end));
|
|
}
|
|
}
|
|
function Ee(e2, t2, i2) {
|
|
return e2 <= t2 && t2 <= i2;
|
|
}
|
|
class Ne extends Fe {
|
|
constructor(e2, t2) {
|
|
super(0), f(this, "chunksRead", 0), this.input = e2, this.options = t2;
|
|
}
|
|
async readWhole() {
|
|
this.chunked = false, await this.readChunk(this.nextChunkOffset);
|
|
}
|
|
async readChunked() {
|
|
this.chunked = true, await this.readChunk(0, this.options.firstChunkSize);
|
|
}
|
|
async readNextChunk(e2 = this.nextChunkOffset) {
|
|
if (this.fullyRead) return this.chunksRead++, false;
|
|
let t2 = this.options.chunkSize, i2 = await this.readChunk(e2, t2);
|
|
return !!i2 && i2.byteLength === t2;
|
|
}
|
|
async readChunk(e2, t2) {
|
|
if (this.chunksRead++, 0 !== (t2 = this.safeWrapAddress(e2, t2))) return this._readChunk(e2, t2);
|
|
}
|
|
safeWrapAddress(e2, t2) {
|
|
return void 0 !== this.size && e2 + t2 > this.size ? Math.max(0, this.size - e2) : t2;
|
|
}
|
|
get nextChunkOffset() {
|
|
if (0 !== this.ranges.list.length) return this.ranges.list[0].length;
|
|
}
|
|
get canReadNextChunk() {
|
|
return this.chunksRead < this.options.chunkLimit;
|
|
}
|
|
get fullyRead() {
|
|
return void 0 !== this.size && this.nextChunkOffset === this.size;
|
|
}
|
|
read() {
|
|
return this.options.chunked ? this.readChunked() : this.readWhole();
|
|
}
|
|
close() {
|
|
}
|
|
}
|
|
D.set("blob", class extends Ne {
|
|
async readWhole() {
|
|
this.chunked = false;
|
|
let e2 = await U(this.input);
|
|
this._swapArrayBuffer(e2);
|
|
}
|
|
readChunked() {
|
|
return this.chunked = true, this.size = this.input.size, super.readChunked();
|
|
}
|
|
async _readChunk(e2, t2) {
|
|
let i2 = t2 ? e2 + t2 : void 0, n2 = this.input.slice(e2, i2), s2 = await U(n2);
|
|
return this.set(s2, e2, true);
|
|
}
|
|
});
|
|
var Ge = Object.freeze({ __proto__: null, default: we, Exifr: ce, fileParsers: T, segmentParsers: A, fileReaders: D, tagKeys: N, tagValues: G, tagRevivers: V, createDictionary: B, extendDictionary: E, fetchUrlAsArrayBuffer: L, readBlobAsArrayBuffer: U, chunkedProps: $2, otherSegments: J, segments: q, tiffBlocks: Q, segmentsAndBlocks: Z, tiffExtractables: ee, inheritables: te, allFormatters: ie, Options: oe, parse: fe, gpsOnlyOptions: Ae, gps: De, thumbnailOnlyOptions: Oe, thumbnail: xe, thumbnailUrl: ve, orientationOnlyOptions: Me, orientation: Re, rotations: Le, get rotateCanvas() {
|
|
return e.rotateCanvas;
|
|
}, get rotateCss() {
|
|
return e.rotateCss;
|
|
}, rotation: Ue });
|
|
D.set("url", class extends Ne {
|
|
async readWhole() {
|
|
this.chunked = false;
|
|
let e2 = await L(this.input);
|
|
e2 instanceof ArrayBuffer ? this._swapArrayBuffer(e2) : e2 instanceof Uint8Array && this._swapBuffer(e2);
|
|
}
|
|
async _readChunk(e2, t2) {
|
|
let i2 = t2 ? e2 + t2 - 1 : void 0, n2 = this.options.httpHeaders || {};
|
|
(e2 || i2) && (n2.range = `bytes=${[e2, i2].join("-")}`);
|
|
let s2 = await u(this.input, { headers: n2 }), r2 = await s2.arrayBuffer(), a2 = r2.byteLength;
|
|
if (416 !== s2.status) return a2 !== t2 && (this.size = e2 + a2), this.set(r2, e2, true);
|
|
}
|
|
});
|
|
I.prototype.getUint64 = function(e2) {
|
|
let t2 = this.getUint32(e2), i2 = this.getUint32(e2 + 4);
|
|
return t2 < 1048575 ? t2 << 32 | i2 : void 0 !== typeof a ? (console.warn("Using BigInt because of type 64uint but JS can only handle 53b numbers."), a(t2) << a(32) | a(i2)) : void m("Trying to read 64b value but JS can only handle 53b numbers.");
|
|
};
|
|
class Ve extends pe {
|
|
parseBoxes(e2 = 0) {
|
|
let t2 = [];
|
|
for (; e2 < this.file.byteLength - 4; ) {
|
|
let i2 = this.parseBoxHead(e2);
|
|
if (t2.push(i2), 0 === i2.length) break;
|
|
e2 += i2.length;
|
|
}
|
|
return t2;
|
|
}
|
|
parseSubBoxes(e2) {
|
|
e2.boxes = this.parseBoxes(e2.start);
|
|
}
|
|
findBox(e2, t2) {
|
|
return void 0 === e2.boxes && this.parseSubBoxes(e2), e2.boxes.find(((e3) => e3.kind === t2));
|
|
}
|
|
parseBoxHead(e2) {
|
|
let t2 = this.file.getUint32(e2), i2 = this.file.getString(e2 + 4, 4), n2 = e2 + 8;
|
|
return 1 === t2 && (t2 = this.file.getUint64(e2 + 8), n2 += 8), { offset: e2, length: t2, kind: i2, start: n2 };
|
|
}
|
|
parseBoxFullHead(e2) {
|
|
if (void 0 !== e2.version) return;
|
|
let t2 = this.file.getUint32(e2.start);
|
|
e2.version = t2 >> 24, e2.start += 4;
|
|
}
|
|
}
|
|
class ze extends Ve {
|
|
static canHandle(e2, t2) {
|
|
if (0 !== t2) return false;
|
|
let i2 = e2.getUint16(2);
|
|
if (i2 > 50) return false;
|
|
let n2 = 16, s2 = [];
|
|
for (; n2 < i2; ) s2.push(e2.getString(n2, 4)), n2 += 4;
|
|
return s2.includes(this.type);
|
|
}
|
|
async parse() {
|
|
let e2 = this.file.getUint32(0), t2 = this.parseBoxHead(e2);
|
|
for (; "meta" !== t2.kind; ) e2 += t2.length, await this.file.ensureChunk(e2, 16), t2 = this.parseBoxHead(e2);
|
|
await this.file.ensureChunk(t2.offset, t2.length), this.parseBoxFullHead(t2), this.parseSubBoxes(t2), this.options.icc.enabled && await this.findIcc(t2), this.options.tiff.enabled && await this.findExif(t2);
|
|
}
|
|
async registerSegment(e2, t2, i2) {
|
|
await this.file.ensureChunk(t2, i2);
|
|
let n2 = this.file.subarray(t2, i2);
|
|
this.createParser(e2, n2);
|
|
}
|
|
async findIcc(e2) {
|
|
let t2 = this.findBox(e2, "iprp");
|
|
if (void 0 === t2) return;
|
|
let i2 = this.findBox(t2, "ipco");
|
|
if (void 0 === i2) return;
|
|
let n2 = this.findBox(i2, "colr");
|
|
void 0 !== n2 && await this.registerSegment("icc", n2.offset + 12, n2.length);
|
|
}
|
|
async findExif(e2) {
|
|
let t2 = this.findBox(e2, "iinf");
|
|
if (void 0 === t2) return;
|
|
let i2 = this.findBox(e2, "iloc");
|
|
if (void 0 === i2) return;
|
|
let n2 = this.findExifLocIdInIinf(t2), s2 = this.findExtentInIloc(i2, n2);
|
|
if (void 0 === s2) return;
|
|
let [r2, a2] = s2;
|
|
await this.file.ensureChunk(r2, a2);
|
|
let o2 = 4 + this.file.getUint32(r2);
|
|
r2 += o2, a2 -= o2, await this.registerSegment("tiff", r2, a2);
|
|
}
|
|
findExifLocIdInIinf(e2) {
|
|
this.parseBoxFullHead(e2);
|
|
let t2, i2, n2, s2, r2 = e2.start, a2 = this.file.getUint16(r2);
|
|
for (r2 += 2; a2--; ) {
|
|
if (t2 = this.parseBoxHead(r2), this.parseBoxFullHead(t2), i2 = t2.start, t2.version >= 2 && (n2 = 3 === t2.version ? 4 : 2, s2 = this.file.getString(i2 + n2 + 2, 4), "Exif" === s2)) return this.file.getUintBytes(i2, n2);
|
|
r2 += t2.length;
|
|
}
|
|
}
|
|
get8bits(e2) {
|
|
let t2 = this.file.getUint8(e2);
|
|
return [t2 >> 4, 15 & t2];
|
|
}
|
|
findExtentInIloc(e2, t2) {
|
|
this.parseBoxFullHead(e2);
|
|
let i2 = e2.start, [n2, s2] = this.get8bits(i2++), [r2, a2] = this.get8bits(i2++), o2 = 2 === e2.version ? 4 : 2, l2 = 1 === e2.version || 2 === e2.version ? 2 : 0, h2 = a2 + n2 + s2, u2 = 2 === e2.version ? 4 : 2, c2 = this.file.getUintBytes(i2, u2);
|
|
for (i2 += u2; c2--; ) {
|
|
let e3 = this.file.getUintBytes(i2, o2);
|
|
i2 += o2 + l2 + 2 + r2;
|
|
let u3 = this.file.getUint16(i2);
|
|
if (i2 += 2, e3 === t2) return u3 > 1 && console.warn("ILOC box has more than one extent but we're only processing one\nPlease create an issue at https://github.com/MikeKovarik/exifr with this file"), [this.file.getUintBytes(i2 + a2, n2), this.file.getUintBytes(i2 + a2 + n2, s2)];
|
|
i2 += u3 * h2;
|
|
}
|
|
}
|
|
}
|
|
class He extends ze {
|
|
}
|
|
f(He, "type", "heic");
|
|
class je extends ze {
|
|
}
|
|
f(je, "type", "avif"), T.set("heic", He), T.set("avif", je), B(N, ["ifd0", "ifd1"], [[256, "ImageWidth"], [257, "ImageHeight"], [258, "BitsPerSample"], [259, "Compression"], [262, "PhotometricInterpretation"], [270, "ImageDescription"], [271, "Make"], [272, "Model"], [273, "StripOffsets"], [274, "Orientation"], [277, "SamplesPerPixel"], [278, "RowsPerStrip"], [279, "StripByteCounts"], [282, "XResolution"], [283, "YResolution"], [284, "PlanarConfiguration"], [296, "ResolutionUnit"], [301, "TransferFunction"], [305, "Software"], [306, "ModifyDate"], [315, "Artist"], [316, "HostComputer"], [317, "Predictor"], [318, "WhitePoint"], [319, "PrimaryChromaticities"], [513, "ThumbnailOffset"], [514, "ThumbnailLength"], [529, "YCbCrCoefficients"], [530, "YCbCrSubSampling"], [531, "YCbCrPositioning"], [532, "ReferenceBlackWhite"], [700, "ApplicationNotes"], [33432, "Copyright"], [33723, "IPTC"], [34665, "ExifIFD"], [34675, "ICC"], [34853, "GpsIFD"], [330, "SubIFD"], [40965, "InteropIFD"], [40091, "XPTitle"], [40092, "XPComment"], [40093, "XPAuthor"], [40094, "XPKeywords"], [40095, "XPSubject"]]), B(N, "exif", [[33434, "ExposureTime"], [33437, "FNumber"], [34850, "ExposureProgram"], [34852, "SpectralSensitivity"], [34855, "ISO"], [34858, "TimeZoneOffset"], [34859, "SelfTimerMode"], [34864, "SensitivityType"], [34865, "StandardOutputSensitivity"], [34866, "RecommendedExposureIndex"], [34867, "ISOSpeed"], [34868, "ISOSpeedLatitudeyyy"], [34869, "ISOSpeedLatitudezzz"], [36864, "ExifVersion"], [36867, "DateTimeOriginal"], [36868, "CreateDate"], [36873, "GooglePlusUploadCode"], [36880, "OffsetTime"], [36881, "OffsetTimeOriginal"], [36882, "OffsetTimeDigitized"], [37121, "ComponentsConfiguration"], [37122, "CompressedBitsPerPixel"], [37377, "ShutterSpeedValue"], [37378, "ApertureValue"], [37379, "BrightnessValue"], [37380, "ExposureCompensation"], [37381, "MaxApertureValue"], [37382, "SubjectDistance"], [37383, "MeteringMode"], [37384, "LightSource"], [37385, "Flash"], [37386, "FocalLength"], [37393, "ImageNumber"], [37394, "SecurityClassification"], [37395, "ImageHistory"], [37396, "SubjectArea"], [37500, "MakerNote"], [37510, "UserComment"], [37520, "SubSecTime"], [37521, "SubSecTimeOriginal"], [37522, "SubSecTimeDigitized"], [37888, "AmbientTemperature"], [37889, "Humidity"], [37890, "Pressure"], [37891, "WaterDepth"], [37892, "Acceleration"], [37893, "CameraElevationAngle"], [40960, "FlashpixVersion"], [40961, "ColorSpace"], [40962, "ExifImageWidth"], [40963, "ExifImageHeight"], [40964, "RelatedSoundFile"], [41483, "FlashEnergy"], [41486, "FocalPlaneXResolution"], [41487, "FocalPlaneYResolution"], [41488, "FocalPlaneResolutionUnit"], [41492, "SubjectLocation"], [41493, "ExposureIndex"], [41495, "SensingMethod"], [41728, "FileSource"], [41729, "SceneType"], [41730, "CFAPattern"], [41985, "CustomRendered"], [41986, "ExposureMode"], [41987, "WhiteBalance"], [41988, "DigitalZoomRatio"], [41989, "FocalLengthIn35mmFormat"], [41990, "SceneCaptureType"], [41991, "GainControl"], [41992, "Contrast"], [41993, "Saturation"], [41994, "Sharpness"], [41996, "SubjectDistanceRange"], [42016, "ImageUniqueID"], [42032, "OwnerName"], [42033, "SerialNumber"], [42034, "LensInfo"], [42035, "LensMake"], [42036, "LensModel"], [42037, "LensSerialNumber"], [42080, "CompositeImage"], [42081, "CompositeImageCount"], [42082, "CompositeImageExposureTimes"], [42240, "Gamma"], [59932, "Padding"], [59933, "OffsetSchema"], [65e3, "OwnerName"], [65001, "SerialNumber"], [65002, "Lens"], [65100, "RawFile"], [65101, "Converter"], [65102, "WhiteBalance"], [65105, "Exposure"], [65106, "Shadows"], [65107, "Brightness"], [65108, "Contrast"], [65109, "Saturation"], [65110, "Sharpness"], [65111, "Smoothness"], [65112, "MoireFilter"], [40965, "InteropIFD"]]), B(N, "gps", [[0, "GPSVersionID"], [1, "GPSLatitudeRef"], [2, "GPSLatitude"], [3, "GPSLongitudeRef"], [4, "GPSLongitude"], [5, "GPSAltitudeRef"], [6, "GPSAltitude"], [7, "GPSTimeStamp"], [8, "GPSSatellites"], [9, "GPSStatus"], [10, "GPSMeasureMode"], [11, "GPSDOP"], [12, "GPSSpeedRef"], [13, "GPSSpeed"], [14, "GPSTrackRef"], [15, "GPSTrack"], [16, "GPSImgDirectionRef"], [17, "GPSImgDirection"], [18, "GPSMapDatum"], [19, "GPSDestLatitudeRef"], [20, "GPSDestLatitude"], [21, "GPSDestLongitudeRef"], [22, "GPSDestLongitude"], [23, "GPSDestBearingRef"], [24, "GPSDestBearing"], [25, "GPSDestDistanceRef"], [26, "GPSDestDistance"], [27, "GPSProcessingMethod"], [28, "GPSAreaInformation"], [29, "GPSDateStamp"], [30, "GPSDifferential"], [31, "GPSHPositioningError"]]), B(G, ["ifd0", "ifd1"], [[274, { 1: "Horizontal (normal)", 2: "Mirror horizontal", 3: "Rotate 180", 4: "Mirror vertical", 5: "Mirror horizontal and rotate 270 CW", 6: "Rotate 90 CW", 7: "Mirror horizontal and rotate 90 CW", 8: "Rotate 270 CW" }], [296, { 1: "None", 2: "inches", 3: "cm" }]]);
|
|
let We = B(G, "exif", [[34850, { 0: "Not defined", 1: "Manual", 2: "Normal program", 3: "Aperture priority", 4: "Shutter priority", 5: "Creative program", 6: "Action program", 7: "Portrait mode", 8: "Landscape mode" }], [37121, { 0: "-", 1: "Y", 2: "Cb", 3: "Cr", 4: "R", 5: "G", 6: "B" }], [37383, { 0: "Unknown", 1: "Average", 2: "CenterWeightedAverage", 3: "Spot", 4: "MultiSpot", 5: "Pattern", 6: "Partial", 255: "Other" }], [37384, { 0: "Unknown", 1: "Daylight", 2: "Fluorescent", 3: "Tungsten (incandescent light)", 4: "Flash", 9: "Fine weather", 10: "Cloudy weather", 11: "Shade", 12: "Daylight fluorescent (D 5700 - 7100K)", 13: "Day white fluorescent (N 4600 - 5400K)", 14: "Cool white fluorescent (W 3900 - 4500K)", 15: "White fluorescent (WW 3200 - 3700K)", 17: "Standard light A", 18: "Standard light B", 19: "Standard light C", 20: "D55", 21: "D65", 22: "D75", 23: "D50", 24: "ISO studio tungsten", 255: "Other" }], [37385, { 0: "Flash did not fire", 1: "Flash fired", 5: "Strobe return light not detected", 7: "Strobe return light detected", 9: "Flash fired, compulsory flash mode", 13: "Flash fired, compulsory flash mode, return light not detected", 15: "Flash fired, compulsory flash mode, return light detected", 16: "Flash did not fire, compulsory flash mode", 24: "Flash did not fire, auto mode", 25: "Flash fired, auto mode", 29: "Flash fired, auto mode, return light not detected", 31: "Flash fired, auto mode, return light detected", 32: "No flash function", 65: "Flash fired, red-eye reduction mode", 69: "Flash fired, red-eye reduction mode, return light not detected", 71: "Flash fired, red-eye reduction mode, return light detected", 73: "Flash fired, compulsory flash mode, red-eye reduction mode", 77: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", 79: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", 89: "Flash fired, auto mode, red-eye reduction mode", 93: "Flash fired, auto mode, return light not detected, red-eye reduction mode", 95: "Flash fired, auto mode, return light detected, red-eye reduction mode" }], [41495, { 1: "Not defined", 2: "One-chip color area sensor", 3: "Two-chip color area sensor", 4: "Three-chip color area sensor", 5: "Color sequential area sensor", 7: "Trilinear sensor", 8: "Color sequential linear sensor" }], [41728, { 1: "Film Scanner", 2: "Reflection Print Scanner", 3: "Digital Camera" }], [41729, { 1: "Directly photographed" }], [41985, { 0: "Normal", 1: "Custom", 2: "HDR (no original saved)", 3: "HDR (original saved)", 4: "Original (for HDR)", 6: "Panorama", 7: "Portrait HDR", 8: "Portrait" }], [41986, { 0: "Auto", 1: "Manual", 2: "Auto bracket" }], [41987, { 0: "Auto", 1: "Manual" }], [41990, { 0: "Standard", 1: "Landscape", 2: "Portrait", 3: "Night", 4: "Other" }], [41991, { 0: "None", 1: "Low gain up", 2: "High gain up", 3: "Low gain down", 4: "High gain down" }], [41996, { 0: "Unknown", 1: "Macro", 2: "Close", 3: "Distant" }], [42080, { 0: "Unknown", 1: "Not a Composite Image", 2: "General Composite Image", 3: "Composite Image Captured While Shooting" }]]);
|
|
const Ke = { 1: "No absolute unit of measurement", 2: "Inch", 3: "Centimeter" };
|
|
We.set(37392, Ke), We.set(41488, Ke);
|
|
const Xe = { 0: "Normal", 1: "Low", 2: "High" };
|
|
function _e(e2) {
|
|
return "object" == typeof e2 && void 0 !== e2.length ? e2[0] : e2;
|
|
}
|
|
function Ye(e2) {
|
|
let t2 = Array.from(e2).slice(1);
|
|
return t2[1] > 15 && (t2 = t2.map(((e3) => String.fromCharCode(e3)))), "0" !== t2[2] && 0 !== t2[2] || t2.pop(), t2.join(".");
|
|
}
|
|
function $e(e2) {
|
|
if ("string" == typeof e2) {
|
|
var [t2, i2, n2, s2, r2, a2] = e2.trim().split(/[-: ]/g).map(Number), o2 = new Date(t2, i2 - 1, n2);
|
|
return Number.isNaN(s2) || Number.isNaN(r2) || Number.isNaN(a2) || (o2.setHours(s2), o2.setMinutes(r2), o2.setSeconds(a2)), Number.isNaN(+o2) ? e2 : o2;
|
|
}
|
|
}
|
|
function Je(e2) {
|
|
if ("string" == typeof e2) return e2;
|
|
let t2 = [];
|
|
if (0 === e2[1] && 0 === e2[e2.length - 1]) for (let i2 = 0; i2 < e2.length; i2 += 2) t2.push(qe(e2[i2 + 1], e2[i2]));
|
|
else for (let i2 = 0; i2 < e2.length; i2 += 2) t2.push(qe(e2[i2], e2[i2 + 1]));
|
|
return S(String.fromCodePoint(...t2));
|
|
}
|
|
function qe(e2, t2) {
|
|
return e2 << 8 | t2;
|
|
}
|
|
We.set(41992, Xe), We.set(41993, Xe), We.set(41994, Xe), B(V, ["ifd0", "ifd1"], [[50827, function(e2) {
|
|
return "string" != typeof e2 ? P(e2) : e2;
|
|
}], [306, $e], [40091, Je], [40092, Je], [40093, Je], [40094, Je], [40095, Je]]), B(V, "exif", [[40960, Ye], [36864, Ye], [36867, $e], [36868, $e], [40962, _e], [40963, _e]]), B(V, "gps", [[0, (e2) => Array.from(e2).join(".")], [7, (e2) => Array.from(e2).join(":")]]);
|
|
const Qe = "http://ns.adobe.com/", Ze = "http://ns.adobe.com/xmp/extension/";
|
|
class et extends ge {
|
|
static canHandle(e2, t2) {
|
|
return 225 === e2.getUint8(t2 + 1) && 1752462448 === e2.getUint32(t2 + 4) && e2.getString(t2 + 4, Qe.length) === Qe;
|
|
}
|
|
static headerLength(e2, t2) {
|
|
return e2.getString(t2 + 4, Ze.length) === Ze ? 79 : 4 + "http://ns.adobe.com/xap/1.0/".length + 1;
|
|
}
|
|
static findPosition(e2, t2) {
|
|
let i2 = super.findPosition(e2, t2);
|
|
return i2.multiSegment = i2.extended = 79 === i2.headerLength, i2.multiSegment ? (i2.chunkCount = e2.getUint8(t2 + 72), i2.chunkNumber = e2.getUint8(t2 + 76), 0 !== e2.getUint8(t2 + 77) && i2.chunkNumber++) : (i2.chunkCount = 1 / 0, i2.chunkNumber = -1), i2;
|
|
}
|
|
static handleMultiSegments(e2) {
|
|
return e2.map(((e3) => e3.chunk.getString())).join("");
|
|
}
|
|
normalizeInput(e2) {
|
|
return "string" == typeof e2 ? e2 : I.from(e2).getString();
|
|
}
|
|
parse(e2 = this.chunk) {
|
|
if (!this.localOptions.parse) return e2;
|
|
e2 = (function(e3) {
|
|
let t3 = {}, i3 = {};
|
|
for (let e4 of ut) t3[e4] = [], i3[e4] = 0;
|
|
return e3.replace(ct, ((e4, n3, s2) => {
|
|
if ("<" === n3) {
|
|
let n4 = ++i3[s2];
|
|
return t3[s2].push(n4), `${e4}#${n4}`;
|
|
}
|
|
return `${e4}#${t3[s2].pop()}`;
|
|
}));
|
|
})(e2);
|
|
let t2 = nt.findAll(e2, "rdf", "Description");
|
|
0 === t2.length && t2.push(new nt("rdf", "Description", void 0, e2));
|
|
let i2, n2 = {};
|
|
for (let e3 of t2) for (let t3 of e3.properties) i2 = ot(t3.ns, n2), st(t3, i2);
|
|
return (function(e3) {
|
|
let t3;
|
|
for (let i3 in e3) t3 = e3[i3] = d(e3[i3]), void 0 === t3 && delete e3[i3];
|
|
return d(e3);
|
|
})(n2);
|
|
}
|
|
assignToOutput(e2, t2) {
|
|
if (this.localOptions.parse) for (let [i2, n2] of Object.entries(t2)) switch (i2) {
|
|
case "tiff":
|
|
this.assignObjectToOutput(e2, "ifd0", n2);
|
|
break;
|
|
case "exif":
|
|
this.assignObjectToOutput(e2, "exif", n2);
|
|
break;
|
|
case "xmlns":
|
|
break;
|
|
default:
|
|
this.assignObjectToOutput(e2, i2, n2);
|
|
}
|
|
else e2.xmp = t2;
|
|
}
|
|
}
|
|
f(et, "type", "xmp"), f(et, "multiSegment", true), A.set("xmp", et);
|
|
class tt {
|
|
static findAll(e2) {
|
|
return lt(e2, /([a-zA-Z0-9-]+):([a-zA-Z0-9-]+)=("[^"]*"|'[^']*')/gm).map(tt.unpackMatch);
|
|
}
|
|
static unpackMatch(e2) {
|
|
let t2 = e2[1], i2 = e2[2], n2 = e2[3].slice(1, -1);
|
|
return n2 = ht(n2), new tt(t2, i2, n2);
|
|
}
|
|
constructor(e2, t2, i2) {
|
|
this.ns = e2, this.name = t2, this.value = i2;
|
|
}
|
|
serialize() {
|
|
return this.value;
|
|
}
|
|
}
|
|
const it = "[\\w\\d-]+";
|
|
class nt {
|
|
static findAll(e2, t2, i2) {
|
|
if (void 0 !== t2 || void 0 !== i2) {
|
|
t2 = t2 || it, i2 = i2 || it;
|
|
var n2 = new RegExp(`<(${t2}):(${i2})(#\\d+)?((\\s+?[\\w\\d-:]+=("[^"]*"|'[^']*'))*\\s*)(\\/>|>([\\s\\S]*?)<\\/\\1:\\2\\3>)`, "gm");
|
|
} else n2 = /<([\w\d-]+):([\w\d-]+)(#\d+)?((\s+?[\w\d-:]+=("[^"]*"|'[^']*'))*\s*)(\/>|>([\s\S]*?)<\/\1:\2\3>)/gm;
|
|
return lt(e2, n2).map(nt.unpackMatch);
|
|
}
|
|
static unpackMatch(e2) {
|
|
let t2 = e2[1], i2 = e2[2], n2 = e2[4], s2 = e2[8];
|
|
return new nt(t2, i2, n2, s2);
|
|
}
|
|
constructor(e2, t2, i2, n2) {
|
|
this.ns = e2, this.name = t2, this.attrString = i2, this.innerXml = n2, this.attrs = tt.findAll(i2), this.children = nt.findAll(n2), this.value = 0 === this.children.length ? ht(n2) : void 0, this.properties = [...this.attrs, ...this.children];
|
|
}
|
|
get isPrimitive() {
|
|
return void 0 !== this.value && 0 === this.attrs.length && 0 === this.children.length;
|
|
}
|
|
get isListContainer() {
|
|
return 1 === this.children.length && this.children[0].isList;
|
|
}
|
|
get isList() {
|
|
let { ns: e2, name: t2 } = this;
|
|
return "rdf" === e2 && ("Seq" === t2 || "Bag" === t2 || "Alt" === t2);
|
|
}
|
|
get isListItem() {
|
|
return "rdf" === this.ns && "li" === this.name;
|
|
}
|
|
serialize() {
|
|
if (0 === this.properties.length && void 0 === this.value) return;
|
|
if (this.isPrimitive) return this.value;
|
|
if (this.isListContainer) return this.children[0].serialize();
|
|
if (this.isList) return at(this.children.map(rt));
|
|
if (this.isListItem && 1 === this.children.length && 0 === this.attrs.length) return this.children[0].serialize();
|
|
let e2 = {};
|
|
for (let t2 of this.properties) st(t2, e2);
|
|
return void 0 !== this.value && (e2.value = this.value), d(e2);
|
|
}
|
|
}
|
|
function st(e2, t2) {
|
|
let i2 = e2.serialize();
|
|
void 0 !== i2 && (t2[e2.name] = i2);
|
|
}
|
|
var rt = (e2) => e2.serialize(), at = (e2) => 1 === e2.length ? e2[0] : e2, ot = (e2, t2) => t2[e2] ? t2[e2] : t2[e2] = {};
|
|
function lt(e2, t2) {
|
|
let i2, n2 = [];
|
|
if (!e2) return n2;
|
|
for (; null !== (i2 = t2.exec(e2)); ) n2.push(i2);
|
|
return n2;
|
|
}
|
|
function ht(e2) {
|
|
if ((function(e3) {
|
|
return null == e3 || "null" === e3 || "undefined" === e3 || "" === e3 || "" === e3.trim();
|
|
})(e2)) return;
|
|
let t2 = Number(e2);
|
|
if (!Number.isNaN(t2)) return t2;
|
|
let i2 = e2.toLowerCase();
|
|
return "true" === i2 || "false" !== i2 && e2.trim();
|
|
}
|
|
const ut = ["rdf:li", "rdf:Seq", "rdf:Bag", "rdf:Alt", "rdf:Description"], ct = new RegExp(`(<|\\/)(${ut.join("|")})`, "g");
|
|
var ft = Object.freeze({ __proto__: null, default: Ge, Exifr: ce, fileParsers: T, segmentParsers: A, fileReaders: D, tagKeys: N, tagValues: G, tagRevivers: V, createDictionary: B, extendDictionary: E, fetchUrlAsArrayBuffer: L, readBlobAsArrayBuffer: U, chunkedProps: $2, otherSegments: J, segments: q, tiffBlocks: Q, segmentsAndBlocks: Z, tiffExtractables: ee, inheritables: te, allFormatters: ie, Options: oe, parse: fe, gpsOnlyOptions: Ae, gps: De, thumbnailOnlyOptions: Oe, thumbnail: xe, thumbnailUrl: ve, orientationOnlyOptions: Me, orientation: Re, rotations: Le, get rotateCanvas() {
|
|
return e.rotateCanvas;
|
|
}, get rotateCss() {
|
|
return e.rotateCss;
|
|
}, rotation: Ue });
|
|
const dt = ["xmp", "icc", "iptc", "tiff"], pt = () => {
|
|
};
|
|
async function gt(e2, t2, i2) {
|
|
let n2 = i2[e2];
|
|
return n2.enabled = true, n2.parse = true, A.get(e2).parse(t2, n2);
|
|
}
|
|
let mt = h("fs", ((e2) => e2.promises));
|
|
D.set("fs", class extends Ne {
|
|
async readWhole() {
|
|
this.chunked = false, this.fs = await mt;
|
|
let e2 = await this.fs.readFile(this.input);
|
|
this._swapBuffer(e2);
|
|
}
|
|
async readChunked() {
|
|
this.chunked = true, this.fs = await mt, await this.open(), await this.readChunk(0, this.options.firstChunkSize);
|
|
}
|
|
async open() {
|
|
void 0 === this.fh && (this.fh = await this.fs.open(this.input, "r"), this.size = (await this.fh.stat(this.input)).size);
|
|
}
|
|
async _readChunk(e2, t2) {
|
|
void 0 === this.fh && await this.open(), e2 + t2 > this.size && (t2 = this.size - e2);
|
|
var i2 = this.subarray(e2, t2, true);
|
|
return await this.fh.read(i2.dataView, 0, t2, e2), i2;
|
|
}
|
|
async close() {
|
|
if (this.fh) {
|
|
let e2 = this.fh;
|
|
this.fh = void 0, await e2.close();
|
|
}
|
|
}
|
|
});
|
|
D.set("base64", class extends Ne {
|
|
constructor(...e2) {
|
|
super(...e2), this.input = this.input.replace(/^data:([^;]+);base64,/gim, ""), this.size = this.input.length / 4 * 3, this.input.endsWith("==") ? this.size -= 2 : this.input.endsWith("=") && (this.size -= 1);
|
|
}
|
|
async _readChunk(e2, t2) {
|
|
let i2, n2, s2 = this.input;
|
|
void 0 === e2 ? (e2 = 0, i2 = 0, n2 = 0) : (i2 = 4 * Math.floor(e2 / 3), n2 = e2 - i2 / 4 * 3), void 0 === t2 && (t2 = this.size);
|
|
let a2 = e2 + t2, l2 = i2 + 4 * Math.ceil(a2 / 3);
|
|
s2 = s2.slice(i2, l2);
|
|
let h2 = Math.min(t2, this.size - e2);
|
|
if (o) {
|
|
let t3 = r.from(s2, "base64").slice(n2, n2 + h2);
|
|
return this.set(t3, e2, true);
|
|
}
|
|
{
|
|
let t3 = this.subarray(e2, h2, true), i3 = atob(s2), r2 = t3.toUint8();
|
|
for (let e3 = 0; e3 < h2; e3++) r2[e3] = i3.charCodeAt(n2 + e3);
|
|
return t3;
|
|
}
|
|
}
|
|
});
|
|
class St extends pe {
|
|
static canHandle(e2, t2) {
|
|
return 18761 === t2 || 19789 === t2;
|
|
}
|
|
extendOptions(e2) {
|
|
let { ifd0: t2, xmp: i2, iptc: n2, icc: s2 } = e2;
|
|
i2.enabled && t2.deps.add(j), n2.enabled && t2.deps.add(W), s2.enabled && t2.deps.add(K2), t2.finalizeFilters();
|
|
}
|
|
async parse() {
|
|
let { tiff: e2, xmp: t2, iptc: i2, icc: n2 } = this.options;
|
|
if (e2.enabled || t2.enabled || i2.enabled || n2.enabled) {
|
|
let e3 = Math.max(C(this.options), this.options.chunkSize);
|
|
await this.file.ensureChunk(0, e3), this.createParser("tiff", this.file), this.parsers.tiff.parseHeader(), await this.parsers.tiff.parseIfd0Block(), this.adaptTiffPropAsSegment("xmp"), this.adaptTiffPropAsSegment("iptc"), this.adaptTiffPropAsSegment("icc");
|
|
}
|
|
}
|
|
adaptTiffPropAsSegment(e2) {
|
|
if (this.parsers.tiff[e2]) {
|
|
let t2 = this.parsers.tiff[e2];
|
|
this.injectSegment(e2, t2);
|
|
}
|
|
}
|
|
}
|
|
f(St, "type", "tiff"), T.set("tiff", St);
|
|
let Ct = h("zlib");
|
|
const yt = "XML:com.adobe.xmp", bt = "ihdr", Pt = "iccp", It = "text", kt = "itxt", wt = [bt, Pt, It, kt, "exif"];
|
|
class Tt extends pe {
|
|
constructor(...e2) {
|
|
super(...e2), f(this, "catchError", ((e3) => this.errors.push(e3))), f(this, "metaChunks", []), f(this, "unknownChunks", []);
|
|
}
|
|
static canHandle(e2, t2) {
|
|
return 35152 === t2 && 2303741511 === e2.getUint32(0) && 218765834 === e2.getUint32(4);
|
|
}
|
|
async parse() {
|
|
let { file: e2 } = this;
|
|
await this.findPngChunksInRange("\x89PNG\r\n\n".length, e2.byteLength), await this.readSegments(this.metaChunks), this.findIhdr(), this.parseTextChunks(), await this.findExif().catch(this.catchError), await this.findXmp().catch(this.catchError), await this.findIcc().catch(this.catchError);
|
|
}
|
|
async findPngChunksInRange(e2, t2) {
|
|
let { file: i2 } = this;
|
|
for (; e2 < t2; ) {
|
|
let t3 = i2.getUint32(e2), n2 = i2.getUint32(e2 + 4), s2 = i2.getString(e2 + 4, 4).toLowerCase(), r2 = t3 + 4 + 4 + 4, a2 = { type: s2, offset: e2, length: r2, start: e2 + 4 + 4, size: t3, marker: n2 };
|
|
wt.includes(s2) ? this.metaChunks.push(a2) : this.unknownChunks.push(a2), e2 += r2;
|
|
}
|
|
}
|
|
parseTextChunks() {
|
|
let e2 = this.metaChunks.filter(((e3) => e3.type === It));
|
|
for (let t2 of e2) {
|
|
let [e3, i2] = this.file.getString(t2.start, t2.size).split("\0");
|
|
this.injectKeyValToIhdr(e3, i2);
|
|
}
|
|
}
|
|
injectKeyValToIhdr(e2, t2) {
|
|
let i2 = this.parsers.ihdr;
|
|
i2 && i2.raw.set(e2, t2);
|
|
}
|
|
findIhdr() {
|
|
let e2 = this.metaChunks.find(((e3) => e3.type === bt));
|
|
e2 && false !== this.options.ihdr.enabled && this.createParser(bt, e2.chunk);
|
|
}
|
|
async findExif() {
|
|
let e2 = this.metaChunks.find(((e3) => "exif" === e3.type));
|
|
e2 && this.injectSegment("tiff", e2.chunk);
|
|
}
|
|
async findXmp() {
|
|
let e2 = this.metaChunks.filter(((e3) => e3.type === kt));
|
|
for (let t2 of e2) {
|
|
t2.chunk.getString(0, yt.length) === yt && this.injectSegment("xmp", t2.chunk);
|
|
}
|
|
}
|
|
async findIcc() {
|
|
let e2 = this.metaChunks.find(((e3) => e3.type === Pt));
|
|
if (!e2) return;
|
|
let { chunk: t2 } = e2, i2 = t2.getUint8Array(0, 81), n2 = 0;
|
|
for (; n2 < 80 && 0 !== i2[n2]; ) n2++;
|
|
let r2 = n2 + 2, a2 = t2.getString(0, n2);
|
|
if (this.injectKeyValToIhdr("ProfileName", a2), s) {
|
|
let e3 = await Ct, i3 = t2.getUint8Array(r2);
|
|
i3 = e3.inflateSync(i3), this.injectSegment("icc", i3);
|
|
}
|
|
}
|
|
}
|
|
f(Tt, "type", "png"), T.set("png", Tt), B(N, "interop", [[1, "InteropIndex"], [2, "InteropVersion"], [4096, "RelatedImageFileFormat"], [4097, "RelatedImageWidth"], [4098, "RelatedImageHeight"]]), E(N, "ifd0", [[11, "ProcessingSoftware"], [254, "SubfileType"], [255, "OldSubfileType"], [263, "Thresholding"], [264, "CellWidth"], [265, "CellLength"], [266, "FillOrder"], [269, "DocumentName"], [280, "MinSampleValue"], [281, "MaxSampleValue"], [285, "PageName"], [286, "XPosition"], [287, "YPosition"], [290, "GrayResponseUnit"], [297, "PageNumber"], [321, "HalftoneHints"], [322, "TileWidth"], [323, "TileLength"], [332, "InkSet"], [337, "TargetPrinter"], [18246, "Rating"], [18249, "RatingPercent"], [33550, "PixelScale"], [34264, "ModelTransform"], [34377, "PhotoshopSettings"], [50706, "DNGVersion"], [50707, "DNGBackwardVersion"], [50708, "UniqueCameraModel"], [50709, "LocalizedCameraModel"], [50736, "DNGLensInfo"], [50739, "ShadowScale"], [50740, "DNGPrivateData"], [33920, "IntergraphMatrix"], [33922, "ModelTiePoint"], [34118, "SEMInfo"], [34735, "GeoTiffDirectory"], [34736, "GeoTiffDoubleParams"], [34737, "GeoTiffAsciiParams"], [50341, "PrintIM"], [50721, "ColorMatrix1"], [50722, "ColorMatrix2"], [50723, "CameraCalibration1"], [50724, "CameraCalibration2"], [50725, "ReductionMatrix1"], [50726, "ReductionMatrix2"], [50727, "AnalogBalance"], [50728, "AsShotNeutral"], [50729, "AsShotWhiteXY"], [50730, "BaselineExposure"], [50731, "BaselineNoise"], [50732, "BaselineSharpness"], [50734, "LinearResponseLimit"], [50735, "CameraSerialNumber"], [50741, "MakerNoteSafety"], [50778, "CalibrationIlluminant1"], [50779, "CalibrationIlluminant2"], [50781, "RawDataUniqueID"], [50827, "OriginalRawFileName"], [50828, "OriginalRawFileData"], [50831, "AsShotICCProfile"], [50832, "AsShotPreProfileMatrix"], [50833, "CurrentICCProfile"], [50834, "CurrentPreProfileMatrix"], [50879, "ColorimetricReference"], [50885, "SRawType"], [50898, "PanasonicTitle"], [50899, "PanasonicTitle2"], [50931, "CameraCalibrationSig"], [50932, "ProfileCalibrationSig"], [50933, "ProfileIFD"], [50934, "AsShotProfileName"], [50936, "ProfileName"], [50937, "ProfileHueSatMapDims"], [50938, "ProfileHueSatMapData1"], [50939, "ProfileHueSatMapData2"], [50940, "ProfileToneCurve"], [50941, "ProfileEmbedPolicy"], [50942, "ProfileCopyright"], [50964, "ForwardMatrix1"], [50965, "ForwardMatrix2"], [50966, "PreviewApplicationName"], [50967, "PreviewApplicationVersion"], [50968, "PreviewSettingsName"], [50969, "PreviewSettingsDigest"], [50970, "PreviewColorSpace"], [50971, "PreviewDateTime"], [50972, "RawImageDigest"], [50973, "OriginalRawFileDigest"], [50981, "ProfileLookTableDims"], [50982, "ProfileLookTableData"], [51043, "TimeCodes"], [51044, "FrameRate"], [51058, "TStop"], [51081, "ReelName"], [51089, "OriginalDefaultFinalSize"], [51090, "OriginalBestQualitySize"], [51091, "OriginalDefaultCropSize"], [51105, "CameraLabel"], [51107, "ProfileHueSatMapEncoding"], [51108, "ProfileLookTableEncoding"], [51109, "BaselineExposureOffset"], [51110, "DefaultBlackRender"], [51111, "NewRawImageDigest"], [51112, "RawToPreviewGain"]]);
|
|
let At = [[273, "StripOffsets"], [279, "StripByteCounts"], [288, "FreeOffsets"], [289, "FreeByteCounts"], [291, "GrayResponseCurve"], [292, "T4Options"], [293, "T6Options"], [300, "ColorResponseUnit"], [320, "ColorMap"], [324, "TileOffsets"], [325, "TileByteCounts"], [326, "BadFaxLines"], [327, "CleanFaxData"], [328, "ConsecutiveBadFaxLines"], [330, "SubIFD"], [333, "InkNames"], [334, "NumberofInks"], [336, "DotRange"], [338, "ExtraSamples"], [339, "SampleFormat"], [340, "SMinSampleValue"], [341, "SMaxSampleValue"], [342, "TransferRange"], [343, "ClipPath"], [344, "XClipPathUnits"], [345, "YClipPathUnits"], [346, "Indexed"], [347, "JPEGTables"], [351, "OPIProxy"], [400, "GlobalParametersIFD"], [401, "ProfileType"], [402, "FaxProfile"], [403, "CodingMethods"], [404, "VersionYear"], [405, "ModeNumber"], [433, "Decode"], [434, "DefaultImageColor"], [435, "T82Options"], [437, "JPEGTables"], [512, "JPEGProc"], [515, "JPEGRestartInterval"], [517, "JPEGLosslessPredictors"], [518, "JPEGPointTransforms"], [519, "JPEGQTables"], [520, "JPEGDCTables"], [521, "JPEGACTables"], [559, "StripRowCounts"], [999, "USPTOMiscellaneous"], [18247, "XP_DIP_XML"], [18248, "StitchInfo"], [28672, "SonyRawFileType"], [28688, "SonyToneCurve"], [28721, "VignettingCorrection"], [28722, "VignettingCorrParams"], [28724, "ChromaticAberrationCorrection"], [28725, "ChromaticAberrationCorrParams"], [28726, "DistortionCorrection"], [28727, "DistortionCorrParams"], [29895, "SonyCropTopLeft"], [29896, "SonyCropSize"], [32781, "ImageID"], [32931, "WangTag1"], [32932, "WangAnnotation"], [32933, "WangTag3"], [32934, "WangTag4"], [32953, "ImageReferencePoints"], [32954, "RegionXformTackPoint"], [32955, "WarpQuadrilateral"], [32956, "AffineTransformMat"], [32995, "Matteing"], [32996, "DataType"], [32997, "ImageDepth"], [32998, "TileDepth"], [33300, "ImageFullWidth"], [33301, "ImageFullHeight"], [33302, "TextureFormat"], [33303, "WrapModes"], [33304, "FovCot"], [33305, "MatrixWorldToScreen"], [33306, "MatrixWorldToCamera"], [33405, "Model2"], [33421, "CFARepeatPatternDim"], [33422, "CFAPattern2"], [33423, "BatteryLevel"], [33424, "KodakIFD"], [33445, "MDFileTag"], [33446, "MDScalePixel"], [33447, "MDColorTable"], [33448, "MDLabName"], [33449, "MDSampleInfo"], [33450, "MDPrepDate"], [33451, "MDPrepTime"], [33452, "MDFileUnits"], [33589, "AdventScale"], [33590, "AdventRevision"], [33628, "UIC1Tag"], [33629, "UIC2Tag"], [33630, "UIC3Tag"], [33631, "UIC4Tag"], [33918, "IntergraphPacketData"], [33919, "IntergraphFlagRegisters"], [33921, "INGRReserved"], [34016, "Site"], [34017, "ColorSequence"], [34018, "IT8Header"], [34019, "RasterPadding"], [34020, "BitsPerRunLength"], [34021, "BitsPerExtendedRunLength"], [34022, "ColorTable"], [34023, "ImageColorIndicator"], [34024, "BackgroundColorIndicator"], [34025, "ImageColorValue"], [34026, "BackgroundColorValue"], [34027, "PixelIntensityRange"], [34028, "TransparencyIndicator"], [34029, "ColorCharacterization"], [34030, "HCUsage"], [34031, "TrapIndicator"], [34032, "CMYKEquivalent"], [34152, "AFCP_IPTC"], [34232, "PixelMagicJBIGOptions"], [34263, "JPLCartoIFD"], [34306, "WB_GRGBLevels"], [34310, "LeafData"], [34687, "TIFF_FXExtensions"], [34688, "MultiProfiles"], [34689, "SharedData"], [34690, "T88Options"], [34732, "ImageLayer"], [34750, "JBIGOptions"], [34856, "Opto-ElectricConvFactor"], [34857, "Interlace"], [34908, "FaxRecvParams"], [34909, "FaxSubAddress"], [34910, "FaxRecvTime"], [34929, "FedexEDR"], [34954, "LeafSubIFD"], [37387, "FlashEnergy"], [37388, "SpatialFrequencyResponse"], [37389, "Noise"], [37390, "FocalPlaneXResolution"], [37391, "FocalPlaneYResolution"], [37392, "FocalPlaneResolutionUnit"], [37397, "ExposureIndex"], [37398, "TIFF-EPStandardID"], [37399, "SensingMethod"], [37434, "CIP3DataFile"], [37435, "CIP3Sheet"], [37436, "CIP3Side"], [37439, "StoNits"], [37679, "MSDocumentText"], [37680, "MSPropertySetStorage"], [37681, "MSDocumentTextPosition"], [37724, "ImageSourceData"], [40965, "InteropIFD"], [40976, "SamsungRawPointersOffset"], [40977, "SamsungRawPointersLength"], [41217, "SamsungRawByteOrder"], [41218, "SamsungRawUnknown"], [41484, "SpatialFrequencyResponse"], [41485, "Noise"], [41489, "ImageNumber"], [41490, "SecurityClassification"], [41491, "ImageHistory"], [41494, "TIFF-EPStandardID"], [41995, "DeviceSettingDescription"], [42112, "GDALMetadata"], [42113, "GDALNoData"], [44992, "ExpandSoftware"], [44993, "ExpandLens"], [44994, "ExpandFilm"], [44995, "ExpandFilterLens"], [44996, "ExpandScanner"], [44997, "ExpandFlashLamp"], [46275, "HasselbladRawImage"], [48129, "PixelFormat"], [48130, "Transformation"], [48131, "Uncompressed"], [48132, "ImageType"], [48256, "ImageWidth"], [48257, "ImageHeight"], [48258, "WidthResolution"], [48259, "HeightResolution"], [48320, "ImageOffset"], [48321, "ImageByteCount"], [48322, "AlphaOffset"], [48323, "AlphaByteCount"], [48324, "ImageDataDiscard"], [48325, "AlphaDataDiscard"], [50215, "OceScanjobDesc"], [50216, "OceApplicationSelector"], [50217, "OceIDNumber"], [50218, "OceImageLogic"], [50255, "Annotations"], [50459, "HasselbladExif"], [50547, "OriginalFileName"], [50560, "USPTOOriginalContentType"], [50656, "CR2CFAPattern"], [50710, "CFAPlaneColor"], [50711, "CFALayout"], [50712, "LinearizationTable"], [50713, "BlackLevelRepeatDim"], [50714, "BlackLevel"], [50715, "BlackLevelDeltaH"], [50716, "BlackLevelDeltaV"], [50717, "WhiteLevel"], [50718, "DefaultScale"], [50719, "DefaultCropOrigin"], [50720, "DefaultCropSize"], [50733, "BayerGreenSplit"], [50737, "ChromaBlurRadius"], [50738, "AntiAliasStrength"], [50752, "RawImageSegmentation"], [50780, "BestQualityScale"], [50784, "AliasLayerMetadata"], [50829, "ActiveArea"], [50830, "MaskedAreas"], [50935, "NoiseReductionApplied"], [50974, "SubTileBlockSize"], [50975, "RowInterleaveFactor"], [51008, "OpcodeList1"], [51009, "OpcodeList2"], [51022, "OpcodeList3"], [51041, "NoiseProfile"], [51114, "CacheVersion"], [51125, "DefaultUserCrop"], [51157, "NikonNEFInfo"], [65024, "KdcIFD"]];
|
|
E(N, "ifd0", At), E(N, "exif", At), B(G, "gps", [[23, { M: "Magnetic North", T: "True North" }], [25, { K: "Kilometers", M: "Miles", N: "Nautical Miles" }]]);
|
|
class Dt extends ge {
|
|
static canHandle(e2, t2) {
|
|
return 224 === e2.getUint8(t2 + 1) && 1246120262 === e2.getUint32(t2 + 4) && 0 === e2.getUint8(t2 + 8);
|
|
}
|
|
parse() {
|
|
return this.parseTags(), this.translate(), this.output;
|
|
}
|
|
parseTags() {
|
|
this.raw = /* @__PURE__ */ new Map([[0, this.chunk.getUint16(0)], [2, this.chunk.getUint8(2)], [3, this.chunk.getUint16(3)], [5, this.chunk.getUint16(5)], [7, this.chunk.getUint8(7)], [8, this.chunk.getUint8(8)]]);
|
|
}
|
|
}
|
|
f(Dt, "type", "jfif"), f(Dt, "headerLength", 9), A.set("jfif", Dt), B(N, "jfif", [[0, "JFIFVersion"], [2, "ResolutionUnit"], [3, "XResolution"], [5, "YResolution"], [7, "ThumbnailWidth"], [8, "ThumbnailHeight"]]);
|
|
class Ot extends ge {
|
|
parse() {
|
|
return this.parseTags(), this.translate(), this.output;
|
|
}
|
|
parseTags() {
|
|
this.raw = new Map([[0, this.chunk.getUint32(0)], [4, this.chunk.getUint32(4)], [8, this.chunk.getUint8(8)], [9, this.chunk.getUint8(9)], [10, this.chunk.getUint8(10)], [11, this.chunk.getUint8(11)], [12, this.chunk.getUint8(12)], ...Array.from(this.raw)]);
|
|
}
|
|
}
|
|
f(Ot, "type", "ihdr"), A.set("ihdr", Ot), B(N, "ihdr", [[0, "ImageWidth"], [4, "ImageHeight"], [8, "BitDepth"], [9, "ColorType"], [10, "Compression"], [11, "Filter"], [12, "Interlace"]]), B(G, "ihdr", [[9, { 0: "Grayscale", 2: "RGB", 3: "Palette", 4: "Grayscale with Alpha", 6: "RGB with Alpha", DEFAULT: "Unknown" }], [10, { 0: "Deflate/Inflate", DEFAULT: "Unknown" }], [11, { 0: "Adaptive", DEFAULT: "Unknown" }], [12, { 0: "Noninterlaced", 1: "Adam7 Interlace", DEFAULT: "Unknown" }]]);
|
|
const xt = "\0\0\0\0";
|
|
class vt extends ge {
|
|
static canHandle(e2, t2) {
|
|
return 226 === e2.getUint8(t2 + 1) && 1229144927 === e2.getUint32(t2 + 4);
|
|
}
|
|
static findPosition(e2, t2) {
|
|
let i2 = super.findPosition(e2, t2);
|
|
return i2.chunkNumber = e2.getUint8(t2 + 16), i2.chunkCount = e2.getUint8(t2 + 17), i2.multiSegment = i2.chunkCount > 1, i2;
|
|
}
|
|
static handleMultiSegments(e2) {
|
|
return (function(e3) {
|
|
let t2 = (function(e4) {
|
|
let t3 = e4[0].constructor, i2 = 0;
|
|
for (let t4 of e4) i2 += t4.length;
|
|
let n2 = new t3(i2), s2 = 0;
|
|
for (let t4 of e4) n2.set(t4, s2), s2 += t4.length;
|
|
return n2;
|
|
})(e3.map(((e4) => e4.chunk.toUint8())));
|
|
return new I(t2);
|
|
})(e2);
|
|
}
|
|
parse() {
|
|
return this.raw = /* @__PURE__ */ new Map(), this.parseHeader(), this.parseTags(), this.translate(), this.output;
|
|
}
|
|
parseHeader() {
|
|
let { raw: e2 } = this;
|
|
this.chunk.byteLength < 84 && m("ICC header is too short");
|
|
for (let [t2, i2] of Object.entries(Mt)) {
|
|
t2 = parseInt(t2, 10);
|
|
let n2 = i2(this.chunk, t2);
|
|
n2 !== xt && e2.set(t2, n2);
|
|
}
|
|
}
|
|
parseTags() {
|
|
let e2, t2, i2, n2, s2, { raw: r2 } = this, a2 = this.chunk.getUint32(128), o2 = 132, l2 = this.chunk.byteLength;
|
|
for (; a2--; ) {
|
|
if (e2 = this.chunk.getString(o2, 4), t2 = this.chunk.getUint32(o2 + 4), i2 = this.chunk.getUint32(o2 + 8), n2 = this.chunk.getString(t2, 4), t2 + i2 > l2) return void console.warn("reached the end of the first ICC chunk. Enable options.tiff.multiSegment to read all ICC segments.");
|
|
s2 = this.parseTag(n2, t2, i2), void 0 !== s2 && s2 !== xt && r2.set(e2, s2), o2 += 12;
|
|
}
|
|
}
|
|
parseTag(e2, t2, i2) {
|
|
switch (e2) {
|
|
case "desc":
|
|
return this.parseDesc(t2);
|
|
case "mluc":
|
|
return this.parseMluc(t2);
|
|
case "text":
|
|
return this.parseText(t2, i2);
|
|
case "sig ":
|
|
return this.parseSig(t2);
|
|
}
|
|
if (!(t2 + i2 > this.chunk.byteLength)) return this.chunk.getUint8Array(t2, i2);
|
|
}
|
|
parseDesc(e2) {
|
|
let t2 = this.chunk.getUint32(e2 + 8) - 1;
|
|
return S(this.chunk.getString(e2 + 12, t2));
|
|
}
|
|
parseText(e2, t2) {
|
|
return S(this.chunk.getString(e2 + 8, t2 - 8));
|
|
}
|
|
parseSig(e2) {
|
|
return S(this.chunk.getString(e2 + 8, 4));
|
|
}
|
|
parseMluc(e2) {
|
|
let { chunk: t2 } = this, i2 = t2.getUint32(e2 + 8), n2 = t2.getUint32(e2 + 12), s2 = e2 + 16, r2 = [];
|
|
for (let a2 = 0; a2 < i2; a2++) {
|
|
let i3 = t2.getString(s2 + 0, 2), a3 = t2.getString(s2 + 2, 2), o2 = t2.getUint32(s2 + 4), l2 = t2.getUint32(s2 + 8) + e2, h2 = S(t2.getUnicodeString(l2, o2));
|
|
r2.push({ lang: i3, country: a3, text: h2 }), s2 += n2;
|
|
}
|
|
return 1 === i2 ? r2[0].text : r2;
|
|
}
|
|
translateValue(e2, t2) {
|
|
return "string" == typeof e2 ? t2[e2] || t2[e2.toLowerCase()] || e2 : t2[e2] || e2;
|
|
}
|
|
}
|
|
f(vt, "type", "icc"), f(vt, "multiSegment", true), f(vt, "headerLength", 18);
|
|
const Mt = { 4: Rt, 8: function(e2, t2) {
|
|
return [e2.getUint8(t2), e2.getUint8(t2 + 1) >> 4, e2.getUint8(t2 + 1) % 16].map(((e3) => e3.toString(10))).join(".");
|
|
}, 12: Rt, 16: Rt, 20: Rt, 24: function(e2, t2) {
|
|
const i2 = e2.getUint16(t2), n2 = e2.getUint16(t2 + 2) - 1, s2 = e2.getUint16(t2 + 4), r2 = e2.getUint16(t2 + 6), a2 = e2.getUint16(t2 + 8), o2 = e2.getUint16(t2 + 10);
|
|
return new Date(Date.UTC(i2, n2, s2, r2, a2, o2));
|
|
}, 36: Rt, 40: Rt, 48: Rt, 52: Rt, 64: (e2, t2) => e2.getUint32(t2), 80: Rt };
|
|
function Rt(e2, t2) {
|
|
return S(e2.getString(t2, 4));
|
|
}
|
|
A.set("icc", vt), B(N, "icc", [[4, "ProfileCMMType"], [8, "ProfileVersion"], [12, "ProfileClass"], [16, "ColorSpaceData"], [20, "ProfileConnectionSpace"], [24, "ProfileDateTime"], [36, "ProfileFileSignature"], [40, "PrimaryPlatform"], [44, "CMMFlags"], [48, "DeviceManufacturer"], [52, "DeviceModel"], [56, "DeviceAttributes"], [64, "RenderingIntent"], [68, "ConnectionSpaceIlluminant"], [80, "ProfileCreator"], [84, "ProfileID"], ["Header", "ProfileHeader"], ["MS00", "WCSProfiles"], ["bTRC", "BlueTRC"], ["bXYZ", "BlueMatrixColumn"], ["bfd", "UCRBG"], ["bkpt", "MediaBlackPoint"], ["calt", "CalibrationDateTime"], ["chad", "ChromaticAdaptation"], ["chrm", "Chromaticity"], ["ciis", "ColorimetricIntentImageState"], ["clot", "ColorantTableOut"], ["clro", "ColorantOrder"], ["clrt", "ColorantTable"], ["cprt", "ProfileCopyright"], ["crdi", "CRDInfo"], ["desc", "ProfileDescription"], ["devs", "DeviceSettings"], ["dmdd", "DeviceModelDesc"], ["dmnd", "DeviceMfgDesc"], ["dscm", "ProfileDescriptionML"], ["fpce", "FocalPlaneColorimetryEstimates"], ["gTRC", "GreenTRC"], ["gXYZ", "GreenMatrixColumn"], ["gamt", "Gamut"], ["kTRC", "GrayTRC"], ["lumi", "Luminance"], ["meas", "Measurement"], ["meta", "Metadata"], ["mmod", "MakeAndModel"], ["ncl2", "NamedColor2"], ["ncol", "NamedColor"], ["ndin", "NativeDisplayInfo"], ["pre0", "Preview0"], ["pre1", "Preview1"], ["pre2", "Preview2"], ["ps2i", "PS2RenderingIntent"], ["ps2s", "PostScript2CSA"], ["psd0", "PostScript2CRD0"], ["psd1", "PostScript2CRD1"], ["psd2", "PostScript2CRD2"], ["psd3", "PostScript2CRD3"], ["pseq", "ProfileSequenceDesc"], ["psid", "ProfileSequenceIdentifier"], ["psvm", "PS2CRDVMSize"], ["rTRC", "RedTRC"], ["rXYZ", "RedMatrixColumn"], ["resp", "OutputResponse"], ["rhoc", "ReflectionHardcopyOrigColorimetry"], ["rig0", "PerceptualRenderingIntentGamut"], ["rig2", "SaturationRenderingIntentGamut"], ["rpoc", "ReflectionPrintOutputColorimetry"], ["sape", "SceneAppearanceEstimates"], ["scoe", "SceneColorimetryEstimates"], ["scrd", "ScreeningDesc"], ["scrn", "Screening"], ["targ", "CharTarget"], ["tech", "Technology"], ["vcgt", "VideoCardGamma"], ["view", "ViewingConditions"], ["vued", "ViewingCondDesc"], ["wtpt", "MediaWhitePoint"]]);
|
|
const Lt = { "4d2p": "Erdt Systems", AAMA: "Aamazing Technologies", ACER: "Acer", ACLT: "Acolyte Color Research", ACTI: "Actix Sytems", ADAR: "Adara Technology", ADBE: "Adobe", ADI: "ADI Systems", AGFA: "Agfa Graphics", ALMD: "Alps Electric", ALPS: "Alps Electric", ALWN: "Alwan Color Expertise", AMTI: "Amiable Technologies", AOC: "AOC International", APAG: "Apago", APPL: "Apple Computer", AST: "AST", "AT&T": "AT&T", BAEL: "BARBIERI electronic", BRCO: "Barco NV", BRKP: "Breakpoint", BROT: "Brother", BULL: "Bull", BUS: "Bus Computer Systems", "C-IT": "C-Itoh", CAMR: "Intel", CANO: "Canon", CARR: "Carroll Touch", CASI: "Casio", CBUS: "Colorbus PL", CEL: "Crossfield", CELx: "Crossfield", CGS: "CGS Publishing Technologies International", CHM: "Rochester Robotics", CIGL: "Colour Imaging Group, London", CITI: "Citizen", CL00: "Candela", CLIQ: "Color IQ", CMCO: "Chromaco", CMiX: "CHROMiX", COLO: "Colorgraphic Communications", COMP: "Compaq", COMp: "Compeq/Focus Technology", CONR: "Conrac Display Products", CORD: "Cordata Technologies", CPQ: "Compaq", CPRO: "ColorPro", CRN: "Cornerstone", CTX: "CTX International", CVIS: "ColorVision", CWC: "Fujitsu Laboratories", DARI: "Darius Technology", DATA: "Dataproducts", DCP: "Dry Creek Photo", DCRC: "Digital Contents Resource Center, Chung-Ang University", DELL: "Dell Computer", DIC: "Dainippon Ink and Chemicals", DICO: "Diconix", DIGI: "Digital", "DL&C": "Digital Light & Color", DPLG: "Doppelganger", DS: "Dainippon Screen", DSOL: "DOOSOL", DUPN: "DuPont", EPSO: "Epson", ESKO: "Esko-Graphics", ETRI: "Electronics and Telecommunications Research Institute", EVER: "Everex Systems", EXAC: "ExactCODE", Eizo: "Eizo", FALC: "Falco Data Products", FF: "Fuji Photo Film", FFEI: "FujiFilm Electronic Imaging", FNRD: "Fnord Software", FORA: "Fora", FORE: "Forefront Technology", FP: "Fujitsu", FPA: "WayTech Development", FUJI: "Fujitsu", FX: "Fuji Xerox", GCC: "GCC Technologies", GGSL: "Global Graphics Software", GMB: "Gretagmacbeth", GMG: "GMG", GOLD: "GoldStar Technology", GOOG: "Google", GPRT: "Giantprint", GTMB: "Gretagmacbeth", GVC: "WayTech Development", GW2K: "Sony", HCI: "HCI", HDM: "Heidelberger Druckmaschinen", HERM: "Hermes", HITA: "Hitachi America", HP: "Hewlett-Packard", HTC: "Hitachi", HiTi: "HiTi Digital", IBM: "IBM", IDNT: "Scitex", IEC: "Hewlett-Packard", IIYA: "Iiyama North America", IKEG: "Ikegami Electronics", IMAG: "Image Systems", IMI: "Ingram Micro", INTC: "Intel", INTL: "N/A (INTL)", INTR: "Intra Electronics", IOCO: "Iocomm International Technology", IPS: "InfoPrint Solutions Company", IRIS: "Scitex", ISL: "Ichikawa Soft Laboratory", ITNL: "N/A (ITNL)", IVM: "IVM", IWAT: "Iwatsu Electric", Idnt: "Scitex", Inca: "Inca Digital Printers", Iris: "Scitex", JPEG: "Joint Photographic Experts Group", JSFT: "Jetsoft Development", JVC: "JVC Information Products", KART: "Scitex", KFC: "KFC Computek Components", KLH: "KLH Computers", KMHD: "Konica Minolta", KNCA: "Konica", KODA: "Kodak", KYOC: "Kyocera", Kart: "Scitex", LCAG: "Leica", LCCD: "Leeds Colour", LDAK: "Left Dakota", LEAD: "Leading Technology", LEXM: "Lexmark International", LINK: "Link Computer", LINO: "Linotronic", LITE: "Lite-On", Leaf: "Leaf", Lino: "Linotronic", MAGC: "Mag Computronic", MAGI: "MAG Innovision", MANN: "Mannesmann", MICN: "Micron Technology", MICR: "Microtek", MICV: "Microvitec", MINO: "Minolta", MITS: "Mitsubishi Electronics America", MITs: "Mitsuba", MNLT: "Minolta", MODG: "Modgraph", MONI: "Monitronix", MONS: "Monaco Systems", MORS: "Morse Technology", MOTI: "Motive Systems", MSFT: "Microsoft", MUTO: "MUTOH INDUSTRIES", Mits: "Mitsubishi Electric", NANA: "NANAO", NEC: "NEC", NEXP: "NexPress Solutions", NISS: "Nissei Sangyo America", NKON: "Nikon", NONE: "none", OCE: "Oce Technologies", OCEC: "OceColor", OKI: "Oki", OKID: "Okidata", OKIP: "Okidata", OLIV: "Olivetti", OLYM: "Olympus", ONYX: "Onyx Graphics", OPTI: "Optiquest", PACK: "Packard Bell", PANA: "Matsushita Electric Industrial", PANT: "Pantone", PBN: "Packard Bell", PFU: "PFU", PHIL: "Philips Consumer Electronics", PNTX: "HOYA", POne: "Phase One A/S", PREM: "Premier Computer Innovations", PRIN: "Princeton Graphic Systems", PRIP: "Princeton Publishing Labs", QLUX: "Hong Kong", QMS: "QMS", QPCD: "QPcard AB", QUAD: "QuadLaser", QUME: "Qume", RADI: "Radius", RDDx: "Integrated Color Solutions", RDG: "Roland DG", REDM: "REDMS Group", RELI: "Relisys", RGMS: "Rolf Gierling Multitools", RICO: "Ricoh", RNLD: "Edmund Ronald", ROYA: "Royal", RPC: "Ricoh Printing Systems", RTL: "Royal Information Electronics", SAMP: "Sampo", SAMS: "Samsung", SANT: "Jaime Santana Pomares", SCIT: "Scitex", SCRN: "Dainippon Screen", SDP: "Scitex", SEC: "Samsung", SEIK: "Seiko Instruments", SEIk: "Seikosha", SGUY: "ScanGuy.com", SHAR: "Sharp Laboratories", SICC: "International Color Consortium", SONY: "Sony", SPCL: "SpectraCal", STAR: "Star", STC: "Sampo Technology", Scit: "Scitex", Sdp: "Scitex", Sony: "Sony", TALO: "Talon Technology", TAND: "Tandy", TATU: "Tatung", TAXA: "TAXAN America", TDS: "Tokyo Denshi Sekei", TECO: "TECO Information Systems", TEGR: "Tegra", TEKT: "Tektronix", TI: "Texas Instruments", TMKR: "TypeMaker", TOSB: "Toshiba", TOSH: "Toshiba", TOTK: "TOTOKU ELECTRIC", TRIU: "Triumph", TSBT: "Toshiba", TTX: "TTX Computer Products", TVM: "TVM Professional Monitor", TW: "TW Casper", ULSX: "Ulead Systems", UNIS: "Unisys", UTZF: "Utz Fehlau & Sohn", VARI: "Varityper", VIEW: "Viewsonic", VISL: "Visual communication", VIVO: "Vivo Mobile Communication", WANG: "Wang", WLBR: "Wilbur Imaging", WTG2: "Ware To Go", WYSE: "WYSE Technology", XERX: "Xerox", XRIT: "X-Rite", ZRAN: "Zoran", Zebr: "Zebra Technologies", appl: "Apple Computer", bICC: "basICColor", berg: "bergdesign", ceyd: "Integrated Color Solutions", clsp: "MacDermid ColorSpan", ds: "Dainippon Screen", dupn: "DuPont", ffei: "FujiFilm Electronic Imaging", flux: "FluxData", iris: "Scitex", kart: "Scitex", lcms: "Little CMS", lino: "Linotronic", none: "none", ob4d: "Erdt Systems", obic: "Medigraph", quby: "Qubyx Sarl", scit: "Scitex", scrn: "Dainippon Screen", sdp: "Scitex", siwi: "SIWI GRAFIKA", yxym: "YxyMaster" }, Ut = { scnr: "Scanner", mntr: "Monitor", prtr: "Printer", link: "Device Link", abst: "Abstract", spac: "Color Space Conversion Profile", nmcl: "Named Color", cenc: "ColorEncodingSpace profile", mid: "MultiplexIdentification profile", mlnk: "MultiplexLink profile", mvis: "MultiplexVisualization profile", nkpf: "Nikon Input Device Profile (NON-STANDARD!)" };
|
|
B(G, "icc", [[4, Lt], [12, Ut], [40, Object.assign({}, Lt, Ut)], [48, Lt], [80, Lt], [64, { 0: "Perceptual", 1: "Relative Colorimetric", 2: "Saturation", 3: "Absolute Colorimetric" }], ["tech", { amd: "Active Matrix Display", crt: "Cathode Ray Tube Display", kpcd: "Photo CD", pmd: "Passive Matrix Display", dcam: "Digital Camera", dcpj: "Digital Cinema Projector", dmpc: "Digital Motion Picture Camera", dsub: "Dye Sublimation Printer", epho: "Electrophotographic Printer", esta: "Electrostatic Printer", flex: "Flexography", fprn: "Film Writer", fscn: "Film Scanner", grav: "Gravure", ijet: "Ink Jet Printer", imgs: "Photo Image Setter", mpfr: "Motion Picture Film Recorder", mpfs: "Motion Picture Film Scanner", offs: "Offset Lithography", pjtv: "Projection Television", rpho: "Photographic Paper Printer", rscn: "Reflective Scanner", silk: "Silkscreen", twax: "Thermal Wax Printer", vidc: "Video Camera", vidm: "Video Monitor" }]]);
|
|
class Ft extends ge {
|
|
static canHandle(e2, t2, i2) {
|
|
return 237 === e2.getUint8(t2 + 1) && "Photoshop" === e2.getString(t2 + 4, 9) && void 0 !== this.containsIptc8bim(e2, t2, i2);
|
|
}
|
|
static headerLength(e2, t2, i2) {
|
|
let n2, s2 = this.containsIptc8bim(e2, t2, i2);
|
|
if (void 0 !== s2) return n2 = e2.getUint8(t2 + s2 + 7), n2 % 2 != 0 && (n2 += 1), 0 === n2 && (n2 = 4), s2 + 8 + n2;
|
|
}
|
|
static containsIptc8bim(e2, t2, i2) {
|
|
for (let n2 = 0; n2 < i2; n2++) if (this.isIptcSegmentHead(e2, t2 + n2)) return n2;
|
|
}
|
|
static isIptcSegmentHead(e2, t2) {
|
|
return 56 === e2.getUint8(t2) && 943868237 === e2.getUint32(t2) && 1028 === e2.getUint16(t2 + 4);
|
|
}
|
|
parse() {
|
|
let { raw: e2 } = this, t2 = this.chunk.byteLength - 1, i2 = false;
|
|
for (let n2 = 0; n2 < t2; n2++) if (28 === this.chunk.getUint8(n2) && 2 === this.chunk.getUint8(n2 + 1)) {
|
|
i2 = true;
|
|
let t3 = this.chunk.getUint16(n2 + 3), s2 = this.chunk.getUint8(n2 + 2), r2 = this.chunk.getLatin1String(n2 + 5, t3);
|
|
e2.set(s2, this.pluralizeValue(e2.get(s2), r2)), n2 += 4 + t3;
|
|
} else if (i2) break;
|
|
return this.translate(), this.output;
|
|
}
|
|
pluralizeValue(e2, t2) {
|
|
return void 0 !== e2 ? e2 instanceof Array ? (e2.push(t2), e2) : [e2, t2] : t2;
|
|
}
|
|
}
|
|
f(Ft, "type", "iptc"), f(Ft, "translateValues", false), f(Ft, "reviveValues", false), A.set("iptc", Ft), B(N, "iptc", [[0, "ApplicationRecordVersion"], [3, "ObjectTypeReference"], [4, "ObjectAttributeReference"], [5, "ObjectName"], [7, "EditStatus"], [8, "EditorialUpdate"], [10, "Urgency"], [12, "SubjectReference"], [15, "Category"], [20, "SupplementalCategories"], [22, "FixtureIdentifier"], [25, "Keywords"], [26, "ContentLocationCode"], [27, "ContentLocationName"], [30, "ReleaseDate"], [35, "ReleaseTime"], [37, "ExpirationDate"], [38, "ExpirationTime"], [40, "SpecialInstructions"], [42, "ActionAdvised"], [45, "ReferenceService"], [47, "ReferenceDate"], [50, "ReferenceNumber"], [55, "DateCreated"], [60, "TimeCreated"], [62, "DigitalCreationDate"], [63, "DigitalCreationTime"], [65, "OriginatingProgram"], [70, "ProgramVersion"], [75, "ObjectCycle"], [80, "Byline"], [85, "BylineTitle"], [90, "City"], [92, "Sublocation"], [95, "State"], [100, "CountryCode"], [101, "Country"], [103, "OriginalTransmissionReference"], [105, "Headline"], [110, "Credit"], [115, "Source"], [116, "CopyrightNotice"], [118, "Contact"], [120, "Caption"], [121, "LocalCaption"], [122, "Writer"], [125, "RasterizedCaption"], [130, "ImageType"], [131, "ImageOrientation"], [135, "LanguageIdentifier"], [150, "AudioType"], [151, "AudioSamplingRate"], [152, "AudioSamplingResolution"], [153, "AudioDuration"], [154, "AudioOutcue"], [184, "JobID"], [185, "MasterDocumentID"], [186, "ShortDocumentID"], [187, "UniqueDocumentID"], [188, "OwnerID"], [200, "ObjectPreviewFileFormat"], [201, "ObjectPreviewFileVersion"], [202, "ObjectPreviewData"], [221, "Prefs"], [225, "ClassifyState"], [228, "SimilarityIndex"], [230, "DocumentNotes"], [231, "DocumentHistory"], [232, "ExifCameraInfo"], [255, "CatalogSets"]]), B(G, "iptc", [[10, { 0: "0 (reserved)", 1: "1 (most urgent)", 2: "2", 3: "3", 4: "4", 5: "5 (normal urgency)", 6: "6", 7: "7", 8: "8 (least urgent)", 9: "9 (user-defined priority)" }], [75, { a: "Morning", b: "Both Morning and Evening", p: "Evening" }], [131, { L: "Landscape", P: "Portrait", S: "Square" }]]), e.Exifr = ce, e.Options = oe, e.allFormatters = ie, e.chunkedProps = $2, e.createDictionary = B, e.default = ft, e.extendDictionary = E, e.fetchUrlAsArrayBuffer = L, e.fileParsers = T, e.fileReaders = D, e.gps = De, e.gpsOnlyOptions = Ae, e.inheritables = te, e.orientation = Re, e.orientationOnlyOptions = Me, e.otherSegments = J, e.parse = fe, e.readBlobAsArrayBuffer = U, e.rotation = Ue, e.rotations = Le, e.segmentParsers = A, e.segments = q, e.segmentsAndBlocks = Z, e.sidecar = async function(e2, t2, i2) {
|
|
let n2 = new oe(t2);
|
|
n2.chunked = false, void 0 === i2 && "string" == typeof e2 && (i2 = (function(e3) {
|
|
let t3 = e3.toLowerCase().split(".").pop();
|
|
if (/* @__PURE__ */ (function(e4) {
|
|
return "exif" === e4 || "tiff" === e4 || "tif" === e4;
|
|
})(t3)) return "tiff";
|
|
if (dt.includes(t3)) return t3;
|
|
})(e2));
|
|
let s2 = await x(e2, n2);
|
|
if (i2) {
|
|
if (dt.includes(i2)) return gt(i2, s2, n2);
|
|
m("Invalid segment type");
|
|
} else {
|
|
if ((function(e3) {
|
|
let t3 = e3.getString(0, 50).trim();
|
|
return t3.includes("<?xpacket") || t3.includes("<x:");
|
|
})(s2)) return gt("xmp", s2, n2);
|
|
for (let [e3] of A) {
|
|
if (!dt.includes(e3)) continue;
|
|
let t3 = await gt(e3, s2, n2).catch(pt);
|
|
if (t3) return t3;
|
|
}
|
|
m("Unknown file format");
|
|
}
|
|
}, e.tagKeys = N, e.tagRevivers = V, e.tagValues = G, e.thumbnail = xe, e.thumbnailOnlyOptions = Oe, e.thumbnailUrl = ve, e.tiffBlocks = Q, e.tiffExtractables = ee, Object.defineProperty(e, "__esModule", { value: true });
|
|
}));
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/wheel@1.0.0/node_modules/wheel/index.js
|
|
var require_wheel = __commonJS({
|
|
"node_modules/.pnpm/wheel@1.0.0/node_modules/wheel/index.js"(exports, module) {
|
|
module.exports = addWheelListener;
|
|
module.exports.addWheelListener = addWheelListener;
|
|
module.exports.removeWheelListener = removeWheelListener;
|
|
function addWheelListener(element, listener, useCapture) {
|
|
element.addEventListener("wheel", listener, useCapture);
|
|
}
|
|
function removeWheelListener(element, listener, useCapture) {
|
|
element.removeEventListener("wheel", listener, useCapture);
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/bezier-easing@2.1.0/node_modules/bezier-easing/src/index.js
|
|
var require_src = __commonJS({
|
|
"node_modules/.pnpm/bezier-easing@2.1.0/node_modules/bezier-easing/src/index.js"(exports, module) {
|
|
var NEWTON_ITERATIONS = 4;
|
|
var NEWTON_MIN_SLOPE = 1e-3;
|
|
var SUBDIVISION_PRECISION = 1e-7;
|
|
var SUBDIVISION_MAX_ITERATIONS = 10;
|
|
var kSplineTableSize = 11;
|
|
var kSampleStepSize = 1 / (kSplineTableSize - 1);
|
|
var float32ArraySupported = typeof Float32Array === "function";
|
|
function A(aA1, aA2) {
|
|
return 1 - 3 * aA2 + 3 * aA1;
|
|
}
|
|
function B(aA1, aA2) {
|
|
return 3 * aA2 - 6 * aA1;
|
|
}
|
|
function C(aA1) {
|
|
return 3 * aA1;
|
|
}
|
|
function calcBezier(aT, aA1, aA2) {
|
|
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
|
|
}
|
|
function getSlope(aT, aA1, aA2) {
|
|
return 3 * A(aA1, aA2) * aT * aT + 2 * B(aA1, aA2) * aT + C(aA1);
|
|
}
|
|
function binarySubdivide(aX, aA, aB, mX1, mX2) {
|
|
var currentX, currentT, i = 0;
|
|
do {
|
|
currentT = aA + (aB - aA) / 2;
|
|
currentX = calcBezier(currentT, mX1, mX2) - aX;
|
|
if (currentX > 0) {
|
|
aB = currentT;
|
|
} else {
|
|
aA = currentT;
|
|
}
|
|
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
|
|
return currentT;
|
|
}
|
|
function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
|
|
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
|
|
var currentSlope = getSlope(aGuessT, mX1, mX2);
|
|
if (currentSlope === 0) {
|
|
return aGuessT;
|
|
}
|
|
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
|
|
aGuessT -= currentX / currentSlope;
|
|
}
|
|
return aGuessT;
|
|
}
|
|
function LinearEasing(x) {
|
|
return x;
|
|
}
|
|
module.exports = function bezier(mX1, mY1, mX2, mY2) {
|
|
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
|
|
throw new Error("bezier x values must be in [0, 1] range");
|
|
}
|
|
if (mX1 === mY1 && mX2 === mY2) {
|
|
return LinearEasing;
|
|
}
|
|
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
|
|
for (var i = 0; i < kSplineTableSize; ++i) {
|
|
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
|
|
}
|
|
function getTForX(aX) {
|
|
var intervalStart = 0;
|
|
var currentSample = 1;
|
|
var lastSample = kSplineTableSize - 1;
|
|
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
|
|
intervalStart += kSampleStepSize;
|
|
}
|
|
--currentSample;
|
|
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
|
var guessForT = intervalStart + dist * kSampleStepSize;
|
|
var initialSlope = getSlope(guessForT, mX1, mX2);
|
|
if (initialSlope >= NEWTON_MIN_SLOPE) {
|
|
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
|
|
} else if (initialSlope === 0) {
|
|
return guessForT;
|
|
} else {
|
|
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
|
|
}
|
|
}
|
|
return function BezierEasing(x) {
|
|
if (x === 0) {
|
|
return 0;
|
|
}
|
|
if (x === 1) {
|
|
return 1;
|
|
}
|
|
return calcBezier(getTForX(x), mY1, mY2);
|
|
};
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/amator@1.1.0/node_modules/amator/index.js
|
|
var require_amator = __commonJS({
|
|
"node_modules/.pnpm/amator@1.1.0/node_modules/amator/index.js"(exports, module) {
|
|
var BezierEasing = require_src();
|
|
var animations = {
|
|
ease: BezierEasing(0.25, 0.1, 0.25, 1),
|
|
easeIn: BezierEasing(0.42, 0, 1, 1),
|
|
easeOut: BezierEasing(0, 0, 0.58, 1),
|
|
easeInOut: BezierEasing(0.42, 0, 0.58, 1),
|
|
linear: BezierEasing(0, 0, 1, 1)
|
|
};
|
|
module.exports = animate;
|
|
module.exports.makeAggregateRaf = makeAggregateRaf;
|
|
module.exports.sharedScheduler = makeAggregateRaf();
|
|
function animate(source, target, options) {
|
|
var start = /* @__PURE__ */ Object.create(null);
|
|
var diff = /* @__PURE__ */ Object.create(null);
|
|
options = options || {};
|
|
var easing = typeof options.easing === "function" ? options.easing : animations[options.easing];
|
|
if (!easing) {
|
|
if (options.easing) {
|
|
console.warn("Unknown easing function in amator: " + options.easing);
|
|
}
|
|
easing = animations.ease;
|
|
}
|
|
var step = typeof options.step === "function" ? options.step : noop;
|
|
var done = typeof options.done === "function" ? options.done : noop;
|
|
var scheduler = getScheduler(options.scheduler);
|
|
var keys = Object.keys(target);
|
|
keys.forEach(function(key) {
|
|
start[key] = source[key];
|
|
diff[key] = target[key] - source[key];
|
|
});
|
|
var durationInMs = typeof options.duration === "number" ? options.duration : 400;
|
|
var durationInFrames = Math.max(1, durationInMs * 0.06);
|
|
var previousAnimationId;
|
|
var frame = 0;
|
|
previousAnimationId = scheduler.next(loop);
|
|
return {
|
|
cancel
|
|
};
|
|
function cancel() {
|
|
scheduler.cancel(previousAnimationId);
|
|
previousAnimationId = 0;
|
|
}
|
|
function loop() {
|
|
var t = easing(frame / durationInFrames);
|
|
frame += 1;
|
|
setValues(t);
|
|
if (frame <= durationInFrames) {
|
|
previousAnimationId = scheduler.next(loop);
|
|
step(source);
|
|
} else {
|
|
previousAnimationId = 0;
|
|
setTimeout(function() {
|
|
done(source);
|
|
}, 0);
|
|
}
|
|
}
|
|
function setValues(t) {
|
|
keys.forEach(function(key) {
|
|
source[key] = diff[key] * t + start[key];
|
|
});
|
|
}
|
|
}
|
|
function noop() {
|
|
}
|
|
function getScheduler(scheduler) {
|
|
if (!scheduler) {
|
|
var canRaf = typeof window !== "undefined" && window.requestAnimationFrame;
|
|
return canRaf ? rafScheduler() : timeoutScheduler();
|
|
}
|
|
if (typeof scheduler.next !== "function") throw new Error("Scheduler is supposed to have next(cb) function");
|
|
if (typeof scheduler.cancel !== "function") throw new Error("Scheduler is supposed to have cancel(handle) function");
|
|
return scheduler;
|
|
}
|
|
function rafScheduler() {
|
|
return {
|
|
next: window.requestAnimationFrame.bind(window),
|
|
cancel: window.cancelAnimationFrame.bind(window)
|
|
};
|
|
}
|
|
function timeoutScheduler() {
|
|
return {
|
|
next: function(cb) {
|
|
return setTimeout(cb, 1e3 / 60);
|
|
},
|
|
cancel: function(id) {
|
|
return clearTimeout(id);
|
|
}
|
|
};
|
|
}
|
|
function makeAggregateRaf() {
|
|
var frontBuffer = /* @__PURE__ */ new Set();
|
|
var backBuffer = /* @__PURE__ */ new Set();
|
|
var frameToken = 0;
|
|
return {
|
|
next,
|
|
cancel: next,
|
|
clearAll
|
|
};
|
|
function clearAll() {
|
|
frontBuffer.clear();
|
|
backBuffer.clear();
|
|
cancelAnimationFrame(frameToken);
|
|
frameToken = 0;
|
|
}
|
|
function next(callback) {
|
|
backBuffer.add(callback);
|
|
renderNextFrame();
|
|
}
|
|
function renderNextFrame() {
|
|
if (!frameToken) frameToken = requestAnimationFrame(renderFrame);
|
|
}
|
|
function renderFrame() {
|
|
frameToken = 0;
|
|
var t = backBuffer;
|
|
backBuffer = frontBuffer;
|
|
frontBuffer = t;
|
|
frontBuffer.forEach(function(callback) {
|
|
callback();
|
|
});
|
|
frontBuffer.clear();
|
|
}
|
|
function cancel(callback) {
|
|
backBuffer.delete(callback);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/ngraph.events@1.4.0/node_modules/ngraph.events/dist/ngraph.events.cjs
|
|
var require_ngraph_events = __commonJS({
|
|
"node_modules/.pnpm/ngraph.events@1.4.0/node_modules/ngraph.events/dist/ngraph.events.cjs"(exports, module) {
|
|
"use strict";
|
|
function c(e) {
|
|
s(e);
|
|
const t = a(e);
|
|
return e.on = t.on, e.off = t.off, e.fire = t.fire, e;
|
|
}
|
|
function a(e) {
|
|
let t = /* @__PURE__ */ Object.create(null);
|
|
return { on: function(n, r, f) {
|
|
if (typeof r != "function") throw new Error("callback is expected to be a function");
|
|
let o = t[n];
|
|
return o || (o = t[n] = []), o.push({ callback: r, ctx: f }), e;
|
|
}, off: function(n, r) {
|
|
if (typeof n > "u") return t = /* @__PURE__ */ Object.create(null), e;
|
|
if (t[n]) if (typeof r != "function") delete t[n];
|
|
else {
|
|
const l = t[n];
|
|
for (let i = 0; i < l.length; ++i) l[i].callback === r && l.splice(i, 1);
|
|
}
|
|
return e;
|
|
}, fire: function(n) {
|
|
const r = t[n];
|
|
if (!r) return e;
|
|
let f;
|
|
arguments.length > 1 && (f = Array.prototype.slice.call(arguments, 1));
|
|
for (let o = 0; o < r.length; ++o) {
|
|
const l = r[o];
|
|
l.callback.apply(l.ctx, f);
|
|
}
|
|
return e;
|
|
} };
|
|
}
|
|
function s(e) {
|
|
if (!e) throw new Error("Eventify cannot use falsy object as events subject");
|
|
const t = ["on", "fire", "off"];
|
|
for (let n = 0; n < t.length; ++n) if (e.hasOwnProperty(t[n])) throw new Error("Subject cannot be eventified, since it already has property '" + t[n] + "'");
|
|
}
|
|
module.exports = c;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/kinetic.js
|
|
var require_kinetic = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/kinetic.js"(exports, module) {
|
|
module.exports = kinetic;
|
|
function kinetic(getPoint, scroll, settings) {
|
|
if (typeof settings !== "object") {
|
|
settings = {};
|
|
}
|
|
var minVelocity = typeof settings.minVelocity === "number" ? settings.minVelocity : 5;
|
|
var amplitude = typeof settings.amplitude === "number" ? settings.amplitude : 0.25;
|
|
var cancelAnimationFrame2 = typeof settings.cancelAnimationFrame === "function" ? settings.cancelAnimationFrame : getCancelAnimationFrame();
|
|
var requestAnimationFrame2 = typeof settings.requestAnimationFrame === "function" ? settings.requestAnimationFrame : getRequestAnimationFrame();
|
|
var lastPoint;
|
|
var timestamp;
|
|
var timeConstant = 342;
|
|
var ticker;
|
|
var vx, targetX, ax;
|
|
var vy, targetY, ay;
|
|
var raf;
|
|
return {
|
|
start,
|
|
stop,
|
|
cancel: dispose
|
|
};
|
|
function dispose() {
|
|
cancelAnimationFrame2(ticker);
|
|
cancelAnimationFrame2(raf);
|
|
}
|
|
function start() {
|
|
lastPoint = getPoint();
|
|
ax = ay = vx = vy = 0;
|
|
timestamp = /* @__PURE__ */ new Date();
|
|
cancelAnimationFrame2(ticker);
|
|
cancelAnimationFrame2(raf);
|
|
ticker = requestAnimationFrame2(track);
|
|
}
|
|
function track() {
|
|
var now = Date.now();
|
|
var elapsed = now - timestamp;
|
|
timestamp = now;
|
|
var currentPoint = getPoint();
|
|
var dx = currentPoint.x - lastPoint.x;
|
|
var dy = currentPoint.y - lastPoint.y;
|
|
lastPoint = currentPoint;
|
|
var dt = 1e3 / (1 + elapsed);
|
|
vx = 0.8 * dx * dt + 0.2 * vx;
|
|
vy = 0.8 * dy * dt + 0.2 * vy;
|
|
ticker = requestAnimationFrame2(track);
|
|
}
|
|
function stop() {
|
|
cancelAnimationFrame2(ticker);
|
|
cancelAnimationFrame2(raf);
|
|
var currentPoint = getPoint();
|
|
targetX = currentPoint.x;
|
|
targetY = currentPoint.y;
|
|
timestamp = Date.now();
|
|
if (vx < -minVelocity || vx > minVelocity) {
|
|
ax = amplitude * vx;
|
|
targetX += ax;
|
|
}
|
|
if (vy < -minVelocity || vy > minVelocity) {
|
|
ay = amplitude * vy;
|
|
targetY += ay;
|
|
}
|
|
raf = requestAnimationFrame2(autoScroll);
|
|
}
|
|
function autoScroll() {
|
|
var elapsed = Date.now() - timestamp;
|
|
var moving = false;
|
|
var dx = 0;
|
|
var dy = 0;
|
|
if (ax) {
|
|
dx = -ax * Math.exp(-elapsed / timeConstant);
|
|
if (dx > 0.5 || dx < -0.5) moving = true;
|
|
else dx = ax = 0;
|
|
}
|
|
if (ay) {
|
|
dy = -ay * Math.exp(-elapsed / timeConstant);
|
|
if (dy > 0.5 || dy < -0.5) moving = true;
|
|
else dy = ay = 0;
|
|
}
|
|
if (moving) {
|
|
scroll(targetX + dx, targetY + dy);
|
|
raf = requestAnimationFrame2(autoScroll);
|
|
}
|
|
}
|
|
}
|
|
function getCancelAnimationFrame() {
|
|
if (typeof cancelAnimationFrame === "function") return cancelAnimationFrame;
|
|
return clearTimeout;
|
|
}
|
|
function getRequestAnimationFrame() {
|
|
if (typeof requestAnimationFrame === "function") return requestAnimationFrame;
|
|
return function(handler) {
|
|
return setTimeout(handler, 16);
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeTextSelectionInterceptor.js
|
|
var require_makeTextSelectionInterceptor = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeTextSelectionInterceptor.js"(exports, module) {
|
|
module.exports = makeTextSelectionInterceptor;
|
|
function makeTextSelectionInterceptor(useFake) {
|
|
if (useFake) {
|
|
return {
|
|
capture: noop,
|
|
release: noop
|
|
};
|
|
}
|
|
var dragObject;
|
|
var prevSelectStart;
|
|
var prevDragStart;
|
|
var wasCaptured = false;
|
|
return {
|
|
capture,
|
|
release
|
|
};
|
|
function capture(domObject) {
|
|
wasCaptured = true;
|
|
prevSelectStart = window.document.onselectstart;
|
|
prevDragStart = window.document.ondragstart;
|
|
window.document.onselectstart = disabled;
|
|
dragObject = domObject;
|
|
dragObject.ondragstart = disabled;
|
|
}
|
|
function release() {
|
|
if (!wasCaptured) return;
|
|
wasCaptured = false;
|
|
window.document.onselectstart = prevSelectStart;
|
|
if (dragObject) dragObject.ondragstart = prevDragStart;
|
|
}
|
|
}
|
|
function disabled(e) {
|
|
e.stopPropagation();
|
|
return false;
|
|
}
|
|
function noop() {
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/transform.js
|
|
var require_transform = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/transform.js"(exports, module) {
|
|
module.exports = Transform;
|
|
function Transform() {
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.scale = 1;
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeSvgController.js
|
|
var require_makeSvgController = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeSvgController.js"(exports, module) {
|
|
module.exports = makeSvgController;
|
|
module.exports.canAttach = isSVGElement;
|
|
function makeSvgController(svgElement, options) {
|
|
if (!isSVGElement(svgElement)) {
|
|
throw new Error("svg element is required for svg.panzoom to work");
|
|
}
|
|
var owner = svgElement.ownerSVGElement;
|
|
if (!owner) {
|
|
throw new Error(
|
|
"Do not apply panzoom to the root <svg> element. Use its child instead (e.g. <g></g>). As of March 2016 only FireFox supported transform on the root element"
|
|
);
|
|
}
|
|
if (!options.disableKeyboardInteraction) {
|
|
owner.setAttribute("tabindex", 0);
|
|
}
|
|
var api = {
|
|
getBBox,
|
|
getScreenCTM,
|
|
getOwner,
|
|
applyTransform,
|
|
initTransform
|
|
};
|
|
return api;
|
|
function getOwner() {
|
|
return owner;
|
|
}
|
|
function getBBox() {
|
|
var boundingBox = svgElement.getBBox();
|
|
return {
|
|
left: boundingBox.x,
|
|
top: boundingBox.y,
|
|
width: boundingBox.width,
|
|
height: boundingBox.height
|
|
};
|
|
}
|
|
function getScreenCTM() {
|
|
var ctm = owner.getCTM();
|
|
if (!ctm) {
|
|
return owner.getScreenCTM();
|
|
}
|
|
return ctm;
|
|
}
|
|
function initTransform(transform) {
|
|
var screenCTM = svgElement.getCTM();
|
|
if (screenCTM === null) {
|
|
screenCTM = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix();
|
|
}
|
|
transform.x = screenCTM.e;
|
|
transform.y = screenCTM.f;
|
|
transform.scale = screenCTM.a;
|
|
owner.removeAttributeNS(null, "viewBox");
|
|
}
|
|
function applyTransform(transform) {
|
|
svgElement.setAttribute("transform", "matrix(" + transform.scale + " 0 0 " + transform.scale + " " + transform.x + " " + transform.y + ")");
|
|
}
|
|
}
|
|
function isSVGElement(element) {
|
|
return element && element.ownerSVGElement && element.getCTM;
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeDomController.js
|
|
var require_makeDomController = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeDomController.js"(exports, module) {
|
|
module.exports = makeDomController;
|
|
module.exports.canAttach = isDomElement;
|
|
function makeDomController(domElement, options) {
|
|
var elementValid = isDomElement(domElement);
|
|
if (!elementValid) {
|
|
throw new Error("panzoom requires DOM element to be attached to the DOM tree");
|
|
}
|
|
var owner = domElement.parentElement;
|
|
domElement.scrollTop = 0;
|
|
if (!options.disableKeyboardInteraction) {
|
|
owner.setAttribute("tabindex", 0);
|
|
}
|
|
var api = {
|
|
getBBox,
|
|
getOwner,
|
|
applyTransform
|
|
};
|
|
return api;
|
|
function getOwner() {
|
|
return owner;
|
|
}
|
|
function getBBox() {
|
|
return {
|
|
left: 0,
|
|
top: 0,
|
|
width: domElement.clientWidth,
|
|
height: domElement.clientHeight
|
|
};
|
|
}
|
|
function applyTransform(transform) {
|
|
domElement.style.transformOrigin = "0 0 0";
|
|
domElement.style.transform = "matrix(" + transform.scale + ", 0, 0, " + transform.scale + ", " + transform.x + ", " + transform.y + ")";
|
|
}
|
|
}
|
|
function isDomElement(element) {
|
|
return element && element.parentElement && element.style;
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/index.js
|
|
var require_panzoom = __commonJS({
|
|
"node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/index.js"(exports, module) {
|
|
"use strict";
|
|
var wheel = require_wheel();
|
|
var animate = require_amator();
|
|
var eventify = require_ngraph_events();
|
|
var kinetic = require_kinetic();
|
|
var createTextSelectionInterceptor = require_makeTextSelectionInterceptor();
|
|
var domTextSelectionInterceptor = createTextSelectionInterceptor();
|
|
var fakeTextSelectorInterceptor = createTextSelectionInterceptor(true);
|
|
var Transform = require_transform();
|
|
var makeSvgController = require_makeSvgController();
|
|
var makeDomController = require_makeDomController();
|
|
var defaultZoomSpeed = 1;
|
|
var defaultDoubleTapZoomSpeed = 1.75;
|
|
var doubleTapSpeedInMS = 300;
|
|
var clickEventTimeInMS = 200;
|
|
module.exports = createPanZoom;
|
|
function createPanZoom(domElement, options) {
|
|
options = options || {};
|
|
var panController = options.controller;
|
|
if (!panController) {
|
|
if (makeSvgController.canAttach(domElement)) {
|
|
panController = makeSvgController(domElement, options);
|
|
} else if (makeDomController.canAttach(domElement)) {
|
|
panController = makeDomController(domElement, options);
|
|
}
|
|
}
|
|
if (!panController) {
|
|
throw new Error(
|
|
"Cannot create panzoom for the current type of dom element"
|
|
);
|
|
}
|
|
var owner = panController.getOwner();
|
|
var storedCTMResult = { x: 0, y: 0 };
|
|
var isDirty = false;
|
|
var transform = new Transform();
|
|
if (panController.initTransform) {
|
|
panController.initTransform(transform);
|
|
}
|
|
var filterKey = typeof options.filterKey === "function" ? options.filterKey : noop;
|
|
var pinchSpeed = typeof options.pinchSpeed === "number" ? options.pinchSpeed : 1;
|
|
var bounds = options.bounds;
|
|
var maxZoom = typeof options.maxZoom === "number" ? options.maxZoom : Number.POSITIVE_INFINITY;
|
|
var minZoom = typeof options.minZoom === "number" ? options.minZoom : 0;
|
|
var boundsPadding = typeof options.boundsPadding === "number" ? options.boundsPadding : 0.05;
|
|
var zoomDoubleClickSpeed = typeof options.zoomDoubleClickSpeed === "number" ? options.zoomDoubleClickSpeed : defaultDoubleTapZoomSpeed;
|
|
var beforeWheel = options.beforeWheel || noop;
|
|
var beforeMouseDown = options.beforeMouseDown || noop;
|
|
var speed = typeof options.zoomSpeed === "number" ? options.zoomSpeed : defaultZoomSpeed;
|
|
var transformOrigin = parseTransformOrigin(options.transformOrigin);
|
|
var textSelection = options.enableTextSelection ? fakeTextSelectorInterceptor : domTextSelectionInterceptor;
|
|
validateBounds(bounds);
|
|
if (options.autocenter) {
|
|
autocenter();
|
|
}
|
|
var frameAnimation;
|
|
var lastTouchEndTime = 0;
|
|
var lastTouchStartTime = 0;
|
|
var pendingClickEventTimeout = 0;
|
|
var lastMouseDownedEvent = null;
|
|
var lastMouseDownTime = /* @__PURE__ */ new Date();
|
|
var lastSingleFingerOffset;
|
|
var touchInProgress = false;
|
|
var panstartFired = false;
|
|
var mouseX;
|
|
var mouseY;
|
|
var clickX;
|
|
var clickY;
|
|
var pinchZoomLength;
|
|
var smoothScroll;
|
|
if ("smoothScroll" in options && !options.smoothScroll) {
|
|
smoothScroll = rigidScroll();
|
|
} else {
|
|
smoothScroll = kinetic(getPoint, scroll, options.smoothScroll);
|
|
}
|
|
var moveByAnimation;
|
|
var zoomToAnimation;
|
|
var multiTouch;
|
|
var paused = false;
|
|
listenForEvents();
|
|
var api = {
|
|
dispose,
|
|
moveBy: internalMoveBy,
|
|
moveTo,
|
|
smoothMoveTo,
|
|
centerOn,
|
|
zoomTo: publicZoomTo,
|
|
zoomAbs,
|
|
smoothZoom,
|
|
smoothZoomAbs,
|
|
showRectangle,
|
|
pause,
|
|
resume,
|
|
isPaused,
|
|
getTransform: getTransformModel,
|
|
getMinZoom,
|
|
setMinZoom,
|
|
getMaxZoom,
|
|
setMaxZoom,
|
|
getTransformOrigin,
|
|
setTransformOrigin,
|
|
getZoomSpeed,
|
|
setZoomSpeed
|
|
};
|
|
eventify(api);
|
|
var initialX = typeof options.initialX === "number" ? options.initialX : transform.x;
|
|
var initialY = typeof options.initialY === "number" ? options.initialY : transform.y;
|
|
var initialZoom = typeof options.initialZoom === "number" ? options.initialZoom : transform.scale;
|
|
if (initialX != transform.x || initialY != transform.y || initialZoom != transform.scale) {
|
|
zoomAbs(initialX, initialY, initialZoom);
|
|
}
|
|
return api;
|
|
function pause() {
|
|
releaseEvents();
|
|
paused = true;
|
|
}
|
|
function resume() {
|
|
if (paused) {
|
|
listenForEvents();
|
|
paused = false;
|
|
}
|
|
}
|
|
function isPaused() {
|
|
return paused;
|
|
}
|
|
function showRectangle(rect) {
|
|
var clientRect = owner.getBoundingClientRect();
|
|
var size = transformToScreen(clientRect.width, clientRect.height);
|
|
var rectWidth = rect.right - rect.left;
|
|
var rectHeight = rect.bottom - rect.top;
|
|
if (!Number.isFinite(rectWidth) || !Number.isFinite(rectHeight)) {
|
|
throw new Error("Invalid rectangle");
|
|
}
|
|
var dw = size.x / rectWidth;
|
|
var dh = size.y / rectHeight;
|
|
var scale = Math.min(dw, dh);
|
|
transform.x = -(rect.left + rectWidth / 2) * scale + size.x / 2;
|
|
transform.y = -(rect.top + rectHeight / 2) * scale + size.y / 2;
|
|
transform.scale = scale;
|
|
}
|
|
function transformToScreen(x, y) {
|
|
if (panController.getScreenCTM) {
|
|
var parentCTM = panController.getScreenCTM();
|
|
var parentScaleX = parentCTM.a;
|
|
var parentScaleY = parentCTM.d;
|
|
var parentOffsetX = parentCTM.e;
|
|
var parentOffsetY = parentCTM.f;
|
|
storedCTMResult.x = x * parentScaleX - parentOffsetX;
|
|
storedCTMResult.y = y * parentScaleY - parentOffsetY;
|
|
} else {
|
|
storedCTMResult.x = x;
|
|
storedCTMResult.y = y;
|
|
}
|
|
return storedCTMResult;
|
|
}
|
|
function autocenter() {
|
|
var w;
|
|
var h;
|
|
var left = 0;
|
|
var top = 0;
|
|
var sceneBoundingBox = getBoundingBox();
|
|
if (sceneBoundingBox) {
|
|
left = sceneBoundingBox.left;
|
|
top = sceneBoundingBox.top;
|
|
w = sceneBoundingBox.right - sceneBoundingBox.left;
|
|
h = sceneBoundingBox.bottom - sceneBoundingBox.top;
|
|
} else {
|
|
var ownerRect = owner.getBoundingClientRect();
|
|
w = ownerRect.width;
|
|
h = ownerRect.height;
|
|
}
|
|
var bbox = panController.getBBox();
|
|
if (bbox.width === 0 || bbox.height === 0) {
|
|
return;
|
|
}
|
|
var dh = h / bbox.height;
|
|
var dw = w / bbox.width;
|
|
var scale = Math.min(dw, dh);
|
|
transform.x = -(bbox.left + bbox.width / 2) * scale + w / 2 + left;
|
|
transform.y = -(bbox.top + bbox.height / 2) * scale + h / 2 + top;
|
|
transform.scale = scale;
|
|
}
|
|
function getTransformModel() {
|
|
return transform;
|
|
}
|
|
function getMinZoom() {
|
|
return minZoom;
|
|
}
|
|
function setMinZoom(newMinZoom) {
|
|
minZoom = newMinZoom;
|
|
}
|
|
function getMaxZoom() {
|
|
return maxZoom;
|
|
}
|
|
function setMaxZoom(newMaxZoom) {
|
|
maxZoom = newMaxZoom;
|
|
}
|
|
function getTransformOrigin() {
|
|
return transformOrigin;
|
|
}
|
|
function setTransformOrigin(newTransformOrigin) {
|
|
transformOrigin = parseTransformOrigin(newTransformOrigin);
|
|
}
|
|
function getZoomSpeed() {
|
|
return speed;
|
|
}
|
|
function setZoomSpeed(newSpeed) {
|
|
if (!Number.isFinite(newSpeed)) {
|
|
throw new Error("Zoom speed should be a number");
|
|
}
|
|
speed = newSpeed;
|
|
}
|
|
function getPoint() {
|
|
return {
|
|
x: transform.x,
|
|
y: transform.y
|
|
};
|
|
}
|
|
function moveTo(x, y) {
|
|
transform.x = x;
|
|
transform.y = y;
|
|
keepTransformInsideBounds();
|
|
triggerEvent("pan");
|
|
makeDirty();
|
|
}
|
|
function moveBy(dx, dy) {
|
|
moveTo(transform.x + dx, transform.y + dy);
|
|
}
|
|
function keepTransformInsideBounds() {
|
|
var boundingBox = getBoundingBox();
|
|
if (!boundingBox) return;
|
|
var adjusted = false;
|
|
var clientRect = getClientRect();
|
|
var diff = boundingBox.left - clientRect.right;
|
|
if (diff > 0) {
|
|
transform.x += diff;
|
|
adjusted = true;
|
|
}
|
|
diff = boundingBox.right - clientRect.left;
|
|
if (diff < 0) {
|
|
transform.x += diff;
|
|
adjusted = true;
|
|
}
|
|
diff = boundingBox.top - clientRect.bottom;
|
|
if (diff > 0) {
|
|
transform.y += diff;
|
|
adjusted = true;
|
|
}
|
|
diff = boundingBox.bottom - clientRect.top;
|
|
if (diff < 0) {
|
|
transform.y += diff;
|
|
adjusted = true;
|
|
}
|
|
return adjusted;
|
|
}
|
|
function getBoundingBox() {
|
|
if (!bounds) return;
|
|
if (typeof bounds === "boolean") {
|
|
var ownerRect = owner.getBoundingClientRect();
|
|
var sceneWidth = ownerRect.width;
|
|
var sceneHeight = ownerRect.height;
|
|
return {
|
|
left: sceneWidth * boundsPadding,
|
|
top: sceneHeight * boundsPadding,
|
|
right: sceneWidth * (1 - boundsPadding),
|
|
bottom: sceneHeight * (1 - boundsPadding)
|
|
};
|
|
}
|
|
return bounds;
|
|
}
|
|
function getClientRect() {
|
|
var bbox = panController.getBBox();
|
|
var leftTop = client(bbox.left, bbox.top);
|
|
return {
|
|
left: leftTop.x,
|
|
top: leftTop.y,
|
|
right: bbox.width * transform.scale + leftTop.x,
|
|
bottom: bbox.height * transform.scale + leftTop.y
|
|
};
|
|
}
|
|
function client(x, y) {
|
|
return {
|
|
x: x * transform.scale + transform.x,
|
|
y: y * transform.scale + transform.y
|
|
};
|
|
}
|
|
function makeDirty() {
|
|
isDirty = true;
|
|
frameAnimation = window.requestAnimationFrame(frame);
|
|
}
|
|
function zoomByRatio(clientX, clientY, ratio) {
|
|
if (isNaN2(clientX) || isNaN2(clientY) || isNaN2(ratio)) {
|
|
throw new Error("zoom requires valid numbers");
|
|
}
|
|
var newScale = transform.scale * ratio;
|
|
if (newScale < minZoom) {
|
|
if (transform.scale === minZoom) return;
|
|
ratio = minZoom / transform.scale;
|
|
}
|
|
if (newScale > maxZoom) {
|
|
if (transform.scale === maxZoom) return;
|
|
ratio = maxZoom / transform.scale;
|
|
}
|
|
var size = transformToScreen(clientX, clientY);
|
|
transform.x = size.x - ratio * (size.x - transform.x);
|
|
transform.y = size.y - ratio * (size.y - transform.y);
|
|
if (bounds && boundsPadding === 1 && minZoom === 1) {
|
|
transform.scale *= ratio;
|
|
keepTransformInsideBounds();
|
|
} else {
|
|
var transformAdjusted = keepTransformInsideBounds();
|
|
if (!transformAdjusted) transform.scale *= ratio;
|
|
}
|
|
triggerEvent("zoom");
|
|
makeDirty();
|
|
}
|
|
function zoomAbs(clientX, clientY, zoomLevel) {
|
|
var ratio = zoomLevel / transform.scale;
|
|
zoomByRatio(clientX, clientY, ratio);
|
|
}
|
|
function centerOn(ui) {
|
|
var parent2 = ui.ownerSVGElement;
|
|
if (!parent2)
|
|
throw new Error("ui element is required to be within the scene");
|
|
var clientRect = ui.getBoundingClientRect();
|
|
var cx = clientRect.left + clientRect.width / 2;
|
|
var cy = clientRect.top + clientRect.height / 2;
|
|
var container = parent2.getBoundingClientRect();
|
|
var dx = container.width / 2 - cx;
|
|
var dy = container.height / 2 - cy;
|
|
internalMoveBy(dx, dy, true);
|
|
}
|
|
function smoothMoveTo(x, y) {
|
|
internalMoveBy(x - transform.x, y - transform.y, true);
|
|
}
|
|
function internalMoveBy(dx, dy, smooth) {
|
|
if (!smooth) {
|
|
return moveBy(dx, dy);
|
|
}
|
|
if (moveByAnimation) moveByAnimation.cancel();
|
|
var from = { x: 0, y: 0 };
|
|
var to = { x: dx, y: dy };
|
|
var lastX = 0;
|
|
var lastY = 0;
|
|
moveByAnimation = animate(from, to, {
|
|
step: function(v) {
|
|
moveBy(v.x - lastX, v.y - lastY);
|
|
lastX = v.x;
|
|
lastY = v.y;
|
|
}
|
|
});
|
|
}
|
|
function scroll(x, y) {
|
|
cancelZoomAnimation();
|
|
moveTo(x, y);
|
|
}
|
|
function dispose() {
|
|
releaseEvents();
|
|
}
|
|
function listenForEvents() {
|
|
owner.addEventListener("mousedown", onMouseDown, { passive: false });
|
|
owner.addEventListener("dblclick", onDoubleClick, { passive: false });
|
|
owner.addEventListener("touchstart", onTouch, { passive: false });
|
|
owner.addEventListener("keydown", onKeyDown2, { passive: false });
|
|
wheel.addWheelListener(owner, onMouseWheel, { passive: false });
|
|
makeDirty();
|
|
}
|
|
function releaseEvents() {
|
|
wheel.removeWheelListener(owner, onMouseWheel);
|
|
owner.removeEventListener("mousedown", onMouseDown);
|
|
owner.removeEventListener("keydown", onKeyDown2);
|
|
owner.removeEventListener("dblclick", onDoubleClick);
|
|
owner.removeEventListener("touchstart", onTouch);
|
|
if (frameAnimation) {
|
|
window.cancelAnimationFrame(frameAnimation);
|
|
frameAnimation = 0;
|
|
}
|
|
smoothScroll.cancel();
|
|
releaseDocumentMouse();
|
|
releaseTouches();
|
|
textSelection.release();
|
|
triggerPanEnd();
|
|
}
|
|
function frame() {
|
|
if (isDirty) applyTransform();
|
|
}
|
|
function applyTransform() {
|
|
isDirty = false;
|
|
panController.applyTransform(transform);
|
|
triggerEvent("transform");
|
|
frameAnimation = 0;
|
|
}
|
|
function onKeyDown2(e) {
|
|
var x = 0, y = 0, z = 0;
|
|
if (e.keyCode === 38) {
|
|
y = 1;
|
|
} else if (e.keyCode === 40) {
|
|
y = -1;
|
|
} else if (e.keyCode === 37) {
|
|
x = 1;
|
|
} else if (e.keyCode === 39) {
|
|
x = -1;
|
|
} else if (e.keyCode === 189 || e.keyCode === 109) {
|
|
z = 1;
|
|
} else if (e.keyCode === 187 || e.keyCode === 107) {
|
|
z = -1;
|
|
}
|
|
if (filterKey(e, x, y, z)) {
|
|
return;
|
|
}
|
|
if (x || y) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
var clientRect = owner.getBoundingClientRect();
|
|
var offset = Math.min(clientRect.width, clientRect.height);
|
|
var moveSpeedRatio = 0.05;
|
|
var dx = offset * moveSpeedRatio * x;
|
|
var dy = offset * moveSpeedRatio * y;
|
|
internalMoveBy(dx, dy);
|
|
}
|
|
if (z) {
|
|
var scaleMultiplier = getScaleMultiplier(z * 100);
|
|
var offset = transformOrigin ? getTransformOriginOffset() : midPoint();
|
|
publicZoomTo(offset.x, offset.y, scaleMultiplier);
|
|
}
|
|
}
|
|
function midPoint() {
|
|
var ownerRect = owner.getBoundingClientRect();
|
|
return {
|
|
x: ownerRect.width / 2,
|
|
y: ownerRect.height / 2
|
|
};
|
|
}
|
|
function onTouch(e) {
|
|
beforeTouch(e);
|
|
clearPendingClickEventTimeout();
|
|
if (e.touches.length === 1) {
|
|
return handleSingleFingerTouch(e, e.touches[0]);
|
|
} else if (e.touches.length === 2) {
|
|
pinchZoomLength = getPinchZoomLength(e.touches[0], e.touches[1]);
|
|
multiTouch = true;
|
|
startTouchListenerIfNeeded();
|
|
}
|
|
}
|
|
function beforeTouch(e) {
|
|
if (options.onTouch && !options.onTouch(e)) {
|
|
return;
|
|
}
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}
|
|
function beforeDoubleClick(e) {
|
|
clearPendingClickEventTimeout();
|
|
if (options.onDoubleClick && !options.onDoubleClick(e)) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
function handleSingleFingerTouch(e) {
|
|
lastTouchStartTime = /* @__PURE__ */ new Date();
|
|
var touch = e.touches[0];
|
|
var offset = getOffsetXY(touch);
|
|
lastSingleFingerOffset = offset;
|
|
var point = transformToScreen(offset.x, offset.y);
|
|
mouseX = point.x;
|
|
mouseY = point.y;
|
|
clickX = mouseX;
|
|
clickY = mouseY;
|
|
smoothScroll.cancel();
|
|
startTouchListenerIfNeeded();
|
|
}
|
|
function startTouchListenerIfNeeded() {
|
|
if (touchInProgress) {
|
|
return;
|
|
}
|
|
touchInProgress = true;
|
|
document.addEventListener("touchmove", handleTouchMove);
|
|
document.addEventListener("touchend", handleTouchEnd);
|
|
document.addEventListener("touchcancel", handleTouchEnd);
|
|
}
|
|
function handleTouchMove(e) {
|
|
if (e.touches.length === 1) {
|
|
e.stopPropagation();
|
|
var touch = e.touches[0];
|
|
var offset = getOffsetXY(touch);
|
|
var point = transformToScreen(offset.x, offset.y);
|
|
var dx = point.x - mouseX;
|
|
var dy = point.y - mouseY;
|
|
if (dx !== 0 && dy !== 0) {
|
|
triggerPanStart();
|
|
}
|
|
mouseX = point.x;
|
|
mouseY = point.y;
|
|
internalMoveBy(dx, dy);
|
|
} else if (e.touches.length === 2) {
|
|
multiTouch = true;
|
|
var t1 = e.touches[0];
|
|
var t2 = e.touches[1];
|
|
var currentPinchLength = getPinchZoomLength(t1, t2);
|
|
var scaleMultiplier = 1 + (currentPinchLength / pinchZoomLength - 1) * pinchSpeed;
|
|
var firstTouchPoint = getOffsetXY(t1);
|
|
var secondTouchPoint = getOffsetXY(t2);
|
|
mouseX = (firstTouchPoint.x + secondTouchPoint.x) / 2;
|
|
mouseY = (firstTouchPoint.y + secondTouchPoint.y) / 2;
|
|
if (transformOrigin) {
|
|
var offset = getTransformOriginOffset();
|
|
mouseX = offset.x;
|
|
mouseY = offset.y;
|
|
}
|
|
publicZoomTo(mouseX, mouseY, scaleMultiplier);
|
|
pinchZoomLength = currentPinchLength;
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
function clearPendingClickEventTimeout() {
|
|
if (pendingClickEventTimeout) {
|
|
clearTimeout(pendingClickEventTimeout);
|
|
pendingClickEventTimeout = 0;
|
|
}
|
|
}
|
|
function handlePotentialClickEvent(e) {
|
|
if (!options.onClick) return;
|
|
clearPendingClickEventTimeout();
|
|
var dx = mouseX - clickX;
|
|
var dy = mouseY - clickY;
|
|
var l = Math.sqrt(dx * dx + dy * dy);
|
|
if (l > 5) return;
|
|
pendingClickEventTimeout = setTimeout(function() {
|
|
pendingClickEventTimeout = 0;
|
|
options.onClick(e);
|
|
}, doubleTapSpeedInMS);
|
|
}
|
|
function handleTouchEnd(e) {
|
|
clearPendingClickEventTimeout();
|
|
if (e.touches.length > 0) {
|
|
var offset = getOffsetXY(e.touches[0]);
|
|
var point = transformToScreen(offset.x, offset.y);
|
|
mouseX = point.x;
|
|
mouseY = point.y;
|
|
} else {
|
|
var now = /* @__PURE__ */ new Date();
|
|
if (now - lastTouchEndTime < doubleTapSpeedInMS) {
|
|
if (transformOrigin) {
|
|
var offset = getTransformOriginOffset();
|
|
smoothZoom(offset.x, offset.y, zoomDoubleClickSpeed);
|
|
} else {
|
|
smoothZoom(lastSingleFingerOffset.x, lastSingleFingerOffset.y, zoomDoubleClickSpeed);
|
|
}
|
|
} else if (now - lastTouchStartTime < clickEventTimeInMS) {
|
|
handlePotentialClickEvent(e);
|
|
}
|
|
lastTouchEndTime = now;
|
|
triggerPanEnd();
|
|
releaseTouches();
|
|
}
|
|
}
|
|
function getPinchZoomLength(finger1, finger2) {
|
|
var dx = finger1.clientX - finger2.clientX;
|
|
var dy = finger1.clientY - finger2.clientY;
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
}
|
|
function onDoubleClick(e) {
|
|
beforeDoubleClick(e);
|
|
var offset = getOffsetXY(e);
|
|
if (transformOrigin) {
|
|
offset = getTransformOriginOffset();
|
|
}
|
|
smoothZoom(offset.x, offset.y, zoomDoubleClickSpeed);
|
|
}
|
|
function onMouseDown(e) {
|
|
clearPendingClickEventTimeout();
|
|
if (beforeMouseDown(e)) return;
|
|
lastMouseDownedEvent = e;
|
|
lastMouseDownTime = /* @__PURE__ */ new Date();
|
|
if (touchInProgress) {
|
|
e.stopPropagation();
|
|
return false;
|
|
}
|
|
var isLeftButton = e.button === 1 && window.event !== null || e.button === 0;
|
|
if (!isLeftButton) return;
|
|
smoothScroll.cancel();
|
|
var offset = getOffsetXY(e);
|
|
var point = transformToScreen(offset.x, offset.y);
|
|
clickX = mouseX = point.x;
|
|
clickY = mouseY = point.y;
|
|
document.addEventListener("mousemove", onMouseMove);
|
|
document.addEventListener("mouseup", onMouseUp);
|
|
textSelection.capture(e.target || e.srcElement);
|
|
return false;
|
|
}
|
|
function onMouseMove(e) {
|
|
if (touchInProgress) return;
|
|
triggerPanStart();
|
|
var offset = getOffsetXY(e);
|
|
var point = transformToScreen(offset.x, offset.y);
|
|
var dx = point.x - mouseX;
|
|
var dy = point.y - mouseY;
|
|
mouseX = point.x;
|
|
mouseY = point.y;
|
|
internalMoveBy(dx, dy);
|
|
}
|
|
function onMouseUp() {
|
|
var now = /* @__PURE__ */ new Date();
|
|
if (now - lastMouseDownTime < clickEventTimeInMS) handlePotentialClickEvent(lastMouseDownedEvent);
|
|
textSelection.release();
|
|
triggerPanEnd();
|
|
releaseDocumentMouse();
|
|
}
|
|
function releaseDocumentMouse() {
|
|
document.removeEventListener("mousemove", onMouseMove);
|
|
document.removeEventListener("mouseup", onMouseUp);
|
|
panstartFired = false;
|
|
}
|
|
function releaseTouches() {
|
|
document.removeEventListener("touchmove", handleTouchMove);
|
|
document.removeEventListener("touchend", handleTouchEnd);
|
|
document.removeEventListener("touchcancel", handleTouchEnd);
|
|
panstartFired = false;
|
|
multiTouch = false;
|
|
touchInProgress = false;
|
|
}
|
|
function onMouseWheel(e) {
|
|
if (beforeWheel(e)) return;
|
|
smoothScroll.cancel();
|
|
var delta = e.deltaY;
|
|
if (e.deltaMode > 0) delta *= 100;
|
|
var scaleMultiplier = getScaleMultiplier(delta);
|
|
if (scaleMultiplier !== 1) {
|
|
var offset = transformOrigin ? getTransformOriginOffset() : getOffsetXY(e);
|
|
publicZoomTo(offset.x, offset.y, scaleMultiplier);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
function getOffsetXY(e) {
|
|
var offsetX, offsetY;
|
|
var ownerRect = owner.getBoundingClientRect();
|
|
offsetX = e.clientX - ownerRect.left;
|
|
offsetY = e.clientY - ownerRect.top;
|
|
return { x: offsetX, y: offsetY };
|
|
}
|
|
function smoothZoom(clientX, clientY, scaleMultiplier) {
|
|
var fromValue = transform.scale;
|
|
var from = { scale: fromValue };
|
|
var to = { scale: scaleMultiplier * fromValue };
|
|
smoothScroll.cancel();
|
|
cancelZoomAnimation();
|
|
zoomToAnimation = animate(from, to, {
|
|
step: function(v) {
|
|
zoomAbs(clientX, clientY, v.scale);
|
|
},
|
|
done: triggerZoomEnd
|
|
});
|
|
}
|
|
function smoothZoomAbs(clientX, clientY, toScaleValue) {
|
|
var fromValue = transform.scale;
|
|
var from = { scale: fromValue };
|
|
var to = { scale: toScaleValue };
|
|
smoothScroll.cancel();
|
|
cancelZoomAnimation();
|
|
zoomToAnimation = animate(from, to, {
|
|
step: function(v) {
|
|
zoomAbs(clientX, clientY, v.scale);
|
|
},
|
|
done: triggerZoomEnd
|
|
});
|
|
}
|
|
function getTransformOriginOffset() {
|
|
var ownerRect = owner.getBoundingClientRect();
|
|
return {
|
|
x: ownerRect.width * transformOrigin.x,
|
|
y: ownerRect.height * transformOrigin.y
|
|
};
|
|
}
|
|
function publicZoomTo(clientX, clientY, scaleMultiplier) {
|
|
smoothScroll.cancel();
|
|
cancelZoomAnimation();
|
|
return zoomByRatio(clientX, clientY, scaleMultiplier);
|
|
}
|
|
function cancelZoomAnimation() {
|
|
if (zoomToAnimation) {
|
|
zoomToAnimation.cancel();
|
|
zoomToAnimation = null;
|
|
}
|
|
}
|
|
function getScaleMultiplier(delta) {
|
|
var sign = Math.sign(delta);
|
|
var deltaAdjustedSpeed = Math.min(0.25, Math.abs(speed * delta / 128));
|
|
return 1 - sign * deltaAdjustedSpeed;
|
|
}
|
|
function triggerPanStart() {
|
|
if (!panstartFired) {
|
|
triggerEvent("panstart");
|
|
panstartFired = true;
|
|
smoothScroll.start();
|
|
}
|
|
}
|
|
function triggerPanEnd() {
|
|
if (panstartFired) {
|
|
if (!multiTouch) smoothScroll.stop();
|
|
triggerEvent("panend");
|
|
}
|
|
}
|
|
function triggerZoomEnd() {
|
|
triggerEvent("zoomend");
|
|
}
|
|
function triggerEvent(name) {
|
|
api.fire(name, api);
|
|
}
|
|
}
|
|
function parseTransformOrigin(options) {
|
|
if (!options) return;
|
|
if (typeof options === "object") {
|
|
if (!isNumber(options.x) || !isNumber(options.y))
|
|
failTransformOrigin(options);
|
|
return options;
|
|
}
|
|
failTransformOrigin();
|
|
}
|
|
function failTransformOrigin(options) {
|
|
console.error(options);
|
|
throw new Error(
|
|
[
|
|
"Cannot parse transform origin.",
|
|
"Some good examples:",
|
|
' "center center" can be achieved with {x: 0.5, y: 0.5}',
|
|
' "top center" can be achieved with {x: 0.5, y: 0}',
|
|
' "bottom right" can be achieved with {x: 1, y: 1}'
|
|
].join("\n")
|
|
);
|
|
}
|
|
function noop() {
|
|
}
|
|
function validateBounds(bounds) {
|
|
var boundsType = typeof bounds;
|
|
if (boundsType === "undefined" || boundsType === "boolean") return;
|
|
var validBounds = isNumber(bounds.left) && isNumber(bounds.top) && isNumber(bounds.bottom) && isNumber(bounds.right);
|
|
if (!validBounds)
|
|
throw new Error(
|
|
"Bounds object is not valid. It can be: undefined, boolean (true|false) or an object {left, top, right, bottom}"
|
|
);
|
|
}
|
|
function isNumber(x) {
|
|
return Number.isFinite(x);
|
|
}
|
|
function isNaN2(value) {
|
|
if (Number.isNaN) {
|
|
return Number.isNaN(value);
|
|
}
|
|
return value !== value;
|
|
}
|
|
function rigidScroll() {
|
|
return {
|
|
start: noop,
|
|
stop: noop,
|
|
cancel: noop
|
|
};
|
|
}
|
|
function autoRun() {
|
|
if (typeof document === "undefined") return;
|
|
var scripts = document.getElementsByTagName("script");
|
|
if (!scripts) return;
|
|
var panzoomScript;
|
|
for (var i = 0; i < scripts.length; ++i) {
|
|
var x = scripts[i];
|
|
if (x.src && x.src.match(/\bpanzoom(\.min)?\.js/)) {
|
|
panzoomScript = x;
|
|
break;
|
|
}
|
|
}
|
|
if (!panzoomScript) return;
|
|
var query = panzoomScript.getAttribute("query");
|
|
if (!query) return;
|
|
var globalName = panzoomScript.getAttribute("name") || "pz";
|
|
var started = Date.now();
|
|
tryAttach();
|
|
function tryAttach() {
|
|
var el2 = document.querySelector(query);
|
|
if (!el2) {
|
|
var now = Date.now();
|
|
var elapsed = now - started;
|
|
if (elapsed < 2e3) {
|
|
setTimeout(tryAttach, 100);
|
|
return;
|
|
}
|
|
console.error("Cannot find the panzoom element", globalName);
|
|
return;
|
|
}
|
|
var options = collectOptions(panzoomScript);
|
|
console.log(options);
|
|
window[globalName] = createPanZoom(el2, options);
|
|
}
|
|
function collectOptions(script) {
|
|
var attrs = script.attributes;
|
|
var options = {};
|
|
for (var j = 0; j < attrs.length; ++j) {
|
|
var attr = attrs[j];
|
|
var nameValue = getPanzoomAttributeNameValue(attr);
|
|
if (nameValue) {
|
|
options[nameValue.name] = nameValue.value;
|
|
}
|
|
}
|
|
return options;
|
|
}
|
|
function getPanzoomAttributeNameValue(attr) {
|
|
if (!attr.name) return;
|
|
var isPanZoomAttribute = attr.name[0] === "p" && attr.name[1] === "z" && attr.name[2] === "-";
|
|
if (!isPanZoomAttribute) return;
|
|
var name = attr.name.substr(3);
|
|
var value = JSON.parse(attr.value);
|
|
return { name, value };
|
|
}
|
|
}
|
|
autoRun();
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist-module/wrappers/jquery.node-module-wrapper.js
|
|
var import_jquery = __toESM(require_jquery(), 1);
|
|
var jquery_node_module_wrapper_default = import_jquery.default;
|
|
|
|
// ui/vendor.ts
|
|
var import_iframeResizer = __toESM(require_iframeResizer());
|
|
var globalAny = globalThis;
|
|
globalAny.$ = jquery_node_module_wrapper_default;
|
|
globalAny.jQuery = jquery_node_module_wrapper_default;
|
|
jquery_node_module_wrapper_default.isArray = Array.isArray;
|
|
|
|
// ui/logger.ts
|
|
window.logRingBuffer = [];
|
|
window.logBufferDirty = false;
|
|
var logBuffer = (ts, type, msg) => {
|
|
const maxLogLength = 8;
|
|
window.logRingBuffer.push({ ts, type, msg });
|
|
if (window.logRingBuffer.length > maxLogLength) window.logRingBuffer.shift();
|
|
window.logBufferDirty = true;
|
|
};
|
|
var scrollBottom = async (el2) => {
|
|
const lastChild = el2.lastElementChild;
|
|
if (lastChild) lastChild.scrollIntoView({ behavior: "smooth" });
|
|
};
|
|
var log = async (...msg) => {
|
|
const dt = /* @__PURE__ */ new Date();
|
|
const ts = `${dt.getHours().toString().padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt.getSeconds().toString().padStart(2, "0")}.${dt.getMilliseconds().toString().padStart(3, "0")}`;
|
|
if (window.logger) {
|
|
if (window.logPrettyPrint) window.logger.innerHTML += window.logPrettyPrint(...msg);
|
|
scrollBottom(window.logger);
|
|
}
|
|
console.log(ts, ...msg);
|
|
logBuffer(ts, "log", msg);
|
|
};
|
|
var debug = async (...msg) => {
|
|
const dt = /* @__PURE__ */ new Date();
|
|
const ts = `${dt.getHours().toString().padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt.getSeconds().toString().padStart(2, "0")}.${dt.getMilliseconds().toString().padStart(3, "0")}`;
|
|
if (window.logger) {
|
|
if (window.logPrettyPrint) window.logger.innerHTML += window.logPrettyPrint(...msg);
|
|
scrollBottom(window.logger);
|
|
}
|
|
console.debug(ts, ...msg);
|
|
logBuffer(ts, "debug", msg);
|
|
};
|
|
var error = async (...msg) => {
|
|
const dt = /* @__PURE__ */ new Date();
|
|
const ts = `${dt.getHours().toString().padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt.getSeconds().toString().padStart(2, "0")}.${dt.getMilliseconds().toString().padStart(3, "0")}`;
|
|
if (window.logger) {
|
|
if (window.logPrettyPrint) window.logger.innerHTML += window.logPrettyPrint(...msg);
|
|
scrollBottom(window.logger);
|
|
}
|
|
console.error(ts, ...msg);
|
|
logBuffer(ts, "error", msg);
|
|
};
|
|
var xhrInternal = async (xhrObj, data, handler, errorHandler, ignore = false, serverTimeout = window.opts.ui_request_timeout || 3e4) => {
|
|
const err = (msg) => {
|
|
if (!ignore) {
|
|
error(`${msg}: state=${xhrObj.readyState} status=${xhrObj.status} response=${xhrObj.responseText}`);
|
|
if (errorHandler) errorHandler(xhrObj);
|
|
}
|
|
};
|
|
xhrObj.setRequestHeader("Content-Type", "application/json");
|
|
xhrObj.timeout = serverTimeout;
|
|
xhrObj.ontimeout = () => err("xhr.ontimeout");
|
|
xhrObj.onerror = () => err("xhr.onerror");
|
|
xhrObj.onabort = () => err("xhr.onabort");
|
|
xhrObj.onreadystatechange = () => {
|
|
if (xhrObj.readyState === 4) {
|
|
if (xhrObj.status === 200) {
|
|
try {
|
|
const json = JSON.parse(xhrObj.responseText);
|
|
if (handler) handler(json);
|
|
} catch {
|
|
}
|
|
} else {
|
|
}
|
|
}
|
|
};
|
|
const req = JSON.stringify(data);
|
|
xhrObj.send(req);
|
|
};
|
|
var xhrGet = (url2, data, handler, errorHandler, ignore = false, serverTimeout = window.opts.ui_request_timeout || 3e4) => {
|
|
const xhr = new XMLHttpRequest();
|
|
const args = Object.keys(data).map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`).join("&");
|
|
xhr.open("GET", `${url2}?${args}`, true);
|
|
xhrInternal(xhr, data, handler, errorHandler, ignore, serverTimeout);
|
|
};
|
|
function xhrPost(url2, data, handler, errorHandler, ignore = false, serverTimeout = window.opts.ui_request_timeout || 3e4) {
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open("POST", url2, true);
|
|
xhrInternal(xhr, data, handler, errorHandler, ignore, serverTimeout);
|
|
}
|
|
window.log = log;
|
|
window.debug = debug;
|
|
window.error = error;
|
|
window.xhrGet = xhrGet;
|
|
window.xhrPost = xhrPost;
|
|
|
|
// ui/authWrap.ts
|
|
var user;
|
|
var token;
|
|
async function getToken() {
|
|
if (token === void 0 || user === void 0) {
|
|
const res = await fetch(`${window.subpath}/token`);
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
user = data.user;
|
|
token = data.token;
|
|
log("getToken", user);
|
|
}
|
|
}
|
|
return { user, token };
|
|
}
|
|
async function authFetch(url2, options = {}) {
|
|
await getToken();
|
|
if (user && token) {
|
|
const encoded = btoa(`${user}:${token}`);
|
|
const headers = new Headers(options.headers);
|
|
headers.set("Authorization", `Basic ${encoded}`);
|
|
options.headers = headers;
|
|
}
|
|
let res;
|
|
try {
|
|
res = await fetch(url2, options);
|
|
if (!res.ok) error("fetch", { status: res?.status || 503, url: url2, user, token });
|
|
} catch (err) {
|
|
if (navigator.onLine) {
|
|
error("fetch", { status: res?.status || 503, url: url2, user, token, error: err });
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
window.authFetch = authFetch;
|
|
|
|
// ui/timers.ts
|
|
var allTimers = [];
|
|
async function timer(name, elapsed) {
|
|
allTimers.push([name, Math.round(elapsed)]);
|
|
}
|
|
window.timer = timer;
|
|
async function logTimers() {
|
|
const filteredTimers = allTimers.filter((t) => t[1] > 100);
|
|
const objTimers = {};
|
|
for (const [name, elapsed] of filteredTimers) objTimers[name] = elapsed;
|
|
debug("startupTimers", objTimers);
|
|
}
|
|
|
|
// ui/script.ts
|
|
var gradioObserver = null;
|
|
async function sleep(ms) {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
function gradioApp() {
|
|
const elems = document.getElementsByTagName("gradio-app");
|
|
const elem = elems.length === 0 ? document : elems[0];
|
|
if (elem !== document) elem.getElementById = (id) => document.getElementById(id);
|
|
if (elem !== document && elem.shadowRoot) {
|
|
return elem.shadowRoot;
|
|
}
|
|
return elem;
|
|
}
|
|
window.gradioApp = gradioApp;
|
|
function getUICurrentTab() {
|
|
return gradioApp().querySelector("#tabs button.selected");
|
|
}
|
|
function getUICurrentTabContent() {
|
|
return gradioApp().querySelector('.tabitem[id^=tab_]:not([style*="display: none"])');
|
|
}
|
|
var uiAfterUpdateCallbacks = [];
|
|
var uiUpdateCallbacks = [];
|
|
var uiLoadedCallbacks = [];
|
|
var uiReadyCallbacks = [];
|
|
var uiTabChangeCallbacks = [];
|
|
var optionsChangedCallbacks = [];
|
|
var uiCurrentTab = null;
|
|
var uiAfterUpdateTimeout;
|
|
function registerCallback(queue, callback) {
|
|
if (queue.includes(callback)) return;
|
|
queue.push(callback);
|
|
}
|
|
function onAfterUiUpdate(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onAfterUiUpdate was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(uiAfterUpdateCallbacks, callback);
|
|
}
|
|
window.onAfterUiUpdate = onAfterUiUpdate;
|
|
function onUiUpdate(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onUiUpdate was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(uiUpdateCallbacks, callback);
|
|
}
|
|
window.onUiUpdate = onUiUpdate;
|
|
function onUiLoaded(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onUiLoaded was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(uiLoadedCallbacks, callback);
|
|
}
|
|
window.onUiLoaded = onUiLoaded;
|
|
function onUiReady(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onUiReady was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(uiReadyCallbacks, callback);
|
|
}
|
|
window.onUiReady = onUiReady;
|
|
function onUiTabChange(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onUiTabChange was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(uiTabChangeCallbacks, callback);
|
|
}
|
|
window.onUiTabChange = onUiTabChange;
|
|
function onOptionsChanged(callback) {
|
|
if (typeof callback !== "function") {
|
|
error(`onOptionsChanged was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
registerCallback(optionsChangedCallbacks, callback);
|
|
}
|
|
window.onOptionsChanged = onOptionsChanged;
|
|
function executeCallbacks(queue, arg) {
|
|
for (const callback of queue) {
|
|
if (!callback) continue;
|
|
try {
|
|
const t0 = performance.now();
|
|
callback(arg);
|
|
const t1 = performance.now();
|
|
if (t1 - t0 > 250) log("callbackSlow", callback.name || callback, `time=${Math.round(t1 - t0)}`);
|
|
timer(callback.name || "anonymousCallback", t1 - t0);
|
|
} catch (e) {
|
|
error(`executeCallbacks: ${callback} ${e}`);
|
|
}
|
|
}
|
|
}
|
|
var anyPromptExists = () => gradioApp().querySelectorAll(".main-prompts").length > 0;
|
|
function scheduleAfterUiUpdateCallbacks() {
|
|
clearTimeout(uiAfterUpdateTimeout);
|
|
uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks), 250);
|
|
}
|
|
var executedOnLoaded = false;
|
|
var ignoreElements = ["logMonitorData", "logWarnings", "logErrors", "tooltip-container", "logger"];
|
|
var ignoreElementsSet = new Set(ignoreElements);
|
|
var ignoreClasses = ["wrap"];
|
|
var mutationTimer;
|
|
var validMutations = [];
|
|
async function mutationCallback(mutations) {
|
|
if (mutations.length <= 0) return;
|
|
for (const mutation of mutations) {
|
|
const { target } = mutation;
|
|
if (target.nodeName === "LABEL") continue;
|
|
if (ignoreElementsSet.has(target.id)) continue;
|
|
if (target.classList?.contains(ignoreClasses[0])) continue;
|
|
validMutations.push(mutation);
|
|
}
|
|
if (validMutations.length < 1) return;
|
|
if (mutationTimer) clearTimeout(mutationTimer);
|
|
mutationTimer = setTimeout(async () => {
|
|
if (!executedOnLoaded && anyPromptExists()) {
|
|
executedOnLoaded = true;
|
|
executeCallbacks(uiLoadedCallbacks);
|
|
}
|
|
if (executedOnLoaded) {
|
|
executeCallbacks(uiUpdateCallbacks, mutations);
|
|
scheduleAfterUiUpdateCallbacks();
|
|
}
|
|
const newTab = getUICurrentTab();
|
|
if (newTab && newTab !== uiCurrentTab) {
|
|
uiCurrentTab = newTab;
|
|
executeCallbacks(uiTabChangeCallbacks);
|
|
}
|
|
validMutations = [];
|
|
mutationTimer = void 0;
|
|
}, 100);
|
|
}
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
log("DOMContentLoaded");
|
|
gradioObserver = new MutationObserver(mutationCallback);
|
|
gradioObserver.observe(gradioApp(), { childList: true, subtree: true, attributes: false });
|
|
});
|
|
document.addEventListener("keydown", (e) => {
|
|
let elem;
|
|
if (e.key === "Escape") elem = getUICurrentTabContent().querySelector("button[id$=_interrupt]");
|
|
if (e.key === "Enter" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id$=_generate]");
|
|
if (e.key === "i" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id$=_reprocess]");
|
|
if (e.key === " " && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id$=_extra_networks_btn]");
|
|
if (e.key === "n" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id$=_extra_networks_btn]");
|
|
if (e.key === "s" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id^=save_]");
|
|
if (e.key === "Insert" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id^=save_]");
|
|
if (e.key === "d" && e.ctrlKey) elem = getUICurrentTabContent().querySelector("button[id^=delete_]");
|
|
if (elem) {
|
|
e.preventDefault();
|
|
log("hotkey", { key: e.key, meta: e.metaKey, ctrl: e.ctrlKey, alt: e.altKey }, elem?.id, elem.nodeName);
|
|
if (elem.nodeName === "BUTTON") elem.click();
|
|
else elem.focus();
|
|
}
|
|
});
|
|
function getSortableCellValue(cell, sortType) {
|
|
const rawValue = cell?.dataset?.sortValue ?? cell?.textContent?.trim() ?? "";
|
|
if (sortType === "number") {
|
|
const numericValue = Number.parseFloat(rawValue);
|
|
return Number.isNaN(numericValue) ? Number.NEGATIVE_INFINITY : numericValue;
|
|
}
|
|
return rawValue.toLowerCase();
|
|
}
|
|
function sortTable(table, columnIndex, sortType, sortOrder) {
|
|
const tbody = table.querySelector("tbody");
|
|
if (!tbody) return;
|
|
const rows = Array.from(tbody.querySelectorAll("tr"));
|
|
const direction = sortOrder === "desc" ? -1 : 1;
|
|
const sortedRows = rows.map((row, index) => ({ row, index })).sort((a, b) => {
|
|
const aCell = a.row.children[columnIndex];
|
|
const bCell = b.row.children[columnIndex];
|
|
const aValue = getSortableCellValue(aCell, sortType);
|
|
const bValue = getSortableCellValue(bCell, sortType);
|
|
if (aValue < bValue) return -1 * direction;
|
|
if (aValue > bValue) return 1 * direction;
|
|
return a.index - b.index;
|
|
});
|
|
tbody.replaceChildren(...sortedRows.map((item) => item.row));
|
|
}
|
|
function applySortIndicators(table, activeHeader, sortOrder) {
|
|
const headers = table.querySelectorAll("th.sortable");
|
|
for (const header of headers) {
|
|
header.classList.remove("sorted-asc", "sorted-desc");
|
|
header.removeAttribute("aria-sort");
|
|
}
|
|
activeHeader.classList.add(sortOrder === "desc" ? "sorted-desc" : "sorted-asc");
|
|
activeHeader.setAttribute("aria-sort", sortOrder === "desc" ? "descending" : "ascending");
|
|
}
|
|
function handleSortableTableClick(event2) {
|
|
const header = event2.target.closest("th.sortable");
|
|
if (!header) return;
|
|
const table = header.closest('table[data-sortable="true"]');
|
|
if (!table) return;
|
|
const headers = Array.from(table.querySelectorAll("th.sortable"));
|
|
const columnIndex = headers.indexOf(header);
|
|
if (columnIndex < 0) return;
|
|
const currentSortKey = table.dataset.sortKey || table.dataset.defaultSortKey;
|
|
const currentSortOrder = table.dataset.sortOrder || table.dataset.defaultSortOrder || "asc";
|
|
const isCurrentHeader = currentSortKey === header.dataset.sortKey;
|
|
const nextOrder = isCurrentHeader && currentSortOrder === "asc" ? "desc" : "asc";
|
|
table.dataset.sortKey = header.dataset.sortKey;
|
|
table.dataset.sortOrder = nextOrder;
|
|
sortTable(table, columnIndex, header.dataset.sortType || "text", nextOrder);
|
|
applySortIndicators(table, header, nextOrder);
|
|
}
|
|
async function initTableSorter() {
|
|
const t0 = performance.now();
|
|
const root = gradioApp();
|
|
if (!root.dataset.tableSorterBound) {
|
|
root.addEventListener("click", handleSortableTableClick);
|
|
root.dataset.tableSorterBound = "true";
|
|
}
|
|
const t1 = performance.now();
|
|
log("initTableSorter", Math.round(t1 - t0));
|
|
timer("initTableSorter", t1 - t0);
|
|
}
|
|
async function deleteFile(filename) {
|
|
if (!filename) return;
|
|
if (!confirm(`Are you sure you want to delete the object - This action cannot be undone? Object: ${filename}`)) return;
|
|
const res = await authFetch(`${window.api}/delete-file?file=${encodeURIComponent(filename)}`);
|
|
if (!res || res.status !== 200) {
|
|
error("FileDelete", { file: filename, status: res?.status, statusText: res?.statusText });
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
log("FileDelete", data);
|
|
}
|
|
window.deleteFile = deleteFile;
|
|
function uiElementIsVisible(el2) {
|
|
if (el2 === document) return true;
|
|
const computedStyle = getComputedStyle(el2);
|
|
const isVisible2 = computedStyle.display !== "none";
|
|
if (!isVisible2) return false;
|
|
return uiElementIsVisible(el2.parentNode);
|
|
}
|
|
function uiElementInSight(el2) {
|
|
const clRect = el2.getBoundingClientRect();
|
|
const windowHeight = window.innerHeight;
|
|
const isOnScreen = clRect.bottom > 0 && clRect.top < windowHeight;
|
|
return isOnScreen;
|
|
}
|
|
|
|
// ui/changelog.ts
|
|
var changelogElements = [];
|
|
var getAllChildren = (el2) => {
|
|
const elements = [];
|
|
for (let i = 0; i < el2.children.length; i++) {
|
|
elements.push(el2.children[i]);
|
|
if (el2.children[i].children.length) elements.push(...getAllChildren(el2.children[i]));
|
|
}
|
|
return elements;
|
|
};
|
|
function getText(el2) {
|
|
let text = "";
|
|
el2.childNodes.forEach((node) => {
|
|
if (node.nodeType === Node.TEXT_NODE) text += node.nodeValue ?? "";
|
|
});
|
|
return text.trim();
|
|
}
|
|
var currentElement = -1;
|
|
function changelogNavigate(found) {
|
|
const result = gradioApp().getElementById("changelog_result");
|
|
if (!result) return;
|
|
result.innerHTML = "";
|
|
const text = document.createElement("p");
|
|
const onPrev = () => {
|
|
if (currentElement > 0) {
|
|
currentElement--;
|
|
found[currentElement].scrollIntoView();
|
|
text.innerHTML = `   search item ${currentElement + 1} of ${found.length}`;
|
|
}
|
|
};
|
|
const onNext = () => {
|
|
if (currentElement < found.length - 1) {
|
|
currentElement++;
|
|
found[currentElement].scrollIntoView();
|
|
text.innerHTML = `   search item ${currentElement + 1} of ${found.length}`;
|
|
}
|
|
};
|
|
const prev = document.createElement("p");
|
|
prev.innerHTML = " \u21E6 ";
|
|
prev.className = "changelog_arrow";
|
|
prev.onclick = onPrev;
|
|
prev.title = "Search previous";
|
|
result.appendChild(prev);
|
|
const next = document.createElement("p");
|
|
next.innerHTML = " \u21E8 ";
|
|
next.className = "changelog_arrow";
|
|
next.title = "Search next";
|
|
next.onclick = onNext;
|
|
result.appendChild(next);
|
|
text.innerHTML = `   found ${found.length} items`;
|
|
result.appendChild(text);
|
|
}
|
|
async function initChangelog() {
|
|
const search = gradioApp().querySelector("#changelog_search > label> textarea");
|
|
const md = gradioApp().getElementById("changelog_markdown");
|
|
if (!(search instanceof HTMLTextAreaElement) || !md) {
|
|
return;
|
|
}
|
|
const searchChangelog = async () => {
|
|
if (changelogElements.length < 100) changelogElements = getAllChildren(md);
|
|
const found = [];
|
|
for (const el2 of changelogElements) {
|
|
if (search.value.length > 1 && getText(el2).toLowerCase().includes(search.value.toLowerCase())) {
|
|
el2.classList.add("changelog_highlight");
|
|
found.push(el2);
|
|
} else {
|
|
el2.classList.remove("changelog_highlight");
|
|
}
|
|
}
|
|
changelogNavigate(found);
|
|
};
|
|
search.addEventListener("keyup", searchChangelog);
|
|
}
|
|
|
|
// ui/control.ts
|
|
function controlInputMode(inputMode, ...args) {
|
|
const updateEl = gradioApp().getElementById("control_update");
|
|
if (updateEl) updateEl.click();
|
|
const tab = gradioApp().querySelector("#control-tab-input button.selected");
|
|
if (!tab) return ["Image", ...args];
|
|
const tabs = Array.from(gradioApp().querySelectorAll("#control-tab-input button"));
|
|
const tabIdx = tabs.findIndex((btn) => btn.classList.contains("selected"));
|
|
const tabNames = ["Image", "Video", "Batch", "Folder"];
|
|
let inputTab = tabNames[tabIdx] || "Image";
|
|
log("controlInputMode", { mode: inputMode, tab: inputTab, kanvas: typeof window.Kanvas });
|
|
if (inputTab === "Image" && typeof window.Kanvas !== "undefined" && window.kanvas) {
|
|
inputTab = "Kanvas";
|
|
for (let i = 0; i < window.kanvas.stages.maxStages; i++) {
|
|
args[4 + i] = window.kanvas.getImage(1 + i, false, false);
|
|
}
|
|
}
|
|
return [inputTab, ...args];
|
|
}
|
|
window.controlInputMode = controlInputMode;
|
|
async function setupControlUI() {
|
|
const t0 = performance.now();
|
|
const tabs = ["input", "output", "preview"];
|
|
for (const tab of tabs) {
|
|
const btn = gradioApp().getElementById(`control-${tab}-button`);
|
|
if (!btn) continue;
|
|
btn.style.cursor = "pointer";
|
|
btn.onclick = () => {
|
|
const t = gradioApp().getElementById(`control-tab-${tab}`);
|
|
if (!t) return;
|
|
t.style.display = t.style.display === "none" ? "block" : "none";
|
|
const c = gradioApp().getElementById(`control-${tab}-column`);
|
|
if (!c) return;
|
|
c.style.flexGrow = c.style.flexGrow === "0" ? "9" : "0";
|
|
};
|
|
}
|
|
const el2 = gradioApp().getElementById("control-input-column");
|
|
if (!el2) return;
|
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
|
if (entries[0].intersectionRatio > 0) {
|
|
const allTabs = Array.from(gradioApp().querySelectorAll("#control-tabs > .tab-nav > .selected"));
|
|
for (const tab of allTabs) {
|
|
if (!(tab instanceof HTMLElement)) continue;
|
|
const name = tab.innerText.toLowerCase();
|
|
for (let i = 0; i < 10; i += 1) {
|
|
const btn = gradioApp().getElementById(`refresh_${name}_models_${i}`);
|
|
if (btn) btn.click();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
intersectionObserver.observe(el2);
|
|
const t1 = performance.now();
|
|
log("setupControlUI", Math.round(t1 - t0));
|
|
timer("setupControlUI", t1 - t0);
|
|
}
|
|
|
|
// ui/extraNetworks.ts
|
|
var activePromptTextarea = {};
|
|
var sortVal = -1;
|
|
var totalCards = -1;
|
|
var lastTab = "control";
|
|
var getENActiveTab = () => {
|
|
let tabName = "";
|
|
if (gradioApp().getElementById("txt2img_prompt")?.checkVisibility() || gradioApp().getElementById("txt2img_generate")?.checkVisibility()) tabName = "txt2img";
|
|
else if (gradioApp().getElementById("img2img_prompt")?.checkVisibility() || gradioApp().getElementById("img2img_generate")?.checkVisibility()) tabName = "img2img";
|
|
else if (gradioApp().getElementById("control_prompt")?.checkVisibility() || gradioApp().getElementById("control_generate")?.checkVisibility()) tabName = "control";
|
|
else if (gradioApp().getElementById("video_prompt")?.checkVisibility() || gradioApp().getElementById("video_generate")?.checkVisibility()) tabName = "video";
|
|
else if (gradioApp().getElementById("extras_image")?.checkVisibility()) tabName = "process";
|
|
else if (gradioApp().getElementById("interrogate_image")?.checkVisibility()) tabName = "caption";
|
|
else if (gradioApp().getElementById("tab-gallery-search")?.checkVisibility()) tabName = "gallery";
|
|
if (["process", "caption", "gallery"].includes(tabName)) {
|
|
tabName = lastTab;
|
|
} else if (tabName !== "") {
|
|
lastTab = tabName;
|
|
}
|
|
if (tabName !== "") return tabName;
|
|
if (gradioApp().getElementById("tab_txt2img")?.style.display === "block") tabName = "txt2img";
|
|
else if (gradioApp().getElementById("tab_img2img")?.style.display === "block") tabName = "img2img";
|
|
else if (gradioApp().getElementById("tab_control")?.style.display === "block") tabName = "control";
|
|
else if (gradioApp().getElementById("tab_video")?.style.display === "block") tabName = "video";
|
|
else tabName = "control";
|
|
return tabName;
|
|
};
|
|
var getENActivePage = () => {
|
|
const tabName = getENActiveTab();
|
|
let page = gradioApp().querySelector(`#${tabName}_extra_networks > .tabs > .tab-nav > .selected`);
|
|
if (!page) page = gradioApp().querySelector(`#${tabName}_extra_tabs > .tab-nav > .selected`);
|
|
const pageName = page ? page.innerText : "";
|
|
const btnApply = gradioApp().getElementById(`${tabName}_extra_apply`);
|
|
if (btnApply) btnApply.style.display = pageName === "Style" ? "inline-flex" : "none";
|
|
return pageName;
|
|
};
|
|
var setENState = (state) => {
|
|
if (!state) return;
|
|
state.tab = getENActiveTab();
|
|
state.page = getENActivePage();
|
|
const el2 = gradioApp().querySelector(`#${state.tab}_extra_state > label > textarea`);
|
|
if (el2) {
|
|
el2.value = JSON.stringify(state);
|
|
updateInput(el2);
|
|
}
|
|
};
|
|
function showCardDetails(event2) {
|
|
const tabName = getENActiveTab();
|
|
const btn = gradioApp().getElementById(`${tabName}_extra_details_btn`);
|
|
btn.click();
|
|
event2.stopPropagation();
|
|
event2.preventDefault();
|
|
}
|
|
window.showCardDetails = showCardDetails;
|
|
function getCardDetails(...args) {
|
|
const el2 = event?.target?.parentElement?.parentElement;
|
|
if (el2?.classList?.contains("card")) setENState({ op: "getCardDetails", item: el2.dataset.name });
|
|
else setENState({ op: "getCardDetails", item: null });
|
|
return [...args];
|
|
}
|
|
function readCardTags(el2, tags) {
|
|
const replaceOutsideBrackets = (input, target, replacement) => input.split(/(<[^>]*>|\{[^}]*\})/g).map((part, i) => {
|
|
if (i % 2 === 0) return part.split(target).join(replacement);
|
|
return part;
|
|
}).join("");
|
|
const clickTag = (e, tag) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const textarea = activePromptTextarea[getENActiveTab()];
|
|
let new_prompt = textarea.value;
|
|
new_prompt = replaceOutsideBrackets(new_prompt, ` ${tag}`, "");
|
|
new_prompt = replaceOutsideBrackets(new_prompt, `${tag} `, "");
|
|
if (new_prompt === textarea.value) new_prompt += ` ${tag}`;
|
|
textarea.value = new_prompt;
|
|
updateInput(textarea);
|
|
};
|
|
if (tags.length === 0) return;
|
|
const cardTags = tags.split("|");
|
|
if (!cardTags || cardTags.length === 0) return;
|
|
const tagsEl = el2.getElementsByClassName("tags")[0];
|
|
if (!tagsEl?.children || tagsEl.children.length > 0) return;
|
|
for (const tag of cardTags) {
|
|
const span = document.createElement("span");
|
|
span.classList.add("tag");
|
|
span.textContent = tag;
|
|
span.onclick = (e) => clickTag(e, tag);
|
|
tagsEl.appendChild(span);
|
|
}
|
|
}
|
|
function readCardDescription(page, item) {
|
|
xhrGet("/sdapi/v1/network/desc", { page, item }, (data) => {
|
|
const tabName = getENActiveTab();
|
|
const description = gradioApp().querySelector(`#${tabName}_description > label > textarea`);
|
|
if (description) {
|
|
description.value = data?.description?.trim() || "";
|
|
window.updateInput(description);
|
|
}
|
|
setENState({ op: "readCardDescription", page, item });
|
|
});
|
|
}
|
|
function getCardsForActivePage() {
|
|
const pageName = getENActivePage();
|
|
if (!pageName) return [];
|
|
let allCards = Array.from(gradioApp().querySelectorAll(".extra-network-cards > .card"));
|
|
allCards = allCards.filter((el2) => el2.dataset.page?.toLowerCase().includes(pageName.toLowerCase()));
|
|
return allCards;
|
|
}
|
|
async function filterExtraNetworksForTab(searchTerm) {
|
|
let items = 0;
|
|
let found = 0;
|
|
searchTerm = searchTerm.toLowerCase().trim();
|
|
const t0 = performance.now();
|
|
const pagename = getENActivePage();
|
|
if (!pagename) return;
|
|
const allPages = Array.from(gradioApp().querySelectorAll(".extra-network-cards"));
|
|
const pages = allPages.filter((el2) => el2.id.toLowerCase().includes(pagename.toLowerCase()));
|
|
for (const pg of pages) {
|
|
const cards = Array.from(pg.querySelectorAll(".card") || []);
|
|
items += cards.length;
|
|
if (searchTerm === "" || searchTerm === "all/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = "";
|
|
});
|
|
} else if (searchTerm === "reference/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.name.toLowerCase().includes("reference/") && elem.dataset.tags === "" ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "base/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("base") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "distilled/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("distilled") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "community/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("community") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "cloud/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("cloud") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "quantized/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("quantized") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "nunchaku/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.tags.toLowerCase().includes("nunchaku") ? "" : "none";
|
|
});
|
|
} else if (searchTerm === "local/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.name.toLowerCase().includes("reference/") ? "none" : "";
|
|
});
|
|
} else if (searchTerm === "diffusers/") {
|
|
cards.forEach((elem) => {
|
|
elem.style.display = elem.dataset.name.toLowerCase().replace("models--", "diffusers").replaceAll("\\", "/").includes("diffusers/") ? "" : "none";
|
|
});
|
|
} else if (searchTerm.startsWith("r#")) {
|
|
searchTerm = searchTerm.substring(2);
|
|
const re = new RegExp(searchTerm, "i");
|
|
cards.forEach((elem) => {
|
|
elem.style.display = re.test(`filename: ${elem.dataset.filename}|name: ${elem.dataset.name}|tags: ${elem.dataset.tags}`) ? "" : "none";
|
|
});
|
|
} else {
|
|
const searchList = searchTerm.split("|").filter((s) => s !== "" && !s.startsWith("-")).map((s) => s.trim());
|
|
const excludeList = searchTerm.split("|").filter((s) => s !== "" && s.trim().startsWith("-")).map((s) => s.trim().substring(1).trim());
|
|
const searchListAll = searchList.map((s) => s.split("&").map((t) => t.trim()));
|
|
const excludeListAll = excludeList.map((s) => s.split("&").map((t) => t.trim()));
|
|
cards.forEach((elem) => {
|
|
let text = "";
|
|
if (elem.dataset.filename) text += `${elem.dataset.filename} `;
|
|
if (elem.dataset.name) text += `${elem.dataset.name} `;
|
|
if (elem.dataset.tags) text += `${elem.dataset.tags} `;
|
|
text = text.toLowerCase().replace("models--", "diffusers").replaceAll("\\", "/");
|
|
if (searchListAll.some((sl) => sl.every((st) => text.includes(st))) && !excludeListAll.some((el2) => el2.every((et) => text.includes(et)))) {
|
|
elem.style.display = "";
|
|
} else {
|
|
elem.style.display = "none";
|
|
}
|
|
});
|
|
}
|
|
found += cards.filter((elem) => elem.style.display === "").length;
|
|
}
|
|
const t1 = performance.now();
|
|
log(`filterExtraNetworks: text="${searchTerm}" items=${items} match=${found} time=${Math.round(t1 - t0)}`);
|
|
timer(`filterExtraNetworks:${searchTerm}`, t1 - t0);
|
|
}
|
|
function sortExtraNetworks(fixed = "no") {
|
|
const t0 = performance.now();
|
|
const sortDesc = ["Default", "Name [A-Z]", "Name [Z-A]", "Date [Newest]", "Date [Oldest]", "Size [Largest]", "Size [Smallest]"];
|
|
const pagename = getENActivePage();
|
|
if (!pagename) return "sort error: unknown page";
|
|
const allPages = Array.from(gradioApp().querySelectorAll(".extra-network-cards"));
|
|
const pages = allPages.filter((el2) => el2.id.toLowerCase().includes(pagename.toLowerCase()));
|
|
let num = 0;
|
|
if (sortVal === -1) sortVal = sortDesc.indexOf(opts.extra_networks_sort);
|
|
if (fixed !== "fixed") sortVal = (sortVal + 1) % sortDesc.length;
|
|
const compareCards = (a, b) => {
|
|
switch (sortVal) {
|
|
case 0:
|
|
return 0;
|
|
case 1:
|
|
return a.dataset.name ? a.dataset.name.localeCompare(b.dataset.name) : 0;
|
|
case 2:
|
|
return b.dataset.name ? b.dataset.name.localeCompare(a.dataset.name) : 0;
|
|
case 3:
|
|
return a.dataset.mtime ? new Date(b.dataset.mtime).getTime() - new Date(a.dataset.mtime).getTime() : 0;
|
|
case 4:
|
|
return b.dataset.mtime ? new Date(a.dataset.mtime).getTime() - new Date(b.dataset.mtime).getTime() : 0;
|
|
case 5:
|
|
return a.dataset.size && !isNaN(a.dataset.size) ? parseFloat(b.dataset.size) - parseFloat(a.dataset.size) : 0;
|
|
case 6:
|
|
return b.dataset.size && !isNaN(b.dataset.size) ? parseFloat(a.dataset.size) - parseFloat(b.dataset.size) : 0;
|
|
}
|
|
return 0;
|
|
};
|
|
for (const pg of pages) {
|
|
const cards = Array.from(pg.querySelectorAll(".card") || []);
|
|
if (cards.length === 0) return "sort: no cards";
|
|
num += cards.length;
|
|
cards.sort(compareCards);
|
|
for (const card of cards) pg.appendChild(card);
|
|
}
|
|
const desc = sortDesc[sortVal];
|
|
const t1 = performance.now();
|
|
log("sortNetworks", { name: pagename, val: sortVal, order: desc, fixed: fixed === "fixed", items: num, time: Math.round(t1 - t0) });
|
|
timer(`sortExtraNetworks:${desc}`, t1 - t0);
|
|
return desc;
|
|
}
|
|
async function markSelectedCards(selected, page = "") {
|
|
log("markSelectedCards", selected, page);
|
|
gradioApp().querySelectorAll(".extra-network-cards .card").forEach((el2) => {
|
|
if (page.length > 0 && el2.dataset.page !== page) return;
|
|
if (selected.includes(el2.dataset.name) || selected.includes(el2.dataset.short)) el2.classList.add("card-selected");
|
|
else el2.classList.remove("card-selected");
|
|
});
|
|
}
|
|
function extractLoraNames(prompt) {
|
|
const regex = /<lora:([^:>]+)(?::[\d.]+)?>/g;
|
|
const names = [];
|
|
let match = regex.exec(prompt);
|
|
while (match !== null) {
|
|
names.push(match[1]);
|
|
match = regex.exec(prompt);
|
|
}
|
|
return names;
|
|
}
|
|
function cardClicked(textToAdd) {
|
|
const tabName = getENActiveTab();
|
|
log("cardClicked", tabName, textToAdd);
|
|
const textarea = activePromptTextarea[tabName];
|
|
if (textarea.value.indexOf(textToAdd) !== -1) textarea.value = textarea.value.replace(textToAdd, "");
|
|
else textarea.value += textToAdd;
|
|
updateInput(textarea);
|
|
markSelectedCards(extractLoraNames(textarea.value), "lora");
|
|
}
|
|
window.cardClicked = cardClicked;
|
|
function extraNetworksSearchButton(event2) {
|
|
const tabName = getENActiveTab();
|
|
const searchTextarea = gradioApp().querySelector(`#${tabName}_extra_search textarea`);
|
|
const button = event2.target;
|
|
if (searchTextarea) {
|
|
searchTextarea.value = `${button.textContent.trim()}/`;
|
|
updateInput(searchTextarea);
|
|
} else {
|
|
console.error(`Could not find the search textarea for the tab: ${tabName}`);
|
|
}
|
|
}
|
|
function extraNetworksFilterVersion(event2) {
|
|
const version = event2.target.textContent.trim();
|
|
const activePage = getENActivePage().toLowerCase();
|
|
const cardContainers = gradioApp().querySelectorAll(".extra-network-cards");
|
|
log("extraNetworksFilterVersion", { activePage, version });
|
|
for (const cardContainer of cardContainers) {
|
|
if (!cardContainer.id.includes(activePage)) continue;
|
|
if (cardContainer.dataset.activeVersion === version) {
|
|
cardContainer.dataset.activeVersion = "";
|
|
cardContainer.querySelectorAll(".card").forEach((card) => {
|
|
card.style.display = "";
|
|
});
|
|
} else {
|
|
cardContainer.dataset.activeVersion = version;
|
|
cardContainer.querySelectorAll(".card").forEach((card) => {
|
|
if (card.dataset.version === version) card.style.display = "";
|
|
else card.style.display = "none";
|
|
});
|
|
}
|
|
}
|
|
}
|
|
var desiredStyle = "";
|
|
function selectStyle(name) {
|
|
desiredStyle = name;
|
|
const tabName = getENActiveTab();
|
|
const button = gradioApp().querySelector(`#${tabName}_styles_select`);
|
|
button.click();
|
|
}
|
|
function applyStyles(styles) {
|
|
let newStyles;
|
|
if (styles) {
|
|
newStyles = Array.isArray(styles) ? styles : [styles];
|
|
} else {
|
|
const tabName = getENActiveTab();
|
|
styles = gradioApp().querySelectorAll(`#${tabName}_styles .token span`);
|
|
newStyles = Array.from(styles).map((el2) => el2.textContent).filter((el2) => el2.length > 0);
|
|
}
|
|
const index = newStyles.indexOf(desiredStyle);
|
|
if (index > -1) newStyles.splice(index, 1);
|
|
else newStyles.push(desiredStyle);
|
|
markSelectedCards(newStyles, "style");
|
|
return newStyles.join("|");
|
|
}
|
|
function quickApplyStyle() {
|
|
const tabName = getENActiveTab();
|
|
const btnApply = gradioApp().getElementById(`${tabName}_extra_apply`);
|
|
if (btnApply) btnApply.click();
|
|
}
|
|
function quickSaveStyle() {
|
|
const tabName = getENActiveTab();
|
|
const btnSave = gradioApp().getElementById(`${tabName}_extra_quicksave`);
|
|
if (btnSave) btnSave.click();
|
|
const btnRefresh = gradioApp().getElementById(`${tabName}_extra_refresh`);
|
|
if (btnRefresh) {
|
|
setTimeout(() => btnRefresh.click(), 100);
|
|
}
|
|
}
|
|
window.quickSaveStyle = quickSaveStyle;
|
|
var enDirty = false;
|
|
function closeDetailsEN(...args) {
|
|
enDirty = true;
|
|
const tabName = getENActiveTab();
|
|
const btnClose = gradioApp().getElementById(`${tabName}_extra_details_close`);
|
|
if (btnClose) setTimeout(() => btnClose.click(), 100);
|
|
const btnRefresh = gradioApp().getElementById(`${tabName}_extra_refresh`);
|
|
if (btnRefresh && enDirty) setTimeout(() => btnRefresh.click(), 100);
|
|
return [...args];
|
|
}
|
|
function refeshDetailsEN(args) {
|
|
const tabName = getENActiveTab();
|
|
const btnRefresh = gradioApp().getElementById(`${tabName}_extra_refresh`);
|
|
if (btnRefresh && enDirty) setTimeout(() => btnRefresh.click(), 100);
|
|
enDirty = false;
|
|
return args;
|
|
}
|
|
function refreshENpage() {
|
|
if (getCardsForActivePage().length === 0) {
|
|
const tabName = getENActiveTab();
|
|
const btnRefresh = gradioApp().getElementById(`${tabName}_extra_refresh`);
|
|
if (btnRefresh) btnRefresh.click();
|
|
}
|
|
}
|
|
function setupExtraNetworksForTab(tabName) {
|
|
let tabs = gradioApp().querySelector(`#${tabName}_extra_tabs`);
|
|
if (tabs) tabs.classList.add("extra-networks");
|
|
const en = gradioApp().getElementById(`${tabName}_extra_networks`);
|
|
tabs = gradioApp().querySelector(`#${tabName}_extra_tabs > div`);
|
|
if (!tabs) return;
|
|
const btnShow = gradioApp().getElementById(`${tabName}_extra_networks_btn`);
|
|
const btnRefresh = gradioApp().getElementById(`${tabName}_extra_refresh`);
|
|
const btnScan = gradioApp().getElementById(`${tabName}_extra_scan`);
|
|
const btnSave = gradioApp().getElementById(`${tabName}_extra_save`);
|
|
const btnClose = gradioApp().getElementById(`${tabName}_extra_close`);
|
|
const btnSort = gradioApp().getElementById(`${tabName}_extra_sort`);
|
|
const btnView = gradioApp().getElementById(`${tabName}_extra_view`);
|
|
const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);
|
|
const btnApply = gradioApp().getElementById(`${tabName}_extra_apply`);
|
|
const buttons = document.createElement("span");
|
|
buttons.classList.add("buttons");
|
|
if (btnRefresh) buttons.appendChild(btnRefresh);
|
|
if (btnModel) buttons.appendChild(btnModel);
|
|
if (btnApply) buttons.appendChild(btnApply);
|
|
if (btnScan) buttons.appendChild(btnScan);
|
|
if (btnSave) buttons.appendChild(btnSave);
|
|
if (btnSort) buttons.appendChild(btnSort);
|
|
if (btnView) buttons.appendChild(btnView);
|
|
if (btnClose) buttons.appendChild(btnClose);
|
|
btnModel.onclick = () => btnModel.classList.toggle("toolbutton-selected");
|
|
tabs.appendChild(buttons);
|
|
const detailsImg = gradioApp().getElementById(`${tabName}_extra_details_img`);
|
|
const detailsClose = gradioApp().getElementById(`${tabName}_extra_details_close`);
|
|
if (detailsImg && detailsClose) {
|
|
detailsImg.title = "Close details";
|
|
detailsImg.onclick = () => detailsClose.click();
|
|
}
|
|
const div = document.createElement("div");
|
|
div.classList.add("second-line");
|
|
tabs.appendChild(div);
|
|
const txtSearch = gradioApp().querySelector(`#${tabName}_extra_search`);
|
|
const txtSearchValue = gradioApp().querySelector(`#${tabName}_extra_search textarea`);
|
|
const txtDescription = gradioApp().getElementById(`${tabName}_description`);
|
|
if (!txtSearch || !txtSearchValue || !txtDescription) return;
|
|
txtSearch.classList.add("search");
|
|
txtDescription.classList.add("description");
|
|
div.appendChild(txtSearch);
|
|
div.appendChild(txtDescription);
|
|
let debouceSearch;
|
|
txtSearchValue.addEventListener("input", (evt) => {
|
|
if (debouceSearch) clearTimeout(debouceSearch);
|
|
debouceSearch = setTimeout(async () => {
|
|
await filterExtraNetworksForTab(txtSearchValue.value.toLowerCase());
|
|
debouceSearch = void 0;
|
|
}, 100);
|
|
});
|
|
let debounceHover;
|
|
let previousCard = null;
|
|
if (window.opts.extra_networks_fetch) {
|
|
gradioApp().getElementById(`${tabName}_extra_tabs`).onmouseover = async (e) => {
|
|
const el2 = e.target.closest(".card");
|
|
if (!el2 || el2.title === previousCard) return;
|
|
if (!debounceHover) {
|
|
debounceHover = setTimeout(() => {
|
|
readCardDescription(el2.dataset.page, el2.dataset.name);
|
|
readCardTags(el2, el2.dataset.tags);
|
|
previousCard = el2.title;
|
|
}, 300);
|
|
}
|
|
el2.onmouseout = () => {
|
|
clearTimeout(debounceHover);
|
|
debounceHover = void 0;
|
|
};
|
|
};
|
|
}
|
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
for (const entry of entries) {
|
|
for (const el2 of Array.from(gradioApp().getElementById(`${tabName}_extra_tabs`).querySelectorAll(".extra-networks-page"))) {
|
|
const h = Math.trunc(entry.contentRect.height);
|
|
if (h <= 0) return;
|
|
const vh = opts.logmonitor_show ? "55vh" : "68vh";
|
|
if (window.opts.extra_networks_card_cover === "sidebar" && window.opts.theme_type === "Standard") el2.style.height = `max(${vh}, ${h - 90}px)`;
|
|
else if (window.opts.extra_networks_card_cover === "inline" && window.opts.theme_type === "Standard") el2.style.height = "25vh";
|
|
else if (window.opts.extra_networks_card_cover === "cover" && window.opts.theme_type === "Standard") el2.style.height = "50vh";
|
|
else el2.style.height = "unset";
|
|
}
|
|
}
|
|
});
|
|
const settingsEl = gradioApp().getElementById(`${tabName}_settings`);
|
|
const interfaceEl = gradioApp().getElementById(`${tabName}_interface`);
|
|
if (settingsEl) resizeObserver.observe(settingsEl);
|
|
if (interfaceEl) resizeObserver.observe(interfaceEl);
|
|
if (!en) return;
|
|
let lastView;
|
|
let heightInitialized = false;
|
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
|
if (!heightInitialized) {
|
|
heightInitialized = true;
|
|
let h;
|
|
const target = window.opts.extra_networks_card_cover === "sidebar" ? 0 : window.opts.extra_networks_height;
|
|
if (window.opts.theme_type === "Standard") h = target > 0 ? target : 55;
|
|
else h = target > 0 ? target : 87;
|
|
for (const el2 of Array.from(gradioApp().getElementById(`${tabName}_extra_tabs`).querySelectorAll(".extra-networks-page"))) {
|
|
if (h > 0) el2.style.height = `${h}vh`;
|
|
el2.parentElement.style.width = "-webkit-fill-available";
|
|
}
|
|
}
|
|
const cards = Array.from(gradioApp().querySelectorAll(".extra-network-cards > .card"));
|
|
if (cards.length > 0 && cards.length !== totalCards) {
|
|
totalCards = cards.length;
|
|
sortExtraNetworks("fixed");
|
|
}
|
|
if (lastView !== entries[0].intersectionRatio > 0) {
|
|
lastView = entries[0].intersectionRatio > 0;
|
|
if (lastView) {
|
|
refreshENpage();
|
|
if (window.opts.extra_networks_card_cover === "cover") {
|
|
en.style.position = "absolute";
|
|
en.style.height = "unset";
|
|
en.style.width = "unset";
|
|
en.style.right = "unset";
|
|
en.style.maxWidth = "unset";
|
|
en.style.maxHeight = "58vh";
|
|
en.style.top = "13em";
|
|
en.style.transition = "";
|
|
en.style.zIndex = 100;
|
|
gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width = "unset";
|
|
} else if (window.opts.extra_networks_card_cover === "sidebar") {
|
|
en.style.position = "absolute";
|
|
en.style.height = "auto";
|
|
en.style.width = `${window.opts.extra_networks_sidebar_width}vw`;
|
|
en.style.maxWidth = "50vw";
|
|
en.style.maxHeight = "unset";
|
|
en.style.right = "0";
|
|
en.style.top = "13em";
|
|
en.style.transition = "width 0.3s ease";
|
|
en.style.zIndex = 100;
|
|
gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width = `calc(100vw - 2em - min(${window.opts.extra_networks_sidebar_width}vw, 50vw))`;
|
|
} else {
|
|
en.style.position = "relative";
|
|
en.style.height = "unset";
|
|
en.style.width = "unset";
|
|
en.style.right = "unset";
|
|
en.style.maxWidth = "unset";
|
|
en.style.maxHeight = "33vh";
|
|
en.style.top = 0;
|
|
en.style.transition = "";
|
|
en.style.zIndex = 0;
|
|
gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width = "unset";
|
|
}
|
|
} else {
|
|
if (window.opts.extra_networks_card_cover === "sidebar") en.style.width = 0;
|
|
gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width = "unset";
|
|
}
|
|
if (tabName === "video") {
|
|
gradioApp().getElementById("framepack_settings").parentNode.style.width = gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width;
|
|
gradioApp().getElementById("ltx_settings").parentNode.style.width = gradioApp().getElementById(`${tabName}_settings`).parentNode.style.width;
|
|
}
|
|
}
|
|
});
|
|
intersectionObserver.observe(en);
|
|
}
|
|
async function showNetworks() {
|
|
for (const tabName of ["txt2img", "img2img", "control", "video"]) {
|
|
const btn = gradioApp().getElementById(`${tabName}_extra_networks_btn`);
|
|
if (window.opts.extra_networks_show && btn) btn.click();
|
|
}
|
|
log("showNetworks");
|
|
}
|
|
async function setupExtraNetworks() {
|
|
setupExtraNetworksForTab("txt2img");
|
|
setupExtraNetworksForTab("img2img");
|
|
setupExtraNetworksForTab("control");
|
|
setupExtraNetworksForTab("video");
|
|
function registerPrompt(tabName, id) {
|
|
const textarea = gradioApp().querySelector(`#${id} > label > textarea`);
|
|
if (!textarea) return;
|
|
if (!activePromptTextarea[tabName]) activePromptTextarea[tabName] = textarea;
|
|
textarea.addEventListener("focus", () => {
|
|
activePromptTextarea[tabName] = textarea;
|
|
});
|
|
}
|
|
registerPrompt("txt2img", "txt2img_prompt");
|
|
registerPrompt("txt2img", "txt2img_neg_prompt");
|
|
registerPrompt("img2img", "img2img_prompt");
|
|
registerPrompt("img2img", "img2img_neg_prompt");
|
|
registerPrompt("control", "control_prompt");
|
|
registerPrompt("control", "control_neg_prompt");
|
|
registerPrompt("video", "video_prompt");
|
|
registerPrompt("video", "video_neg_prompt");
|
|
log("initNetworks", window.opts.extra_networks_card_size);
|
|
document.documentElement.style.setProperty("--card-size", `${window.opts.extra_networks_card_size}px`);
|
|
}
|
|
window.applyStyles = applyStyles;
|
|
window.closeDetailsEN = closeDetailsEN;
|
|
window.getENActivePage = getENActivePage;
|
|
window.getCardDetails = getCardDetails;
|
|
window.sortExtraNetworks = sortExtraNetworks;
|
|
window.refeshDetailsEN = refeshDetailsEN;
|
|
window.extraNetworksSearchButton = extraNetworksSearchButton;
|
|
window.extraNetworksFilterVersion = extraNetworksFilterVersion;
|
|
window.selectStyle = selectStyle;
|
|
|
|
// ui/generationParams.ts
|
|
function attachGalleryListeners(tabName) {
|
|
const gallery = gradioApp().querySelector(`#${tabName}_gallery`);
|
|
if (!gallery) return null;
|
|
gallery.addEventListener("click", () => {
|
|
const btn = gradioApp().getElementById(`${tabName}_generation_info_button`);
|
|
if (btn) btn.click();
|
|
});
|
|
gallery.addEventListener("keydown", (e) => {
|
|
if (e.keyCode === 37 || e.keyCode === 39) {
|
|
const btn = gradioApp().getElementById(`${tabName}_generation_info_button`);
|
|
if (btn) btn.click();
|
|
}
|
|
});
|
|
return gallery;
|
|
}
|
|
var txt2imgGallery;
|
|
var img2imgGallery;
|
|
var controlGallery;
|
|
var modal;
|
|
async function initiGenerationParams() {
|
|
const t0 = performance.now();
|
|
if (!modal) modal = gradioApp().getElementById("lightboxModal");
|
|
if (!modal) return;
|
|
const modalObserver = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutationRecord) => {
|
|
const tabName = getENActiveTab();
|
|
const mutationTarget = mutationRecord.target;
|
|
if (mutationTarget instanceof HTMLElement && mutationTarget.style.display === "none") {
|
|
const btn = gradioApp().getElementById(`${tabName}_generation_info_button`);
|
|
if (btn) btn.click();
|
|
}
|
|
});
|
|
});
|
|
if (!txt2imgGallery) txt2imgGallery = attachGalleryListeners("txt2img");
|
|
if (!img2imgGallery) img2imgGallery = attachGalleryListeners("img2img");
|
|
if (!controlGallery) controlGallery = attachGalleryListeners("control");
|
|
modalObserver.observe(modal, { attributes: true, attributeFilter: ["style"] });
|
|
const t1 = performance.now();
|
|
log("initGenerationParams", Math.round(t1 - t0));
|
|
timer("initGenerationParams", t1 - t0);
|
|
}
|
|
|
|
// ui/imageParams.ts
|
|
async function initDragDrop() {
|
|
log("initDragDrop");
|
|
window.addEventListener("drop", (e) => {
|
|
const target = e.composedPath()[0];
|
|
if (!target.placeholder) return;
|
|
if (target.placeholder.indexOf("Prompt") === -1) return;
|
|
const tabName = getENActiveTab();
|
|
const promptTarget = `${tabName}_prompt_image`;
|
|
const imgParent = gradioApp().getElementById(promptTarget);
|
|
log("dropEvent", target, promptTarget, imgParent);
|
|
if (!imgParent) return;
|
|
const fileInput = imgParent.querySelector('input[type="file"]');
|
|
if (!imgParent || !fileInput) return;
|
|
if ((e.dataTransfer?.files?.length || 0) > 0) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
if (fileInput instanceof HTMLInputElement) fileInput.files = e.dataTransfer.files;
|
|
fileInput.dispatchEvent(new Event("change"));
|
|
log("dropEvent files", fileInput.files);
|
|
}
|
|
});
|
|
}
|
|
|
|
// ui/notification.ts
|
|
var lastHeadImg = null;
|
|
var notificationButton = null;
|
|
async function sendNotification() {
|
|
try {
|
|
if (!notificationButton) {
|
|
notificationButton = gradioApp().getElementById("request_notifications");
|
|
if (notificationButton) notificationButton.addEventListener("click", () => Notification.requestPermission(), true);
|
|
}
|
|
if (document.hasFocus()) return;
|
|
let galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] .thumbnail-item > img');
|
|
if (!galleryPreviews || galleryPreviews.length === 0) galleryPreviews = gradioApp().querySelectorAll(".thumbnail-item > img");
|
|
if (!galleryPreviews || galleryPreviews.length === 0) return;
|
|
const headImg = galleryPreviews[0]?.src;
|
|
if (!headImg || headImg === lastHeadImg || headImg.includes("logo-bg-")) return;
|
|
const audioNotification = gradioApp().querySelector("#audio_notification audio");
|
|
if (audioNotification instanceof HTMLAudioElement) audioNotification.play();
|
|
lastHeadImg = headImg;
|
|
const imgs = new Set(Array.from(galleryPreviews).map((img) => img instanceof HTMLImageElement ? img.src : ""));
|
|
const notification = new Notification("SD.Next", {
|
|
body: `Generated ${imgs.size > 1 ? imgs.size - window.opts.return_grid : 1} image${imgs.size > 1 ? "s" : ""}`,
|
|
icon: headImg,
|
|
image: headImg
|
|
});
|
|
notification.onclick = function onClick() {
|
|
parent.focus();
|
|
this.close();
|
|
};
|
|
log("sendNotifications");
|
|
} catch (e) {
|
|
error(`sendNotification: ${e}`);
|
|
}
|
|
}
|
|
|
|
// ui/progressBar.ts
|
|
var lastState = {};
|
|
var refreshInterval = 1e4;
|
|
var progressTimeout = 180;
|
|
var startTimeout = 5;
|
|
function setRefreshInterval() {
|
|
refreshInterval = window.opts.live_preview_refresh_period || 500;
|
|
log("refreshInterval", document.visibilityState, refreshInterval);
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (window.opts.live_preview_require_focus !== false && document.hidden) refreshInterval = Math.max(2500, window.opts.live_preview_refresh_period || 1e3);
|
|
else refreshInterval = window.opts.live_preview_refresh_period || 1e3;
|
|
});
|
|
}
|
|
function checkPaused(state) {
|
|
lastState.paused = state ? !state : !lastState.paused;
|
|
const t_el = document.getElementById("txt2img_pause");
|
|
const i_el = document.getElementById("img2img_pause");
|
|
const c_el = document.getElementById("control_pause");
|
|
const v_el = document.getElementById("video_pause");
|
|
if (t_el) t_el.innerText = lastState.paused ? "Resume" : "Pause";
|
|
if (i_el) i_el.innerText = lastState.paused ? "Resume" : "Pause";
|
|
if (c_el) c_el.innerText = lastState.paused ? "Resume" : "Pause";
|
|
if (v_el) v_el.innerText = lastState.paused ? "Resume" : "Pause";
|
|
}
|
|
function setProgress(res) {
|
|
const elements = ["txt2img_generate", "img2img_generate", "extras_generate", "control_generate", "video_generate", "framepack_generate"];
|
|
const progress = res?.progress || 0;
|
|
const job = res?.job || "";
|
|
let perc;
|
|
let eta = "";
|
|
if (job === "VAE") perc = "Decode";
|
|
else {
|
|
perc = res && progress > 0 && progress < 1 ? `${Math.round(100 * progress)}% ` : "";
|
|
let sec = res?.eta || 0;
|
|
if (res?.paused) eta = "Paused";
|
|
else if (res?.completed || progress > 0.99) eta = "Finishing";
|
|
else if (sec === 0) eta = "Start";
|
|
else {
|
|
const min = Math.floor(sec / 60);
|
|
sec %= 60;
|
|
eta = min > 0 ? `${Math.round(min)}m ${Math.round(sec)}s` : `${Math.round(sec)}s`;
|
|
}
|
|
}
|
|
document.title = `SD.Next ${perc}`;
|
|
for (const elId of elements) {
|
|
const el2 = document.getElementById(elId);
|
|
if (el2) {
|
|
const jobLabel = (res ? `${job} ${perc}${eta}` : "Generate").trim();
|
|
el2.innerText = jobLabel;
|
|
if (!window.waitForUiReady) {
|
|
const gradient = perc !== "" ? perc : "100%";
|
|
if (jobLabel === "Generate") el2.style.background = "var(--primary-500)";
|
|
else if (jobLabel.endsWith("Decode")) continue;
|
|
else if (jobLabel.endsWith("Start") || jobLabel.endsWith("Finishing")) el2.style.background = "var(--primary-800)";
|
|
else if (res && progress > 0 && progress < 1) el2.style.background = `linear-gradient(to right, var(--primary-500) 0%, var(--primary-800) ${gradient}, var(--neutral-700) ${gradient})`;
|
|
else el2.style.background = "var(--primary-500)";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function requestInterrupt() {
|
|
setProgress();
|
|
}
|
|
function randomId() {
|
|
return `task(${Math.random().toString(36).slice(2, 7)}${Math.random().toString(36).slice(2, 7)}${Math.random().toString(36).slice(2, 7)})`;
|
|
}
|
|
function requestProgress(id_task = "undefined", progressEl = null, galleryEl = null, atEnd = null, onProgress = null, once = false) {
|
|
if (id_task) localStorage.setItem("task", id_task);
|
|
let hasStarted = false;
|
|
let dateStart = Date.now();
|
|
let prevProgress = null;
|
|
const parentGallery = galleryEl ? galleryEl.parentNode : null;
|
|
let livePreview;
|
|
let img;
|
|
const initLivePreview = () => {
|
|
if (!parentGallery) return;
|
|
const footers = Array.from(gradioApp().querySelectorAll(".gallery_footer"));
|
|
for (const footer of footers) {
|
|
if (footer.id !== "gallery_footer") footer.style.display = "none";
|
|
}
|
|
const galleries = Array.from(gradioApp().querySelectorAll(".gallery_main"));
|
|
for (const gallery of galleries) {
|
|
if (gallery.id !== "gallery_gallery") gallery.style.display = "none";
|
|
}
|
|
livePreview = document.createElement("div");
|
|
livePreview.className = "livePreview";
|
|
parentGallery.insertBefore(livePreview, galleryEl);
|
|
img = new Image();
|
|
img.id = "livePreviewImage";
|
|
livePreview.appendChild(img);
|
|
img.onload = () => {
|
|
img.style.width = `min(100%, max(${img.naturalWidth}px, 512px))`;
|
|
parentGallery.style.minHeight = `min(82vh, ${img.naturalHeight}px)`;
|
|
parentGallery.style.maxHeight = `min(82vh, ${img.naturalHeight}px)`;
|
|
parentGallery.style.overflow = "hidden";
|
|
};
|
|
};
|
|
const removeLivePreview = (ok2 = false) => {
|
|
debug("taskEnd:", id_task);
|
|
localStorage.removeItem("task");
|
|
setProgress();
|
|
const footers = Array.from(gradioApp().querySelectorAll(".gallery_footer"));
|
|
for (const footer of footers) footer.style.display = "flex";
|
|
const galleries = Array.from(gradioApp().querySelectorAll(".gallery_main"));
|
|
for (const gallery of galleries) gallery.style.display = "flex";
|
|
try {
|
|
if (parentGallery && livePreview) {
|
|
if (ok2) {
|
|
const previewImg = gradioApp().querySelector("#livePreviewImage");
|
|
const galleryImg = gradioApp().querySelector("#control_gallery img");
|
|
if (previewImg?.src && galleryImg) galleryImg.src = previewImg.src;
|
|
}
|
|
parentGallery.removeChild(livePreview);
|
|
parentGallery.style.minHeight = "unset";
|
|
parentGallery.style.maxHeight = "unset";
|
|
parentGallery.style.overflow = "unset";
|
|
}
|
|
} catch {
|
|
}
|
|
checkPaused(true);
|
|
sendNotification();
|
|
if (atEnd) atEnd();
|
|
};
|
|
const previewVisible = () => {
|
|
try {
|
|
return !galleryEl?.closest(".section")?.classList.contains("minimize");
|
|
} catch {
|
|
return true;
|
|
}
|
|
};
|
|
const startLivePreview = (taskId, id_live_preview) => {
|
|
if (window.opts.live_preview_refresh_period === 0) return;
|
|
let request_id = -1;
|
|
if (document.hidden || !previewVisible()) {
|
|
if (!window.opts.live_preview_require_focus) request_id = id_live_preview;
|
|
} else {
|
|
request_id = id_live_preview;
|
|
}
|
|
const onProgressHandler = (res) => {
|
|
if (res?.debug) debug("progress:", { start: dateStart, id: request_id, res });
|
|
lastState = res;
|
|
const elapsedFromStart = (Date.now() - dateStart) / 1e3;
|
|
hasStarted = hasStarted || res.active;
|
|
if (res.completed || !res.active && (hasStarted || once)) {
|
|
debug("progress", { end: res, reason: res.completed ? "completed" : "inactive" });
|
|
if (!res.paused) removeLivePreview(true);
|
|
return;
|
|
}
|
|
if (elapsedFromStart > progressTimeout && !res.queued && res.progress === prevProgress) {
|
|
debug("progress", { end: res, reason: "progressSimeout" });
|
|
if (!res.paused) removeLivePreview(false);
|
|
return;
|
|
}
|
|
if (elapsedFromStart > startTimeout && !res.queued && !res.active) {
|
|
debug("progress", { end: res, reason: "startTimeout" });
|
|
if (!res.paused) removeLivePreview(false);
|
|
return;
|
|
}
|
|
if (res.progress !== prevProgress) {
|
|
dateStart = Date.now();
|
|
prevProgress = res.progress;
|
|
}
|
|
setProgress(res);
|
|
if (res.live_preview && !livePreview) initLivePreview();
|
|
if (res.live_preview && galleryEl) {
|
|
if (img.src !== res.live_preview) img.src = res.live_preview;
|
|
id_live_preview = res.id_live_preview;
|
|
}
|
|
if (onProgress) onProgress(res);
|
|
setTimeout(() => startLivePreview(id_task, id_live_preview), window.opts.live_preview_refresh_period || 500);
|
|
};
|
|
const onProgressErrorHandler = (err) => {
|
|
error("progress", { error: err });
|
|
removeLivePreview(false);
|
|
};
|
|
xhrPost("./internal/progress", { id_task, id_live_preview: request_id }, onProgressHandler, onProgressErrorHandler, false, 3e4);
|
|
};
|
|
debug("progress", { start: dateStart });
|
|
startLivePreview(id_task, 0);
|
|
}
|
|
window.checkPaused = checkPaused;
|
|
window.requestInterrupt = requestInterrupt;
|
|
window.randomId = randomId;
|
|
window.requestProgress = requestProgress;
|
|
|
|
// ui/ui.ts
|
|
window.opts = {};
|
|
window.localization = {};
|
|
window.titles = {};
|
|
var fontSizeApplyRaf = 0;
|
|
var pendingFontSize = null;
|
|
var appliedFontSize = null;
|
|
var cachedGradioRoot = null;
|
|
var wait_time = 800;
|
|
var token_timeouts = {};
|
|
var uiLoaded = false;
|
|
var promptsInitialized = false;
|
|
window.args_to_array = Array.from;
|
|
function set_theme(theme) {
|
|
const gradioURL = window.location.href;
|
|
if (!gradioURL.includes("?__theme=")) window.location.replace(`${gradioURL}?__theme=${theme}`);
|
|
}
|
|
function update_token_counter(button_id) {
|
|
if (token_timeouts[button_id]) clearTimeout(token_timeouts[button_id]);
|
|
token_timeouts[button_id] = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time);
|
|
}
|
|
function clip_gallery_urls(gallery) {
|
|
const files = gallery.map((v) => v.data);
|
|
navigator.clipboard.writeText(JSON.stringify(files)).then(
|
|
() => log("clipboard:", files),
|
|
(err) => error(`clipboard: ${files} ${err}`)
|
|
);
|
|
}
|
|
function isVisible(el2) {
|
|
if (!el2) return false;
|
|
const rect = el2.getBoundingClientRect();
|
|
if (rect.width === 0 && rect.height === 0) return false;
|
|
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
}
|
|
function all_gallery_buttons() {
|
|
let allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');
|
|
if (allGalleryButtons.length === 0) allGalleryButtons = gradioApp().querySelectorAll(".gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small");
|
|
const visibleGalleryButtons = [];
|
|
allGalleryButtons.forEach((elem) => {
|
|
if (elem.parentElement.offsetParent) visibleGalleryButtons.push(elem);
|
|
});
|
|
return visibleGalleryButtons;
|
|
}
|
|
function selected_gallery_button() {
|
|
let allCurrentButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small.selected');
|
|
if (allCurrentButtons.length === 0) allCurrentButtons = gradioApp().querySelectorAll(".gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small.selected");
|
|
let visibleCurrentButton = null;
|
|
allCurrentButtons.forEach((elem) => {
|
|
if (elem.parentElement.offsetParent) visibleCurrentButton = elem;
|
|
});
|
|
return visibleCurrentButton;
|
|
}
|
|
function selected_gallery_index() {
|
|
const buttons = all_gallery_buttons();
|
|
const button = selected_gallery_button();
|
|
let result = -1;
|
|
buttons.forEach((v, i) => {
|
|
if (v === button) {
|
|
result = i;
|
|
}
|
|
});
|
|
if (result === -1 && gradioApp().getElementById("tab-gallery-search")?.checkVisibility()) {
|
|
const gallerySelection2 = window.getGallerySelection();
|
|
if (Number.isInteger(gallerySelection2.index)) result = gallerySelection2.index;
|
|
}
|
|
return result;
|
|
}
|
|
function selected_gallery_files(tabname) {
|
|
let allImages = [];
|
|
let allThumbnails;
|
|
if (tabname && tabname !== "gallery") allThumbnails = gradioApp().querySelectorAll("div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small");
|
|
else allThumbnails = gradioApp().querySelectorAll(".gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small");
|
|
try {
|
|
allImages = Array.from(allThumbnails).map((v) => v.querySelector("img"));
|
|
if (tabname && tabname !== "gallery") allImages = allImages.filter((img) => isVisible(img));
|
|
allImages = allImages.map((img) => {
|
|
let fn = img.src;
|
|
if (fn.includes("file=")) fn = fn.split("file=")[1];
|
|
return decodeURI(fn);
|
|
});
|
|
} catch (err) {
|
|
error(`selected_gallery_files: ${err}`);
|
|
}
|
|
let selectedIndex = -1;
|
|
if (tabname && tabname !== "gallery") selectedIndex = selected_gallery_index();
|
|
return [allImages, selectedIndex];
|
|
}
|
|
function extract_image_from_gallery(gallery) {
|
|
if (gallery.length === 0) return [null];
|
|
if (gallery.length === 1) return [gallery[0]];
|
|
let index = selected_gallery_index();
|
|
if (index < 0 || index >= gallery.length) index = 0;
|
|
return [gallery[index]];
|
|
}
|
|
function send_to_kanvas(gallery) {
|
|
const [image] = extract_image_from_gallery(gallery);
|
|
log("sendToKanvas", image);
|
|
if (window.loadFromURL && image && image.data) window.loadFromURL(image.data);
|
|
}
|
|
async function setTheme(val, old) {
|
|
if (!old || val === old) return;
|
|
old = old.replace("modern/", "");
|
|
val = val.replace("modern/", "");
|
|
const links = Array.from(document.getElementsByTagName("link")).filter((l) => l.href.includes(old));
|
|
if (links.length === 0) {
|
|
log("setTheme: current theme not matched", old);
|
|
return;
|
|
}
|
|
for (const link of links) {
|
|
const href = link.href.replace(old, val);
|
|
const res = await fetch(href);
|
|
if (res.ok) {
|
|
log("setTheme", old, val);
|
|
link.href = link.href.replace(old, val);
|
|
} else {
|
|
log("setTheme: CSS not found", val);
|
|
}
|
|
}
|
|
}
|
|
function setFontSize(val, old) {
|
|
const size = Number(val || opts.font_size);
|
|
if (!Number.isFinite(size)) return;
|
|
if (size === old || size === appliedFontSize || size === pendingFontSize) return;
|
|
pendingFontSize = size;
|
|
if (fontSizeApplyRaf) return;
|
|
fontSizeApplyRaf = requestAnimationFrame(() => {
|
|
const t0 = performance.now();
|
|
fontSizeApplyRaf = 0;
|
|
const nextSize = pendingFontSize;
|
|
pendingFontSize = null;
|
|
if (!Number.isFinite(nextSize) || nextSize === appliedFontSize) return;
|
|
cachedGradioRoot = cachedGradioRoot || gradioApp();
|
|
const rootStyle = cachedGradioRoot.style;
|
|
document.documentElement.style.setProperty("--font-size", `${nextSize}px`);
|
|
rootStyle.setProperty("--font-size", `${nextSize}px`);
|
|
rootStyle.setProperty("--text-xxs", `${nextSize - 3}px`);
|
|
rootStyle.setProperty("--text-xs", `${nextSize - 2}px`);
|
|
rootStyle.setProperty("--text-sm", `${nextSize - 1}px`);
|
|
rootStyle.setProperty("--text-md", `${nextSize}px`);
|
|
rootStyle.setProperty("--text-lg", `${nextSize + 1}px`);
|
|
rootStyle.setProperty("--text-xl", `${nextSize + 2}px`);
|
|
rootStyle.setProperty("--text-xxl", `${nextSize + 3}px`);
|
|
appliedFontSize = nextSize;
|
|
const t1 = performance.now();
|
|
log("setFontSize", nextSize, `time=${Math.round(t1 - t0)}`);
|
|
timer("setFontSize", t1 - t0);
|
|
});
|
|
}
|
|
function switchToTab(tab) {
|
|
const tabs = Array.from(gradioApp().querySelectorAll("#tabs > .tab-nav > button"));
|
|
const btn = tabs?.find((t) => t.innerText === tab);
|
|
log("switchToTab", tab);
|
|
if (btn) btn.click();
|
|
}
|
|
function switch_to_txt2img(...args) {
|
|
switchToTab("Text");
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_img2img_tab(no) {
|
|
switchToTab("Image");
|
|
gradioApp().getElementById("mode_img2img").querySelectorAll("button")[no].click();
|
|
}
|
|
function switch_to_img2img(...args) {
|
|
switchToTab("Image");
|
|
switch_to_img2img_tab(0);
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_inpaint(...args) {
|
|
switchToTab("Image");
|
|
switch_to_img2img_tab(1);
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_sketch(...args) {
|
|
switchToTab("Image");
|
|
switch_to_img2img_tab(2);
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_composite(...args) {
|
|
switchToTab("Image");
|
|
switch_to_img2img_tab(3);
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_extras(...args) {
|
|
switchToTab("Process");
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_control(...args) {
|
|
switchToTab("Control");
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_video(...args) {
|
|
switchToTab("Video");
|
|
return Array.from(arguments);
|
|
}
|
|
function switch_to_caption(...args) {
|
|
switchToTab("Caption");
|
|
return Array.from(arguments);
|
|
}
|
|
function get_tab_index(tabId) {
|
|
let res = 0;
|
|
gradioApp().getElementById(tabId)?.querySelector("div").querySelectorAll("button").forEach((button, i) => {
|
|
if (button.className.indexOf("selected") !== -1) res = i;
|
|
});
|
|
return res;
|
|
}
|
|
function create_tab_index_args(tabId, args) {
|
|
const res = Array.from(args);
|
|
res[0] = get_tab_index(tabId);
|
|
return res;
|
|
}
|
|
function get_img2img_tab_index(...args) {
|
|
const res = Array.from(arguments);
|
|
res.splice(-2);
|
|
res[0] = get_tab_index("mode_img2img");
|
|
return res;
|
|
}
|
|
function create_submit_args(args) {
|
|
const res = Array.from(args);
|
|
if (Array.isArray(res[res.length - 3])) res[res.length - 3] = null;
|
|
return res;
|
|
}
|
|
function getCaptionActiveTab(...args) {
|
|
const res = create_tab_index_args("mode_caption", args);
|
|
return res;
|
|
}
|
|
function clearGallery(tabname) {
|
|
const gallery = gradioApp().getElementById(`${tabname}_gallery`);
|
|
gallery.classList.remove("logo");
|
|
const footer = gradioApp().getElementById(`${tabname}_footer`);
|
|
footer.style.display = "flex";
|
|
}
|
|
function submit_txt2img(...args) {
|
|
log("submitTxt");
|
|
clearGallery("txt2img");
|
|
const id = randomId();
|
|
requestProgress(id, null, gradioApp().getElementById("txt2img_gallery"));
|
|
const res = create_submit_args(args);
|
|
res[0] = id;
|
|
res[1] = window.submit_state;
|
|
window.submit_state = "";
|
|
return res;
|
|
}
|
|
function submit_img2img(...args) {
|
|
log("submitImg");
|
|
clearGallery("img2img");
|
|
const id = randomId();
|
|
requestProgress(id, null, gradioApp().getElementById("img2img_gallery"));
|
|
const res = create_submit_args(args);
|
|
res[0] = id;
|
|
res[1] = window.submit_state;
|
|
res[2] = get_tab_index("mode_img2img");
|
|
window.submit_state = "";
|
|
return res;
|
|
}
|
|
function submit_control(...args) {
|
|
log("submitControl");
|
|
clearGallery("control");
|
|
const id = randomId();
|
|
requestProgress(id, null, gradioApp().getElementById("control_gallery"));
|
|
const res = create_submit_args(args);
|
|
res[0] = id;
|
|
res[1] = window.submit_state;
|
|
const tabs = Array.from(gradioApp().querySelectorAll("#control-tabs > .tab-nav > button"));
|
|
const tabIdx = tabs.findIndex((btn) => btn.classList.contains("selected"));
|
|
const tabNames = ["ControlNet", "T2I Adapter", "XS", "Lite", "Reference"];
|
|
const selectedTab = tabNames[tabIdx] || "ControlNet";
|
|
res[2] = selectedTab.toLowerCase();
|
|
window.submit_state = "";
|
|
return res;
|
|
}
|
|
function submit_video(...args) {
|
|
log("submitVideo");
|
|
clearGallery("video");
|
|
const id = randomId();
|
|
requestProgress(id, null, gradioApp().getElementById("video_gallery"));
|
|
const res = create_submit_args(args);
|
|
res[0] = id;
|
|
res[1] = window.submit_state;
|
|
window.submit_state = "";
|
|
return res;
|
|
}
|
|
function submit_framepack(...args) {
|
|
const id = randomId();
|
|
log("submitFramepack", id);
|
|
requestProgress(id, null, null);
|
|
window.submit_state = "";
|
|
args[0] = id;
|
|
return args;
|
|
}
|
|
function submit_ltx(...args) {
|
|
const id = randomId();
|
|
log("submitFramepack", id);
|
|
requestProgress(id, null, null);
|
|
window.submit_state = "";
|
|
args[0] = id;
|
|
return args;
|
|
}
|
|
function submit_video_wrapper(...args) {
|
|
const modernEl = gradioApp().querySelector(".video_output.fade-in");
|
|
let id = modernEl ? modernEl.id : args[0];
|
|
id = id.replace("video-selector-", "");
|
|
log("submitVideoWrapper", id);
|
|
const btn = gradioApp().getElementById(`${id}_generate_btn`);
|
|
if (btn) btn.click();
|
|
}
|
|
function submit_postprocessing(...args) {
|
|
log("SubmitExtras");
|
|
clearGallery("extras");
|
|
return args;
|
|
}
|
|
window.submit_state = "";
|
|
function modelmerger(...args) {
|
|
const id = randomId();
|
|
const res = create_submit_args(args);
|
|
res[0] = id;
|
|
return res;
|
|
}
|
|
var promptTokenCountUpdateFuncs = {};
|
|
var registeredPromptTextareas = /* @__PURE__ */ new WeakSet();
|
|
var registeredPromptIds = /* @__PURE__ */ new Set();
|
|
var pendingCounterPlacement = /* @__PURE__ */ new Set();
|
|
var promptRegistrationConfig = [
|
|
["txt2img_prompt", "txt2img_token_counter", "txt2img_token_button"],
|
|
["txt2img_neg_prompt", "txt2img_negative_token_counter", "txt2img_negative_token_button"],
|
|
["img2img_prompt", "img2img_token_counter", "img2img_token_button"],
|
|
["img2img_neg_prompt", "img2img_negative_token_counter", "img2img_negative_token_button"],
|
|
["control_prompt", "control_token_counter", "control_token_button"],
|
|
["control_neg_prompt", "control_negative_token_counter", "control_negative_token_button"]
|
|
];
|
|
var promptRegistrationRaf = 0;
|
|
var promptRegistrationCursor = 0;
|
|
var promptRegistrationInProgress = false;
|
|
function scheduleIdleUI(task) {
|
|
if (typeof window.requestIdleCallback === "function") {
|
|
window.requestIdleCallback(task, { timeout: 500 });
|
|
} else {
|
|
setTimeout(task, 0);
|
|
}
|
|
}
|
|
function recalculatePromptTokens(name) {
|
|
if (promptTokenCountUpdateFuncs[name]) {
|
|
promptTokenCountUpdateFuncs[name]();
|
|
}
|
|
}
|
|
function recalculate_prompts_txt2img(...args) {
|
|
recalculatePromptTokens("txt2img_prompt");
|
|
recalculatePromptTokens("txt2img_neg_prompt");
|
|
return Array.from(arguments);
|
|
}
|
|
function recalculate_prompts_img2img(...args) {
|
|
recalculatePromptTokens("img2img_prompt");
|
|
recalculatePromptTokens("img2img_neg_prompt");
|
|
return Array.from(arguments);
|
|
}
|
|
function recalculate_prompts_inpaint(...args) {
|
|
recalculatePromptTokens("img2img_prompt");
|
|
recalculatePromptTokens("img2img_neg_prompt");
|
|
return Array.from(arguments);
|
|
}
|
|
function recalculate_prompts_control(...args) {
|
|
recalculatePromptTokens("control_prompt");
|
|
recalculatePromptTokens("control_neg_prompt");
|
|
return Array.from(arguments);
|
|
}
|
|
function registerDragDrop() {
|
|
const qs = gradioApp().getElementById("quicksettings");
|
|
if (!qs) return;
|
|
qs.addEventListener("dragover", (evt) => {
|
|
evt.preventDefault();
|
|
evt.dataTransfer.dropEffect = "copy";
|
|
});
|
|
qs.addEventListener("drop", (evt) => {
|
|
evt.preventDefault();
|
|
evt.dataTransfer.dropEffect = "copy";
|
|
for (const f of evt.dataTransfer.files) {
|
|
log("QuickSettingsDrop", f);
|
|
}
|
|
});
|
|
}
|
|
function registerTextareaCallback() {
|
|
if (promptsInitialized) return;
|
|
if (promptRegistrationInProgress) return;
|
|
const t0 = performance.now();
|
|
const app = gradioApp();
|
|
if (!app) return;
|
|
const registerTextarea = (id, id_counter, id_button) => {
|
|
const prompt = app.getElementById(id);
|
|
const counter = app.getElementById(id_counter);
|
|
const localTextarea = prompt?.querySelector("label > textarea");
|
|
if (!prompt || !counter || !localTextarea || !prompt.parentElement) return false;
|
|
const promptParent = prompt.parentElement;
|
|
const needsCounterPlacement = counter.parentElement !== promptParent || counter.nextElementSibling !== prompt;
|
|
if (needsCounterPlacement && !pendingCounterPlacement.has(id)) {
|
|
pendingCounterPlacement.add(id);
|
|
scheduleIdleUI(() => {
|
|
pendingCounterPlacement.delete(id);
|
|
const currentPrompt = app.getElementById(id);
|
|
const currentCounter = app.getElementById(id_counter);
|
|
if (!currentPrompt || !currentCounter || !currentPrompt.parentElement) return;
|
|
const currentParent = currentPrompt.parentElement;
|
|
if (currentCounter.parentElement !== currentParent || currentCounter.nextElementSibling !== currentPrompt) {
|
|
currentParent.insertBefore(currentCounter, currentPrompt);
|
|
}
|
|
if (currentParent.style.position !== "relative") {
|
|
currentParent.style.position = "relative";
|
|
}
|
|
});
|
|
}
|
|
if (!promptTokenCountUpdateFuncs[id]) promptTokenCountUpdateFuncs[id] = () => {
|
|
update_token_counter(id_button);
|
|
};
|
|
if (!registeredPromptTextareas.has(localTextarea)) {
|
|
localTextarea.addEventListener("input", promptTokenCountUpdateFuncs[id]);
|
|
registeredPromptTextareas.add(localTextarea);
|
|
}
|
|
return true;
|
|
};
|
|
const runPromptRegistrationStep = () => {
|
|
promptRegistrationRaf = 0;
|
|
const total = promptRegistrationConfig.length;
|
|
let cfg = null;
|
|
for (let attempts = 0; attempts < total; attempts += 1) {
|
|
const nextCfg = promptRegistrationConfig[promptRegistrationCursor];
|
|
promptRegistrationCursor = (promptRegistrationCursor + 1) % total;
|
|
const [id] = nextCfg;
|
|
if (!registeredPromptIds.has(id)) {
|
|
cfg = nextCfg;
|
|
break;
|
|
}
|
|
}
|
|
if (cfg) {
|
|
const [id] = cfg;
|
|
if (registerTextarea(...cfg)) {
|
|
registeredPromptIds.add(id);
|
|
} else {
|
|
promptRegistrationInProgress = false;
|
|
return;
|
|
}
|
|
}
|
|
promptsInitialized = registeredPromptIds.size === total;
|
|
if (promptsInitialized) {
|
|
promptRegistrationInProgress = false;
|
|
const t1 = performance.now();
|
|
log("initPrompts", { count: registeredPromptIds.size, time: Math.round(t1 - t0) });
|
|
timer("initPrompts", t1 - t0);
|
|
return;
|
|
}
|
|
promptRegistrationRaf = requestAnimationFrame(runPromptRegistrationStep);
|
|
};
|
|
promptRegistrationInProgress = true;
|
|
promptRegistrationRaf = requestAnimationFrame(runPromptRegistrationStep);
|
|
}
|
|
onAfterUiUpdate(registerTextareaCallback);
|
|
var delay = (ms) => new Promise((resolve) => {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
async function restartReload(initial = true) {
|
|
document.body.style = "background: #222222; font-size: 1rem; font-family:monospace; margin-top:20%; color:lightgray; text-align:center";
|
|
document.body.innerHTML = "<h1>Server shutdown in progress...</h1>";
|
|
if (initial) await delay(1e4);
|
|
try {
|
|
const res = await authFetch(`${window.api}/progress?skip_current_image=true`);
|
|
console.log("restartReload", res);
|
|
if (res?.ok) {
|
|
document.body.innerHTML = "<h1>Server restart in progress...</h1>";
|
|
setTimeout(() => location.reload(), 1e4);
|
|
} else {
|
|
setTimeout(() => restartReload(false), 2500);
|
|
}
|
|
} catch {
|
|
setTimeout(() => restartReload(false), 2500);
|
|
}
|
|
return [];
|
|
}
|
|
function updateInput2(target) {
|
|
const e = new Event("input", { bubbles: true });
|
|
Object.defineProperty(e, "target", { value: target });
|
|
target.dispatchEvent(e);
|
|
}
|
|
var desiredCheckpointName = null;
|
|
function selectCheckpoint(name) {
|
|
desiredCheckpointName = name;
|
|
const tabName = getENActiveTab();
|
|
const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);
|
|
const isRefiner = btnModel && btnModel.classList.contains("toolbutton-selected");
|
|
if (isRefiner) gradioApp().getElementById("change_refiner").click();
|
|
else gradioApp().getElementById("change_checkpoint").click();
|
|
log(`selectCheckpoint ${isRefiner ? "refiner" : "model"}: ${desiredCheckpointName}`);
|
|
markSelectedCards([desiredCheckpointName], "model");
|
|
setTimeout(requestProgress, 250);
|
|
}
|
|
var desiredVAEName = null;
|
|
function selectVAE(name) {
|
|
desiredVAEName = name;
|
|
gradioApp().getElementById("change_vae").click();
|
|
log(`selectVAE: ${desiredVAEName}`);
|
|
markSelectedCards([desiredVAEName], "vae");
|
|
}
|
|
var desiredUNetName = null;
|
|
function consumeDesiredCheckpointName(v) {
|
|
const res = desiredCheckpointName;
|
|
desiredCheckpointName = null;
|
|
return [res || v, null];
|
|
}
|
|
function consumeDesiredVAEName(v) {
|
|
const res = desiredVAEName;
|
|
desiredVAEName = null;
|
|
return [res || v, null];
|
|
}
|
|
function consumeDesiredUNetName(v) {
|
|
const res = desiredUNetName;
|
|
desiredUNetName = null;
|
|
return [res || v, null];
|
|
}
|
|
function getDesiredCheckpointName() {
|
|
return desiredCheckpointName;
|
|
}
|
|
function selectUNet(name) {
|
|
desiredUNetName = name;
|
|
gradioApp().getElementById("change_unet").click();
|
|
log(`selectUNet: ${desiredUNetName}`);
|
|
markSelectedCards([desiredUNetName], "unet");
|
|
}
|
|
function selectReference(name) {
|
|
log(`selectReference: ${name}`);
|
|
desiredCheckpointName = name;
|
|
gradioApp().getElementById("change_reference").click();
|
|
markSelectedCards([desiredCheckpointName], "model");
|
|
setTimeout(requestProgress, 250);
|
|
}
|
|
function currentImageResolutionimg2img(_a, _b, scaleBy) {
|
|
const img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img');
|
|
return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];
|
|
}
|
|
function currentImageResolutioncontrol(_a, _b, scaleBy) {
|
|
if (window.kanvas) {
|
|
const active2 = window.kanvas.stages?.getActiveStage();
|
|
return [active2?.width || 0, active2?.height || 0, scaleBy];
|
|
}
|
|
const img = gradioApp().querySelector('#control-tab-input > div[style="display: block;"] img');
|
|
return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];
|
|
}
|
|
function updateImg2imgResizeToTextAfterChangingImage() {
|
|
const el2 = gradioApp().getElementById("img2img_update_resize_to");
|
|
if (el2) setTimeout(() => gradioApp().getElementById("img2img_update_resize_to").click(), 500);
|
|
return [];
|
|
}
|
|
async function toggleCompact(val, old) {
|
|
if (val === old) return;
|
|
log("toggleCompact", val, old);
|
|
if (val) {
|
|
gradioApp().style.setProperty("--layout-gap", "var(--spacing-md)");
|
|
gradioApp().querySelectorAll("input[type=range]").forEach((el2) => el2.classList.add("hidden"));
|
|
gradioApp().querySelectorAll("div .form").forEach((el2) => el2.classList.add("form-compact"));
|
|
gradioApp().querySelectorAll(".small-accordion .label-wrap").forEach((el2) => el2.classList.add("accordion-compact"));
|
|
} else {
|
|
gradioApp().style.setProperty("--layout-gap", "var(--spacing-xxl)");
|
|
gradioApp().querySelectorAll("input[type=range]").forEach((el2) => el2.classList.remove("hidden"));
|
|
gradioApp().querySelectorAll("div .form").forEach((el2) => el2.classList.remove("form-compact"));
|
|
gradioApp().querySelectorAll(".small-accordion .label-wrap").forEach((el2) => el2.classList.remove("accordion-compact"));
|
|
}
|
|
}
|
|
var kanvasNotifyTimer;
|
|
function notifyKanvasResize(width, height) {
|
|
if (window.resizeStage) {
|
|
const w = Number(width);
|
|
const h = Number(height);
|
|
clearTimeout(kanvasNotifyTimer);
|
|
kanvasNotifyTimer = setTimeout(() => window.resizeStage?.(w, h), 250);
|
|
}
|
|
}
|
|
async function reconnectUI() {
|
|
const t0 = performance.now();
|
|
const gallery = gradioApp().getElementById("txt2img_gallery");
|
|
const task_id = localStorage.getItem("task");
|
|
const api_logo = Array.from(gradioApp().querySelectorAll("img")).filter((el2) => el2.src.endsWith("api-logo.svg"));
|
|
if (api_logo.length > 0) api_logo[0].remove();
|
|
if (task_id) {
|
|
debug("task check:", task_id);
|
|
requestProgress(task_id, null, gallery, null, null, true);
|
|
}
|
|
uiLoaded = true;
|
|
const sd_model = gradioApp().getElementById("setting_sd_model_checkpoint");
|
|
let loadingStarted = 0;
|
|
let loadingMonitor = null;
|
|
const sd_model_callback = () => {
|
|
const loading = sd_model.querySelector(".eta-bar");
|
|
if (!loading) {
|
|
loadingStarted = 0;
|
|
clearInterval(loadingMonitor);
|
|
} else if (loadingStarted === 0) {
|
|
loadingStarted = Date.now();
|
|
loadingMonitor = setInterval(() => {
|
|
const elapsed = Date.now() - loadingStarted;
|
|
if (elapsed > 3e3 && loading) loading.style.display = "none";
|
|
}, 5e3);
|
|
}
|
|
};
|
|
const sd_model_observer = new MutationObserver(sd_model_callback);
|
|
sd_model_observer.observe(sd_model, { attributes: true, childList: true, subtree: true });
|
|
const t1 = performance.now();
|
|
log("reconnectUI", Math.round(t1 - t0));
|
|
timer("reconnectUI", t1 - t0);
|
|
}
|
|
window.restartReload = restartReload;
|
|
window.updateInput = updateInput2;
|
|
window.notifyKanvasResize = notifyKanvasResize;
|
|
window.clip_gallery_urls = clip_gallery_urls;
|
|
window.extract_image_from_gallery = extract_image_from_gallery;
|
|
window.getCaptionActiveTab = getCaptionActiveTab;
|
|
window.get_img2img_tab_index = get_img2img_tab_index;
|
|
window.modelmerger = modelmerger;
|
|
window.selected_gallery_index = selected_gallery_index;
|
|
window.selected_gallery_files = selected_gallery_files;
|
|
window.send_to_kanvas = send_to_kanvas;
|
|
window.submit_control = submit_control;
|
|
window.submit_framepack = submit_framepack;
|
|
window.submit_img2img = submit_img2img;
|
|
window.submit_ltx = submit_ltx;
|
|
window.submit_postprocessing = submit_postprocessing;
|
|
window.submit = submit_txt2img;
|
|
window.submit_txt2img = submit_txt2img;
|
|
window.submit_video = submit_video;
|
|
window.submit_video_wrapper = submit_video_wrapper;
|
|
window.switch_to_txt2img = switch_to_txt2img;
|
|
window.switch_to_img2img_tab = switch_to_img2img_tab;
|
|
window.switch_to_img2img = switch_to_img2img;
|
|
window.switch_to_inpaint = switch_to_inpaint;
|
|
window.switch_to_sketch = switch_to_sketch;
|
|
window.switch_to_composite = switch_to_composite;
|
|
window.switch_to_extras = switch_to_extras;
|
|
window.switch_to_control = switch_to_control;
|
|
window.switch_to_video = switch_to_video;
|
|
window.switch_to_caption = switch_to_caption;
|
|
window.recalculate_prompts_txt2img = recalculate_prompts_txt2img;
|
|
window.recalculate_prompts_img2img = recalculate_prompts_img2img;
|
|
window.recalculate_prompts_inpaint = recalculate_prompts_inpaint;
|
|
window.recalculate_prompts_control = recalculate_prompts_control;
|
|
window.selectCheckpoint = selectCheckpoint;
|
|
window.selectVAE = selectVAE;
|
|
window.selectUNet = selectUNet;
|
|
window.selectReference = selectReference;
|
|
window.consumeDesiredCheckpointName = consumeDesiredCheckpointName;
|
|
window.consumeDesiredVAEName = consumeDesiredVAEName;
|
|
window.consumeDesiredUNetName = consumeDesiredUNetName;
|
|
window.getDesiredCheckpointName = getDesiredCheckpointName;
|
|
window.currentImageResolutionimg2img = currentImageResolutionimg2img;
|
|
window.currentImageResolutioncontrol = currentImageResolutioncontrol;
|
|
window.updateImg2imgResizeToTextAfterChangingImage = updateImg2imgResizeToTextAfterChangingImage;
|
|
window.create_submit_args = create_submit_args;
|
|
window.set_theme = set_theme;
|
|
|
|
// ui/inputAccordion.ts
|
|
function inputAccordionChecked(id, checked) {
|
|
const accordion = gradioApp().getElementById(id);
|
|
if (!(accordion instanceof HTMLElement)) return;
|
|
const acc = accordion;
|
|
acc.visibleCheckbox.checked = checked;
|
|
acc.onVisibleCheckboxChange();
|
|
}
|
|
function setupAccordion(accordion) {
|
|
if (!(accordion instanceof HTMLElement)) return;
|
|
const acc = accordion;
|
|
const labelWrap = accordion.querySelector(".label-wrap");
|
|
const gradioCheckbox = gradioApp().querySelector(`#${accordion.id}-checkbox input`);
|
|
const extra = gradioApp().querySelector(`#${accordion.id}-extra`);
|
|
if (!(labelWrap instanceof HTMLElement) || !(gradioCheckbox instanceof HTMLInputElement)) return;
|
|
const span = labelWrap.querySelector("span");
|
|
if (!(span instanceof HTMLElement)) return;
|
|
let linked = true;
|
|
const isOpen = () => labelWrap.classList.contains("open");
|
|
const observerAccordionOpen = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutationRecord) => {
|
|
accordion.classList.toggle("input-accordion-open", isOpen());
|
|
if (linked) {
|
|
acc.visibleCheckbox.checked = isOpen();
|
|
acc.onVisibleCheckboxChange();
|
|
}
|
|
});
|
|
});
|
|
observerAccordionOpen.observe(labelWrap, { attributes: true, attributeFilter: ["class"] });
|
|
if (extra instanceof Node) labelWrap.insertBefore(extra, labelWrap.lastElementChild);
|
|
acc.onChecked = (checked) => {
|
|
if (isOpen() !== checked) labelWrap.click();
|
|
};
|
|
const visibleCheckbox = document.createElement("INPUT");
|
|
visibleCheckbox.type = "checkbox";
|
|
visibleCheckbox.checked = isOpen();
|
|
visibleCheckbox.id = `${accordion.id}-visible-checkbox`;
|
|
visibleCheckbox.className = `${gradioCheckbox.className} input-accordion-checkbox`;
|
|
span.insertBefore(visibleCheckbox, span.firstChild);
|
|
acc.visibleCheckbox = visibleCheckbox;
|
|
acc.onVisibleCheckboxChange = () => {
|
|
if (linked && isOpen() !== visibleCheckbox.checked) labelWrap.click();
|
|
gradioCheckbox.checked = visibleCheckbox.checked;
|
|
updateInput2(gradioCheckbox);
|
|
};
|
|
visibleCheckbox.addEventListener("click", (event2) => {
|
|
linked = false;
|
|
event2.stopPropagation();
|
|
});
|
|
visibleCheckbox.addEventListener("input", acc.onVisibleCheckboxChange);
|
|
}
|
|
window.inputAccordionChecked = inputAccordionChecked;
|
|
function initAccordions() {
|
|
for (const accordion of gradioApp().querySelectorAll(".input-accordion")) setupAccordion(accordion);
|
|
}
|
|
|
|
// ui/indexdb.ts
|
|
var db = null;
|
|
async function initIndexDB() {
|
|
async function createDB() {
|
|
return new Promise((resolve, reject) => {
|
|
const request = indexedDB.open("SDNext", 2);
|
|
request.onerror = (evt) => reject(evt);
|
|
request.onsuccess = (evt) => {
|
|
db = evt.target.result;
|
|
const countAll = db.transaction(["thumbs"], "readwrite").objectStore("thumbs").count();
|
|
countAll.onsuccess = () => log("initIndexDB", countAll.result);
|
|
resolve();
|
|
};
|
|
request.onupgradeneeded = (evt) => {
|
|
db = evt.target.result;
|
|
const oldver = evt.oldVersion;
|
|
if (oldver < 1) {
|
|
const store = db.createObjectStore("thumbs", { keyPath: "hash" });
|
|
store.createIndex("hash", "hash", { unique: true });
|
|
}
|
|
if (oldver < 2) {
|
|
const existingStore = request.transaction.objectStore("thumbs");
|
|
existingStore.createIndex("folder", "folder", { unique: false });
|
|
}
|
|
resolve();
|
|
};
|
|
});
|
|
}
|
|
if (!db) await createDB();
|
|
}
|
|
function idbIsReady() {
|
|
return db !== null;
|
|
}
|
|
function configureTransactionAbort({
|
|
transaction,
|
|
signal,
|
|
resolve,
|
|
reject
|
|
}, resolveValue) {
|
|
function abortTransaction() {
|
|
signal.removeEventListener("abort", abortTransaction);
|
|
transaction.abort();
|
|
}
|
|
signal.addEventListener("abort", abortTransaction);
|
|
transaction.onabort = () => {
|
|
signal.removeEventListener("abort", abortTransaction);
|
|
reject(new DOMException(`Aborting database transaction. ${signal.reason}`, "AbortError"));
|
|
};
|
|
transaction.onerror = (e) => {
|
|
signal.removeEventListener("abort", abortTransaction);
|
|
reject(new Error("Database transaction error."));
|
|
};
|
|
transaction.oncomplete = () => {
|
|
signal.removeEventListener("abort", abortTransaction);
|
|
resolve(resolveValue);
|
|
};
|
|
return abortTransaction;
|
|
}
|
|
async function add(record) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db.transaction(["thumbs"], "readwrite").objectStore("thumbs").add(record);
|
|
request.onsuccess = (evt) => resolve(evt);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
async function get(hash3) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db.transaction(["thumbs"], "readonly").objectStore("thumbs").index("hash").get(hash3);
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
async function idbGetAllKeys(index = null, query = null) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let request;
|
|
const transaction = db.transaction("thumbs", "readonly");
|
|
transaction.onabort = (e) => reject(e);
|
|
const store = transaction.objectStore("thumbs");
|
|
if (index) request = store.index(index).getAllKeys(query);
|
|
else request = store.getAllKeys(query);
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (e) => reject(e);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
async function idbCount(folder) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let request;
|
|
const transaction = db.transaction("thumbs", "readonly");
|
|
transaction.onabort = (e) => reject(e);
|
|
const store = transaction.objectStore("thumbs");
|
|
if (folder) request = store.index("folder").count(folder);
|
|
else request = store.count();
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (e) => reject(e);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
async function idbFolderCleanup(keepSet, folder, signal) {
|
|
if (!db) return null;
|
|
const existing = await idbGetAllKeys("folder", folder);
|
|
const removals = new Set((existing ?? []).map((entry) => String(entry)).filter((entry) => !keepSet.has(entry)));
|
|
const totalRemovals = removals.size;
|
|
if (signal.aborted) {
|
|
throw new Error(`Aborting. ${String(signal.reason)}`);
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction("thumbs", "readwrite");
|
|
const props = { transaction, signal, resolve, reject };
|
|
configureTransactionAbort(props, totalRemovals);
|
|
const store = transaction.objectStore("thumbs");
|
|
removals.forEach((entry) => {
|
|
store.delete(entry);
|
|
});
|
|
});
|
|
}
|
|
var idbAdd = add;
|
|
var idbGet = get;
|
|
|
|
// ui/logMonitor.ts
|
|
var logMonitorEl = null;
|
|
var logMonitorStatus = true;
|
|
var logWarnings = 0;
|
|
var logErrors = 0;
|
|
var logConnected = false;
|
|
function dateToStr(ts) {
|
|
const dt = new Date(1e3 * ts);
|
|
const year = dt.getFullYear();
|
|
const mo = String(dt.getMonth() + 1).padStart(2, "0");
|
|
const day = String(dt.getDate()).padStart(2, "0");
|
|
const hour = String(dt.getHours()).padStart(2, "0");
|
|
const min = String(dt.getMinutes()).padStart(2, "0");
|
|
const sec = String(dt.getSeconds()).padStart(2, "0");
|
|
const ms = String(dt.getMilliseconds()).padStart(3, "0");
|
|
const s = `${year}-${mo}-${day} ${hour}:${min}:${sec}.${ms}`;
|
|
return s;
|
|
}
|
|
function htmlEscape(text) {
|
|
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
}
|
|
function parseLogLine(line) {
|
|
let str = line.replaceAll("\n", " ").replaceAll("\\", "\\\\");
|
|
const tracebackIndex = str.indexOf("Traceback");
|
|
if (tracebackIndex !== -1) str = str.substring(0, tracebackIndex);
|
|
const parsed = JSON.parse(str);
|
|
return {
|
|
created: Number(parsed.created ?? Date.now()),
|
|
level: String(parsed.level ?? "INFO"),
|
|
module: String(parsed.module ?? "logMonitor"),
|
|
facility: String(parsed.facility ?? "ui"),
|
|
msg: String(parsed.msg ?? "")
|
|
};
|
|
}
|
|
async function logMonitor() {
|
|
const addLogLine = (line) => {
|
|
if (!logMonitorEl) logMonitorEl = document.getElementById("logMonitorData");
|
|
if (!logMonitorEl) return;
|
|
try {
|
|
const l = parseLogLine(line);
|
|
const row = document.createElement("tr");
|
|
const level = `<td style="color: var(--color-${l.level.toLowerCase()})">${l.level}</td>`;
|
|
if (l.level === "WARNING") logWarnings++;
|
|
if (l.level === "ERROR") logErrors++;
|
|
const module = `<td style="color: var(--neutral-400)">${l.module}</td>`;
|
|
const facilityText = l.facility.length > 20 ? `${l.facility.substring(0, 20)}...` : l.facility;
|
|
const facility = l.facility !== "sd" ? `<td>${facilityText}</td>` : "<td></td>";
|
|
row.innerHTML = `<td>${dateToStr(l.created)}</td>${level}${facility}${module}<td>${htmlEscape(l.msg)}</td>`;
|
|
logMonitorEl.appendChild(row);
|
|
} catch (err) {
|
|
error(`logMonitor: ${String(err)}`);
|
|
error(`logMonitor: ${line}`);
|
|
}
|
|
};
|
|
const cleanupLog = (atBottom2) => {
|
|
if (!logMonitorEl) return;
|
|
while (logMonitorEl.childElementCount > 100 && logMonitorEl.firstElementChild) {
|
|
logMonitorEl.removeChild(logMonitorEl.firstElementChild);
|
|
}
|
|
if (atBottom2) logMonitorEl.scrollTop = logMonitorEl.scrollHeight;
|
|
else if (logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = "border-bottom: 2px solid var(--highlight-color);";
|
|
const elWarn = document.getElementById("logWarnings");
|
|
const elErr = document.getElementById("logErrors");
|
|
const modenUIBtn = document.getElementById("btn_console");
|
|
if (elWarn) elWarn.innerText = String(logWarnings);
|
|
if (elErr) elErr.innerText = String(logErrors);
|
|
if (modenUIBtn) modenUIBtn.setAttribute("error-count", logErrors > 0 ? String(logErrors) : "");
|
|
};
|
|
const txtGallery = document.getElementById("txt2img_gallery");
|
|
if (txtGallery) txtGallery.style.height = window.opts.logmonitor_show ? "50vh" : "55vh";
|
|
const imgGallery = document.getElementById("img2img_gallery");
|
|
if (imgGallery) imgGallery.style.height = window.opts.logmonitor_show ? "50vh" : "55vh";
|
|
if (!window.opts.logmonitor_show) {
|
|
Array.from(document.getElementsByClassName("log-monitor")).forEach((el2) => {
|
|
if (el2 instanceof HTMLElement) el2.style.display = "none";
|
|
});
|
|
return;
|
|
}
|
|
if (logMonitorStatus) setTimeout(logMonitor, window.opts.logmonitor_refresh_period);
|
|
else setTimeout(logMonitor, 10 * 1e3);
|
|
logMonitorStatus = false;
|
|
if (!logMonitorEl) {
|
|
logMonitorEl = document.getElementById("logMonitorData");
|
|
if (logMonitorEl) {
|
|
logMonitorEl.addEventListener("scroll", () => {
|
|
const atBottom2 = logMonitorEl.scrollHeight <= logMonitorEl.scrollTop + logMonitorEl.clientHeight;
|
|
if (atBottom2 && logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = "";
|
|
});
|
|
}
|
|
}
|
|
if (!logMonitorEl) return;
|
|
const atBottom = logMonitorEl.scrollHeight <= logMonitorEl.scrollTop + logMonitorEl.clientHeight;
|
|
try {
|
|
const res = await authFetch(`${window.api}/log?clear=True`);
|
|
if (res?.ok) {
|
|
logMonitorStatus = true;
|
|
const lines = await res.json();
|
|
if (logMonitorEl && lines?.length > 0 && logMonitorEl.parentElement?.parentElement instanceof HTMLElement) {
|
|
logMonitorEl.parentElement.parentElement.style.display = window.opts.logmonitor_show ? "block" : "none";
|
|
}
|
|
for (const line of lines) addLogLine(line);
|
|
if (!logConnected) {
|
|
logConnected = true;
|
|
xhrPost(`${window.api}/log`, { debug: "connected" });
|
|
}
|
|
} else {
|
|
logConnected = false;
|
|
logErrors++;
|
|
addLogLine(`{ "created": ${Date.now()}, "level":"ERROR", "module":"logMonitor", "facility":"ui", "msg":"Failed to fetch log: ${res?.status} ${res?.statusText}" }`);
|
|
}
|
|
cleanupLog(atBottom);
|
|
} catch {
|
|
logConnected = false;
|
|
logErrors++;
|
|
addLogLine(`{ "created": ${Date.now()}, "level":"ERROR", "module":"logMonitor", "facility":"ui", "msg":"Failed to fetch log: server unreachable" }`);
|
|
cleanupLog(atBottom);
|
|
}
|
|
}
|
|
async function initLogMonitor() {
|
|
const el2 = document.getElementsByTagName("footer")[0];
|
|
if (!el2) return;
|
|
const t0 = performance.now();
|
|
el2.classList.add("log-monitor");
|
|
const uiDisabled = Array.isArray(window.opts.ui_disabled) ? window.opts.ui_disabled : [];
|
|
if (uiDisabled.includes("logs")) return;
|
|
el2.innerHTML = `
|
|
<table id="logMonitor" style="width: 100%;">
|
|
<thead style="display: block; text-align: left; border-bottom: solid 1px var(--button-primary-border-color)">
|
|
<tr>
|
|
<th style="width: 144px">Time</th>
|
|
<th>Level</th>
|
|
<th style="width: 0"></th>
|
|
<th style="width: 154px">Module</th>
|
|
<th>Message</th>
|
|
<th style="position: absolute; right: 7em">Warnings <span id="logWarnings">0</span></th>
|
|
<th style="position: absolute; right: 1em">Errors <span id="logErrors">0</span></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="logMonitorData" style="white-space: nowrap; height: 10vh; width: 100vw; display: block; overflow-x: hidden; overflow-y: scroll; color: var(--neutral-400)">
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
el2.style.display = "none";
|
|
authFetch(`${window.api}/start?agent=${encodeURI(navigator.userAgent)}`);
|
|
logMonitor();
|
|
const t1 = performance.now();
|
|
log("initLogMonitor", { show: window.opts.logmonitor_show, time: Math.round(t1 - t0) });
|
|
timer("initLogMonitor", t1 - t0);
|
|
}
|
|
|
|
// ui/settings.ts
|
|
var settingsInitialized = false;
|
|
var opts_metadata = {};
|
|
var opts_tabs = {};
|
|
function getSettingsTabs() {
|
|
let nodes = gradioApp().querySelectorAll("#tab_settings .tabitem");
|
|
if (!nodes || nodes.length === 0) nodes = gradioApp().querySelectorAll(".tab-content .tabitem");
|
|
return nodes;
|
|
}
|
|
var monitoredOpts = [
|
|
{ sd_model_checkpoint: null },
|
|
{ sd_backend: () => gradioApp().getElementById("refresh_sd_model_checkpoint")?.click() }
|
|
];
|
|
function monitorOption(option, callback) {
|
|
monitoredOpts.push({ [option]: callback });
|
|
}
|
|
var AppyOpts = [
|
|
// monitored opts
|
|
{ compact_view: (val, old) => toggleCompact(val, old) },
|
|
{ gradio_theme: (val, old) => setTheme(val, old) },
|
|
{ font_size: (val, old) => setFontSize(val, old) }
|
|
];
|
|
async function updateOpts(json_string) {
|
|
const t0 = performance.now();
|
|
const settings_data = JSON.parse(json_string);
|
|
const new_opts = settings_data.values;
|
|
opts_metadata = settings_data.metadata;
|
|
const t1 = performance.now();
|
|
for (const op of monitoredOpts) {
|
|
const [key, callback] = Object.entries(op)[0];
|
|
if (Object.hasOwn(opts, key) && opts[key] !== new_opts[key]) {
|
|
log("updateOpt", key, opts[key], new_opts[key]);
|
|
if (callback) callback(new_opts[key], opts[key]);
|
|
}
|
|
}
|
|
for (const op of AppyOpts) {
|
|
const [key, callback] = Object.entries(op)[0];
|
|
if (callback) {
|
|
const t3 = performance.now();
|
|
callback(new_opts[key], opts[key]);
|
|
const t4 = performance.now();
|
|
if (t4 - t3 > 100) debug("AppyOptSlow", key, `time=${Math.round(t4 - t3)}`);
|
|
}
|
|
}
|
|
window.opts = new_opts;
|
|
Object.entries(opts_metadata).forEach(([opt, meta]) => {
|
|
if (!opts_tabs[meta.tab_name]) opts_tabs[meta.tab_name] = {};
|
|
if (!opts_tabs[meta.tab_name].unsaved_keys) opts_tabs[meta.tab_name].unsaved_keys = /* @__PURE__ */ new Set();
|
|
if (!opts_tabs[meta.tab_name].saved_keys) opts_tabs[meta.tab_name].saved_keys = /* @__PURE__ */ new Set();
|
|
if (!meta.is_stored) opts_tabs[meta.tab_name].unsaved_keys.add(opt);
|
|
else opts_tabs[meta.tab_name].saved_keys.add(opt);
|
|
});
|
|
const t2 = performance.now();
|
|
log("updateOpts", `settings=${Object.keys(new_opts).length} callbacks=${Math.round(t2 - t1)} apply=${Math.round(t1 - t0)}`);
|
|
timer("updateOpts", t2 - t0);
|
|
}
|
|
function showAllSettings() {
|
|
getSettingsTabs().forEach((elem) => {
|
|
if (elem.id === "settings_tab_licenses" || elem.id === "settings_show_all_pages") return;
|
|
elem.style.display = "block";
|
|
});
|
|
}
|
|
function markIfModified(setting_name, value) {
|
|
if (!opts_metadata[setting_name]) return;
|
|
const elem = gradioApp().getElementById(`modification_indicator_${setting_name}`);
|
|
if (!elem) return;
|
|
const previous_value = JSON.stringify(opts[setting_name]);
|
|
const current_value = JSON.stringify(value);
|
|
const changed_value = previous_value !== current_value;
|
|
if (changed_value) elem.title = `click to revert to previous value: ${previous_value}`;
|
|
const { is_stored } = opts_metadata[setting_name];
|
|
if (is_stored) elem.title = "custom value";
|
|
elem.disabled = !changed_value && !is_stored;
|
|
elem.classList.toggle("changed", changed_value);
|
|
elem.classList.toggle("saved", is_stored);
|
|
const { tab_name } = opts_metadata[setting_name];
|
|
if (!opts_tabs[tab_name].changed) opts_tabs[tab_name].changed = /* @__PURE__ */ new Set();
|
|
const changed_items = opts_tabs[tab_name].changed;
|
|
if (changed_value) changed_items.add(setting_name);
|
|
else changed_items.delete(setting_name);
|
|
const unsaved = opts_tabs[tab_name].unsaved_keys;
|
|
const saved = opts_tabs[tab_name].saved_keys;
|
|
const tab_nav_indicator = gradioApp().getElementById(`modification_indicator_${tab_name}`);
|
|
tab_nav_indicator.disabled = changed_items.size === 0 && unsaved.size === 0;
|
|
tab_nav_indicator.title = "";
|
|
tab_nav_indicator.classList.toggle("changed", changed_items.size > 0);
|
|
tab_nav_indicator.classList.toggle("saved", saved.size > 0);
|
|
if (changed_items.size > 0) tab_nav_indicator.title += `click to reset ${changed_items.size} unapplied changes in this tab
|
|
`;
|
|
if (saved.size > 0) tab_nav_indicator.title += `${saved.size} custom values
|
|
${unsaved.size} default values`;
|
|
}
|
|
window.markIfModified = markIfModified;
|
|
function updateAllOpts() {
|
|
if (Object.keys(opts).length !== 0) return false;
|
|
const json_elem = gradioApp().getElementById("settings_json");
|
|
log("updateAllOpts", !!json_elem);
|
|
if (!json_elem) return false;
|
|
json_elem.parentElement.style.display = "none";
|
|
const textarea = json_elem.querySelector("textarea");
|
|
const jsdata = textarea.value;
|
|
updateOpts(jsdata);
|
|
return true;
|
|
}
|
|
async function onAfterUiUpdateCallback() {
|
|
if (!updateAllOpts()) return;
|
|
const json_elem = gradioApp().getElementById("settings_json");
|
|
const textarea = json_elem.querySelector("textarea");
|
|
executeCallbacks(optionsChangedCallbacks);
|
|
registerDragDrop();
|
|
Object.defineProperty(textarea, "value", {
|
|
set(newValue) {
|
|
const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
|
|
const oldValue = valueProp.get.call(textarea);
|
|
valueProp.set.call(textarea, newValue);
|
|
if (oldValue !== newValue) updateOpts(textarea.value);
|
|
executeCallbacks(optionsChangedCallbacks);
|
|
},
|
|
get() {
|
|
const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
|
|
return valueProp.get.call(textarea);
|
|
}
|
|
});
|
|
const settingsSearch = gradioApp().querySelectorAll("#settings_search > label > textarea")[0];
|
|
let settingsTimer;
|
|
let settingSearchValue = "";
|
|
function doSettingsSearch() {
|
|
if (settingSearchValue === settingsSearch.value.trim().toLowerCase()) return;
|
|
showAllSettings();
|
|
const value = settingsSearch.value.trim().toLowerCase();
|
|
log("doSettingsSearch", value);
|
|
settingSearchValue = value;
|
|
getSettingsTabs().forEach((section) => {
|
|
section.querySelectorAll(".dirtyable").forEach((setting) => {
|
|
const visible = setting.innerText.toLowerCase().includes(value) || setting.id.toLowerCase().includes(value);
|
|
const parent2 = setting.closest(".settings_section");
|
|
if (!visible) parent2.style.display = "none";
|
|
else parent2.style.removeProperty("display");
|
|
});
|
|
});
|
|
}
|
|
settingsSearch.oninput = (e) => {
|
|
if (settingsTimer) clearTimeout(settingsTimer);
|
|
settingsTimer = setTimeout(doSettingsSearch, 250);
|
|
};
|
|
settingsSearch.onkeypress = (e) => {
|
|
if (e.key === "Enter") {
|
|
if (settingsTimer) clearTimeout(settingsTimer);
|
|
doSettingsSearch();
|
|
}
|
|
};
|
|
}
|
|
onAfterUiUpdate(onAfterUiUpdateCallback);
|
|
async function onOptionsChangedCallback() {
|
|
const setting_elems = gradioApp().querySelectorAll('#settings [id^="setting_"]');
|
|
setting_elems.forEach((elem) => {
|
|
const setting_name = elem.id.replace("setting_", "");
|
|
markIfModified(setting_name, opts[setting_name]);
|
|
});
|
|
}
|
|
onOptionsChanged(onOptionsChangedCallback);
|
|
async function initModels() {
|
|
const warn = () => `
|
|
<p style='color: white'>No models available</p>
|
|
- Select a model from reference list to download or<br>
|
|
- Set model path to a folder containing your models<br>
|
|
Current model path: ${opts.ckpt_dir}<br>
|
|
`;
|
|
const el2 = gradioApp().getElementById("main_info");
|
|
const en = gradioApp().getElementById("txt2img_extra_networks");
|
|
if (!el2 || !en) return;
|
|
const req = await authFetch(`${window.api}/sd-models`);
|
|
const res = req.ok ? await req.json() : [];
|
|
log("initModels", res.length);
|
|
const ready = () => `
|
|
<p style='color: white'>Ready</p>
|
|
${res.length} models available<br>
|
|
`;
|
|
el2.innerHTML = res.length > 0 ? ready() : warn();
|
|
el2.style.display = "block";
|
|
setTimeout(() => {
|
|
el2.style.display = "none";
|
|
}, res.length === 0 ? 3e4 : 1500);
|
|
if (res.length === 0) {
|
|
if (en.classList.contains("hide")) gradioApp().getElementById("txt2img_extra_networks_btn").click();
|
|
const repeat = setInterval(() => {
|
|
const buttons = Array.from(gradioApp().querySelectorAll("#txt2img_model_subdirs > button")) || [];
|
|
const reference = buttons.find((b) => b.innerText === "Reference" || b.innerText === "Distilled" || b.innerText === "Community" || b.innerText === "Quantized" || b.innerText === "Cloud");
|
|
if (reference) {
|
|
clearInterval(repeat);
|
|
reference.click();
|
|
log("enReferenceSelect");
|
|
}
|
|
}, 100);
|
|
}
|
|
}
|
|
async function initSettings() {
|
|
if (settingsInitialized) return;
|
|
const t0 = performance.now();
|
|
settingsInitialized = true;
|
|
const tabNavElements = gradioApp().querySelector("#settings > .tab-nav");
|
|
if (!tabNavElements) {
|
|
error("initSettings", "No tab nav elements found");
|
|
return;
|
|
}
|
|
const tabNavButtons = gradioApp().querySelectorAll("#settings > .tab-nav > button");
|
|
const tabElements = gradioApp().querySelectorAll("#settings > div:not(.tab-nav)");
|
|
const observer = new MutationObserver((mutations) => {
|
|
const showAllPages = gradioApp().getElementById("settings_show_all_pages");
|
|
if (showAllPages.style.display === "none") return;
|
|
const mutation = (mut) => mut.type === "attributes" && mut.attributeName === "style";
|
|
if (mutations.some(mutation)) showAllSettings();
|
|
});
|
|
const tabContentWrapper = document.createElement("div");
|
|
tabContentWrapper.className = "tab-content";
|
|
tabNavElements.parentElement.insertBefore(tabContentWrapper, tabNavElements.nextSibling);
|
|
tabElements.forEach((elem, index) => {
|
|
const tabName = elem.id.replace("settings_section_tab_", "");
|
|
const indicator = gradioApp().getElementById(`modification_indicator_${tabName}`);
|
|
if (indicator) {
|
|
tabNavElements.insertBefore(document.createElement("br"), tabNavButtons[index]);
|
|
tabNavElements.insertBefore(indicator, tabNavButtons[index]);
|
|
}
|
|
tabContentWrapper.appendChild(elem);
|
|
observer.observe(elem, { attributes: true, attributeFilter: ["style"] });
|
|
});
|
|
const t1 = performance.now();
|
|
log("initSettings", Math.round(t1 - t0));
|
|
timer("initSettings", t1 - t0);
|
|
}
|
|
|
|
// ui/monitor.ts
|
|
var monitorActive = false;
|
|
var ConnectionMonitorState = class _ConnectionMonitorState {
|
|
static ws;
|
|
static url = "";
|
|
static delay = 1e3;
|
|
static element;
|
|
static version = "";
|
|
static commit = "";
|
|
static branch = "";
|
|
static model = "";
|
|
static startup = /* @__PURE__ */ new Date();
|
|
static online = false;
|
|
static ts = /* @__PURE__ */ new Date();
|
|
static getModel() {
|
|
const cp = window.opts?.sd_model_checkpoint || "";
|
|
return cp ? this.trimModelName(cp) : "unknown model";
|
|
}
|
|
static trimModelName(name) {
|
|
return name.replace(/\s*\[.*\]\s*$/, "").split(/[\\/]/).pop().trim() || "unknown model";
|
|
}
|
|
static setData({ online, data }) {
|
|
if (online !== this.online) {
|
|
this.online = online;
|
|
this.ts = /* @__PURE__ */ new Date();
|
|
debug("monitorState", { online: _ConnectionMonitorState.online, ts: _ConnectionMonitorState.ts });
|
|
}
|
|
if (data?.updated) this.version = data.updated;
|
|
if (data?.commit) this.commit = data.commit;
|
|
if (data?.branch) this.branch = data.branch;
|
|
if (data?.model) this.model = this.trimModelName(data.model);
|
|
}
|
|
static toHTML() {
|
|
if (!this.model) this.model = this.getModel();
|
|
return `
|
|
Version: <b>${this.version}</b><br>
|
|
Commit: <b>${this.commit}</b><br>
|
|
Branch: <b>${this.branch}</b><br>
|
|
Status: ${this.online ? '<b style="color:lime">online</b>' : '<b style="color:darkred">offline</b>'}<br>
|
|
Model: <b>${this.model}</b><br>
|
|
Since: ${this.startup.toLocaleString()}<br>
|
|
`;
|
|
}
|
|
static updateState() {
|
|
if (!this.element) {
|
|
const el2 = document.getElementById("logo_nav");
|
|
if (el2) this.element = el2;
|
|
else return;
|
|
}
|
|
this.element.dataset.hint = this.toHTML();
|
|
this.element.style.backgroundColor = this.online ? "var(--sd-main-accent-color)" : "var(--color-error)";
|
|
}
|
|
};
|
|
async function updateIndicator(online, data = {}, msg) {
|
|
ConnectionMonitorState.setData({ online, data });
|
|
ConnectionMonitorState.updateState();
|
|
if (msg) log("monitorConnection:", { online, data, msg });
|
|
}
|
|
async function wsMonitorLoop() {
|
|
const delayed = Date.now() - ConnectionMonitorState.ts.getTime();
|
|
if (delayed > 60 * 60 && ConnectionMonitorState.delay < 10 && !ConnectionMonitorState.online) ConnectionMonitorState.delay = 1e4;
|
|
else if (delayed > 5 * 60 && ConnectionMonitorState.delay < 5 && !ConnectionMonitorState.online) ConnectionMonitorState.delay = 5e3;
|
|
else ConnectionMonitorState.delay = 2e3;
|
|
try {
|
|
ConnectionMonitorState.ws = new WebSocket(`${ConnectionMonitorState.url}/queue/join`);
|
|
ConnectionMonitorState.ws.onopen = () => {
|
|
};
|
|
ConnectionMonitorState.ws.onmessage = () => updateIndicator(true);
|
|
ConnectionMonitorState.ws.onclose = () => setTimeout(wsMonitorLoop, ConnectionMonitorState.delay);
|
|
ConnectionMonitorState.ws.onerror = (e) => updateIndicator(false, {}, String(e.message || "unknown error"));
|
|
} catch (e) {
|
|
updateIndicator(false, {}, String(e.message || e));
|
|
setTimeout(monitorConnection, ConnectionMonitorState.delay);
|
|
}
|
|
}
|
|
async function monitorConnection() {
|
|
if (!monitorActive) {
|
|
monitorActive = true;
|
|
monitorOption("sd_model_checkpoint", (newVal) => {
|
|
ConnectionMonitorState.model = newVal;
|
|
ConnectionMonitorState.updateState();
|
|
});
|
|
}
|
|
ConnectionMonitorState.startup = /* @__PURE__ */ new Date();
|
|
let data = {};
|
|
try {
|
|
const res = await authFetch(`${window.api}/version`);
|
|
if (!res) throw new Error("No response");
|
|
data = await res.json();
|
|
log("monitorConnection:", { data });
|
|
ConnectionMonitorState.startup = /* @__PURE__ */ new Date();
|
|
ConnectionMonitorState.url = res.url.split("/sdapi")[0].replace("https:", "wss:").replace("http:", "ws:");
|
|
updateIndicator(true, data);
|
|
wsMonitorLoop();
|
|
} catch {
|
|
updateIndicator(false, data);
|
|
setTimeout(monitorConnection, ConnectionMonitorState.delay);
|
|
}
|
|
}
|
|
|
|
// ui/promptChecker.ts
|
|
function checkBrackets(textArea, counterElt) {
|
|
const counts = {};
|
|
const errors = [];
|
|
function checkPair(open, close, kind) {
|
|
if (counts[open] !== counts[close]) errors.push(`${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`);
|
|
}
|
|
(textArea.value.match(/[(){}[\]]/g) || []).forEach((bracket) => {
|
|
counts[bracket] = (counts[bracket] || 0) + 1;
|
|
});
|
|
checkPair("(", ")", "round brackets");
|
|
checkPair("[", "]", "square brackets");
|
|
checkPair("{", "}", "curly brackets");
|
|
counterElt.title = errors.join("\n");
|
|
counterElt.classList.toggle("error", errors.length !== 0);
|
|
}
|
|
function setupBracketChecking(idPrompt, idCounter) {
|
|
const textarea = gradioApp().querySelector(`#${idPrompt} > label > textarea`);
|
|
const counter = gradioApp().getElementById(idCounter);
|
|
if (!(textarea instanceof HTMLTextAreaElement) || !counter) return;
|
|
textarea.addEventListener("input", () => checkBrackets(textarea, counter));
|
|
}
|
|
async function initPromptChecker() {
|
|
const t0 = performance.now();
|
|
setupBracketChecking("txt2img_prompt", "txt2img_token_counter");
|
|
setupBracketChecking("txt2img_neg_prompt", "txt2img_negative_token_counter");
|
|
setupBracketChecking("img2img_prompt", "img2img_token_counter");
|
|
setupBracketChecking("img2img_neg_prompt", "img2img_negative_token_counter");
|
|
setupBracketChecking("control_prompt", "control_token_counter");
|
|
setupBracketChecking("control_neg_prompt", "control_negative_token_counter");
|
|
setupBracketChecking("video_prompt", "video_token_counter");
|
|
setupBracketChecking("video_neg_prompt", "video_negative_token_counter");
|
|
const t1 = performance.now();
|
|
log("initPromptChecker", Math.round(t1 - t0));
|
|
timer("initPromptChecker", t1 - t0);
|
|
}
|
|
|
|
// ui/js/sha256.ts
|
|
var digestLength = 32;
|
|
var blockSize = 64;
|
|
var K = new Uint32Array([
|
|
1116352408,
|
|
1899447441,
|
|
3049323471,
|
|
3921009573,
|
|
961987163,
|
|
1508970993,
|
|
2453635748,
|
|
2870763221,
|
|
3624381080,
|
|
310598401,
|
|
607225278,
|
|
1426881987,
|
|
1925078388,
|
|
2162078206,
|
|
2614888103,
|
|
3248222580,
|
|
3835390401,
|
|
4022224774,
|
|
264347078,
|
|
604807628,
|
|
770255983,
|
|
1249150122,
|
|
1555081692,
|
|
1996064986,
|
|
2554220882,
|
|
2821834349,
|
|
2952996808,
|
|
3210313671,
|
|
3336571891,
|
|
3584528711,
|
|
113926993,
|
|
338241895,
|
|
666307205,
|
|
773529912,
|
|
1294757372,
|
|
1396182291,
|
|
1695183700,
|
|
1986661051,
|
|
2177026350,
|
|
2456956037,
|
|
2730485921,
|
|
2820302411,
|
|
3259730800,
|
|
3345764771,
|
|
3516065817,
|
|
3600352804,
|
|
4094571909,
|
|
275423344,
|
|
430227734,
|
|
506948616,
|
|
659060556,
|
|
883997877,
|
|
958139571,
|
|
1322822218,
|
|
1537002063,
|
|
1747873779,
|
|
1955562222,
|
|
2024104815,
|
|
2227730452,
|
|
2361852424,
|
|
2428436474,
|
|
2756734187,
|
|
3204031479,
|
|
3329325298
|
|
]);
|
|
function hashBlocks(w, v, p, pos, len) {
|
|
let a;
|
|
let b;
|
|
let c;
|
|
let d;
|
|
let e;
|
|
let f;
|
|
let g;
|
|
let h;
|
|
let u;
|
|
let i;
|
|
let j;
|
|
let t1;
|
|
let t2;
|
|
while (len >= 64) {
|
|
a = v[0];
|
|
b = v[1];
|
|
c = v[2];
|
|
d = v[3];
|
|
e = v[4];
|
|
f = v[5];
|
|
g = v[6];
|
|
h = v[7];
|
|
for (i = 0; i < 16; i++) {
|
|
j = pos + i * 4;
|
|
w[i] = (p[j] & 255) << 24 | (p[j + 1] & 255) << 16 | (p[j + 2] & 255) << 8 | p[j + 3] & 255;
|
|
}
|
|
for (i = 16; i < 64; i++) {
|
|
u = w[i - 2];
|
|
t1 = (u >>> 17 | u << 32 - 17) ^ (u >>> 19 | u << 32 - 19) ^ u >>> 10;
|
|
u = w[i - 15];
|
|
t2 = (u >>> 7 | u << 32 - 7) ^ (u >>> 18 | u << 32 - 18) ^ u >>> 3;
|
|
w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0);
|
|
}
|
|
for (i = 0; i < 64; i++) {
|
|
t1 = (((e >>> 6 | e << 32 - 6) ^ (e >>> 11 | e << 32 - 11) ^ (e >>> 25 | e << 32 - 25)) + (e & f ^ ~e & g) | 0) + (h + (K[i] + w[i] | 0) | 0) | 0;
|
|
t2 = ((a >>> 2 | a << 32 - 2) ^ (a >>> 13 | a << 32 - 13) ^ (a >>> 22 | a << 32 - 22)) + (a & b ^ a & c ^ b & c) | 0;
|
|
h = g;
|
|
g = f;
|
|
f = e;
|
|
e = d + t1 | 0;
|
|
d = c;
|
|
c = b;
|
|
b = a;
|
|
a = t1 + t2 | 0;
|
|
}
|
|
v[0] += a;
|
|
v[1] += b;
|
|
v[2] += c;
|
|
v[3] += d;
|
|
v[4] += e;
|
|
v[5] += f;
|
|
v[6] += g;
|
|
v[7] += h;
|
|
pos += 64;
|
|
len -= 64;
|
|
}
|
|
return pos;
|
|
}
|
|
var Hash = (
|
|
/** @class */
|
|
(function() {
|
|
function Hash2() {
|
|
this.digestLength = digestLength;
|
|
this.blockSize = blockSize;
|
|
this.state = new Int32Array(8);
|
|
this.temp = new Int32Array(64);
|
|
this.buffer = new Uint8Array(128);
|
|
this.bufferLength = 0;
|
|
this.bytesHashed = 0;
|
|
this.finished = false;
|
|
this.reset();
|
|
}
|
|
Hash2.prototype.reset = function() {
|
|
this.state[0] = 1779033703;
|
|
this.state[1] = 3144134277;
|
|
this.state[2] = 1013904242;
|
|
this.state[3] = 2773480762;
|
|
this.state[4] = 1359893119;
|
|
this.state[5] = 2600822924;
|
|
this.state[6] = 528734635;
|
|
this.state[7] = 1541459225;
|
|
this.bufferLength = 0;
|
|
this.bytesHashed = 0;
|
|
this.finished = false;
|
|
return this;
|
|
};
|
|
Hash2.prototype.clean = function() {
|
|
for (var i = 0; i < this.buffer.length; i++) {
|
|
this.buffer[i] = 0;
|
|
}
|
|
for (var i = 0; i < this.temp.length; i++) {
|
|
this.temp[i] = 0;
|
|
}
|
|
this.reset();
|
|
};
|
|
Hash2.prototype.update = function(data, dataLength) {
|
|
if (dataLength === void 0) {
|
|
dataLength = data.length;
|
|
}
|
|
if (this.finished) {
|
|
throw new Error("SHA256: can't update because hash was finished.");
|
|
}
|
|
let dataPos = 0;
|
|
this.bytesHashed += dataLength;
|
|
if (this.bufferLength > 0) {
|
|
while (this.bufferLength < 64 && dataLength > 0) {
|
|
this.buffer[this.bufferLength++] = data[dataPos++];
|
|
dataLength--;
|
|
}
|
|
if (this.bufferLength === 64) {
|
|
hashBlocks(this.temp, this.state, this.buffer, 0, 64);
|
|
this.bufferLength = 0;
|
|
}
|
|
}
|
|
if (dataLength >= 64) {
|
|
dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);
|
|
dataLength %= 64;
|
|
}
|
|
while (dataLength > 0) {
|
|
this.buffer[this.bufferLength++] = data[dataPos++];
|
|
dataLength--;
|
|
}
|
|
return this;
|
|
};
|
|
Hash2.prototype.finish = function(out) {
|
|
if (!this.finished) {
|
|
const bytesHashed = this.bytesHashed;
|
|
const left = this.bufferLength;
|
|
const bitLenHi = bytesHashed / 536870912 | 0;
|
|
const bitLenLo = bytesHashed << 3;
|
|
const padLength = bytesHashed % 64 < 56 ? 64 : 128;
|
|
this.buffer[left] = 128;
|
|
for (let i = left + 1; i < padLength - 8; i++) {
|
|
this.buffer[i] = 0;
|
|
}
|
|
this.buffer[padLength - 8] = bitLenHi >>> 24 & 255;
|
|
this.buffer[padLength - 7] = bitLenHi >>> 16 & 255;
|
|
this.buffer[padLength - 6] = bitLenHi >>> 8 & 255;
|
|
this.buffer[padLength - 5] = bitLenHi >>> 0 & 255;
|
|
this.buffer[padLength - 4] = bitLenLo >>> 24 & 255;
|
|
this.buffer[padLength - 3] = bitLenLo >>> 16 & 255;
|
|
this.buffer[padLength - 2] = bitLenLo >>> 8 & 255;
|
|
this.buffer[padLength - 1] = bitLenLo >>> 0 & 255;
|
|
hashBlocks(this.temp, this.state, this.buffer, 0, padLength);
|
|
this.finished = true;
|
|
}
|
|
for (let i = 0; i < 8; i++) {
|
|
out[i * 4 + 0] = this.state[i] >>> 24 & 255;
|
|
out[i * 4 + 1] = this.state[i] >>> 16 & 255;
|
|
out[i * 4 + 2] = this.state[i] >>> 8 & 255;
|
|
out[i * 4 + 3] = this.state[i] >>> 0 & 255;
|
|
}
|
|
return this;
|
|
};
|
|
Hash2.prototype.digest = function() {
|
|
const out = new Uint8Array(this.digestLength);
|
|
this.finish(out);
|
|
return out;
|
|
};
|
|
Hash2.prototype._saveState = function(out) {
|
|
for (let i = 0; i < this.state.length; i++) {
|
|
out[i] = this.state[i];
|
|
}
|
|
};
|
|
Hash2.prototype._restoreState = function(from, bytesHashed) {
|
|
for (let i = 0; i < this.state.length; i++) {
|
|
this.state[i] = from[i];
|
|
}
|
|
this.bytesHashed = bytesHashed;
|
|
this.finished = false;
|
|
this.bufferLength = 0;
|
|
};
|
|
return Hash2;
|
|
})()
|
|
);
|
|
window.Hash = Hash;
|
|
var HMAC = (
|
|
/** @class */
|
|
(function() {
|
|
function HMAC2(key) {
|
|
this.inner = new Hash();
|
|
this.outer = new Hash();
|
|
this.blockSize = this.inner.blockSize;
|
|
this.digestLength = this.inner.digestLength;
|
|
const pad = new Uint8Array(this.blockSize);
|
|
if (key.length > this.blockSize) {
|
|
new Hash().update(key).finish(pad).clean();
|
|
} else {
|
|
for (let i = 0; i < key.length; i++) {
|
|
pad[i] = key[i];
|
|
}
|
|
}
|
|
for (let i = 0; i < pad.length; i++) {
|
|
pad[i] ^= 54;
|
|
}
|
|
this.inner.update(pad);
|
|
for (let i = 0; i < pad.length; i++) {
|
|
pad[i] ^= 54 ^ 92;
|
|
}
|
|
this.outer.update(pad);
|
|
this.istate = new Uint32Array(8);
|
|
this.ostate = new Uint32Array(8);
|
|
this.inner._saveState(this.istate);
|
|
this.outer._saveState(this.ostate);
|
|
for (let i = 0; i < pad.length; i++) {
|
|
pad[i] = 0;
|
|
}
|
|
}
|
|
HMAC2.prototype.reset = function() {
|
|
this.inner._restoreState(this.istate, this.inner.blockSize);
|
|
this.outer._restoreState(this.ostate, this.outer.blockSize);
|
|
return this;
|
|
};
|
|
HMAC2.prototype.clean = function() {
|
|
for (let i = 0; i < this.istate.length; i++) {
|
|
this.ostate[i] = this.istate[i] = 0;
|
|
}
|
|
this.inner.clean();
|
|
this.outer.clean();
|
|
};
|
|
HMAC2.prototype.update = function(data) {
|
|
this.inner.update(data);
|
|
return this;
|
|
};
|
|
HMAC2.prototype.finish = function(out) {
|
|
if (this.outer.finished) {
|
|
this.outer.finish(out);
|
|
} else {
|
|
this.inner.finish(out);
|
|
this.outer.update(out, this.digestLength).finish(out);
|
|
}
|
|
return this;
|
|
};
|
|
HMAC2.prototype.digest = function() {
|
|
const out = new Uint8Array(this.digestLength);
|
|
this.finish(out);
|
|
return out;
|
|
};
|
|
return HMAC2;
|
|
})()
|
|
);
|
|
window.HMAC = HMAC;
|
|
function hash2(data) {
|
|
const h = new Hash().update(data);
|
|
const digest = h.digest();
|
|
h.clean();
|
|
return digest;
|
|
}
|
|
window.hash = hash2;
|
|
function hmac(key, data) {
|
|
const h = new HMAC(key).update(data);
|
|
const digest = h.digest();
|
|
h.clean();
|
|
return digest;
|
|
}
|
|
window.hmac = hmac;
|
|
function fillBuffer(buffer, hmac2, info, counter) {
|
|
const num = counter[0];
|
|
if (num === 0) {
|
|
throw new Error("hkdf: cannot expand more");
|
|
}
|
|
hmac2.reset();
|
|
if (num > 1) {
|
|
hmac2.update(buffer);
|
|
}
|
|
if (info) {
|
|
hmac2.update(info);
|
|
}
|
|
hmac2.update(counter);
|
|
hmac2.finish(buffer);
|
|
counter[0]++;
|
|
}
|
|
var hkdfSalt = new Uint8Array(digestLength);
|
|
function hkdf(key, salt, info, length) {
|
|
if (salt === void 0) {
|
|
salt = hkdfSalt;
|
|
}
|
|
if (length === void 0) {
|
|
length = 32;
|
|
}
|
|
const counter = new Uint8Array([1]);
|
|
const okm = hmac(salt, key);
|
|
const hmac_ = new HMAC(okm);
|
|
const buffer = new Uint8Array(hmac_.digestLength);
|
|
let bufpos = buffer.length;
|
|
const out = new Uint8Array(length);
|
|
for (let i = 0; i < length; i++) {
|
|
if (bufpos === buffer.length) {
|
|
fillBuffer(buffer, hmac_, info, counter);
|
|
bufpos = 0;
|
|
}
|
|
out[i] = buffer[bufpos++];
|
|
}
|
|
hmac_.clean();
|
|
buffer.fill(0);
|
|
counter.fill(0);
|
|
return out;
|
|
}
|
|
window.hkdf = hkdf;
|
|
function pbkdf2(password, salt, iterations, dkLen) {
|
|
const prf = new HMAC(password);
|
|
const len = prf.digestLength;
|
|
const ctr = new Uint8Array(4);
|
|
const t = new Uint8Array(len);
|
|
const u = new Uint8Array(len);
|
|
const dk = new Uint8Array(dkLen);
|
|
for (var i = 0; i * len < dkLen; i++) {
|
|
const c = i + 1;
|
|
ctr[0] = c >>> 24 & 255;
|
|
ctr[1] = c >>> 16 & 255;
|
|
ctr[2] = c >>> 8 & 255;
|
|
ctr[3] = c >>> 0 & 255;
|
|
prf.reset();
|
|
prf.update(salt);
|
|
prf.update(ctr);
|
|
prf.finish(u);
|
|
for (var j = 0; j < len; j++) {
|
|
t[j] = u[j];
|
|
}
|
|
for (var j = 2; j <= iterations; j++) {
|
|
prf.reset();
|
|
prf.update(u).finish(u);
|
|
for (let k = 0; k < len; k++) {
|
|
t[k] ^= u[k];
|
|
}
|
|
}
|
|
for (var j = 0; j < len && i * len + j < dkLen; j++) {
|
|
dk[i * len + j] = t[j];
|
|
}
|
|
}
|
|
for (var i = 0; i < len; i++) {
|
|
t[i] = u[i] = 0;
|
|
}
|
|
for (var i = 0; i < 4; i++) {
|
|
ctr[i] = 0;
|
|
}
|
|
prf.clean();
|
|
return dk;
|
|
}
|
|
window.pbkdf2 = pbkdf2;
|
|
|
|
// ui/gallery.ts
|
|
var ws;
|
|
var url;
|
|
var currentSort = "none";
|
|
var currentName = "";
|
|
var currentImage = null;
|
|
var currentTitle = "";
|
|
var currentGalleryFolder = null;
|
|
var outstanding = 0;
|
|
var gallerySelection = { files: [], index: -1 };
|
|
var maintenanceController = new AbortController();
|
|
var maxFetchRequests = 32;
|
|
var fragmentSize = 100;
|
|
var minCleanupCount = 1e3;
|
|
var minCleanupTime = 1e3 * 60 * 60;
|
|
var folderStylesheet = new CSSStyleSheet();
|
|
var fileStylesheet = new CSSStyleSheet();
|
|
var iconStopwatch = String.fromCodePoint(9201);
|
|
var separatorStates = /* @__PURE__ */ new Map();
|
|
var el = {
|
|
folders: void 0,
|
|
files: void 0,
|
|
search: void 0,
|
|
status: void 0,
|
|
btnSend: void 0,
|
|
overlay: void 0,
|
|
size: void 0
|
|
};
|
|
var cleanupTimers = {};
|
|
var maintenanceTimers = {};
|
|
var fetchQueue = [];
|
|
var SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "png", "webp", "tiff", "jp2", "jxl", "gif", "mp4", "mkv", "avi", "mjpeg", "mpg", "avr"];
|
|
var gallerySorter = {
|
|
nameA: { name: "Name Ascending", func: (a, b) => a.name.localeCompare(b.name) },
|
|
nameD: { name: "Name Descending", func: (b, a) => a.name.localeCompare(b.name) },
|
|
sizeD: { name: "Size Ascending", func: (a, b) => a.size - b.size },
|
|
sizeA: { name: "Size Descending", func: (b, a) => a.size - b.size },
|
|
resD: { name: "Resolution Ascending", func: (a, b) => a.width * a.height - b.width * b.height },
|
|
resA: { name: "Resolution Descending", func: (b, a) => a.width * a.height - b.width * b.height },
|
|
modD: { name: "Modified Ascending", func: (a, b) => a.mtime - b.mtime },
|
|
modA: { name: "Modified Descending", func: (b, a) => a.mtime - b.mtime },
|
|
none: { name: "None", func: void 0 }
|
|
};
|
|
var sortMode = gallerySorter.none;
|
|
async function getHash(str) {
|
|
let hex = "";
|
|
const strBuf = new TextEncoder().encode(str);
|
|
let hashBuf;
|
|
if (crypto?.subtle?.digest) {
|
|
hashBuf = await crypto.subtle.digest("SHA-256", strBuf);
|
|
} else {
|
|
const hashResult = hash(strBuf);
|
|
hashBuf = hashResult.buffer;
|
|
}
|
|
const view = new DataView(hashBuf);
|
|
for (let i = 0; i < hashBuf.byteLength; i += 4) hex += `00000000${view.getUint32(i).toString(16)}`.slice(-8);
|
|
return hex;
|
|
}
|
|
function getVisibleGalleryFiles() {
|
|
if (!el.files) return [];
|
|
return Array.from(el.files.children).filter((node) => node.name && node.offsetParent);
|
|
}
|
|
function updateGallerySelectionClasses(files = gallerySelection.files, index = gallerySelection.index) {
|
|
files.forEach((file, i) => {
|
|
file.classList.toggle("gallery-file-selected", i === index);
|
|
});
|
|
}
|
|
function refreshGallerySelection() {
|
|
updateGallerySelectionClasses(gallerySelection.files, -1);
|
|
const files = getVisibleGalleryFiles();
|
|
const index = files.findIndex((file) => file.src === currentImage);
|
|
gallerySelection = { files, index };
|
|
updateGallerySelectionClasses(files, index);
|
|
}
|
|
function resetGallerySelection() {
|
|
updateGallerySelectionClasses(gallerySelection.files, -1);
|
|
gallerySelection = { files: [], index: -1 };
|
|
currentImage = null;
|
|
currentName = "";
|
|
currentTitle = "";
|
|
}
|
|
function applyGallerySelection(index, { send = true } = {}) {
|
|
if (!gallerySelection.files.length) refreshGallerySelection();
|
|
const { files } = gallerySelection;
|
|
if (!files.length) return;
|
|
if (!Number.isInteger(index) || index < 0 || index >= files.length) {
|
|
log("gallery selection index out of range", index, files.length);
|
|
resetGallerySelection();
|
|
return;
|
|
}
|
|
gallerySelection.index = index;
|
|
currentImage = files[index].src;
|
|
currentName = files[index].name;
|
|
currentTitle = files[index].title;
|
|
updateGallerySelectionClasses(files, index);
|
|
if (send && el.btnSend) el.btnSend.click();
|
|
}
|
|
function setGallerySelectionByElement(element, options) {
|
|
if (!gallerySelection.files.length) refreshGallerySelection();
|
|
let index = gallerySelection.files.findIndex((file) => file === element);
|
|
if (index < 0) {
|
|
refreshGallerySelection();
|
|
index = gallerySelection.files.findIndex((file) => file === element);
|
|
}
|
|
if (index >= 0) applyGallerySelection(index, options);
|
|
}
|
|
function buildGalleryFileUrl(path) {
|
|
return new URL(`/file=${encodeURI(path)}`, window.location.origin).toString();
|
|
}
|
|
window.getGallerySelection = () => ({ index: gallerySelection.index, files: gallerySelection.files });
|
|
window.setGallerySelection = (index, options) => applyGallerySelection(index, options);
|
|
window.getGallerySelectedUrl = () => currentImage ? buildGalleryFileUrl(currentImage) : null;
|
|
async function awaitForGallery(expectedSize, signal) {
|
|
while (Math.max(galleryHashes.size, galleryHashes.fallback) < expectedSize && !signal.aborted) await new Promise((resolve) => {
|
|
setTimeout(resolve, 500);
|
|
});
|
|
signal.throwIfAborted();
|
|
}
|
|
function updateGalleryStyles() {
|
|
if (opts.theme_type?.toLowerCase() === "modern") {
|
|
folderStylesheet.replace(`
|
|
.gallery-folder {
|
|
cursor: pointer;
|
|
padding: 8px 6px 8px 6px;
|
|
background-color: var(--sd-button-normal-color);
|
|
border-radius: var(--sd-border-radius);
|
|
text-align: left;
|
|
direction: rtl; /* Used to overflow the beginning instead of the end */
|
|
min-width: 12em;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
transition-duration: 0.2s;
|
|
transition-property: color, opacity, background-color, border-color;
|
|
transition-timing-function: ease-out;
|
|
}
|
|
.gallery-folder:hover {
|
|
background-color: var(--button-primary-background-fill-hover, var(--sd-button-hover-color));
|
|
}
|
|
.gallery-folder-selected {
|
|
background-color: var(--sd-button-selected-color);
|
|
color: var(--sd-button-selected-text-color);
|
|
}
|
|
.gallery-folder-icon {
|
|
font-size: 1.2em;
|
|
color: var(--sd-button-icon-color);
|
|
margin-right: 1em;
|
|
filter: drop-shadow(1px 1px 2px black);
|
|
float: left;
|
|
}
|
|
`);
|
|
} else {
|
|
folderStylesheet.replace(`
|
|
.gallery-folder {
|
|
cursor: pointer;
|
|
padding: 8px 6px 8px 6px;
|
|
max-width: 200px;
|
|
overflow-x: hidden;
|
|
text-wrap: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.gallery-folder:hover {
|
|
background-color: var(--button-primary-background-fill-hover);
|
|
}
|
|
.gallery-folder-selected {
|
|
background-color: var(--button-primary-background-fill);
|
|
}
|
|
`);
|
|
}
|
|
const size = el.size ? el.size.value : opts.extra_networks_card_size;
|
|
fileStylesheet.replace(`
|
|
.gallery-file {
|
|
object-fit: contain;
|
|
cursor: pointer;
|
|
height: ${size}px;
|
|
width: ${opts.browser_fixed_width ? `${size}px` : "unset"};
|
|
}
|
|
.gallery-file:hover {
|
|
filter: grayscale(100%);
|
|
}
|
|
.gallery-overlay {
|
|
position: absolute;
|
|
height: 24px;
|
|
background-color: rgba(0,0,0,0.7);
|
|
display: block;
|
|
text-align: right;
|
|
padding: 4px;
|
|
font-size: 1.2em;
|
|
letter-spacing: 0.5em;
|
|
width: 140px;
|
|
margin-top: calc(140px - 32px);
|
|
opacity: 75%;
|
|
}
|
|
:host(.gallery-file-selected) .gallery-file {
|
|
box-shadow: 0 0 0 2px var(--sd-button-selected-color);
|
|
}
|
|
`);
|
|
}
|
|
var HashSet = class extends Set {
|
|
fallback = 0;
|
|
constructor(val) {
|
|
super(val);
|
|
this.fallback = 0;
|
|
}
|
|
add(value) {
|
|
++this.fallback;
|
|
super.add(value);
|
|
return this;
|
|
}
|
|
clear() {
|
|
this.fallback = 0;
|
|
super.clear();
|
|
}
|
|
};
|
|
var galleryHashes = new HashSet();
|
|
var SimpleProgressBar = class {
|
|
#container = document.createElement("div");
|
|
#progress = document.createElement("div");
|
|
#textDiv = document.createElement("div");
|
|
#text = document.createElement("span");
|
|
#visible = false;
|
|
#interval;
|
|
#max = 0;
|
|
defaultStats = { queue: 0, fetch: 0, hash: 0, db: 0, cached: 0, fetched: 0, failed: 0, error: 0, callback: 0, elapsed: 0, count: 0 };
|
|
stats = { ...this.defaultStats };
|
|
/** @type {Set} */
|
|
#monitoredSet;
|
|
constructor(monitoredSet) {
|
|
this.#monitoredSet = monitoredSet;
|
|
this.#container.style.cssText = "position:relative; overflow:hidden; border-radius:var(--sd-border-radius); width:100%; background-color:hsla(0,0%,36%,0.3); height:1.2rem; margin:0; padding:0; display:none;";
|
|
this.#progress.style.cssText = "position:absolute; left:0; height:100%; width:0; transition:width 200ms;";
|
|
this.#progress.style.backgroundColor = "var(--sd-main-accent-color)";
|
|
this.#textDiv.style.cssText = "position:relative; margin:auto; width:max-content; height:100%;";
|
|
this.#text.style.cssText = "user-select:none; color:white;";
|
|
this.#textDiv.append(this.#text);
|
|
this.#container.append(this.#progress, this.#textDiv);
|
|
}
|
|
start(total) {
|
|
if (total <= 0) return;
|
|
this.hide();
|
|
this.#max = total;
|
|
this.#interval = setInterval(() => this.update(this.#monitoredSet.size, this.#max), 100);
|
|
}
|
|
attachTo(element) {
|
|
if (element.hasChildNodes) element.innerHTML = "";
|
|
element.appendChild(this.#container);
|
|
}
|
|
hide() {
|
|
this.#container.style.display = "none";
|
|
this.#visible = false;
|
|
this.#progress.style.width = "0";
|
|
this.#text.textContent = "";
|
|
}
|
|
update(loaded, max) {
|
|
this.#progress.style.width = `${Math.floor(loaded / max * 100)}%`;
|
|
this.#text.textContent = `${loaded}/${max}`;
|
|
if (!this.#visible) {
|
|
this.#container.style.display = "block";
|
|
this.#visible = true;
|
|
}
|
|
if (loaded >= max) this.stop();
|
|
}
|
|
stop() {
|
|
clearInterval(this.#interval);
|
|
this.#interval = void 0;
|
|
if (this.stats.count) {
|
|
debug("gallery: thumbnail stats", this.stats);
|
|
this.stats = { ...this.defaultStats };
|
|
}
|
|
setTimeout(() => this.hide(), 100);
|
|
}
|
|
};
|
|
var pb = new SimpleProgressBar(galleryHashes);
|
|
var SimpleFunctionQueue = class {
|
|
#id;
|
|
#running;
|
|
#queue;
|
|
constructor(id) {
|
|
this.#id = id;
|
|
this.#running = false;
|
|
this.#queue = [];
|
|
}
|
|
static abortLogger(identifier, result) {
|
|
if (typeof result === "string" || result instanceof DOMException && result.name === "AbortError") {
|
|
log(identifier, typeof result === "object" && result !== null ? result.message || result : result);
|
|
} else {
|
|
error(identifier, result.message);
|
|
}
|
|
}
|
|
/**
|
|
* @param {{
|
|
* signal: AbortSignal,
|
|
* callback: Function
|
|
* }} config
|
|
*/
|
|
enqueue(config) {
|
|
if (!(config.signal instanceof AbortSignal) || typeof config.callback !== "function") {
|
|
throw new Error("Invalid configuration. Object must contain an AbortSignal and a function");
|
|
}
|
|
if (config.signal.aborted) {
|
|
debug(`${this.#id} Queue: Skipping addition to queue due to "${config.signal.reason}"`);
|
|
return;
|
|
}
|
|
this.#queue.push(config);
|
|
this.#tryRunNext();
|
|
}
|
|
async #tryRunNext() {
|
|
if (this.#running || !this.#queue.length) return;
|
|
try {
|
|
const { signal, callback } = this.#queue.shift();
|
|
if (signal.aborted) {
|
|
return;
|
|
}
|
|
this.#running = true;
|
|
if (callback.constructor.name.toLowerCase() === "asyncfunction") {
|
|
await callback();
|
|
} else {
|
|
callback();
|
|
}
|
|
} catch (err) {
|
|
error(`${this.#id} Queue:`, err);
|
|
} finally {
|
|
this.#running = false;
|
|
this.#tryRunNext();
|
|
}
|
|
}
|
|
};
|
|
var GalleryFolder = class _GalleryFolder extends HTMLElement {
|
|
static folders = /* @__PURE__ */ new Set();
|
|
/** @type {GalleryFolder | null} */
|
|
static #active = null;
|
|
constructor(folder) {
|
|
super();
|
|
if (typeof folder === "object" && folder !== null) {
|
|
this.name = decodeURI(folder.path || "");
|
|
this.label = decodeURI(folder.label || folder.path || "");
|
|
} else {
|
|
this.name = decodeURI(folder);
|
|
this.label = this.name;
|
|
}
|
|
this.style.overflowX = "hidden";
|
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
this.shadow.adoptedStyleSheets = [folderStylesheet];
|
|
this.div = document.createElement("div");
|
|
}
|
|
connectedCallback() {
|
|
if (_GalleryFolder.folders.has(this)) return;
|
|
this.div.className = "gallery-folder";
|
|
this.div.innerHTML = `<span class="gallery-folder-icon">\uF03E</span> ${this.label}`;
|
|
this.div.title = this.name;
|
|
this.addEventListener("click", this.updateSelected);
|
|
this.addEventListener("click", fetchFilesWS);
|
|
this.shadow.appendChild(this.div);
|
|
_GalleryFolder.folders.add(this);
|
|
if (this.name === currentGalleryFolder) {
|
|
this.updateSelected();
|
|
}
|
|
}
|
|
async disconnectedCallback() {
|
|
await Promise.resolve();
|
|
if (this.isConnected) return;
|
|
_GalleryFolder.folders.delete(this);
|
|
if (_GalleryFolder.#active === this) {
|
|
_GalleryFolder.#active = null;
|
|
}
|
|
}
|
|
static getActive() {
|
|
return _GalleryFolder.#active;
|
|
}
|
|
updateSelected() {
|
|
this.div.classList.add("gallery-folder-selected");
|
|
_GalleryFolder.#active = this;
|
|
for (const folder of _GalleryFolder.folders) {
|
|
if (folder !== this) folder.div.classList.remove("gallery-folder-selected");
|
|
}
|
|
}
|
|
};
|
|
async function awaitForOutstanding(signal) {
|
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
if (outstanding < maxFetchRequests) return;
|
|
await new Promise((resolve, reject) => {
|
|
const onResolve = () => {
|
|
signal?.removeEventListener("abort", onAbort);
|
|
resolve(true);
|
|
};
|
|
const onAbort = () => {
|
|
const idx = fetchQueue.findIndex((item) => item.resolve === onResolve);
|
|
if (idx !== -1) fetchQueue.splice(idx, 1);
|
|
reject(new DOMException("Aborted", "AbortError"));
|
|
};
|
|
fetchQueue.push({ resolve: onResolve });
|
|
signal?.addEventListener("abort", onAbort);
|
|
});
|
|
}
|
|
async function delayFetchThumb(fn, signal) {
|
|
const t0 = performance.now();
|
|
try {
|
|
await awaitForOutstanding(signal);
|
|
} catch (err) {
|
|
if (err.name === "AbortError") return void 0;
|
|
throw err;
|
|
}
|
|
pb.stats.queue = (pb.stats.queue || 0) + Math.round(performance.now() - t0);
|
|
const t1 = performance.now();
|
|
try {
|
|
outstanding++;
|
|
const ts = t0.toString();
|
|
const res = await authFetch(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: "low" });
|
|
if (!res.ok) {
|
|
error(`fetchThumb: ${res.statusText}`);
|
|
return void 0;
|
|
}
|
|
const json = await res.json();
|
|
if (!res || !json || json.error || Object.keys(json).length === 0) {
|
|
if (json.error) error(`fetchThumb: ${json.error}`);
|
|
return void 0;
|
|
}
|
|
return json;
|
|
} finally {
|
|
outstanding--;
|
|
pb.stats.fetch = (pb.stats.fetch || 0) + Math.round(performance.now() - t1);
|
|
if (fetchQueue.length > 0 && outstanding < maxFetchRequests) {
|
|
const nextRequest = fetchQueue.shift();
|
|
nextRequest.resolve();
|
|
}
|
|
}
|
|
}
|
|
var GalleryFile = class extends HTMLElement {
|
|
/** @type {AbortSignal} */
|
|
#signal;
|
|
constructor(folder, file, signal) {
|
|
super();
|
|
this.folder = folder;
|
|
this.name = file;
|
|
this.#signal = signal;
|
|
this.src = `${this.folder}/${this.name}`.replace(/\/+/g, "/");
|
|
this.fullFolder = this.src.replace(/\/[^/]+$/, "");
|
|
this.size = 0;
|
|
this.mtime = 0;
|
|
this.hash = void 0;
|
|
this.exif = "";
|
|
this.width = 0;
|
|
this.height = 0;
|
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
this.shadow.adoptedStyleSheets = [fileStylesheet];
|
|
this.firstRun = true;
|
|
}
|
|
async connectedCallback() {
|
|
if (!this.firstRun) return;
|
|
this.firstRun = false;
|
|
const t0 = performance.now();
|
|
pb.stats.count = (pb.stats.count || 0) + 1;
|
|
const dir = this.name.match(/(.*)[/\\]/);
|
|
if (dir && dir[1]) {
|
|
const dirPath = dir[1];
|
|
const isOpen = separatorStates.get(dirPath);
|
|
if (isOpen === false) this.style.display = "none";
|
|
}
|
|
this.hash = await getHash(`${this.src}/${this.size}/${this.mtime}`).catch((err) => {
|
|
error("getHash:", err);
|
|
return null;
|
|
});
|
|
pb.stats.hash = (pb.stats.hash || 0) + Math.round(performance.now() - t0);
|
|
let cachedData;
|
|
if (opts.browser_cache) {
|
|
const t1 = performance.now();
|
|
cachedData = await idbGet(this.hash).catch(() => void 0);
|
|
pb.stats.db = (pb.stats.db || 0) + Math.round(performance.now() - t1);
|
|
}
|
|
const img = document.createElement("img");
|
|
img.className = "gallery-file";
|
|
img.loading = "lazy";
|
|
img.onload = async () => {
|
|
img.title += `
|
|
Resolution: ${this.width} x ${this.height}`;
|
|
this.title = img.title;
|
|
if (!cachedData && opts.browser_cache) {
|
|
if (this.width === 0 || this.height === 0) {
|
|
this.width = img.naturalWidth;
|
|
this.height = img.naturalHeight;
|
|
}
|
|
}
|
|
};
|
|
let ok2 = true;
|
|
if (cachedData?.img) {
|
|
img.src = cachedData.img;
|
|
this.exif = cachedData.exif;
|
|
this.width = cachedData.width;
|
|
this.height = cachedData.height;
|
|
this.size = cachedData.size;
|
|
this.mtime = new Date(cachedData.mtime);
|
|
pb.stats.cached = (pb.stats.cached || 0) + 1;
|
|
} else {
|
|
try {
|
|
const json = await delayFetchThumb(this.src, this.#signal);
|
|
if (!json) {
|
|
ok2 = false;
|
|
pb.stats.failed = (pb.stats.failed || 0) + 1;
|
|
} else {
|
|
img.src = json.data;
|
|
this.exif = json.exif;
|
|
this.width = json.width;
|
|
this.height = json.height;
|
|
this.size = json.size;
|
|
this.mtime = new Date(json.mtime);
|
|
pb.stats.fetched = (pb.stats.fetched || 0) + 1;
|
|
if (opts.browser_cache && this.hash) {
|
|
idbAdd({
|
|
hash: this.hash,
|
|
folder: this.fullFolder,
|
|
file: this.name,
|
|
size: this.size,
|
|
mtime: this.mtime,
|
|
width: this.width,
|
|
height: this.height,
|
|
src: this.src,
|
|
exif: this.exif,
|
|
img: img.src
|
|
// exif: await getExif(img), // alternative client-side exif
|
|
// img: await createThumb(img), // alternative client-side thumb
|
|
});
|
|
}
|
|
}
|
|
} catch (err) {
|
|
img.src = `file=${this.src}`;
|
|
pb.stats.error = (pb.stats.error || 0) + 1;
|
|
}
|
|
}
|
|
pb.stats.callback = (pb.stats.callback || 0) + Math.round(performance.now() - t0);
|
|
if (this.#signal.aborted) return;
|
|
galleryHashes.add(this.hash);
|
|
if (!ok2) return;
|
|
img.onclick = () => {
|
|
setGallerySelectionByElement(this, { send: true });
|
|
};
|
|
img.onpointerenter = () => {
|
|
el.overlay.display = "block";
|
|
this.shadow.appendChild(el.overlay);
|
|
currentImage = this.src;
|
|
currentName = this.name;
|
|
currentTitle = this.title;
|
|
};
|
|
img.onpointerleave = () => {
|
|
el.overlay.display = "none";
|
|
};
|
|
img.title = `Folder: ${this.folder}
|
|
File: ${this.name}
|
|
Size: ${this.size.toLocaleString()} bytes
|
|
Modified: ${this.mtime.toLocaleString()}`;
|
|
this.title = img.title;
|
|
const shouldDisplayBasedOnSearch = this.title.toLowerCase().includes(el.search.value.toLowerCase());
|
|
if (this.style.display !== "none") this.style.display = shouldDisplayBasedOnSearch ? "flex" : "none";
|
|
this.shadow.appendChild(img);
|
|
pb.stats.elapsed = (pb.stats.elapsed || 0) + Math.round(performance.now() - t0);
|
|
}
|
|
};
|
|
async function handleSeparator(separator) {
|
|
separator.classList.toggle("gallery-separator-hidden");
|
|
const nowHidden = separator.classList.contains("gallery-separator-hidden");
|
|
separatorStates.set(separator.title, !nowHidden);
|
|
const arrow = separator.querySelector(".gallery-separator-arrow");
|
|
arrow.style.transform = nowHidden ? "rotate(0deg)" : "rotate(90deg)";
|
|
const all = Array.from(el.files.children);
|
|
for (const f of all) {
|
|
if (!f.name) continue;
|
|
const fileDir = f.name.match(/(.*)[/\\]/);
|
|
const fileDirPath = fileDir ? fileDir[1] : "";
|
|
if (separator.title.length > 0 && fileDirPath === separator.title) {
|
|
f.style.display = nowHidden ? "none" : "unset";
|
|
}
|
|
}
|
|
}
|
|
async function addSeparators() {
|
|
document.querySelectorAll(".gallery-separator").forEach((node) => {
|
|
el.files.removeChild(node);
|
|
});
|
|
const all = Array.from(el.files.children);
|
|
let lastDir;
|
|
const hasRootFiles = all.some((f) => f.name && !f.name.match(/[/\\]/));
|
|
let isFirstSeparator = !hasRootFiles;
|
|
for (const f of all) {
|
|
let dir = f.name?.match(/(.*)[/\\]/);
|
|
if (!dir) dir = "";
|
|
else dir = dir[1];
|
|
if (dir !== lastDir) {
|
|
lastDir = dir;
|
|
if (dir.length > 0) {
|
|
let fileCount = 0;
|
|
for (const file of all) {
|
|
if (!file.name) continue;
|
|
const fileDir = file.name.match(/(.*)[/\\]/);
|
|
const fileDirPath = fileDir ? fileDir[1] : "";
|
|
if (fileDirPath === dir) fileCount++;
|
|
}
|
|
const sep = document.createElement("div");
|
|
sep.className = "gallery-separator";
|
|
sep.title = dir;
|
|
const isOpen = separatorStates.has(dir) ? separatorStates.get(dir) : isFirstSeparator;
|
|
separatorStates.set(dir, isOpen);
|
|
if (isFirstSeparator) isFirstSeparator = false;
|
|
if (!isOpen) {
|
|
sep.classList.add("gallery-separator-hidden");
|
|
}
|
|
const arrow = document.createElement("span");
|
|
arrow.className = "gallery-separator-arrow";
|
|
arrow.textContent = "\u25B6";
|
|
arrow.style.transform = isOpen ? "rotate(90deg)" : "rotate(0deg)";
|
|
const dirName = document.createElement("span");
|
|
dirName.className = "gallery-separator-name";
|
|
dirName.textContent = dir;
|
|
dirName.title = dir;
|
|
const count = document.createElement("span");
|
|
count.className = "gallery-separator-count";
|
|
count.textContent = `${fileCount} files`;
|
|
sep.dataset.totalFiles = String(fileCount);
|
|
sep.appendChild(arrow);
|
|
sep.appendChild(dirName);
|
|
sep.appendChild(count);
|
|
sep.onclick = () => handleSeparator(sep);
|
|
el.files.insertBefore(sep, f);
|
|
}
|
|
}
|
|
}
|
|
for (const f of all) {
|
|
if (!f.name) continue;
|
|
const dir = f.name.match(/(.*)[/\\]/);
|
|
if (dir && dir[1]) {
|
|
const dirPath = dir[1];
|
|
const isOpen = separatorStates.get(dirPath);
|
|
if (isOpen === false) {
|
|
f.style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var gallerySendImage = (_images) => [currentImage];
|
|
window.gallerySendImage = gallerySendImage;
|
|
function updateStatusWithSort(...messages) {
|
|
if (!el.status) return;
|
|
messages.unshift(["Sort", sortMode.name]);
|
|
const fragment = document.createDocumentFragment();
|
|
for (let i = 0; i < messages.length; i++) {
|
|
const div = document.createElement("div");
|
|
if (Array.isArray(messages[i])) {
|
|
const [text1, text2] = messages[i];
|
|
const tDiv1 = document.createElement("div");
|
|
tDiv1.innerText = `${text1}:`;
|
|
const tDiv2 = document.createElement("div");
|
|
tDiv2.innerText = text2;
|
|
tDiv2.title = text2;
|
|
div.append(tDiv1, tDiv2);
|
|
} else {
|
|
const tDiv1 = document.createElement("div");
|
|
tDiv1.innerText = messages[i];
|
|
div.append(tDiv1);
|
|
}
|
|
fragment.append(div);
|
|
}
|
|
if (el.status.hasChildNodes()) el.status.innerHTML = "";
|
|
el.status.append(fragment);
|
|
}
|
|
async function injectGalleryStatusCSS() {
|
|
const style = document.createElement("style");
|
|
style.textContent = `
|
|
#tab-gallery-status {
|
|
display: inline-flex;
|
|
flex-flow: row wrap;
|
|
justify-content: ${opts.theme_type?.toLowerCase() === "modern" ? "flex-start" : "flex-end"};
|
|
}
|
|
#tab-gallery-status > div {
|
|
display: flex;
|
|
max-width: 100%;
|
|
white-space: nowrap;
|
|
& div {
|
|
&:first-child {
|
|
flex-shrink: 0;
|
|
margin-right: 4px;
|
|
}
|
|
&:last-child:not(:first-child) {
|
|
flex-shrink: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
direction: rtl;
|
|
text-align: left;
|
|
}
|
|
}
|
|
}
|
|
#tab-gallery-status > div:not(:last-child)::after {
|
|
content: '|';
|
|
margin-inline: 6px;
|
|
}`;
|
|
document.head.append(style);
|
|
}
|
|
async function wsConnect(socket, timeout = 5e3) {
|
|
const intrasleep = 100;
|
|
const ttl = timeout / intrasleep;
|
|
const isOpened = () => socket.readyState === WebSocket.OPEN;
|
|
if (socket.readyState !== WebSocket.CONNECTING) return isOpened();
|
|
let loop = 0;
|
|
while (socket.readyState === WebSocket.CONNECTING && loop < ttl) {
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, intrasleep);
|
|
});
|
|
loop++;
|
|
}
|
|
return isOpened();
|
|
}
|
|
async function gallerySearch() {
|
|
if (el.search.busy) clearTimeout(el.search.busy);
|
|
el.search.busy = setTimeout(async () => {
|
|
const t0 = performance.now();
|
|
const str = el.search.value.toLowerCase();
|
|
const allFiles = Array.from(el.files.children).filter((node) => node.name);
|
|
const allSeparators = Array.from(el.files.children).filter((node) => node.classList.contains("gallery-separator"));
|
|
if (str === "") {
|
|
allSeparators.forEach((sep) => {
|
|
sep.style.display = "flex";
|
|
const isOpen = separatorStates.has(sep.title) ? separatorStates.get(sep.title) : false;
|
|
const countSpan = sep.querySelector(".gallery-separator-count");
|
|
if (countSpan && sep.dataset.totalFiles) {
|
|
countSpan.textContent = `${sep.dataset.totalFiles} files`;
|
|
}
|
|
const arrow = sep.querySelector(".gallery-separator-arrow");
|
|
sep.classList.toggle("gallery-separator-hidden", !isOpen);
|
|
if (arrow) arrow.style.transform = isOpen ? "rotate(90deg)" : "rotate(0deg)";
|
|
});
|
|
allFiles.forEach((f) => {
|
|
const dir = f.name.match(/(.*)[/\\]/);
|
|
const dirPath = dir && dir[1] ? dir[1] : "";
|
|
const isOpen = separatorStates.get(dirPath);
|
|
f.style.display = !dirPath || isOpen ? "unset" : "none";
|
|
});
|
|
updateStatusWithSort("Filter", "Cleared", ["Images", allFiles.length.toLocaleString()]);
|
|
return;
|
|
}
|
|
let totalFound = 0;
|
|
const directoryMatches = /* @__PURE__ */ new Map();
|
|
const fileMatches = /* @__PURE__ */ new WeakSet();
|
|
const r = /^(.+)([=<>])(.*)/;
|
|
for (const f of allFiles) {
|
|
let isMatch = false;
|
|
if (r.test(str)) {
|
|
const match = str.match(r);
|
|
const key = match[1].trim();
|
|
const op = match[2].trim();
|
|
let val = match[3].trim();
|
|
if (key === "mtime") val = new Date(val);
|
|
if (op === "=" && f[key] === val || op === ">" && f[key] > val || op === "<" && f[key] < val) {
|
|
isMatch = true;
|
|
}
|
|
} else if (f.title?.toLowerCase().includes(str) || f.exif?.toLowerCase().includes(str)) {
|
|
isMatch = true;
|
|
}
|
|
if (isMatch) {
|
|
fileMatches.add(f);
|
|
totalFound++;
|
|
const dir = f.name.match(/(.*)[/\\]/);
|
|
const dirPath = dir && dir[1] ? dir[1] : "";
|
|
directoryMatches.set(dirPath, (directoryMatches.get(dirPath) || 0) + 1);
|
|
}
|
|
}
|
|
for (const sep of allSeparators) {
|
|
const dirPath = sep.title;
|
|
const foundCount = directoryMatches.get(dirPath) || 0;
|
|
if (foundCount > 0) {
|
|
sep.style.display = "flex";
|
|
sep.classList.remove("gallery-separator-hidden");
|
|
const arrow = sep.querySelector(".gallery-separator-arrow");
|
|
if (arrow) arrow.style.transform = "rotate(90deg)";
|
|
} else {
|
|
sep.style.display = "none";
|
|
}
|
|
}
|
|
for (const f of allFiles) {
|
|
f.style.display = fileMatches.has(f) ? "unset" : "none";
|
|
}
|
|
const t1 = performance.now();
|
|
updateStatusWithSort("Filter", ["Images", `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], `${iconStopwatch} ${Math.round(t1 - t0).toLocaleString()}ms`);
|
|
timer(`galleryFilter:${str}`, t1 - t0);
|
|
refreshGallerySelection();
|
|
}, 250);
|
|
}
|
|
async function gallerySort(key) {
|
|
if (currentSort.startsWith(key)) currentSort = currentSort.endsWith("A") ? `${key}D` : `${key}A`;
|
|
else currentSort = `${key}A`;
|
|
if (!Object.hasOwn(gallerySorter, currentSort)) {
|
|
error(`Gallery: "${currentSort}" is not a valid gallery sorting key`);
|
|
return;
|
|
}
|
|
const t0 = performance.now();
|
|
const arr = Array.from(el.files.children).filter((node) => node.name);
|
|
if (arr.length === 0) return;
|
|
const fragment = document.createDocumentFragment();
|
|
const getDirPath = (node) => {
|
|
const match = node.name.match(/(.*)[/\\]/);
|
|
return match ? match[1] : "";
|
|
};
|
|
const rootFiles = arr.filter((node) => !getDirPath(node));
|
|
const subfolderFiles = arr.filter((node) => getDirPath(node));
|
|
const folderGroups = /* @__PURE__ */ new Map();
|
|
for (const file of subfolderFiles) {
|
|
const dir = getDirPath(file);
|
|
if (!folderGroups.has(dir)) {
|
|
folderGroups.set(dir, []);
|
|
}
|
|
folderGroups.get(dir).push(file);
|
|
}
|
|
sortMode = gallerySorter[currentSort];
|
|
rootFiles.sort(sortMode.func);
|
|
rootFiles.forEach((node) => fragment.appendChild(node));
|
|
const sortedFolderNames = Array.from(folderGroups.keys()).sort((a, b) => a.localeCompare(b));
|
|
for (const folderName of sortedFolderNames) {
|
|
const files = folderGroups.get(folderName);
|
|
files.sort(sortMode.func);
|
|
files.forEach((node) => fragment.appendChild(node));
|
|
}
|
|
if (fragment.children.length === 0) return;
|
|
el.files.innerHTML = "";
|
|
el.files.appendChild(fragment);
|
|
addSeparators();
|
|
const all = Array.from(el.files.children);
|
|
for (const f of all) {
|
|
if (!f.name) continue;
|
|
const dir = f.name.match(/(.*)[/\\]/);
|
|
if (dir && dir[1]) {
|
|
const dirPath = dir[1];
|
|
const isOpen = separatorStates.get(dirPath);
|
|
if (isOpen === false) {
|
|
f.style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
const t1 = performance.now();
|
|
log(`gallerySort: sort=${sortMode.name} len=${arr.length} time=${Math.floor(t1 - t0)}`);
|
|
updateStatusWithSort(["Images", arr.length.toLocaleString()], `${iconStopwatch} ${Math.round(t1 - t0).toLocaleString()}ms`);
|
|
timer(`gallerySort:${sortMode.name}`, t1 - t0);
|
|
refreshGallerySelection();
|
|
}
|
|
window.gallerySort = gallerySort;
|
|
function showCleaningMsg(count, all = false) {
|
|
const parent2 = el.folders.parentElement;
|
|
const cleaningOverlay = document.createElement("div");
|
|
const msgDiv = document.createElement("div");
|
|
const msgText = document.createElement("div");
|
|
const msgInfo = document.createElement("div");
|
|
const anim = document.createElement("span");
|
|
parent2.style.position = "relative";
|
|
cleaningOverlay.style.cssText = "position: absolute; height: 100%; width: 100%; background-color: var(--sd-main-accent-color); display: flex; align-items: center; justify-content: center; align-content: center; flex-wrap: wrap; opacity: 0.8; border-radius: var(--sd-border-radius);";
|
|
msgDiv.style.cssText = "display: block; color: var(--sd-button-normal-color); padding: 12px; border-radius: 8px; border-radius: var(--sd-border-radius);";
|
|
msgText.style.cssText = "font-size: 1.2em";
|
|
msgInfo.style.cssText = "font-size: 0.9em; text-align: center;";
|
|
msgText.innerText = "Thumbnail cleanup...";
|
|
msgInfo.innerText = all ? "Clearing all entries" : `Found ${count} old entries`;
|
|
anim.classList.add("idbBusyAnim");
|
|
msgDiv.append(msgText, msgInfo);
|
|
cleaningOverlay.append(msgDiv, anim);
|
|
parent2.append(cleaningOverlay);
|
|
return () => {
|
|
cleaningOverlay.remove();
|
|
};
|
|
}
|
|
var maintenanceQueue = new SimpleFunctionQueue("Gallery Maintenance");
|
|
async function thumbCacheCleanup(folder, imgCount, controller, force = false) {
|
|
if (!opts.browser_cache && !force) return;
|
|
if (!folder || !imgCount) return;
|
|
if (Date.now() - cleanupTimers[folder] < minCleanupTime) return;
|
|
cleanupTimers[folder] = Date.now();
|
|
try {
|
|
if (typeof folder !== "string" || typeof imgCount !== "number") {
|
|
throw new Error("Function called with invalid arguments");
|
|
}
|
|
debug("thumbCacheCleanup", { folder, imgCount });
|
|
await awaitForGallery(imgCount, controller.signal);
|
|
} catch (err) {
|
|
error("thumbCacheCleanup", { folder, error: err });
|
|
return;
|
|
}
|
|
maintenanceQueue.enqueue({
|
|
signal: controller.signal,
|
|
callback: async () => {
|
|
if (Date.now() - maintenanceTimers[folder] < minCleanupTime) return;
|
|
maintenanceTimers[folder] = Date.now();
|
|
const t0 = performance.now();
|
|
const keptGalleryHashes = force ? /* @__PURE__ */ new Set() : new Set(galleryHashes.values());
|
|
const folderNormalized = folder.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
const recursiveFolder = IDBKeyRange.bound(folderNormalized, `${folderNormalized}\uFFFF`, false, true);
|
|
if (keptGalleryHashes.size < minCleanupCount && !force) return;
|
|
const cachedHashesCount = await idbCount(recursiveFolder).catch((e) => {
|
|
error("maintenanceQueue", { folder, error: e });
|
|
return Infinity;
|
|
});
|
|
const cleanupCount = cachedHashesCount - keptGalleryHashes.size;
|
|
if (!force && (cleanupCount < minCleanupCount || !Number.isFinite(cleanupCount))) return;
|
|
log("galleryMaintenance", { folder });
|
|
if (controller.signal.aborted) {
|
|
debug("maintenanceQueue", { folder, reason: controller.signal.reason });
|
|
return;
|
|
}
|
|
const cb_clearMsg = showCleaningMsg(cleanupCount);
|
|
await idbFolderCleanup(keptGalleryHashes, recursiveFolder, controller.signal).then((delcount) => {
|
|
const t1 = performance.now();
|
|
log("galleryMaintenance", { folder, kept: keptGalleryHashes.size, deleted: delcount, time: Math.round(t1 - t0) });
|
|
timer(`thumbnailDBCleanup:${folder}`, t1 - t0);
|
|
currentGalleryFolder = null;
|
|
updateStatusWithSort("Thumbnail cache cleared");
|
|
}).catch((reason) => {
|
|
SimpleFunctionQueue.abortLogger("thumbCacheCleanup", reason);
|
|
}).finally(async () => {
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, 1e3);
|
|
});
|
|
cb_clearMsg();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
function resetGalleryState(reason) {
|
|
maintenanceController.abort(reason);
|
|
const controller = new AbortController();
|
|
maintenanceController = controller;
|
|
galleryHashes.clear();
|
|
pb.hide();
|
|
resetGallerySelection();
|
|
return controller;
|
|
}
|
|
function clearCache() {
|
|
if (!currentGalleryFolder) return;
|
|
const controller = resetGalleryState("Clearing folder thumbnails cache");
|
|
el.files.innerHTML = "";
|
|
log("clearCache", { folder: currentGalleryFolder });
|
|
thumbCacheCleanup(currentGalleryFolder, 0, controller, true);
|
|
}
|
|
window.clearCache = clearCache;
|
|
async function fetchFilesHT(evt, controller) {
|
|
const t0 = performance.now();
|
|
const fragment = document.createDocumentFragment();
|
|
updateStatusWithSort(["Folder", evt.target.name], "in-progress");
|
|
let numFiles = 0;
|
|
const res = await authFetch(`${window.api}/browser/files?folder=${encodeURI(evt.target.name)}`);
|
|
if (!res || res.status !== 200) {
|
|
updateStatusWithSort(["Folder", evt.target.name], ["Failed", res?.statusText || "No response"]);
|
|
return;
|
|
}
|
|
const jsonData = await res.json();
|
|
for (const line of jsonData) {
|
|
const data = decodeURI(line).split("##F##");
|
|
const fileName = data[1];
|
|
const ext = fileName.split(".").pop().toLowerCase();
|
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
numFiles++;
|
|
const f = new GalleryFile(data[0], fileName, controller.signal);
|
|
fragment.appendChild(f);
|
|
}
|
|
}
|
|
if (controller.signal.aborted) return;
|
|
el.files.appendChild(fragment);
|
|
const t1 = performance.now();
|
|
log(`gallery: folder=${evt.target.name} num=${numFiles} method=http time=${Math.floor(t1 - t0)}ms`);
|
|
timer(`galleryFetch:${evt.target.name}`, t1 - t0);
|
|
updateStatusWithSort(["Folder", evt.target.name], ["Images", numFiles.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
|
|
pb.start(numFiles);
|
|
addSeparators();
|
|
refreshGallerySelection();
|
|
thumbCacheCleanup(evt.target.name, numFiles, controller);
|
|
}
|
|
async function fetchFilesWS(evt) {
|
|
if (!url) return;
|
|
const controller = resetGalleryState("Gallery update");
|
|
el.files.innerHTML = "";
|
|
updateGalleryStyles();
|
|
if (ws && ws.readyState === WebSocket.OPEN) ws.close();
|
|
let wsConnected = false;
|
|
try {
|
|
ws = new WebSocket(`${url}/sdapi/v1/browser/files`);
|
|
wsConnected = await wsConnect(ws);
|
|
} catch (err) {
|
|
log("gallery: ws connect error", err);
|
|
return;
|
|
}
|
|
log(`gallery: connected=${wsConnected} state=${ws?.readyState} url=${ws?.url}`);
|
|
currentGalleryFolder = evt.target.name;
|
|
if (!wsConnected) {
|
|
await fetchFilesHT(evt, controller);
|
|
return;
|
|
}
|
|
updateStatusWithSort(["Folder", evt.target.name]);
|
|
const t0 = performance.now();
|
|
let numFiles = 0;
|
|
let t1 = performance.now();
|
|
let fragment = document.createDocumentFragment();
|
|
ws.onmessage = (event2) => {
|
|
t1 = performance.now();
|
|
const data = decodeURI(event2.data).split("##F##");
|
|
if (data[0] === "#END#") {
|
|
ws.close();
|
|
} else {
|
|
const fileName = data[1];
|
|
const ext = fileName.split(".").pop().toLowerCase();
|
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
const file = new GalleryFile(data[0], fileName, controller.signal);
|
|
numFiles++;
|
|
fragment.appendChild(file);
|
|
if (numFiles % fragmentSize === 0) {
|
|
updateStatusWithSort(["Folder", evt.target.name], ["Images", numFiles.toLocaleString()], "in-progress", `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
|
|
el.files.appendChild(fragment);
|
|
fragment = document.createDocumentFragment();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
ws.onclose = (event2) => {
|
|
if (controller.signal.aborted) return;
|
|
el.files.appendChild(fragment);
|
|
log(`gallery: folder=${evt.target.name} num=${numFiles} method=ws time=${Math.floor(t1 - t0)}ms`);
|
|
updateStatusWithSort(["Folder", evt.target.name], ["Images", numFiles.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
|
|
pb.start(numFiles);
|
|
addSeparators();
|
|
refreshGallerySelection();
|
|
thumbCacheCleanup(evt.target.name, numFiles, controller);
|
|
};
|
|
ws.onerror = (event2) => {
|
|
log("gallery ws error", event2);
|
|
};
|
|
ws.send(encodeURI(evt.target.name));
|
|
}
|
|
async function updateFolders() {
|
|
const res = await authFetch(`${window.api}/browser/folders`);
|
|
if (!res || res.status !== 200) return;
|
|
url = res.url.split("/sdapi")[0].replace("http", "ws");
|
|
const folders = await res.json();
|
|
el.folders.innerHTML = "";
|
|
for (const folder of folders) {
|
|
const f = new GalleryFolder(folder);
|
|
el.folders.appendChild(f);
|
|
}
|
|
}
|
|
async function monitorGalleries() {
|
|
async function galleryMutation(mutations) {
|
|
const galleries = mutations.filter((m) => m.target?.classList?.contains("preview"));
|
|
for (const gallery of galleries) {
|
|
const links = gallery.target.querySelectorAll("a");
|
|
for (const link of links) {
|
|
const href = link.getAttribute("href");
|
|
if (!href) continue;
|
|
const fn = href.split("/").pop().split("\\").pop();
|
|
link.setAttribute("download", fn);
|
|
}
|
|
}
|
|
}
|
|
const galleryElements = gradioApp().querySelectorAll(".gradio-gallery");
|
|
for (const gallery of galleryElements) {
|
|
const galleryObserver = new MutationObserver(galleryMutation);
|
|
galleryObserver.observe(gallery, { childList: true, subtree: true, attributes: true });
|
|
}
|
|
}
|
|
async function setOverlayAnimation() {
|
|
const busyAnimation = document.createElement("style");
|
|
busyAnimation.textContent = ".idbBusyAnim{width:16px;height:16px;border-radius:50%;display:block;margin:40px;position:relative;background:#aa3d00;color:#fff;box-shadow:-24px 0,24px 0;box-sizing:border-box;animation:2s ease-in-out infinite overlayRotation}@keyframes overlayRotation{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}";
|
|
document.head.append(busyAnimation);
|
|
}
|
|
async function initGalleryAutoRefresh() {
|
|
const isModern = opts.theme_type?.toLowerCase() === "modern";
|
|
let galleryTab = isModern ? document.getElementById("gallery_tabitem") : document.getElementById("tab_gallery");
|
|
let timeout = 0;
|
|
while (!galleryTab && timeout++ < 60) {
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, 2500);
|
|
});
|
|
galleryTab = isModern ? document.getElementById("gallery_tabitem") : document.getElementById("tab_gallery");
|
|
}
|
|
if (!galleryTab) {
|
|
error("Gallery: timeout");
|
|
return;
|
|
}
|
|
const displayNoneRegEx = /display:\s*none/;
|
|
async function galleryAutoRefresh(mutations) {
|
|
if (!opts.browser_gallery_autoupdate) return;
|
|
for (const mutation of mutations) {
|
|
switch (mutation.attributeName) {
|
|
case "class":
|
|
if (mutation.oldValue.includes("hidden") && !mutation.target.classList.contains("hidden")) {
|
|
await updateFolders();
|
|
GalleryFolder.getActive()?.click();
|
|
}
|
|
break;
|
|
case "style":
|
|
if (displayNoneRegEx.test(mutation.oldValue) && !displayNoneRegEx.test(mutation.target.style.display)) {
|
|
await updateFolders();
|
|
GalleryFolder.getActive()?.click();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
const galleryVisObserver = new MutationObserver(galleryAutoRefresh);
|
|
galleryVisObserver.observe(galleryTab, { attributeFilter: ["class", "style"], attributeOldValue: true });
|
|
}
|
|
async function overlayDelete(evt) {
|
|
const res = await authFetch(`${window.api}/delete-image?file=${encodeURIComponent(currentImage)}`);
|
|
evt.stopPropagation();
|
|
if (!res || res.status !== 200) {
|
|
error("galleryDelete", { file: currentImage, status: res?.status, statusText: res?.statusText });
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
log("galleryDelete", data);
|
|
GalleryFolder.getActive()?.click();
|
|
}
|
|
async function overlayDownload(evt) {
|
|
log("galleryDownload", currentImage);
|
|
const link = document.createElement("a");
|
|
link.href = `/file=${encodeURIComponent(currentImage)}`;
|
|
link.download = currentName;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
evt.stopPropagation();
|
|
}
|
|
async function overlayInfo(evt) {
|
|
evt.stopPropagation();
|
|
const tgt = document.getElementById("html_info_formatted_gallery");
|
|
if (!tgt) return;
|
|
const res = await authFetch(`${window.api}/png-info?file=${encodeURI(currentImage)}`);
|
|
if (!res || res.status !== 200) return;
|
|
const data = await res.json();
|
|
log("galleryInfo res", data);
|
|
const prompt = data?.parameters?.Prompt || "";
|
|
const negative = data?.parameters?.Negative || data?.parameters?.["Negative prompt"] || "";
|
|
const raw = data?.info || "";
|
|
const params = data?.parameters || {};
|
|
delete params.Prompt;
|
|
delete params.Negative;
|
|
delete params["Negative prompt"];
|
|
const paramsFormatted = Object.entries(params).map(([key, value]) => `<b>${key}:</b> ${value}`).join(" | ");
|
|
tgt.innerHTML = `
|
|
<div><b>File:</b> ${currentImage}</div>
|
|
<div><b>Prompt:</b> ${prompt}</div>
|
|
<div><b>Negative:</b> ${negative}</div>
|
|
<div>${paramsFormatted}</div>
|
|
<div><b>Raw:</b><pre style="white-space: pre-wrap; margin: 0.5em">${raw}</pre></div>
|
|
`;
|
|
const img = document.querySelector("#gallery_gallery img");
|
|
if (img) img.src = `/file=${encodeURIComponent(currentImage)}?t=${Date.now()}`;
|
|
const status = document.querySelector("#html_log_gallery p");
|
|
if (status) status.innerText = currentTitle;
|
|
}
|
|
async function createOverlay() {
|
|
if (el.overlay) return;
|
|
el.overlay = document.createElement("div");
|
|
el.overlay.className = "gallery-overlay";
|
|
const btnDownload = document.createElement("span");
|
|
btnDownload.innerHTML = "\u{F1464}";
|
|
btnDownload.title = "Download image";
|
|
btnDownload.style.cursor = "pointer";
|
|
btnDownload.addEventListener("click", overlayDownload);
|
|
const btnDelete = document.createElement("span");
|
|
btnDelete.innerHTML = "\uF05C";
|
|
btnDelete.title = "Delete image";
|
|
btnDelete.style.cursor = "pointer";
|
|
btnDelete.addEventListener("click", overlayDelete);
|
|
const btnInfo = document.createElement("span");
|
|
btnInfo.innerHTML = "\uF05A";
|
|
btnInfo.title = "Image metadata";
|
|
btnInfo.style.cursor = "pointer";
|
|
btnInfo.addEventListener("click", overlayInfo);
|
|
el.overlay.append(btnInfo, btnDelete, btnDownload);
|
|
}
|
|
async function blockQueueUntilReady() {
|
|
maintenanceQueue.enqueue({
|
|
signal: new AbortController().signal,
|
|
// Use standalone AbortSignal that can't be aborted
|
|
callback: async () => {
|
|
let timeout = 0;
|
|
while (!idbIsReady() && timeout++ < 60) {
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, 1e3);
|
|
});
|
|
}
|
|
if (!idbIsReady()) {
|
|
throw new Error("Timed out waiting for thumbnail cache");
|
|
}
|
|
}
|
|
});
|
|
}
|
|
async function initGallery() {
|
|
const t0 = performance.now();
|
|
el.folders = gradioApp().getElementById("tab-gallery-folders");
|
|
el.files = gradioApp().getElementById("tab-gallery-files");
|
|
el.status = gradioApp().getElementById("tab-gallery-status");
|
|
el.search = gradioApp().querySelector("#tab-gallery-search textarea");
|
|
el.size = document.getElementById("tab-gallery-thumb-size");
|
|
if (!el.folders || !el.files || !el.status || !el.search) {
|
|
error("initGallery", "Missing gallery elements");
|
|
return;
|
|
}
|
|
if (el.size) {
|
|
el.size.value = opts.extra_networks_card_size;
|
|
el.size.addEventListener("input", updateGalleryStyles);
|
|
}
|
|
blockQueueUntilReady();
|
|
createOverlay();
|
|
updateGalleryStyles();
|
|
injectGalleryStatusCSS();
|
|
setOverlayAnimation();
|
|
const progress = gradioApp().getElementById("tab-gallery-progress");
|
|
if (progress) pb.attachTo(progress);
|
|
else log("initGallery", "Failed to attach loading progress bar");
|
|
el.search.addEventListener("input", gallerySearch);
|
|
el.btnSend = gradioApp().getElementById("tab-gallery-send-image");
|
|
document.getElementById("tab-gallery-files").style.height = opts.logmonitor_show ? "75vh" : "85vh";
|
|
monitorGalleries();
|
|
updateFolders();
|
|
initGalleryAutoRefresh();
|
|
[
|
|
"browser_folders",
|
|
"outdir_samples",
|
|
"outdir_txt2img_samples",
|
|
"outdir_img2img_samples",
|
|
"outdir_control_samples",
|
|
"outdir_extras_samples",
|
|
"outdir_save",
|
|
"outdir_video",
|
|
"outdir_init_images",
|
|
"outdir_grids",
|
|
"outdir_txt2img_grids",
|
|
"outdir_img2img_grids",
|
|
"outdir_control_grids"
|
|
].forEach((op) => {
|
|
monitorOption(op, updateFolders);
|
|
});
|
|
const t1 = performance.now();
|
|
log("initGallery", Math.round(t1 - t0));
|
|
timer("initGallery", t1 - t0);
|
|
}
|
|
customElements.define("gallery-folder", GalleryFolder);
|
|
customElements.define("gallery-file", GalleryFile);
|
|
|
|
// ui/imageViewer.ts
|
|
var import_exifr = __toESM(require_full_umd());
|
|
var import_panzoom = __toESM(require_panzoom());
|
|
var previewDrag = false;
|
|
var modalPreviewZone;
|
|
var previewInstance;
|
|
function cycleImageFit() {
|
|
const root = document.documentElement;
|
|
const current = getComputedStyle(root).getPropertyValue("--sd-image-fit").trim();
|
|
let next = "contain";
|
|
if (current === "contain") next = "cover";
|
|
else if (current === "cover") next = "fill";
|
|
else if (current === "fill") next = "scale-down";
|
|
else if (current === "scale-down") next = "none";
|
|
root.style.setProperty("--sd-image-fit", next);
|
|
log("cycleImageFit", current, next);
|
|
}
|
|
window.cycleImageFit = cycleImageFit;
|
|
function closeModal(evt, force = false) {
|
|
if (force) gradioApp().getElementById("lightboxModal").style.display = "none";
|
|
if (previewDrag) return;
|
|
if (evt?.button !== 0) return;
|
|
gradioApp().getElementById("lightboxModal").style.display = "none";
|
|
let thumbnails = Array.from(gradioApp().querySelectorAll(".thumbnails .thumbnail-item"));
|
|
thumbnails = thumbnails.filter((el2) => el2.checkVisibility());
|
|
if (thumbnails.length === 0) return;
|
|
thumbnails[0].focus();
|
|
}
|
|
function modalImageSwitch(offset) {
|
|
const negmod = (n, m) => (n % m + m) % m;
|
|
const galleryButtons = all_gallery_buttons();
|
|
if (galleryButtons.length > 1) {
|
|
const currentButton = selected_gallery_button();
|
|
let result = -1;
|
|
galleryButtons.forEach((v, i) => {
|
|
if (v === currentButton) result = i;
|
|
});
|
|
if (result !== -1) {
|
|
const nextButton = galleryButtons[negmod(result + offset, galleryButtons.length)];
|
|
nextButton.click();
|
|
const modalImage2 = gradioApp().getElementById("modalImage");
|
|
const modal3 = gradioApp().getElementById("lightboxModal");
|
|
modalImage2.src = nextButton.children[0].src;
|
|
if (modalImage2.style.display === "none") modal3.style.setProperty("background-image", `url(${modalImage2.src})`);
|
|
return;
|
|
}
|
|
}
|
|
const galleryFilesContainer = gradioApp().getElementById("tab-gallery-files");
|
|
if (!galleryFilesContainer || !galleryFilesContainer.offsetParent) return;
|
|
const gallerySelection2 = window.getGallerySelection();
|
|
if (!gallerySelection2.files.length || gallerySelection2.files.length <= 1) return;
|
|
const baseIndex = gallerySelection2.index >= 0 ? gallerySelection2.index : 0;
|
|
const nextIndex = negmod(baseIndex + offset, gallerySelection2.files.length);
|
|
window.setGallerySelection(nextIndex, { send: true });
|
|
const modalImage = gradioApp().getElementById("modalImage");
|
|
const modal2 = gradioApp().getElementById("lightboxModal");
|
|
const directSrc = window.getGallerySelectedUrl();
|
|
if (modalImage && modal2 && directSrc) {
|
|
modalImage.src = directSrc;
|
|
if (modalImage.style.display === "none") modal2.style.setProperty("background-image", `url(${directSrc})`);
|
|
}
|
|
}
|
|
function modalSaveImage(event2) {
|
|
const tabName = getENActiveTab();
|
|
const saveBtn = gradioApp().getElementById(`save_${tabName}`);
|
|
log("modalSaveImage", tabName, saveBtn);
|
|
if (saveBtn) saveBtn.click();
|
|
modalImageSwitch(0);
|
|
}
|
|
function modalKeyHandler(event2) {
|
|
log("modalKeyHandler", event2.key);
|
|
switch (event2.key) {
|
|
case "s":
|
|
modalSaveImage();
|
|
break;
|
|
case "ArrowLeft":
|
|
modalImageSwitch(-1);
|
|
break;
|
|
case "ArrowRight":
|
|
modalImageSwitch(1);
|
|
break;
|
|
case "Escape":
|
|
closeModal(null, true);
|
|
break;
|
|
}
|
|
event2.stopPropagation();
|
|
}
|
|
function decodeBytes(bytes) {
|
|
if (!bytes || bytes.length < 8) return "";
|
|
const prefix = new TextDecoder("ascii").decode(bytes.slice(0, 8));
|
|
const data = bytes.slice(8);
|
|
if (prefix.startsWith("ASCII")) return new TextDecoder("ascii").decode(data).replace(/\0+$/, "");
|
|
if (prefix.startsWith("UNICODE")) return new TextDecoder("utf-16be").decode(data).replace(/\0+$/, "");
|
|
if (prefix.startsWith("JIS")) return new TextDecoder("shift-jis").decode(data).replace(/\0+$/, "");
|
|
return new TextDecoder().decode(bytes).replace(/\0+$/, "");
|
|
}
|
|
async function getExif(el2) {
|
|
let exif = "";
|
|
try {
|
|
exif = await import_exifr.default.parse(el2, { userComment: true });
|
|
} catch (e) {
|
|
log("getExif", el2, e);
|
|
return exif;
|
|
}
|
|
let html = "";
|
|
let params;
|
|
if (!exif) {
|
|
log("getExif", "exif is none");
|
|
return html;
|
|
}
|
|
if (exif.parameters) params = exif.parameters;
|
|
else if (exif.userComment) params = decodeBytes(exif.userComment);
|
|
else params = "";
|
|
if (params.length > 0) html += `<b>Prompt</b> ${params || ""}<br>`;
|
|
html = html.replace("Negative prompt:", "<br><b>Negative</b>");
|
|
html = html.replace("Steps:", "<br><b>Params</b> Steps:");
|
|
html = html.replaceAll("\n", "<br>");
|
|
html = html.replaceAll("<br><br>", "<br>");
|
|
return html;
|
|
}
|
|
async function displayExif(el2) {
|
|
const modalExif = gradioApp().getElementById("modalExif");
|
|
const html = await getExif(el2);
|
|
modalExif.innerHTML = html;
|
|
}
|
|
function showModal(event2) {
|
|
const source = event2.target || event2.srcElement;
|
|
const modalImage = gradioApp().getElementById("modalImage");
|
|
const lb = gradioApp().getElementById("lightboxModal");
|
|
lb.ownerSVGElement = modalImage;
|
|
modalImage.onload = () => {
|
|
previewInstance.moveTo(0, 0);
|
|
modalPreviewZone.focus();
|
|
if (opts.viewer_show_metadata) displayExif(modalImage);
|
|
};
|
|
modalImage.src = source.src;
|
|
if (modalImage.style.display === "none") lb.style.setProperty("background-image", `url(${source.src})`);
|
|
lb.style.display = "flex";
|
|
lb.onkeydown = modalKeyHandler;
|
|
event2.stopPropagation();
|
|
}
|
|
function modalDownloadImage() {
|
|
const link = document.createElement("a");
|
|
link.style.display = "none";
|
|
link.href = gradioApp().getElementById("modalImage").src;
|
|
link.download = "image";
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
setTimeout(() => {
|
|
URL.revokeObjectURL(link.href);
|
|
link.parentNode.removeChild(link);
|
|
}, 0);
|
|
}
|
|
function modalZoomSet(modalImage, enable) {
|
|
localStorage.setItem("modalZoom", enable ? "yes" : "no");
|
|
if (modalImage) modalImage.classList.toggle("modalImageFullscreen", !!enable);
|
|
}
|
|
function setupImageForLightbox(image) {
|
|
if (image.dataset.modded) return;
|
|
image.dataset.modded = "true";
|
|
image.style.cursor = "pointer";
|
|
image.style.userSelect = "none";
|
|
}
|
|
function modalZoomToggle(event2) {
|
|
const modalImage = gradioApp().getElementById("modalImage");
|
|
modalZoomSet(modalImage, !modalImage.classList.contains("modalImageFullscreen"));
|
|
event2.stopPropagation();
|
|
modalImageSwitch(0);
|
|
}
|
|
function modalTileToggle(event2) {
|
|
const modalImage = gradioApp().getElementById("modalImage");
|
|
const modal2 = gradioApp().getElementById("lightboxModal");
|
|
const isTiling = modalImage.style.display === "none";
|
|
if (isTiling) {
|
|
modalImage.style.display = "block";
|
|
modal2.style.setProperty("background-image", "none");
|
|
} else {
|
|
modalImage.style.display = "none";
|
|
modal2.style.setProperty("background-image", `url(${modalImage.src})`);
|
|
}
|
|
event2.stopPropagation();
|
|
modalImageSwitch(0);
|
|
}
|
|
function modalResetInstance(event2) {
|
|
const modalImage = document.getElementById("modalImage");
|
|
previewInstance.dispose();
|
|
previewInstance = (0, import_panzoom.default)(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5, filterKey: () => true });
|
|
event2.stopPropagation();
|
|
modalImageSwitch(0);
|
|
}
|
|
function modalToggleParams(event2) {
|
|
const modalExif = gradioApp().getElementById("modalExif");
|
|
if (modalExif.style.display === "none" || modalExif.style.display === "") {
|
|
modalExif.style.display = "block";
|
|
} else {
|
|
modalExif.style.display = "none";
|
|
}
|
|
event2.stopPropagation();
|
|
modalImageSwitch(0);
|
|
}
|
|
function galleryClickEventHandler(event2) {
|
|
if (event2.button !== 0) return;
|
|
if (event2.target.nodeName === "IMG" && !event2.target.parentNode.classList.contains("thumbnail-item")) {
|
|
const initialZoom = (localStorage.getItem("modalZoom") || true) === "yes";
|
|
modalZoomSet(gradioApp().getElementById("modalImage"), initialZoom);
|
|
event2.preventDefault();
|
|
showModal(event2);
|
|
}
|
|
}
|
|
async function bindImageViewer() {
|
|
const galleryPreviews = gradioApp().querySelectorAll(".gradio-gallery > div.preview");
|
|
for (const galleryPreview of galleryPreviews) {
|
|
if (!galleryPreview.hasAttribute("data-listener")) galleryPreview.addEventListener("click", galleryClickEventHandler, true);
|
|
galleryPreview.setAttribute("data-listener", "true");
|
|
galleryPreview.querySelectorAll("img").forEach(setupImageForLightbox);
|
|
}
|
|
}
|
|
async function initImageViewer() {
|
|
const t0 = performance.now();
|
|
const modal2 = document.createElement("div");
|
|
modal2.id = "lightboxModal";
|
|
modalPreviewZone = document.createElement("div");
|
|
modalPreviewZone.className = "lightboxModalPreviewZone";
|
|
const modalImage = document.createElement("img");
|
|
modalImage.id = "modalImage";
|
|
modalPreviewZone.appendChild(modalImage);
|
|
previewInstance = (0, import_panzoom.default)(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5, filterKey: () => true });
|
|
const modalZoom = document.createElement("span");
|
|
modalZoom.id = "modal_zoom";
|
|
modalZoom.className = "cursor";
|
|
modalZoom.innerHTML = "\uF531";
|
|
modalZoom.title = "Toggle zoomed view";
|
|
modalZoom.addEventListener("click", modalZoomToggle, true);
|
|
const modalReset = document.createElement("span");
|
|
modalReset.id = "modal_reset";
|
|
modalReset.className = "cursor";
|
|
modalReset.innerHTML = "\uF532";
|
|
modalReset.title = "Reset zoomed view";
|
|
modalReset.addEventListener("click", modalResetInstance, true);
|
|
const modalTile = document.createElement("span");
|
|
modalTile.id = "modal_tile";
|
|
modalTile.className = "cursor";
|
|
modalTile.innerHTML = "\u{F0570}";
|
|
modalTile.title = "Preview tiling";
|
|
modalTile.addEventListener("click", modalTileToggle, true);
|
|
const modalSave = document.createElement("span");
|
|
modalSave.id = "modal_save";
|
|
modalSave.className = "cursor";
|
|
modalSave.innerHTML = "\u{F0193}";
|
|
modalSave.title = "Save Image";
|
|
modalSave.addEventListener("click", modalSaveImage, true);
|
|
const modalDownload = document.createElement("span");
|
|
modalDownload.id = "modal_download";
|
|
modalDownload.className = "cursor";
|
|
modalDownload.innerHTML = "\u{F1462}";
|
|
modalDownload.title = "Download Image";
|
|
modalDownload.addEventListener("click", modalDownloadImage, true);
|
|
const modalClose = document.createElement("span");
|
|
modalClose.id = "modal_close";
|
|
modalClose.className = "cursor";
|
|
modalClose.innerHTML = "\u{F0157}";
|
|
modalClose.title = "Close";
|
|
modalClose.addEventListener("click", (evt) => closeModal(evt, true), true);
|
|
const modalToggleParamsBtn = document.createElement("span");
|
|
modalToggleParamsBtn.id = "modal_toggle_params";
|
|
modalToggleParamsBtn.className = "cursor";
|
|
modalToggleParamsBtn.innerHTML = "\uF05A";
|
|
modalToggleParamsBtn.title = "Toggle Parameters";
|
|
modalToggleParamsBtn.addEventListener("click", modalToggleParams, true);
|
|
const modalExif = document.createElement("div");
|
|
modalExif.id = "modalExif";
|
|
modalExif.style = "position: absolute; bottom: 0px; width: 100%; background-color: rgba(0, 0, 0, 0.5); color: var(--neutral-300); padding: 1em; font-size: small; line-height: 1.2em; z-index: 1; display: none;";
|
|
modalPreviewZone.addEventListener("mousedown", () => {
|
|
previewDrag = false;
|
|
});
|
|
modalPreviewZone.addEventListener("touchstart", () => {
|
|
previewDrag = false;
|
|
}, { passive: true });
|
|
modalPreviewZone.addEventListener("mousemove", () => {
|
|
previewDrag = true;
|
|
});
|
|
modalPreviewZone.addEventListener("touchmove", () => {
|
|
previewDrag = true;
|
|
}, { passive: true });
|
|
modalPreviewZone.addEventListener("scroll", () => {
|
|
previewDrag = true;
|
|
});
|
|
modalPreviewZone.addEventListener("mouseup", (evt) => closeModal(evt));
|
|
modalPreviewZone.addEventListener("touchend", (evt) => closeModal(evt));
|
|
const modalPrev = document.createElement("a");
|
|
modalPrev.className = "modalPrev";
|
|
modalPrev.innerHTML = "❮";
|
|
modalPrev.addEventListener("click", () => modalImageSwitch(-1), true);
|
|
const modalNext = document.createElement("a");
|
|
modalNext.className = "modalNext";
|
|
modalNext.innerHTML = "❯";
|
|
modalNext.addEventListener("click", () => modalImageSwitch(1), true);
|
|
const modalControls = document.createElement("div");
|
|
modalControls.className = "modalControls gradio-container";
|
|
modal2.appendChild(modalPrev);
|
|
modal2.appendChild(modalPreviewZone);
|
|
modal2.appendChild(modalNext);
|
|
modal2.append(modalControls);
|
|
modalControls.appendChild(modalZoom);
|
|
modalControls.appendChild(modalReset);
|
|
modalControls.appendChild(modalTile);
|
|
modalControls.appendChild(modalSave);
|
|
modalControls.appendChild(modalDownload);
|
|
modalControls.appendChild(modalToggleParamsBtn);
|
|
modalControls.appendChild(modalClose);
|
|
modal2.append(modalExif);
|
|
gradioApp().appendChild(modal2);
|
|
const t1 = performance.now();
|
|
log("initImageViewer", Math.round(t1 - t0));
|
|
timer("initImageViewer", t1 - t0);
|
|
}
|
|
onAfterUiUpdate(bindImageViewer);
|
|
|
|
// ui/autocomplete_xn.ts
|
|
function lowerBound(items, query) {
|
|
let lo = 0;
|
|
let hi = items.length;
|
|
while (lo < hi) {
|
|
const mid = lo + hi >>> 1;
|
|
if (items[mid].name < query) lo = mid + 1;
|
|
else hi = mid;
|
|
}
|
|
return lo;
|
|
}
|
|
var XnIndex = class {
|
|
items;
|
|
constructor(items) {
|
|
this.items = items.map(({ name, display }) => ({
|
|
name: String(name).toLowerCase(),
|
|
display: display ?? name
|
|
}));
|
|
this.items.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
search(prefix, limit = 20) {
|
|
const query = String(prefix).toLowerCase();
|
|
if (!query) return this.items.slice(0, limit);
|
|
const start = lowerBound(this.items, query);
|
|
const matches = [];
|
|
for (let i = start; i < this.items.length && matches.length < limit; i++) {
|
|
if (!this.items[i].name.startsWith(query)) break;
|
|
matches.push(this.items[i]);
|
|
}
|
|
if (matches.length === 0 && query.length >= 3) {
|
|
for (let i = 0; i < this.items.length && matches.length < limit; i++) {
|
|
if (this.items[i].name.includes(query)) matches.push(this.items[i]);
|
|
}
|
|
}
|
|
return matches.slice(0, limit);
|
|
}
|
|
};
|
|
var xnEngine = {
|
|
lora: new XnIndex([]),
|
|
embed: new XnIndex([]),
|
|
wildcard: new XnIndex([]),
|
|
async fetchJson(path) {
|
|
try {
|
|
const resp = await fetch(`${window.api}${path}`, { credentials: "include" });
|
|
if (!resp.ok) throw new Error(`${resp.status}`);
|
|
return await resp.json();
|
|
} catch (e) {
|
|
log("autoComplete", { xnFetchFailed: path, error: String(e) });
|
|
return null;
|
|
}
|
|
},
|
|
async loadAll() {
|
|
const loraData = await this.fetchJson("/loras");
|
|
if (Array.isArray(loraData)) {
|
|
const items = [];
|
|
for (const lo of loraData) {
|
|
if (typeof lo === "object" && lo && "name" in lo && typeof lo.name === "string") items.push({ name: lo.name });
|
|
if (typeof lo === "object" && lo && "alias" in lo && typeof lo.alias === "string" && lo.alias !== lo.name) items.push({ name: lo.alias });
|
|
}
|
|
this.lora = new XnIndex(items);
|
|
}
|
|
const embData = await this.fetchJson("/embeddings");
|
|
if (embData && typeof embData === "object") {
|
|
const loaded = Array.isArray(embData.loaded) ? embData.loaded : [];
|
|
this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) })));
|
|
}
|
|
const wcData = await this.fetchJson("/wildcards");
|
|
if (Array.isArray(wcData)) {
|
|
this.wildcard = new XnIndex(
|
|
wcData.filter((w) => typeof w === "object" && w && "name" in w && typeof w.name === "string").map((w) => ({ name: w.name }))
|
|
);
|
|
}
|
|
log("autoComplete", {
|
|
xnLoaded: true,
|
|
lora: this.lora.items.length,
|
|
embed: this.embed.items.length,
|
|
wildcard: this.wildcard.items.length
|
|
});
|
|
},
|
|
searchLoras(prefix, limit = 20) {
|
|
return this.lora.search(prefix, limit).map((item) => ({ ...item, kind: "lora" }));
|
|
},
|
|
searchEmbeddings(prefix, limit = 20) {
|
|
return this.embed.search(prefix, limit).map((item) => ({ ...item, kind: "embed" }));
|
|
},
|
|
searchWildcards(prefix, limit = 20) {
|
|
return this.wildcard.search(prefix, limit).map((item) => ({ ...item, kind: "wildcard" }));
|
|
}
|
|
};
|
|
|
|
// ui/autocomplete.ts
|
|
var CATEGORY_COLORS = {
|
|
0: "#0075f8",
|
|
// general
|
|
1: "#cc0000",
|
|
// artist
|
|
2: "#ff4500",
|
|
// studio
|
|
3: "#9900ff",
|
|
// copyright
|
|
4: "#00ab2c",
|
|
// character
|
|
5: "#ed5d1f",
|
|
// species
|
|
6: "#8a66ff",
|
|
// genre
|
|
7: "#00cccc",
|
|
// medium
|
|
8: "#6b7280",
|
|
// meta
|
|
9: "#228b22",
|
|
// lore
|
|
10: "#e67e22",
|
|
// lens
|
|
11: "#f1c40f",
|
|
// lighting
|
|
12: "#1abc9c",
|
|
// composition
|
|
13: "#e84393"
|
|
// color
|
|
};
|
|
var CATEGORY_NAMES = {
|
|
0: "general",
|
|
1: "artist",
|
|
2: "studio",
|
|
3: "copyright",
|
|
4: "character",
|
|
5: "species",
|
|
6: "genre",
|
|
7: "medium",
|
|
8: "meta",
|
|
9: "lore",
|
|
10: "lens",
|
|
11: "lighting",
|
|
12: "composition",
|
|
13: "color"
|
|
};
|
|
var KIND_GLYPHS = {
|
|
tag: { glyph: "\u25CF", color: null },
|
|
// color pulled from tag category
|
|
lora: { glyph: "\u25C6", color: "#8a66ff" },
|
|
embed: { glyph: "\u25B2", color: "#1abc9c" },
|
|
wildcard: { glyph: "\u2605", color: "#f1c40f" }
|
|
};
|
|
var active = false;
|
|
function formatCount(count) {
|
|
if (count >= 1e6) return `${(count / 1e6).toFixed(1)}M`;
|
|
if (count >= 1e3) return `${Math.round(count / 1e3)}k`;
|
|
return String(count);
|
|
}
|
|
var caretMirror = null;
|
|
var caretMarker = null;
|
|
var MIRROR_PROPS = [
|
|
"fontFamily",
|
|
"fontSize",
|
|
"fontWeight",
|
|
"fontStyle",
|
|
"lineHeight",
|
|
"letterSpacing",
|
|
"wordSpacing",
|
|
"textTransform",
|
|
"padding",
|
|
"border",
|
|
"boxSizing"
|
|
];
|
|
function caretViewportY(textarea) {
|
|
if (!caretMirror) {
|
|
caretMirror = document.createElement("div");
|
|
caretMirror.className = "autocomplete-mirror";
|
|
caretMirror.style.whiteSpace = "pre-wrap";
|
|
caretMirror.style.wordWrap = "break-word";
|
|
caretMirror.style.position = "absolute";
|
|
caretMirror.style.left = "-9999px";
|
|
caretMirror.style.overflow = "hidden";
|
|
caretMarker = document.createElement("span");
|
|
caretMarker.textContent = "\u200B";
|
|
document.body.appendChild(caretMirror);
|
|
}
|
|
const cs = getComputedStyle(textarea);
|
|
for (const p of MIRROR_PROPS) caretMirror.style[p] = cs[p];
|
|
caretMirror.style.width = `${textarea.offsetWidth}px`;
|
|
caretMirror.textContent = textarea.value.substring(0, textarea.selectionStart);
|
|
caretMirror.appendChild(caretMarker);
|
|
const offset = caretMarker.offsetTop + caretMarker.offsetHeight;
|
|
return textarea.getBoundingClientRect().top + offset - textarea.scrollTop;
|
|
}
|
|
var TagIndex = class {
|
|
categories;
|
|
tags;
|
|
aliasEntries;
|
|
translations;
|
|
tagByName;
|
|
translationEntries;
|
|
constructor(data) {
|
|
this.categories = data.categories || {};
|
|
this.tags = data.tags.map(([name, category, count, aliases = []]) => ({
|
|
name: name.toLowerCase(),
|
|
display: name,
|
|
category,
|
|
count,
|
|
aliases
|
|
}));
|
|
this.tags.sort((a, b) => a.name.localeCompare(b.name));
|
|
this.aliasEntries = [];
|
|
for (const tag of this.tags) {
|
|
if (!tag.aliases || tag.aliases.length === 0) continue;
|
|
for (const alias of tag.aliases) {
|
|
this.aliasEntries.push({ name: alias.toLowerCase(), display: alias, tag });
|
|
}
|
|
}
|
|
this.aliasEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
this.translations = /* @__PURE__ */ new Map();
|
|
this.tagByName = new Map(this.tags.map((t) => [t.name, t]));
|
|
if (data.translations && typeof data.translations === "object") {
|
|
for (const [foreign, canonical] of Object.entries(data.translations)) {
|
|
if (typeof foreign !== "string" || typeof canonical !== "string") continue;
|
|
this.translations.set(foreign.toLowerCase(), { canonical: canonical.toLowerCase(), foreign });
|
|
}
|
|
}
|
|
this.translationEntries = [...this.translations.entries()].map(([foreignLower, { canonical, foreign }]) => ({ name: foreignLower, foreign, canonical })).sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
/** Prefix search with binary search across canonical names and aliases. Returns matches sorted by count descending. */
|
|
search(prefix, limit = 20) {
|
|
const query = prefix.toLowerCase().replace(/ /g, "_");
|
|
if (!query) return [];
|
|
const matches = [];
|
|
const start = lowerBound(this.tags, query);
|
|
for (let i = start; i < this.tags.length && matches.length < limit * 5; i++) {
|
|
if (!this.tags[i].name.startsWith(query)) break;
|
|
matches.push(this.tags[i]);
|
|
}
|
|
const aliasStart = lowerBound(this.aliasEntries, query);
|
|
for (let i = aliasStart; i < this.aliasEntries.length && matches.length < limit * 10; i++) {
|
|
const entry = this.aliasEntries[i];
|
|
if (!entry.name.startsWith(query)) break;
|
|
matches.push({ ...entry.tag, matchedVia: "alias", matchedAlias: entry.display });
|
|
}
|
|
if (matches.length === 0 && query.length >= 4) {
|
|
for (let i = 0; i < this.tags.length && matches.length < limit * 5; i++) {
|
|
if (this.tags[i].name.includes(query)) matches.push(this.tags[i]);
|
|
}
|
|
for (let i = 0; i < this.aliasEntries.length && matches.length < limit * 10; i++) {
|
|
const entry = this.aliasEntries[i];
|
|
if (entry.name.includes(query)) matches.push({ ...entry.tag, matchedVia: "alias", matchedAlias: entry.display });
|
|
}
|
|
}
|
|
if (this.translationEntries.length > 0) {
|
|
const tStart = lowerBound(this.translationEntries, query);
|
|
for (let i = tStart; i < this.translationEntries.length && matches.length < limit * 10; i++) {
|
|
const entry = this.translationEntries[i];
|
|
if (!entry.name.startsWith(query)) break;
|
|
const canonicalTag = this.tagByName.get(entry.canonical);
|
|
if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: "translation", matchedTerm: entry.foreign });
|
|
}
|
|
if (query.length >= 2) {
|
|
for (let i = 0; i < this.translationEntries.length && matches.length < limit * 10; i++) {
|
|
const entry = this.translationEntries[i];
|
|
if (entry.name.includes(query) && !entry.name.startsWith(query)) {
|
|
const canonicalTag = this.tagByName.get(entry.canonical);
|
|
if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: "translation", matchedTerm: entry.foreign });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const seen = /* @__PURE__ */ new Map();
|
|
for (const tag of matches) {
|
|
const existing = seen.get(tag.name);
|
|
if (!existing || existing.matchedVia && !tag.matchedVia) seen.set(tag.name, tag);
|
|
}
|
|
const result = [...seen.values()];
|
|
result.sort((a, b) => b.count - a.count);
|
|
return result.slice(0, limit);
|
|
}
|
|
};
|
|
var engine = {
|
|
indices: /* @__PURE__ */ new Map(),
|
|
// name -> TagIndex
|
|
categoryColors: { ...CATEGORY_COLORS },
|
|
categoryNames: { ...CATEGORY_NAMES },
|
|
async loadEnabled() {
|
|
const enabled = window.opts?.autocomplete_enabled || [];
|
|
active = window.opts?.autocomplete_active || false;
|
|
if (!active) {
|
|
this.indices.clear();
|
|
return;
|
|
}
|
|
const t0 = performance.now();
|
|
const toLoad = enabled.filter((n) => !this.indices.has(n));
|
|
const toRemove = [...this.indices.keys()].filter((n) => !enabled.includes(n));
|
|
toRemove.forEach((n) => this.indices.delete(n));
|
|
await Promise.all(toLoad.map(async (name) => {
|
|
try {
|
|
const resp = await fetch(`${window.api}/autocomplete/${name}`, { credentials: "include" });
|
|
if (!resp.ok) throw new Error(`${resp.status}`);
|
|
const data = await resp.json();
|
|
this.indices.set(name, new TagIndex(data));
|
|
if (data.categories) {
|
|
Object.entries(data.categories).forEach(([id, cat]) => {
|
|
const category = cat;
|
|
if (category.color) this.categoryColors[id] = category.color;
|
|
if (category.name) this.categoryNames[id] = category.name;
|
|
});
|
|
}
|
|
const t1 = performance.now();
|
|
log("autoComplete", { loaded: name, tags: data.tags?.length || 0, time: Math.round(t1 - t0) });
|
|
timer(`autocompleteLoad:${name}`, t1 - t0);
|
|
} catch (e) {
|
|
log("autoComplete", { failed: name, error: e });
|
|
}
|
|
}));
|
|
},
|
|
searchAll(prefix, limit = 20) {
|
|
if (this.indices.size === 0) return [];
|
|
const all = [];
|
|
this.indices.forEach((index) => {
|
|
all.push(...index.search(prefix, limit));
|
|
});
|
|
const seen = /* @__PURE__ */ new Map();
|
|
all.forEach((tag) => {
|
|
const existing = seen.get(tag.name);
|
|
if (!existing || tag.count > existing.count) seen.set(tag.name, tag);
|
|
});
|
|
const results = [...seen.values()];
|
|
results.sort((a, b) => b.count - a.count);
|
|
return results.slice(0, limit);
|
|
}
|
|
};
|
|
function getCurrentWord(textarea) {
|
|
const { value, selectionStart } = textarea;
|
|
if (selectionStart !== textarea.selectionEnd) return null;
|
|
let wordStart = selectionStart;
|
|
while (wordStart > 0) {
|
|
const ch = value[wordStart - 1];
|
|
if (ch === "," || ch === "\n") break;
|
|
wordStart--;
|
|
}
|
|
while (wordStart < selectionStart && value[wordStart] === " ") wordStart++;
|
|
const segment = value.slice(wordStart, selectionStart);
|
|
const before = value.slice(0, selectionStart);
|
|
const lastOpen = before.lastIndexOf("<");
|
|
const lastClose = before.lastIndexOf(">");
|
|
if (lastOpen > lastClose && lastOpen >= wordStart) {
|
|
const inside = before.slice(lastOpen + 1);
|
|
const colon = inside.indexOf(":");
|
|
if (colon < 0) {
|
|
return { word: "", start: lastOpen, end: selectionStart, mode: "lora" };
|
|
}
|
|
if (inside.slice(0, colon).toLowerCase() === "lora") {
|
|
return { word: inside.slice(colon + 1), start: lastOpen, end: selectionStart, mode: "lora" };
|
|
}
|
|
return null;
|
|
}
|
|
if (segment.startsWith("__") && !segment.slice(2).includes("__")) {
|
|
return { word: segment.slice(2), start: wordStart, end: selectionStart, mode: "wildcard" };
|
|
}
|
|
if (segment.startsWith("@")) {
|
|
return { word: segment.slice(1), start: wordStart, end: selectionStart, mode: "artist" };
|
|
}
|
|
if (!segment) return null;
|
|
return { word: segment, start: wordStart, end: selectionStart, mode: "tag" };
|
|
}
|
|
var ARTIST_CATEGORY_ID = 1;
|
|
function escapeParensForPrompt(name) {
|
|
return name.replace(/([()])/g, "\\$1");
|
|
}
|
|
function insertExtraNetwork(textarea, item, kind) {
|
|
const info = getCurrentWord(textarea);
|
|
if (!info || info.mode !== kind) return;
|
|
const { value } = textarea;
|
|
const before = value.slice(0, info.start);
|
|
const after = value.slice(info.end);
|
|
let insertion;
|
|
if (kind === "lora") {
|
|
insertion = `<lora:${item.display ?? item.name}:1.0>`;
|
|
} else if (kind === "wildcard") {
|
|
insertion = `__${item.display ?? item.name}__`;
|
|
} else {
|
|
return;
|
|
}
|
|
textarea.value = before + insertion + after;
|
|
const cursorPos = before.length + insertion.length;
|
|
textarea.selectionStart = cursorPos;
|
|
textarea.selectionEnd = cursorPos;
|
|
if (typeof updateInput2 === "function") updateInput2(textarea);
|
|
}
|
|
function insertTag(textarea, tagName, kind = "tag") {
|
|
const info = getCurrentWord(textarea);
|
|
if (!info || info.mode !== "tag" && info.mode !== "artist") return;
|
|
const { value } = textarea;
|
|
const before = value.slice(0, info.start);
|
|
const after = value.slice(info.end);
|
|
const useComma = window.opts?.autocomplete_append_comma ?? true;
|
|
const sep = useComma ? "," : "";
|
|
const needsSepBefore = before.length > 0 && before.trimEnd().length > 0 && !before.trimEnd().endsWith(",");
|
|
const prefix = needsSepBefore ? `${sep} ` : "";
|
|
let suffix = `${sep} `;
|
|
if (after.length > 0 && after.trimStart().startsWith(",")) suffix = " ";
|
|
const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;
|
|
let body = tagName;
|
|
if (kind !== "embed" && !keepUnderscores) body = body.replace(/_/g, " ");
|
|
if (info.mode === "artist" && window.opts?.autocomplete_at_prefix_artist) body = `@${body}`;
|
|
const insertion = `${prefix}${escapeParensForPrompt(body)}${suffix}`;
|
|
textarea.value = before.trimEnd() + (before.trimEnd().length > 0 ? " " : "") + insertion + after.trimStart();
|
|
const cursorPos = before.trimEnd().length + (before.trimEnd().length > 0 ? 1 : 0) + insertion.length;
|
|
textarea.selectionStart = cursorPos;
|
|
textarea.selectionEnd = cursorPos;
|
|
if (typeof updateInput2 === "function") updateInput2(textarea);
|
|
}
|
|
var dropdown = {
|
|
el: null,
|
|
listEl: null,
|
|
selectedIndex: -1,
|
|
results: [],
|
|
textarea: null,
|
|
query: "",
|
|
visible: false,
|
|
resizeObserver: null,
|
|
init() {
|
|
this.el = document.createElement("div");
|
|
this.el.className = "autocompleteResults";
|
|
this.el.style.display = "none";
|
|
this.listEl = document.createElement("ul");
|
|
this.listEl.className = "autocompleteResultsList";
|
|
this.el.appendChild(this.listEl);
|
|
document.body.appendChild(this.el);
|
|
this.el.addEventListener("mousedown", (e) => e.preventDefault());
|
|
this.el.addEventListener("click", (e) => {
|
|
const li = e.target.closest("li");
|
|
if (!li) return;
|
|
const idx = [...this.listEl.children].indexOf(li);
|
|
if (idx >= 0 && idx < this.results.length) {
|
|
this.selectedIndex = idx;
|
|
this.accept();
|
|
}
|
|
});
|
|
this.resizeObserver = new ResizeObserver(() => {
|
|
if (this.visible) this.position();
|
|
});
|
|
},
|
|
show(results, textarea, query) {
|
|
if (results.length === 0) {
|
|
this.hide();
|
|
return;
|
|
}
|
|
if (this.textarea && this.textarea !== textarea) this.hide();
|
|
if (this.textarea !== textarea) this.resizeObserver?.observe(textarea);
|
|
this.results = results;
|
|
this.textarea = textarea;
|
|
this.query = query || "";
|
|
this.selectedIndex = -1;
|
|
this.render();
|
|
this.position();
|
|
this.el.style.display = "";
|
|
this.visible = true;
|
|
},
|
|
hide() {
|
|
if (this.textarea) this.resizeObserver?.unobserve(this.textarea);
|
|
this.textarea = null;
|
|
this.el.style.display = "none";
|
|
this.visible = false;
|
|
this.results = [];
|
|
this.selectedIndex = -1;
|
|
},
|
|
render() {
|
|
const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;
|
|
const queryNorm = this.query.toLowerCase().replace(/ /g, "_");
|
|
this.listEl.replaceChildren();
|
|
this.results.forEach((tag, i) => {
|
|
const li = document.createElement("li");
|
|
if (i === this.selectedIndex) li.classList.add("selected");
|
|
const dot = document.createElement("span");
|
|
dot.className = "autocomplete-category";
|
|
const kind = tag.kind || "tag";
|
|
const kindStyle = KIND_GLYPHS[kind] || KIND_GLYPHS.tag;
|
|
dot.style.color = kindStyle.color || engine.categoryColors[tag.category] || "#888";
|
|
dot.textContent = kindStyle.glyph;
|
|
dot.title = kind === "tag" ? engine.categoryNames[tag.category] || "" : kind;
|
|
const name = document.createElement("span");
|
|
name.className = "autocomplete-tag";
|
|
const swapForKind = kind !== "embed";
|
|
const tagText = swapForKind && !keepUnderscores ? tag.display.replace(/_/g, " ") : tag.display;
|
|
const canonicalMatch = tag.name.indexOf(queryNorm);
|
|
if (canonicalMatch >= 0 && queryNorm.length > 0) {
|
|
const mark = document.createElement("mark");
|
|
mark.textContent = tagText.slice(canonicalMatch, canonicalMatch + queryNorm.length);
|
|
name.append(
|
|
document.createTextNode(tagText.slice(0, canonicalMatch)),
|
|
mark,
|
|
document.createTextNode(tagText.slice(canonicalMatch + queryNorm.length))
|
|
);
|
|
} else {
|
|
name.textContent = tagText;
|
|
}
|
|
let annotationTerm = null;
|
|
if (tag.matchedVia === "alias") annotationTerm = tag.matchedAlias;
|
|
else if (tag.matchedVia === "translation") annotationTerm = tag.matchedTerm;
|
|
if (annotationTerm) {
|
|
const annotationDisplay = swapForKind && !keepUnderscores ? annotationTerm.replace(/_/g, " ") : annotationTerm;
|
|
const annotationLower = annotationTerm.toLowerCase();
|
|
const annotationMatch = annotationLower.indexOf(queryNorm);
|
|
const prefix = tag.matchedVia === "translation" ? " \u{1F310} " : " (";
|
|
const suffix = tag.matchedVia === "translation" ? "" : ")";
|
|
name.appendChild(document.createTextNode(prefix));
|
|
if (annotationMatch >= 0 && queryNorm.length > 0) {
|
|
const mark = document.createElement("mark");
|
|
mark.textContent = annotationDisplay.slice(annotationMatch, annotationMatch + queryNorm.length);
|
|
name.append(
|
|
document.createTextNode(annotationDisplay.slice(0, annotationMatch)),
|
|
mark,
|
|
document.createTextNode(annotationDisplay.slice(annotationMatch + queryNorm.length))
|
|
);
|
|
} else {
|
|
name.appendChild(document.createTextNode(annotationDisplay));
|
|
}
|
|
if (suffix) name.appendChild(document.createTextNode(suffix));
|
|
}
|
|
const count = document.createElement("span");
|
|
count.className = "autocomplete-count";
|
|
count.textContent = tag.count > 0 ? formatCount(tag.count) : "";
|
|
li.append(dot, name, count);
|
|
li.addEventListener("mouseenter", () => {
|
|
this.selectedIndex = i;
|
|
this.updateSelection();
|
|
});
|
|
this.listEl.appendChild(li);
|
|
});
|
|
},
|
|
position() {
|
|
if (!this.textarea) return;
|
|
const rect = this.textarea.getBoundingClientRect();
|
|
const cursorBottom = caretViewportY(this.textarea);
|
|
const anchorY = Math.max(rect.top, Math.min(cursorBottom, rect.bottom));
|
|
const spaceBelow = window.innerHeight - anchorY;
|
|
const dropHeight = Math.min(this.el.scrollHeight, 300);
|
|
if (spaceBelow >= dropHeight || spaceBelow >= anchorY - rect.top) {
|
|
this.el.style.top = `${anchorY + 2}px`;
|
|
} else {
|
|
this.el.style.top = `${anchorY - dropHeight - 2}px`;
|
|
}
|
|
this.el.style.left = `${rect.left}px`;
|
|
this.el.style.width = `${rect.width}px`;
|
|
},
|
|
updateSelection() {
|
|
[...this.listEl.children].forEach((li, i) => {
|
|
li.classList.toggle("selected", i === this.selectedIndex);
|
|
});
|
|
const selected = this.listEl.children[this.selectedIndex];
|
|
if (selected) selected.scrollIntoView({ block: "nearest" });
|
|
},
|
|
navigate(dir) {
|
|
if (this.results.length === 0) return;
|
|
if (this.selectedIndex === -1) {
|
|
this.selectedIndex = dir > 0 ? 0 : this.results.length - 1;
|
|
} else {
|
|
this.selectedIndex = (this.selectedIndex + dir + this.results.length) % this.results.length;
|
|
}
|
|
this.updateSelection();
|
|
},
|
|
accept() {
|
|
if (this.selectedIndex < 0 || this.selectedIndex >= this.results.length) {
|
|
if (this.results.length > 0) {
|
|
this.selectedIndex = 0;
|
|
this.updateSelection();
|
|
}
|
|
return;
|
|
}
|
|
const result = this.results[this.selectedIndex];
|
|
if (this.textarea) {
|
|
if (result.kind === "lora" || result.kind === "wildcard") {
|
|
insertExtraNetwork(this.textarea, result, result.kind);
|
|
} else {
|
|
insertTag(this.textarea, result.display ?? result.name, result.kind);
|
|
}
|
|
}
|
|
this.hide();
|
|
}
|
|
};
|
|
var debounceInput;
|
|
var debounceFocus;
|
|
function onInput(textarea) {
|
|
if (!active) return;
|
|
if (textarea.dataset.imeActive === "1") return;
|
|
const minChars = window.opts?.autocomplete_min_chars ?? 3;
|
|
const info = getCurrentWord(textarea);
|
|
if (!info) {
|
|
dropdown.hide();
|
|
return;
|
|
}
|
|
let threshold = minChars;
|
|
if (info.mode === "lora" || info.mode === "wildcard") threshold = 0;
|
|
else if (info.mode === "artist") threshold = 1;
|
|
if (info.word.length < threshold) {
|
|
dropdown.hide();
|
|
return;
|
|
}
|
|
clearTimeout(debounceInput);
|
|
debounceInput = setTimeout(() => {
|
|
let results;
|
|
if (info.mode === "lora") {
|
|
results = xnEngine.searchLoras(info.word);
|
|
} else if (info.mode === "wildcard") {
|
|
results = xnEngine.searchWildcards(info.word);
|
|
} else if (info.mode === "artist") {
|
|
results = engine.searchAll(info.word).filter((t) => t.category === ARTIST_CATEGORY_ID);
|
|
} else {
|
|
const tagResults = engine.searchAll(info.word);
|
|
const embedResults = xnEngine.searchEmbeddings(info.word);
|
|
results = [...embedResults, ...tagResults];
|
|
}
|
|
dropdown.show(results, textarea, info.word);
|
|
}, 150);
|
|
}
|
|
function onKeyDown(e) {
|
|
if (!dropdown.visible) return;
|
|
if (e.isComposing) return;
|
|
const hasModifier = e.ctrlKey || e.metaKey || e.altKey;
|
|
switch (e.key) {
|
|
case "ArrowDown":
|
|
if (hasModifier) return;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
dropdown.navigate(1);
|
|
break;
|
|
case "ArrowUp":
|
|
if (hasModifier) return;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
dropdown.navigate(-1);
|
|
break;
|
|
case "Enter":
|
|
if (hasModifier) return;
|
|
if (dropdown.selectedIndex >= 0) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
dropdown.accept();
|
|
}
|
|
break;
|
|
case "Tab":
|
|
if (hasModifier) return;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
dropdown.accept();
|
|
break;
|
|
case "Escape":
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
dropdown.hide();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
function attachAutocomplete(textarea) {
|
|
textarea.addEventListener("input", () => onInput(textarea));
|
|
textarea.addEventListener("keydown", onKeyDown);
|
|
textarea.addEventListener("compositionstart", () => {
|
|
textarea.dataset.imeActive = "1";
|
|
});
|
|
textarea.addEventListener("compositionend", () => {
|
|
delete textarea.dataset.imeActive;
|
|
});
|
|
textarea.addEventListener("focusin", () => {
|
|
if (dropdown.visible && dropdown.textarea && dropdown.textarea !== textarea) dropdown.hide();
|
|
clearTimeout(debounceFocus);
|
|
debounceFocus = void 0;
|
|
onInput(textarea);
|
|
});
|
|
textarea.addEventListener("focusout", () => {
|
|
clearTimeout(debounceInput);
|
|
debounceFocus = setTimeout(() => dropdown.hide(), 200);
|
|
});
|
|
}
|
|
var PROMPT_IDS = [
|
|
"txt2img_prompt",
|
|
"txt2img_neg_prompt",
|
|
"img2img_prompt",
|
|
"img2img_neg_prompt",
|
|
"control_prompt",
|
|
"control_neg_prompt",
|
|
"video_prompt",
|
|
"video_neg_prompt"
|
|
];
|
|
function patchActiveButton() {
|
|
const buttons = [...gradioApp().querySelectorAll(".autocomplete-active")];
|
|
active = window.opts?.autocomplete_active || false;
|
|
buttons.forEach((btn) => {
|
|
btn.classList.toggle("autocomplete-active", active);
|
|
btn.classList.toggle("autocomplete-inactive", !active);
|
|
btn.parentElement.onclick = () => {
|
|
active = !active;
|
|
window.opts.autocomplete_active = !active;
|
|
btn.classList.toggle("autocomplete-active", active);
|
|
btn.classList.toggle("autocomplete-inactive", !active);
|
|
};
|
|
});
|
|
}
|
|
var bridgeWarnedMissingDescriptor = false;
|
|
function patchConfigBridge() {
|
|
const proto = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
|
|
if (!proto?.get || !proto?.set) {
|
|
if (!bridgeWarnedMissingDescriptor) {
|
|
log("autoComplete", { bridge: "skipped", reason: "HTMLTextAreaElement.prototype.value descriptor missing" });
|
|
bridgeWarnedMissingDescriptor = true;
|
|
}
|
|
return;
|
|
}
|
|
const elements = gradioApp().querySelectorAll('[id$="_tag_autocomplete_config_json"]');
|
|
for (const el2 of elements) {
|
|
const textarea = el2.querySelector("textarea");
|
|
if (!textarea || textarea.acBridgePatched) continue;
|
|
textarea.acBridgePatched = true;
|
|
Object.defineProperty(textarea, "value", {
|
|
set(newValue) {
|
|
const oldValue = proto.get.call(textarea);
|
|
proto.set.call(textarea, newValue);
|
|
if (oldValue !== newValue && newValue) {
|
|
try {
|
|
const cfg = JSON.parse(newValue);
|
|
for (const [key, val] of Object.entries(cfg)) window.opts[key] = val;
|
|
executeCallbacks(optionsChangedCallbacks);
|
|
} catch {
|
|
}
|
|
}
|
|
},
|
|
get() {
|
|
return proto.get.call(textarea);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
async function initAutocomplete() {
|
|
const t0 = performance.now();
|
|
const enabled = window.opts?.autocomplete_enabled || [];
|
|
active = window.opts?.autocomplete_active || false;
|
|
log("autoComplete", { active, enabled });
|
|
const style = document.createElement("style");
|
|
style.textContent = `
|
|
.autocompleteResults { position: fixed; z-index: 9999; max-height: 300px; overflow-y: auto;
|
|
background: var(--sd-main-background-color, var(--background-fill-primary, #1f2937));
|
|
border: 1px solid var(--sd-input-border-color, var(--border-color-primary, #374151));
|
|
border-radius: var(--sd-border-radius, 6px); box-shadow: 0 4px 16px rgba(0,0,0,0.4);
|
|
font-size: 13px; scrollbar-width: thin; color: var(--body-text-color-subdued); }
|
|
.autocompleteResultsList { list-style: none; margin: 0; padding: 4px 0; }
|
|
.autocompleteResultsList > li { display: flex; align-items: center; padding: 6px 12px; cursor: pointer;
|
|
gap: 8px; line-height: 1.4; transition: background 0.1s ease; border-bottom: 1px solid rgba(255,255,255,0.03); }
|
|
.autocompleteResultsList > li:last-child { border-bottom: none; }
|
|
.autocompleteResultsList > li:hover { background: var(--sd-panel-background-color, var(--input-background-fill-focus, #374151)); }
|
|
.autocompleteResultsList > li.selected { background: var(--sd-main-accent-color, var(--button-primary-background-fill, #4b5563)); }
|
|
.autocomplete-category { font-size: 10px; flex-shrink: 0; width: 10px; text-align: center; cursor: help; }
|
|
.autocomplete-tag { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.autocomplete-tag mark { background: transparent; color: inherit; font-weight: 700; }
|
|
.autocomplete-count { font-size: 0.75em; opacity: 0.45; flex-shrink: 0; font-variant-numeric: tabular-nums;
|
|
background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 8px; min-width: 28px; text-align: right; }
|
|
`;
|
|
document.head.appendChild(style);
|
|
dropdown.init();
|
|
await engine.loadEnabled();
|
|
xnEngine.loadAll();
|
|
let attached = 0;
|
|
PROMPT_IDS.forEach((id) => {
|
|
const textarea = gradioApp().querySelector(`#${id} > label > textarea`);
|
|
if (textarea) {
|
|
attachAutocomplete(textarea);
|
|
attached++;
|
|
}
|
|
});
|
|
async function optionsChangedCallback() {
|
|
const newActive = window.opts?.autocomplete_active || false;
|
|
const newEnabled = window.opts?.autocomplete_enabled || [];
|
|
const currentKeys = [...engine.indices.keys()].sort().join(",");
|
|
const newKeys = [...newEnabled].sort().join(",");
|
|
if (currentKeys !== newKeys || active !== newActive) {
|
|
log("autoComplete", { reload: newEnabled });
|
|
await engine.loadEnabled();
|
|
active = newActive;
|
|
patchActiveButton();
|
|
}
|
|
xnEngine.loadAll();
|
|
}
|
|
onOptionsChanged(optionsChangedCallback);
|
|
patchConfigBridge();
|
|
patchActiveButton();
|
|
onAfterUiUpdate(patchConfigBridge);
|
|
const t1 = performance.now();
|
|
log("autoComplete", { attached, dicts: engine.indices.size, time: Math.round(t1 - t0) });
|
|
timer("autocompleteInit", t1 - t0);
|
|
}
|
|
|
|
// ui/setHints.ts
|
|
var hintsObserver = null;
|
|
var allLocales = ["en", "tb", "nb", "hr", "es", "it", "fr", "de", "pt", "ru", "zh", "ja", "ko", "hi", "ar", "bn", "ur", "id", "vi", "tr", "sr", "po", "he", "xx", "qq", "tlh"];
|
|
var localeData = {
|
|
prev: null,
|
|
locale: null,
|
|
data: [],
|
|
timeout: null,
|
|
finished: false,
|
|
initial: true,
|
|
type: 2,
|
|
hint: null,
|
|
btn: null,
|
|
expandTimeout: void 0,
|
|
// Property for expansion timeout
|
|
currentElement: null
|
|
// Track current element for expansion
|
|
};
|
|
var localeTimeout;
|
|
var isTouchDevice = "ontouchstart" in window;
|
|
async function cycleLocale() {
|
|
clearTimeout(localeTimeout);
|
|
localeTimeout = setTimeout(() => {
|
|
log("cycleLocale", localeData.prev, localeData.locale);
|
|
const index = allLocales.indexOf(localeData.prev);
|
|
localeData.locale = allLocales[(index + 1) % allLocales.length];
|
|
localeData.btn.innerText = localeData.locale;
|
|
localeData.finished = false;
|
|
localeData.data = [];
|
|
localeData.prev = localeData.locale;
|
|
window.opts.ui_locale = localeData.locale;
|
|
setHints();
|
|
}, 250);
|
|
}
|
|
async function resetLocale() {
|
|
clearTimeout(localeTimeout);
|
|
localeData.locale = "en";
|
|
log("resetLocale", localeData.locale);
|
|
const index = allLocales.indexOf(localeData.locale);
|
|
localeData.locale = allLocales[index % allLocales.length];
|
|
localeData.btn.innerText = localeData.locale;
|
|
localeData.finished = false;
|
|
localeData.data = [];
|
|
window.opts.ui_locale = localeData.locale;
|
|
setHints();
|
|
}
|
|
async function tooltipCreate() {
|
|
localeData.hint = document.createElement("div");
|
|
localeData.hint.className = "tooltip";
|
|
localeData.hint.id = "tooltip-container";
|
|
localeData.hint.innerText = "this is a hint";
|
|
gradioApp().appendChild(localeData.hint);
|
|
localeData.btn = gradioApp().getElementById("locale-container");
|
|
if (!localeData.btn) {
|
|
localeData.btn = document.createElement("div");
|
|
localeData.btn.className = "locale";
|
|
localeData.btn.id = "locale-container";
|
|
gradioApp().appendChild(localeData.btn);
|
|
}
|
|
localeData.btn.innerText = localeData.locale;
|
|
localeData.btn.ondblclick = resetLocale;
|
|
localeData.btn.onclick = cycleLocale;
|
|
if (window.opts.tooltips === "None") localeData.type = 0;
|
|
if (window.opts.tooltips === "Browser default") localeData.type = 1;
|
|
if (window.opts.tooltips === "UI tooltips") localeData.type = 2;
|
|
if (localeData.type === 2) {
|
|
if (isTouchDevice) {
|
|
gradioApp().addEventListener("touchstart", tooltipShowDelegated);
|
|
gradioApp().addEventListener("touchend", tooltipHideDelegated);
|
|
}
|
|
gradioApp().addEventListener("pointerover", tooltipShowDelegated);
|
|
gradioApp().addEventListener("pointerout", tooltipHideDelegated);
|
|
}
|
|
if (!hintsObserver) initializeDOMObserver();
|
|
}
|
|
async function expandTooltip(element, longHint) {
|
|
if (localeData.currentElement === element && localeData.hint.classList.contains("tooltip-show")) {
|
|
const ring = localeData.hint.querySelector(".tooltip-progress-ring");
|
|
if (ring) ring.style.opacity = "0";
|
|
localeData.hint.classList.add("tooltip-expanded");
|
|
setTimeout(() => {
|
|
const longContent = localeData.hint.querySelector(".long-content");
|
|
if (longContent) longContent.classList.add("show");
|
|
}, 100);
|
|
}
|
|
}
|
|
async function tooltipShowDelegated(e) {
|
|
if (e.target.dataset && e.target.dataset.hint) tooltipShow(e);
|
|
}
|
|
async function tooltipHideDelegated(e) {
|
|
if (e.target.dataset && e.target.dataset.hint) tooltipHide(e);
|
|
}
|
|
async function tooltipShow(e) {
|
|
if (localeData.expandTimeout) {
|
|
clearTimeout(localeData.expandTimeout);
|
|
localeData.expandTimeout = void 0;
|
|
}
|
|
localeData.hint.classList.remove("tooltip-expanded");
|
|
localeData.currentElement = e.target;
|
|
if (e.target.dataset.hint) {
|
|
const progressRing = ` // create progress ring SVG
|
|
<div class="tooltip-progress-ring">
|
|
<svg viewBox="0 0 12 12">
|
|
<circle class="ring-background" cx="6" cy="6" r="5"></circle>
|
|
<circle class="ring-progress" cx="6" cy="6" r="5"></circle>
|
|
</svg>
|
|
</div>
|
|
`;
|
|
let content = `
|
|
<div class="tooltip-header">
|
|
<b>${e.target.textContent}</b>
|
|
${e.target.dataset.longHint ? progressRing : ""}
|
|
</div>
|
|
<div class="separator"></div>
|
|
${e.target.dataset.hint}
|
|
`;
|
|
if (e.target.dataset.longHint) content += `<div class="long-content"><div class="separator"></div>${e.target.dataset.longHint}</div>`;
|
|
if (e.target.dataset.reload) {
|
|
const reloadType = e.target.dataset.reload;
|
|
let reloadText = "";
|
|
if (reloadType === "model") reloadText = "Requires model reload";
|
|
else if (reloadType === "server") reloadText = "Requires server restart";
|
|
if (reloadText) {
|
|
content += `
|
|
<div class="tooltip-reload-notice">
|
|
<div class="separator"></div>
|
|
<span class="tooltip-reload-text">${reloadText}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
localeData.hint.innerHTML = content;
|
|
localeData.hint.classList.add("tooltip-show");
|
|
if (e.clientX > window.innerWidth / 2) localeData.hint.classList.add("tooltip-left");
|
|
else localeData.hint.classList.remove("tooltip-left");
|
|
if (e.target.dataset.longHint) {
|
|
const ring = localeData.hint.querySelector(".tooltip-progress-ring");
|
|
const ringProgress = localeData.hint.querySelector(".ring-progress");
|
|
if (ring && ringProgress) {
|
|
setTimeout(() => {
|
|
ring.classList.add("active");
|
|
ringProgress.classList.add("animate");
|
|
}, 100);
|
|
}
|
|
localeData.expandTimeout = setTimeout(() => expandTooltip(e.target, e.target.dataset.longHint), 3e3);
|
|
}
|
|
}
|
|
}
|
|
async function tooltipHide(e) {
|
|
if (localeData.expandTimeout) {
|
|
clearTimeout(localeData.expandTimeout);
|
|
localeData.expandTimeout = void 0;
|
|
}
|
|
localeData.hint.classList.remove("tooltip-show", "tooltip-expanded");
|
|
localeData.currentElement = null;
|
|
}
|
|
async function getLocaleData(desiredLocale = null) {
|
|
if (desiredLocale) desiredLocale = desiredLocale.split(":")[0];
|
|
if (desiredLocale === "Auto") {
|
|
try {
|
|
localeData.locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;
|
|
localeData.locale = localeData.locale.split("-")[0];
|
|
localeData.prev = localeData.locale;
|
|
} catch (e) {
|
|
localeData.locale = "en";
|
|
log("getLocale", e);
|
|
}
|
|
} else {
|
|
localeData.locale = desiredLocale || "en";
|
|
localeData.prev = localeData.locale;
|
|
}
|
|
log("getLocale", desiredLocale, localeData.locale);
|
|
let json = {};
|
|
try {
|
|
let res = await fetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);
|
|
if (!res || !res.ok) {
|
|
localeData.locale = "en";
|
|
res = await fetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);
|
|
}
|
|
json = await res.json();
|
|
} catch {
|
|
}
|
|
try {
|
|
const res = await fetch(`${window.subpath}/file=ui/locale/override_${localeData.locale}.json`);
|
|
if (res && res.ok) json.override = await res.json();
|
|
} catch {
|
|
}
|
|
return json;
|
|
}
|
|
async function replaceTextContent(el2, text) {
|
|
if (el2.children.length === 1 && el2.firstElementChild.classList.contains("mask-icon")) return;
|
|
if (el2.querySelector("span")) el2 = el2.querySelector("span");
|
|
if (el2.querySelector("div")) el2 = el2.querySelector("div");
|
|
if (el2.classList.contains("mask-icon")) return;
|
|
if (el2.dataset.selector) {
|
|
el2 = el2.firstElementChild || el2.querySelector(el2.dataset.selector);
|
|
replaceTextContent(el2, text);
|
|
return;
|
|
}
|
|
el2.textContent = text;
|
|
}
|
|
async function setHint(el2, entry) {
|
|
if (localeData.type === 1) {
|
|
el2.title = entry.hint;
|
|
} else if (localeData.type === 2) {
|
|
el2.dataset.hint = entry.hint;
|
|
if (entry.longHint && entry.longHint.length > 0) el2.dataset.longHint = entry.longHint;
|
|
if (entry.reload && entry.reload.length > 0) el2.dataset.reload = entry.reload;
|
|
} else {
|
|
}
|
|
}
|
|
async function setHints() {
|
|
let json;
|
|
let overrideData = [];
|
|
if (localeData.finished) return;
|
|
if (Object.keys(opts).length === 0) return;
|
|
const elements = [.../* @__PURE__ */ new Set([
|
|
...Array.from(gradioApp().querySelectorAll("button")),
|
|
...Array.from(gradioApp().querySelectorAll("h2")),
|
|
...Array.from(gradioApp().querySelectorAll("label > span")),
|
|
...Array.from(gradioApp().querySelectorAll(".label-wrap > span")),
|
|
...Array.from(gradioApp().querySelectorAll('span[data-testid="block-info"]'))
|
|
// radio/checkboxgroup titles render as a bare block-info span, not under a label
|
|
])];
|
|
if (elements.length === 0) return;
|
|
if (localeData.data.length === 0) {
|
|
json = await getLocaleData(window.opts.ui_locale);
|
|
overrideData = Object.values(json.override || {}).flat().filter((e) => e.hint.length > 0);
|
|
const jsonData = Object.values(json).flat().filter((e) => e.hint.length > 0);
|
|
localeData.data = [...overrideData, ...jsonData];
|
|
}
|
|
if (!localeData.hint) tooltipCreate();
|
|
let localized = 0;
|
|
let hints = 0;
|
|
const t0 = performance.now();
|
|
for (const el2 of elements) {
|
|
let found;
|
|
if (el2.id) found = localeData.data.find((l) => l.id && (l.id === el2.id || el2.id.endsWith(l.id)));
|
|
if (!found) {
|
|
if (el2.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el2.dataset.original.toLowerCase().trim());
|
|
else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el2.textContent.toLowerCase().trim());
|
|
}
|
|
if (found?.localized?.length > 0) {
|
|
if (!el2.dataset.original) el2.dataset.original = el2.textContent;
|
|
replaceTextContent(el2, found.localized);
|
|
localized++;
|
|
} else if (found?.label && !localeData.initial && localeData.locale === "en") {
|
|
replaceTextContent(el2, found.label);
|
|
}
|
|
if (found?.hint?.length > 0) {
|
|
hints++;
|
|
setHint(el2, found);
|
|
}
|
|
}
|
|
localeData.finished = true;
|
|
localeData.initial = false;
|
|
const t1 = performance.now();
|
|
timer("setHints", t1 - t0);
|
|
log("touchDevice", isTouchDevice);
|
|
log("setHints", { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });
|
|
}
|
|
async function applyHintToElement(el2) {
|
|
if (!localeData.data || localeData.data.length === 0) return;
|
|
const isValidElement = el2.tagName === "BUTTON" || el2.tagName === "H2" || el2.classList.contains("hint") || el2.tagName === "SPAN" && (el2.parentElement?.tagName === "LABEL" || el2.parentElement?.classList.contains("label-wrap") || el2.dataset.testid === "block-info");
|
|
if (!isValidElement) return;
|
|
let found;
|
|
if (el2.id) found = localeData.data.find((l) => l.id && (l.id === el2.id || el2.id.endsWith(l.id)));
|
|
if (!found) {
|
|
if (el2.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el2.dataset.original.toLowerCase().trim());
|
|
else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el2.textContent.toLowerCase().trim());
|
|
}
|
|
if (el2.textContent && el2.textContent.length > 0 && found?.localized?.length > 0) {
|
|
if (!el2.dataset.original) el2.dataset.original = el2.textContent;
|
|
replaceTextContent(el2, found.localized);
|
|
}
|
|
if (found?.hint?.length > 0) setHint(el2, found);
|
|
}
|
|
function initializeDOMObserver() {
|
|
if (hintsObserver) hintsObserver.disconnect();
|
|
hintsObserver = new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
if (mutation.type === "childList") {
|
|
for (const node of mutation.addedNodes) {
|
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
applyHintToElement(node);
|
|
const elements = [
|
|
...Array.from(node.querySelectorAll("button")),
|
|
...Array.from(gradioApp().querySelectorAll("h1")),
|
|
...Array.from(gradioApp().querySelectorAll("h2")),
|
|
...Array.from(gradioApp().querySelectorAll("h3")),
|
|
...Array.from(gradioApp().querySelectorAll(".hint")),
|
|
...Array.from(node.querySelectorAll("label > span")),
|
|
...Array.from(node.querySelectorAll(".label-wrap > span")),
|
|
...Array.from(node.querySelectorAll('span[data-testid="block-info"]'))
|
|
];
|
|
if (node.matches && (node.matches("button") || node.matches("h1") || node.matches("h2") || node.matches("h3") || node.matches("label > span") || node.matches(".hint") || node.matches(".label-wrap > span") || node.matches('span[data-testid="block-info"]'))) {
|
|
elements.push(node);
|
|
}
|
|
elements.forEach((el2) => applyHintToElement(el2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
const targetNode = gradioApp();
|
|
if (targetNode) {
|
|
hintsObserver.observe(targetNode, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
}
|
|
}
|
|
function disconnectHintsObserver() {
|
|
if (hintsObserver) {
|
|
hintsObserver.disconnect();
|
|
hintsObserver = null;
|
|
}
|
|
}
|
|
|
|
// ui/contextMenus.ts
|
|
var contextMenuInit = () => {
|
|
let eventListenerApplied = false;
|
|
const menuSpecs = /* @__PURE__ */ new Map();
|
|
const uid = () => Date.now().toString(36) + Math.random().toString(36).substring(2);
|
|
function showContextMenu(event2, _element, menuEntries) {
|
|
const posx = event2.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
|
|
const posy = event2.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
|
const oldMenu = gradioApp().querySelector("#context-menu");
|
|
if (oldMenu) oldMenu.remove();
|
|
const contextMenu = document.createElement("nav");
|
|
contextMenu.id = "context-menu";
|
|
contextMenu.style.top = `${posy}px`;
|
|
contextMenu.style.left = `${posx}px`;
|
|
const contextMenuList = document.createElement("ul");
|
|
contextMenuList.className = "context-menu-items";
|
|
contextMenu.append(contextMenuList);
|
|
menuEntries.forEach((entry) => {
|
|
const contextMenuEntry = document.createElement("a");
|
|
contextMenuEntry.innerHTML = entry.name;
|
|
contextMenuEntry.addEventListener("click", () => entry.func());
|
|
contextMenuList.append(contextMenuEntry);
|
|
});
|
|
gradioApp().appendChild(contextMenu);
|
|
const menuWidth = contextMenu.offsetWidth + 4;
|
|
const menuHeight = contextMenu.offsetHeight + 4;
|
|
const windowWidth = window.innerWidth;
|
|
const windowHeight = window.innerHeight;
|
|
if (windowWidth - posx < menuWidth) contextMenu.style.left = `${windowWidth - menuWidth}px`;
|
|
if (windowHeight - posy < menuHeight) contextMenu.style.top = `${windowHeight - menuHeight}px`;
|
|
}
|
|
function appendContextMenuOption2(targetElementSelector, entryName, entryFunction, primary = false) {
|
|
let currentItems = menuSpecs.get(targetElementSelector);
|
|
if (!currentItems) {
|
|
currentItems = [];
|
|
menuSpecs.set(targetElementSelector, currentItems);
|
|
}
|
|
const newItem = {
|
|
id: `${targetElementSelector}_${uid()}`,
|
|
name: entryName,
|
|
func: entryFunction,
|
|
primary
|
|
// isNew: true,
|
|
};
|
|
currentItems.push(newItem);
|
|
return newItem.id;
|
|
}
|
|
function removeContextMenuOption2(id) {
|
|
menuSpecs.forEach((v, k) => {
|
|
let index = -1;
|
|
v.forEach((e, ei) => {
|
|
if (e.id === id) {
|
|
index = ei;
|
|
}
|
|
});
|
|
if (index >= 0) v.splice(index, 1);
|
|
});
|
|
}
|
|
window.appendContextMenuOption = appendContextMenuOption2;
|
|
window.removeContextMenuOption = removeContextMenuOption2;
|
|
async function addContextMenuEventListener2() {
|
|
if (eventListenerApplied) return;
|
|
log("initContextMenu");
|
|
gradioApp().addEventListener("click", (e) => {
|
|
const mouseEvent = e;
|
|
if (!mouseEvent.isTrusted) return;
|
|
const oldMenu = gradioApp().querySelector("#context-menu");
|
|
if (oldMenu) oldMenu.remove();
|
|
menuSpecs.forEach((v, k) => {
|
|
const items = v.filter((item) => item.primary);
|
|
const target = mouseEvent.target;
|
|
if (!target) return;
|
|
const matched = target.closest(k);
|
|
if (items.length > 0 && matched) {
|
|
showContextMenu(mouseEvent, matched, items);
|
|
mouseEvent.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
gradioApp().addEventListener("contextmenu", (e) => {
|
|
const mouseEvent = e;
|
|
const oldMenu = gradioApp().querySelector("#context-menu");
|
|
if (oldMenu) oldMenu.remove();
|
|
menuSpecs.forEach((v, k) => {
|
|
const items = v.filter((item) => !item.primary);
|
|
const target = mouseEvent.target;
|
|
if (!target) return;
|
|
const matched = target.closest(k);
|
|
if (items.length > 0 && matched) {
|
|
showContextMenu(mouseEvent, matched, items);
|
|
mouseEvent.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
eventListenerApplied = true;
|
|
}
|
|
return [appendContextMenuOption2, removeContextMenuOption2, addContextMenuEventListener2];
|
|
};
|
|
var initContextResponse = contextMenuInit();
|
|
var appendContextMenuOption = initContextResponse[0];
|
|
var removeContextMenuOption = initContextResponse[1];
|
|
var addContextMenuEventListener = initContextResponse[2];
|
|
var generateOnRepeatInterval = null;
|
|
var generateForever = (genbuttonid) => {
|
|
if (generateOnRepeatInterval) {
|
|
log("generateForever: cancel");
|
|
clearInterval(generateOnRepeatInterval);
|
|
generateOnRepeatInterval = null;
|
|
} else {
|
|
const genbutton = gradioApp().querySelector(genbuttonid);
|
|
if (!(genbutton instanceof HTMLElement)) return;
|
|
const isBusy = () => {
|
|
let busy2 = document.getElementById("progressbar")?.style.display === "block";
|
|
if (!busy2) {
|
|
const outerButton = genbutton.parentElement.closest("button");
|
|
busy2 = outerButton?.classList.contains("generate") && outerButton?.classList.contains("active");
|
|
}
|
|
return busy2;
|
|
};
|
|
log("generateForever: start");
|
|
if (!isBusy()) genbutton.click();
|
|
generateOnRepeatInterval = setInterval(() => {
|
|
if (!isBusy()) genbutton.click();
|
|
}, 500);
|
|
}
|
|
};
|
|
window.generateForever = generateForever;
|
|
var reprocessClick = (tabId, state) => {
|
|
const btn = document.getElementById(`${tabId}_${state}`);
|
|
window.submit_state = state;
|
|
if (btn) btn.click();
|
|
};
|
|
var getStatus = async () => {
|
|
const headers = new Headers();
|
|
const body = JSON.stringify({ id_task: -1, id_live_preview: false });
|
|
headers.set("Content-Type", "application/json");
|
|
const tab = getUICurrentTabContent()?.id.replace("tab_", "") || "";
|
|
const el2 = gradioApp().querySelector(`#html_log_${tab} .performance p`);
|
|
let res;
|
|
let data;
|
|
res = await fetch("./internal/progress", { method: "POST", headers, body });
|
|
if (res?.ok) {
|
|
data = await res.json();
|
|
log("progressInternal:", data);
|
|
if (el2) el2.innerText += `
|
|
Progress internal:
|
|
${JSON.stringify(data, null, 2)}`;
|
|
}
|
|
res = await authFetch("./sdapi/v1/progress?skip_current_image=true", { method: "GET", headers });
|
|
if (res?.ok) {
|
|
data = await res.json();
|
|
log("progressAPI:", data);
|
|
if (el2) el2.innerText += `
|
|
Progress API:
|
|
${JSON.stringify(data, null, 2)}`;
|
|
}
|
|
};
|
|
async function initContextMenu() {
|
|
for (const tab of ["txt2img", "img2img", "control", "video"]) {
|
|
appendContextMenuOption(`#${tab}_generate`, "Get server status", getStatus);
|
|
appendContextMenuOption(`#${tab}_generate`, "Copy prompt to clipboard", () => navigator.clipboard.writeText(document.querySelector(`#${tab}_prompt > label > textarea`).value));
|
|
appendContextMenuOption(`#${tab}_generate`, "Generate forever", () => generateForever(`#${tab}_generate`));
|
|
appendContextMenuOption(`#${tab}_generate`, "Apply selected style", quickApplyStyle);
|
|
appendContextMenuOption(`#${tab}_generate`, "Quick save style", quickSaveStyle);
|
|
appendContextMenuOption(`#${tab}_reprocess`, "Decode full quality", () => reprocessClick(tab, "reprocess_decode"), true);
|
|
appendContextMenuOption(`#${tab}_reprocess`, "Refine & HiRes pass", () => reprocessClick(tab, "reprocess_refine"), true);
|
|
appendContextMenuOption(`#${tab}_reprocess`, "Detailer pass", () => reprocessClick(tab, "reprocess_detail"), true);
|
|
}
|
|
for (const tab of ["gallery", "txt2img", "img2img", "extras"]) {
|
|
appendContextMenuOption(`#${tab}_tabitem #control_tab`, "Transfer only prompt to Images tab", () => {
|
|
document.querySelector(`#image_buttons_${tab} #control_tab_prompt`)?.click();
|
|
document.getElementById("control_nav")?.click();
|
|
});
|
|
appendContextMenuOption(`#${tab}_tabitem #control_tab`, "Transfer all parameters to Images tab", () => {
|
|
document.querySelector(`#image_buttons_${tab} #control_tab_params`)?.click();
|
|
document.getElementById("control_nav")?.click();
|
|
});
|
|
}
|
|
addContextMenuEventListener();
|
|
}
|
|
|
|
// ui/uiConfig.ts
|
|
function uiOpenSubmenus() {
|
|
const accordions = Array.from(gradioApp().querySelectorAll(".gradio-accordion"));
|
|
const states = {};
|
|
accordions.forEach((el2) => {
|
|
const labelEl = el2.querySelector(".label-wrap > span:not(.icon)");
|
|
const name = labelEl instanceof HTMLElement ? labelEl.innerText.trim() : "";
|
|
if (!name) return;
|
|
const children = Array.from(el2.childNodes);
|
|
const open = children.filter((c) => c instanceof HTMLElement && c.style.display === "block");
|
|
if (states[name] === void 0) states[name] = open.length > 0;
|
|
});
|
|
return states;
|
|
}
|
|
async function getUIDefaults() {
|
|
const btn = gradioApp().getElementById("ui_defaults_view");
|
|
if (!btn) return;
|
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
|
if (entries[0].intersectionRatio <= 0) {
|
|
}
|
|
if (entries[0].intersectionRatio > 0) btn.click();
|
|
});
|
|
intersectionObserver.observe(btn);
|
|
}
|
|
window.uiOpenSubmenus = uiOpenSubmenus;
|
|
|
|
// ui/loader.ts
|
|
var appStartTime = performance.now();
|
|
var monitorLogActive = false;
|
|
async function preloadImages() {
|
|
const dark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
const imagePromises = [];
|
|
const num = Math.floor(9.99 * Math.random());
|
|
const imageUrls = [
|
|
`file=ui/assets/logo-bg-${dark ? "dark" : "light"}.jpg`,
|
|
`file=ui/assets/logo-bg-${num}.jpg`
|
|
];
|
|
for (const url2 of imageUrls) {
|
|
const img = new Image();
|
|
const promise = new Promise((resolve, reject) => {
|
|
img.onload = () => resolve();
|
|
img.onerror = () => reject(new Error(`failed to preload image: ${url2}`));
|
|
});
|
|
img.src = url2;
|
|
imagePromises.push(promise);
|
|
}
|
|
try {
|
|
await Promise.all(imagePromises);
|
|
return true;
|
|
} catch (err) {
|
|
error(`preloadImages: ${err}`);
|
|
return false;
|
|
}
|
|
}
|
|
function joinArgs(messages) {
|
|
let output = "";
|
|
for (let i = 0; i < messages.length; i++) {
|
|
let arg = messages[i];
|
|
if (arg === void 0) arg = "undefined";
|
|
if (arg === null) arg = "null";
|
|
output += " ";
|
|
if (typeof arg === "object") output += JSON.stringify(arg).replace(/["]+/g, "");
|
|
else output += arg;
|
|
}
|
|
return output;
|
|
}
|
|
function monitorLog() {
|
|
if (window.logBufferDirty) {
|
|
window.logBufferDirty = false;
|
|
const maxLines = 100;
|
|
const lines = [];
|
|
for (let i = Math.max(0, window.logRingBuffer.length - maxLines); i < window.logRingBuffer.length; i++) {
|
|
const logEntry = window.logRingBuffer[i];
|
|
let color = "white";
|
|
if (logEntry.type === "error") color = "palevioletred";
|
|
else if (logEntry.type === "debug") color = "gray";
|
|
const html = `<div class="splash-log-row" style="color: ${color}">${logEntry.ts} ${joinArgs(logEntry.msg)}</div>`;
|
|
lines.push(html);
|
|
}
|
|
const splashLogEl = document.getElementById("splashLog");
|
|
if (splashLogEl) splashLogEl.innerHTML = lines.join("");
|
|
}
|
|
if (monitorLogActive) setTimeout(monitorLog, 250);
|
|
}
|
|
async function removeSplash() {
|
|
const splash = document.getElementById("splash");
|
|
if (splash) splash.remove();
|
|
log("removeSplash");
|
|
const t = Math.round(performance.now() - appStartTime);
|
|
log("startupTime", t);
|
|
timer("splashVisible", t);
|
|
xhrPost(`${window.api}/log`, { message: `ready time=${t}` });
|
|
monitorLogActive = false;
|
|
}
|
|
async function createSplash() {
|
|
const dark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
log("createSplash", { theme: dark ? "dark" : "light" });
|
|
const num = Math.floor(9.99 * Math.random());
|
|
const splash = `
|
|
<div id="splash" class="splash" style="background: ${dark ? "black" : "white"}">
|
|
<div class="loading"><div class="loader"></div></div>
|
|
<div id="motd" class="motd""></div>
|
|
<div id="splashLog" class="splash-log" style="position: fixed; bottom: 0; text-align: left; padding: 8vh 8px 8px 8px; font-size: 12px; width: 100%; background: linear-gradient(0deg, darkslategray, transparent); opacity: 50%;"></div>
|
|
</div>`;
|
|
document.body.insertAdjacentHTML("beforeend", splash);
|
|
const ok2 = await preloadImages();
|
|
if (!ok2) {
|
|
removeSplash();
|
|
return;
|
|
}
|
|
const imgEl = `<div id="spash-img" class="splash-img" alt="logo" style="background-image: url(file=ui/assets/logo-bg-${dark ? "dark" : "light"}.jpg), url(file=ui/assets/logo-bg-${num}.jpg); background-blend-mode: ${dark ? "multiply" : "lighten"}"></div>`;
|
|
const splashEl = document.getElementById("splash");
|
|
if (splashEl) splashEl.insertAdjacentHTML("afterbegin", imgEl);
|
|
monitorLogActive = true;
|
|
monitorLog();
|
|
await authFetch(`${window.api}/motd`).then((res) => res.text()).then((text) => {
|
|
const clean = text.replace(/["]+/g, "");
|
|
log("getMOTD", clean);
|
|
const motdEl = document.getElementById("motd");
|
|
if (motdEl) motdEl.innerHTML = clean;
|
|
}).catch((err) => error(`getMOTD: ${err}`));
|
|
log("loadGradioUi");
|
|
}
|
|
window.onload = createSplash;
|
|
|
|
// ui/legacy.ts
|
|
function addLegacyNotice() {
|
|
log("legacyNotice");
|
|
const notice = document.createElement("div");
|
|
notice.id = "legacy-notice";
|
|
notice.className = "legacy-standard";
|
|
notice.textContent = "Legacy";
|
|
notice.title = "Standard UI is a legacy interface that is no longer maintained and will be removed in the future. Please switch to ModernUI for best experience.";
|
|
document.body.appendChild(notice);
|
|
}
|
|
|
|
// ui/startup.ts
|
|
window.api = "/sdapi/v1";
|
|
window.subpath = "";
|
|
var startupPromises = [];
|
|
var ok = false;
|
|
async function waitForOpts() {
|
|
const t0 = performance.now();
|
|
let t1 = performance.now();
|
|
while (true) {
|
|
if (t1 - t0 > 12e4) {
|
|
log("waitForOpts timeout");
|
|
break;
|
|
}
|
|
if (window.opts && Object.keys(window.opts).length > 0) {
|
|
ok = window.opts.theme_type === "Modern" ? "uiux_separator_appearance" in window.opts : true;
|
|
if (ok) {
|
|
log("waitForOpts", Math.round(t1 - t0));
|
|
timer("waitForOpts", t1 - t0);
|
|
break;
|
|
}
|
|
}
|
|
await sleep(100);
|
|
t1 = performance.now();
|
|
}
|
|
}
|
|
async function postStartup() {
|
|
log("postStartup");
|
|
disconnectHintsObserver();
|
|
logTimers();
|
|
}
|
|
async function initStartup() {
|
|
const t0 = performance.now();
|
|
log("initGradio", Math.round(t0 - appStartTime));
|
|
timer("initGradio", t0 - appStartTime);
|
|
log("initUi");
|
|
if (window.setupLogger) await window.setupLogger();
|
|
startupPromises.push(initModels());
|
|
startupPromises.push(getUIDefaults());
|
|
startupPromises.push(initPromptChecker());
|
|
startupPromises.push(initContextMenu());
|
|
startupPromises.push(initDragDrop());
|
|
startupPromises.push(Promise.resolve(initAccordions()));
|
|
startupPromises.push(Promise.resolve(initSettings()));
|
|
startupPromises.push(Promise.resolve(initImageViewer()));
|
|
startupPromises.push(Promise.resolve(initGallery()));
|
|
startupPromises.push(Promise.resolve(initiGenerationParams()));
|
|
startupPromises.push(Promise.resolve(initChangelog()));
|
|
startupPromises.push(Promise.resolve(setupControlUI()));
|
|
await reconnectUI();
|
|
await waitForOpts();
|
|
log("mountURL", window.opts.subpath);
|
|
if (window.opts.subpath?.length > 0) {
|
|
window.subpath = window.opts.subpath;
|
|
window.api = `${window.subpath}/sdapi/v1`;
|
|
}
|
|
startupPromises.push(initLogMonitor());
|
|
executeCallbacks(uiReadyCallbacks);
|
|
if (window.waitForUiReady) await window.waitForUiReady();
|
|
startupPromises.push(Promise.resolve(initGallery()));
|
|
startupPromises.push(Promise.resolve(setRefreshInterval()));
|
|
startupPromises.push(Promise.resolve(setupExtraNetworks()));
|
|
startupPromises.push(Promise.resolve(initAutocomplete()));
|
|
startupPromises.push(Promise.resolve(monitorConnection()));
|
|
startupPromises.push(Promise.resolve(showNetworks()));
|
|
startupPromises.push(Promise.resolve(setHints()));
|
|
startupPromises.push(Promise.resolve(applyStyles()));
|
|
startupPromises.push(Promise.resolve(initIndexDB()));
|
|
startupPromises.push(Promise.resolve(initTableSorter()));
|
|
if (window.opts.theme_type !== "Modern") addLegacyNotice();
|
|
const t1 = performance.now();
|
|
log("initStartup", Math.round(1e3 * (t1 - t0) / 1e6));
|
|
removeSplash();
|
|
await Promise.all(startupPromises);
|
|
const t2 = performance.now();
|
|
log("initComplete", Math.round(1e3 * (t2 - t0) / 1e6));
|
|
postStartup();
|
|
}
|
|
onUiLoaded(initStartup);
|
|
onUiReady(() => log("uiReady"));
|
|
|
|
// ui/extensions.ts
|
|
function extensions_apply(_extensionsDisabledList, _extensionsUpdateList, disableAll) {
|
|
const disable = [];
|
|
const update = [];
|
|
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach((x) => {
|
|
if (!(x instanceof HTMLInputElement)) return;
|
|
if (x.name.startsWith("enable_") && !x.checked) disable.push(x.name.substring(7));
|
|
if (x.name.startsWith("update_") && x.checked) update.push(x.name.substring(7));
|
|
});
|
|
restartReload();
|
|
log("Extensions apply:", { disable, update });
|
|
return [JSON.stringify(disable), JSON.stringify(update), disableAll];
|
|
}
|
|
function extensions_check(_info, _extensionsDisabledList, searchText, sortColumn) {
|
|
const disable = [];
|
|
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach((x) => {
|
|
if (!(x instanceof HTMLInputElement)) return;
|
|
if (x.name.startsWith("enable_") && !x.checked) disable.push(x.name.substring(7));
|
|
});
|
|
const id = randomId();
|
|
log("Extensions check:", { disable });
|
|
return [id, JSON.stringify(disable), searchText, sortColumn];
|
|
}
|
|
function install_extension(button, url2) {
|
|
button.disabled = true;
|
|
button.value = "Installing...";
|
|
button.innerHTML = "installing";
|
|
const textarea = gradioApp().querySelector("#extension_to_install textarea");
|
|
if (!(textarea instanceof HTMLTextAreaElement)) return;
|
|
textarea.value = url2;
|
|
updateInput2(textarea);
|
|
log("Extension install:", { url: url2 });
|
|
const installBtn = gradioApp().querySelector("#install_extension_button");
|
|
if (installBtn instanceof HTMLElement) installBtn.click();
|
|
}
|
|
function uninstall_extension(button, url2) {
|
|
button.disabled = true;
|
|
button.value = "Uninstalling...";
|
|
button.innerHTML = "uninstalling";
|
|
const textarea = gradioApp().querySelector("#extension_to_install textarea");
|
|
if (!(textarea instanceof HTMLTextAreaElement)) return;
|
|
textarea.value = url2;
|
|
updateInput2(textarea);
|
|
log("Extension uninstall:", { url: url2 });
|
|
const uninstallBtn = gradioApp().querySelector("#uninstall_extension_button");
|
|
if (uninstallBtn instanceof HTMLElement) uninstallBtn.click();
|
|
}
|
|
function update_extension(button, url2) {
|
|
button.value = "Updating...";
|
|
button.innerHTML = "updating";
|
|
const textarea = gradioApp().querySelector("#extension_to_install textarea");
|
|
if (!(textarea instanceof HTMLTextAreaElement)) return;
|
|
textarea.value = url2;
|
|
updateInput2(textarea);
|
|
log("Extension update:", { url: url2 });
|
|
const updateBtn = gradioApp().querySelector("#update_extension_button");
|
|
if (updateBtn instanceof HTMLInputElement) updateBtn.click();
|
|
}
|
|
window.extensions_apply = extensions_apply;
|
|
window.extensions_check = extensions_check;
|
|
window.uninstall_extension = uninstall_extension;
|
|
window.install_extension = install_extension;
|
|
window.update_extension = update_extension;
|
|
|
|
// ui/dragDrop.ts
|
|
function isValidImageList(files) {
|
|
return files && files?.length === 1 && ["image/png", "image/gif", "image/jpeg"].includes(files[0].type);
|
|
}
|
|
function dropReplaceImage(imgWrap, files) {
|
|
log("dropReplaceImage", imgWrap, files);
|
|
if (!isValidImageList(files)) return;
|
|
const tmpFile = files[0];
|
|
imgWrap.querySelector(".modify-upload button + button, .touch-none + div button + button")?.click();
|
|
const callback = () => {
|
|
const fileInput = imgWrap.querySelector('input[type="file"]');
|
|
if (fileInput instanceof HTMLInputElement) {
|
|
if (files.length === 0) {
|
|
const dt = new DataTransfer();
|
|
dt.items.add(tmpFile);
|
|
fileInput.files = dt.files;
|
|
} else {
|
|
fileInput.files = files;
|
|
}
|
|
fileInput.dispatchEvent(new Event("change"));
|
|
}
|
|
};
|
|
if (imgWrap.closest("#pnginfo_image")) {
|
|
const oldFetch = window.fetch;
|
|
window.fetch = async (input, options) => {
|
|
const response = await oldFetch(input, options);
|
|
if (input === "api/predict/") {
|
|
const content = await response.text();
|
|
window.fetch = oldFetch;
|
|
window.requestAnimationFrame(() => callback());
|
|
return new Response(content, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
headers: response.headers
|
|
});
|
|
}
|
|
return response;
|
|
};
|
|
} else {
|
|
window.requestAnimationFrame(() => callback());
|
|
}
|
|
}
|
|
window.document.addEventListener("dragover", (e) => {
|
|
const target = e.composedPath()[0];
|
|
const imgWrap = target.closest('[data-testid="image"]');
|
|
if (!imgWrap && target.placeholder && target.placeholder.indexOf("Prompt") === -1) return;
|
|
if ((e.dataTransfer?.files?.length || 0) > 0) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = "copy";
|
|
}
|
|
});
|
|
window.document.addEventListener("drop", (e) => {
|
|
const target = e.composedPath()[0];
|
|
log("dropEvent", e, target);
|
|
if (!target.placeholder) return;
|
|
if (target.placeholder.indexOf("Prompt") === -1) return;
|
|
const imgWrap = target.closest('[data-testid="image"]');
|
|
if (!imgWrap) return;
|
|
if ((e.dataTransfer?.files?.length || 0) > 0) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
dropReplaceImage(imgWrap, e.dataTransfer.files);
|
|
}
|
|
});
|
|
window.addEventListener("paste", (e) => {
|
|
log("pasteEvent", e);
|
|
const files = e.clipboardData?.files;
|
|
if (!isValidImageList(files)) return;
|
|
const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')].filter((el2) => uiElementIsVisible(el2)).sort((a, b) => Number(uiElementInSight(b)) - Number(uiElementInSight(a)));
|
|
if (!visibleImageFields.length) return;
|
|
const firstFreeImageField = visibleImageFields.filter((el2) => el2.querySelector("input[type=file]"))?.[0];
|
|
dropReplaceImage(firstFreeImageField || visibleImageFields[visibleImageFields.length - 1], files);
|
|
});
|
|
|
|
// ui/civitai.ts
|
|
String.prototype.format = function format(args) {
|
|
let thisString = "";
|
|
for (let charPos = 0; charPos < this.length; charPos++) thisString += this[charPos];
|
|
for (const key in args) {
|
|
const stringKey = `{${key}}`;
|
|
thisString = thisString.replace(new RegExp(stringKey, "g"), String(args[key]));
|
|
}
|
|
return thisString;
|
|
};
|
|
var selectedURL = [];
|
|
var selectedName = [];
|
|
var selectedType = [];
|
|
var selectedBase = [];
|
|
var selectedModelId = [];
|
|
var selectedVersionId = [];
|
|
function clearModelDetails() {
|
|
const el2 = gradioApp().getElementById("model-details") || gradioApp().getElementById("civitai_models_output") || gradioApp().getElementById("models_outcome");
|
|
if (!el2) return;
|
|
el2.innerHTML = "";
|
|
}
|
|
window.clearModelDetails = clearModelDetails;
|
|
var modelDetailsHTML = `
|
|
<div>
|
|
<img src="{image}" alt="model image" class="preview" style="display: none">
|
|
<button style="float: right" class="lg secondary gradio-button tool extra-details-close" id="model_details_close" data-hint="Close" onclick="clearModelDetails()"> \u2715</button>
|
|
<table id="model-details-table" class="model-details simple-table">
|
|
<tr><td>Name</td><td>{name}</td></tr>
|
|
<tr><td>Type</td><td>{type}</td></tr>
|
|
<tr><td>Tags</td><td><div>{tags}</div></td></tr>
|
|
<tr><td>NSFW</td><td>{nsfw} | {level}</td></tr>
|
|
<tr><td>Availability</td><td>{availability}</td></tr>
|
|
<tr><td>Downloads</td><td>{downloads}</td></tr>
|
|
<tr><td>Author</td><td>{creator}</td></tr>
|
|
<tr><td>Description</td><td><div>{desc}</div></td></tr>
|
|
<tr><td>Download</td><td><div class="div-link" onclick="startCivitAllDownload(event)">All variants</div></td></tr>
|
|
</table>
|
|
<br>
|
|
<table id="model-versions-table" class="model-versions simple-table">
|
|
<thead>
|
|
<tr>
|
|
<th> </th>
|
|
<th>Version</th>
|
|
<th>Type</th>
|
|
<th>Base</th>
|
|
<th>File</th>
|
|
<th>Updated</th>
|
|
<th>Size</th>
|
|
<th>Availability</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{versions}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`;
|
|
var modelVersionsHTML = `
|
|
<tr>
|
|
<td>{url}</td>
|
|
<td>{name}</td>
|
|
<td>{type}</td>
|
|
<td>{base}</td>
|
|
<td>{file}</td>
|
|
<td>{mtime}</td>
|
|
<td>{size}</td>
|
|
<td>{availability}</td>
|
|
<td><div>{desc}</div></td>
|
|
</tr>
|
|
`;
|
|
async function modelCardClick(id) {
|
|
log("modelCardClick id", id);
|
|
const el2 = gradioApp().getElementById("model-details") || gradioApp().getElementById("civitai_models_output") || gradioApp().getElementById("models_outcome");
|
|
if (!el2) return;
|
|
const res = await authFetch(`${window.api}/civitai?model_id=${encodeURI(id)}`);
|
|
if (!res || res.status !== 200) {
|
|
error(`modelCardClick: id=${id} status=${res ? res.status : "unknown"}`);
|
|
return;
|
|
}
|
|
const dataArray = await res.json();
|
|
log("modelCardClick data", dataArray);
|
|
if (!dataArray || dataArray.length === 0) return;
|
|
const data = dataArray[0];
|
|
const versionsHTML = data.versions.map((v) => modelVersionsHTML.format({
|
|
url: `<div class="link" onclick="startCivitDownload('${v.files[0]?.url}', '${v.files[0]?.name}', '${data.type}', '${v.base || ""}', ${data.id}, ${v.id})"> \u{F01DA} </div>`,
|
|
name: v.name || "unknown",
|
|
type: v.files[0]?.type || "unknown",
|
|
base: v.base || "unknown",
|
|
mtime: new Date(v.mtime).toLocaleDateString(),
|
|
availability: v.availability || "unknown",
|
|
size: v.files[0]?.size ? `${(v.files[0].size / 1024 / 1024).toFixed(2)} MB` : "unknown",
|
|
file: `<a href=${v.files[0]?.url} target="_blank" rel="noopener noreferrer">${v.files[0]?.name || "unknown"}</a>`,
|
|
desc: v.desc || "no description available"
|
|
})).join("");
|
|
const url2 = `<a href="${data.url}" target="_blank" rel="noopener noreferrer">${data.name || "unknown"}</a>`;
|
|
const creator = `<a href="https://civitai.com/user/${data.creator}" target="_blank" rel="noopener noreferrer">${data.creator || "unknown"}</a>`;
|
|
const images = data.versions.map((v) => v.images).flat().map((i) => i.url);
|
|
const modelHTML = modelDetailsHTML.format({
|
|
name: url2,
|
|
type: data.type || "unknown",
|
|
tags: data.tags?.join(", ") || "",
|
|
nsfw: data.nsfw ? "yes" : "no",
|
|
level: data.level?.toString() || "",
|
|
availability: data.availability || "unknown",
|
|
downloads: data.downloads?.toString() || "",
|
|
creator,
|
|
desc: data.desc || "no description available",
|
|
image: images.length > 0 ? images[0] : "/sdapi/v1/network/thumb?filename=ui/assets/missing.png",
|
|
versions: versionsHTML || ""
|
|
});
|
|
el2.innerHTML = modelHTML;
|
|
}
|
|
window.modelCardClick = modelCardClick;
|
|
function startCivitDownload(url2, name, type, base, modelId, versionId) {
|
|
log("startCivitDownload", { url: url2, name, type, base, modelId, versionId });
|
|
selectedURL = [url2];
|
|
selectedName = [name];
|
|
selectedType = [type];
|
|
selectedBase = [base || ""];
|
|
selectedModelId = [modelId || 0];
|
|
selectedVersionId = [versionId || 0];
|
|
const civitDownloadBtn = gradioApp().getElementById("civitai_download_btn");
|
|
if (civitDownloadBtn) civitDownloadBtn.click();
|
|
}
|
|
window.startCivitDownload = startCivitDownload;
|
|
function startCivitAllDownload(evt) {
|
|
log("startCivitAllDownload", evt);
|
|
const table = gradioApp().getElementById("model-versions-table");
|
|
if (!table) return;
|
|
const versions = table.querySelectorAll("tr");
|
|
selectedURL = [];
|
|
selectedName = [];
|
|
selectedType = [];
|
|
selectedBase = [];
|
|
selectedModelId = [];
|
|
selectedVersionId = [];
|
|
for (const version of versions) {
|
|
const parsed = version.querySelector("td:nth-child(1) div")?.getAttribute("onclick")?.match(/startCivitDownload\('([^']+)', '([^']+)', '([^']+)', '([^']*)', (\d+), (\d+)\)/);
|
|
if (!parsed || parsed.length < 7) continue;
|
|
selectedURL.push(parsed[1]);
|
|
selectedName.push(parsed[2]);
|
|
selectedType.push(parsed[3]);
|
|
selectedBase.push(parsed[4]);
|
|
selectedModelId.push(parseInt(parsed[5], 10));
|
|
selectedVersionId.push(parseInt(parsed[6], 10));
|
|
}
|
|
const civitDownloadBtn = gradioApp().getElementById("civitai_download_btn");
|
|
if (civitDownloadBtn) civitDownloadBtn.click();
|
|
}
|
|
window.startCivitAllDownload = startCivitAllDownload;
|
|
function downloadCivitModel(modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken, innerHTML) {
|
|
log("downloadCivitModel", { modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken });
|
|
const el2 = gradioApp().getElementById("civitai_models_output") || gradioApp().getElementById("models_outcome");
|
|
const currentHTML = el2?.innerHTML || "";
|
|
return [selectedURL, selectedName, selectedType, selectedBase, selectedModelId, selectedVersionId, modelPath, civitToken, currentHTML];
|
|
}
|
|
window.downloadCivitModel = downloadCivitModel;
|
|
var civitMutualExcludeBound = false;
|
|
function civitaiMutualExclude() {
|
|
if (civitMutualExcludeBound) return;
|
|
const searchEl = gradioApp().querySelector("#civit_search_text textarea");
|
|
const tagEl = gradioApp().querySelector("#civit_search_tag textarea");
|
|
if (!searchEl || !tagEl) return;
|
|
civitMutualExcludeBound = true;
|
|
searchEl.addEventListener("input", () => {
|
|
tagEl.closest(".gradio-textbox")?.classList.toggle("disabled-look", !!searchEl.value.trim());
|
|
});
|
|
tagEl.addEventListener("input", () => {
|
|
searchEl.closest(".gradio-textbox")?.classList.toggle("disabled-look", !!tagEl.value.trim());
|
|
});
|
|
}
|
|
onUiLoaded(civitaiMutualExclude);
|
|
|
|
// ui/guidance.ts
|
|
var guiders = {
|
|
None: "",
|
|
"LSC: LayerSkipConfig": "https://github.com/huggingface/diffusers/blob/041501aea92919c9c7f36e189fc9cf7d865ebb96/src/diffusers/hooks/layer_skip.py#L41",
|
|
"CFG: ClassifierFreeGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeGuidance",
|
|
"Auto: AutoGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AutoGuidance",
|
|
"Zero: ClassifierFreeZeroStar": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeZeroStarGuidance",
|
|
"PAG: PerturbedAttentionGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.PerturbedAttentionGuidance",
|
|
"APG: AdaptiveProjectedGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AdaptiveProjectedGuidance",
|
|
"SLG: SkipLayerGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SkipLayerGuidance",
|
|
"SEG: SmoothedEnergyGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SmoothedEnergyGuidance",
|
|
"TCFG: TangentialClassifierFreeGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.TangentialClassifierFreeGuidance",
|
|
"FDG: FrequencyDecoupledGuidance": "https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.FrequencyDecoupledGuidance"
|
|
};
|
|
function getGuidanceDocs(guider) {
|
|
const key = typeof guider === "object" && guider?.label ? guider.label : guider;
|
|
const url2 = guiders[key];
|
|
log("getGuidanceDocs", guider, url2);
|
|
if (url2) window.open(url2, "_blank");
|
|
}
|
|
window.getGuidanceDocs = getGuidanceDocs;
|
|
|
|
// ui/timesheet.ts
|
|
var Bubble = class {
|
|
type;
|
|
label;
|
|
min;
|
|
start;
|
|
end;
|
|
scale;
|
|
offset;
|
|
width;
|
|
duration;
|
|
title;
|
|
constructor(min, start, end, label, scale, type) {
|
|
this.type = type;
|
|
this.label = label;
|
|
this.min = min;
|
|
this.start = start;
|
|
this.end = end;
|
|
this.scale = scale;
|
|
this.offset = Math.round(this.scale * (this.start - this.min));
|
|
this.width = Math.round(this.scale * (this.end - this.start));
|
|
this.duration = Math.round(1e3 * (this.end - this.start)) / 1e3;
|
|
this.title = `Job: ${this.label}
|
|
Duration: ${this.duration}s
|
|
Start: ${new Date(1e3 * this.start).toLocaleString()}
|
|
End: ${new Date(1e3 * this.end).toLocaleString()}`;
|
|
}
|
|
getDateLabel() {
|
|
return Math.round(1e3 * (this.end - this.start)) / 1e3;
|
|
}
|
|
};
|
|
var Timesheet = class {
|
|
min;
|
|
max;
|
|
data;
|
|
container;
|
|
scale;
|
|
constructor(container, data) {
|
|
this.min = Math.floor(data[0].start);
|
|
this.max = Math.round(data[data.length - 1].end + 0.5);
|
|
this.data = data;
|
|
this.container = container;
|
|
const box = container.getBoundingClientRect();
|
|
const width = box.width - 140;
|
|
this.scale = width / (this.max - this.min);
|
|
let html = [];
|
|
for (let c = 0; c <= this.max - this.min; c++) html.push(`<section style="width: ${this.scale}px;"></section>`);
|
|
container.className = "timesheet color-scheme-default";
|
|
container.innerHTML = `<div class="scale"">${html.join("")}</div>`;
|
|
html = [];
|
|
for (let n = 0, m = this.data.length; n < m; n++) {
|
|
const cur = this.data[n];
|
|
const bubble = new Bubble(this.min, cur.start, cur.end, cur.label, this.scale, cur.type);
|
|
const line = [
|
|
`<span title="${bubble.title}" style="margin-left: ${bubble.offset}px; width: ${bubble.width}px;" class="bubble bubble-${bubble.type}" data-duration="${bubble.duration}"></span>`,
|
|
`<span class="date" title="${bubble.title}">${bubble.duration}</span> `,
|
|
`<span class="label" title="${bubble.title}">${bubble.label}</span>`
|
|
].join("");
|
|
html.push(`<li>${line}</li>`);
|
|
}
|
|
this.container.innerHTML += `<ul class="data">${html.join("")}</ul>`;
|
|
}
|
|
};
|
|
|
|
// ui/history.ts
|
|
var inferenceTypes = ["inference", "vae", "te"];
|
|
var ioTypes = ["load", "save"];
|
|
function refreshHistory() {
|
|
log("refreshHistory");
|
|
authFetch(`${window.api}/history`, { priority: "low" }).then((res) => {
|
|
if (!res) return;
|
|
const timeline = document.getElementById("history_timeline");
|
|
const table = document.getElementById("history_table");
|
|
if (!timeline || !table) return;
|
|
timeline.innerHTML = "";
|
|
res.json().then((rawData) => {
|
|
let data = rawData;
|
|
if (!data || !data.length) {
|
|
table.innerHTML = "<p>No history data available.</p>";
|
|
return;
|
|
}
|
|
let html = "<table><thead><tr><th>Time</th><th>ID</th><th>Job</th><th>Action</th><th>Duration</th><th>Outputs</th></tr></thead><tbody>";
|
|
for (const entry of data) {
|
|
const ts2 = new Date(1e3 * entry.timestamp).toLocaleString();
|
|
const duration = entry.duration ? entry.duration.toFixed(3) : "";
|
|
const outputs = entry.outputs.join(", ");
|
|
html += `<tr><td>${ts2}</td><td>${entry.id}</td><td>${entry.job}</td><td>${entry.op}</td><td>${duration}</td><td>${outputs}</td></tr>`;
|
|
}
|
|
html += "</tbody></table>";
|
|
table.innerHTML = html;
|
|
let startIdx = -1;
|
|
for (let i = data.length - 1; i >= 0; --i) {
|
|
const e = data[i];
|
|
if ((e.job === "control" || e.job === "text" || e.job === "control" || e.job === "image") && e.op === "begin") {
|
|
startIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (startIdx >= 0) data = data.slice(startIdx);
|
|
const ts = [];
|
|
for (const entry of data) {
|
|
if (entry.op === "begin") {
|
|
const start = entry.timestamp;
|
|
const endEntry = data.find((e) => e.id === entry.id && e.op === "end");
|
|
const end = endEntry?.timestamp ?? data[data.length - 1].timestamp;
|
|
if (end - start < 0.02) continue;
|
|
if (inferenceTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = "inference";
|
|
else if (ioTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = "io";
|
|
else entry.type = "default";
|
|
if (start && end) ts.push({ start, end, label: entry.job, type: entry.type });
|
|
}
|
|
}
|
|
if (!ts.length) return;
|
|
new Timesheet(timeline, ts);
|
|
});
|
|
});
|
|
}
|
|
window.refreshHistory = refreshHistory;
|
|
|
|
// ui/aspectRatioOverlay.ts
|
|
var currentWidth = null;
|
|
var currentHeight = null;
|
|
var arFrameTimeout;
|
|
function dimensionChange(e, isWidth, isHeight) {
|
|
const { target } = e;
|
|
if (!(target instanceof HTMLInputElement)) return;
|
|
if (isWidth) currentWidth = Number(target.value);
|
|
if (isHeight) currentHeight = Number(target.value);
|
|
const tabImg2img = gradioApp().querySelector("#tab_img2img");
|
|
if (!(tabImg2img instanceof HTMLElement)) return;
|
|
const inImg2img = tabImg2img.style.display === "block";
|
|
if (!inImg2img) return;
|
|
let targetElement = null;
|
|
const tabIndex = get_tab_index("mode_img2img");
|
|
if (tabIndex === 0) targetElement = gradioApp().querySelector("#img2img_image div[data-testid=image] img");
|
|
else if (tabIndex === 1) targetElement = gradioApp().querySelector("#img2img_sketch div[data-testid=image] img");
|
|
else if (tabIndex === 2) targetElement = gradioApp().querySelector("#img2maskimg div[data-testid=image] img");
|
|
else if (tabIndex === 3) targetElement = gradioApp().querySelector("#composite div[data-testid=image] img");
|
|
if (targetElement && currentWidth && currentHeight) {
|
|
let arPreviewRect = gradioApp().querySelector("#imageARPreview");
|
|
if (!arPreviewRect) {
|
|
arPreviewRect = document.createElement("div");
|
|
arPreviewRect.id = "imageARPreview";
|
|
gradioApp().appendChild(arPreviewRect);
|
|
}
|
|
const viewportOffset = targetElement.getBoundingClientRect();
|
|
const viewportscale = Math.min(targetElement.clientWidth / targetElement.naturalWidth, targetElement.clientHeight / targetElement.naturalHeight);
|
|
const scaledx = targetElement.naturalWidth * viewportscale;
|
|
const scaledy = targetElement.naturalHeight * viewportscale;
|
|
const cleintRectTop = viewportOffset.top + window.scrollY;
|
|
const cleintRectLeft = viewportOffset.left + window.scrollX;
|
|
const cleintRectCentreY = cleintRectTop + targetElement.clientHeight / 2;
|
|
const cleintRectCentreX = cleintRectLeft + targetElement.clientWidth / 2;
|
|
const arscale = Math.min(scaledx / currentWidth, scaledy / currentHeight);
|
|
const arscaledx = currentWidth * arscale;
|
|
const arscaledy = currentHeight * arscale;
|
|
const arRectTop = cleintRectCentreY - arscaledy / 2;
|
|
const arRectLeft = cleintRectCentreX - arscaledx / 2;
|
|
const arRectWidth = arscaledx;
|
|
const arRectHeight = arscaledy;
|
|
arPreviewRect.style.top = `${arRectTop}px`;
|
|
arPreviewRect.style.left = `${arRectLeft}px`;
|
|
arPreviewRect.style.width = `${arRectWidth}px`;
|
|
arPreviewRect.style.height = `${arRectHeight}px`;
|
|
if (arFrameTimeout) clearTimeout(arFrameTimeout);
|
|
arFrameTimeout = setTimeout(() => {
|
|
arPreviewRect.style.display = "none";
|
|
}, 2e3);
|
|
arPreviewRect.style.display = "block";
|
|
}
|
|
}
|
|
function aspectRatioCallback() {
|
|
const arPreviewRect = gradioApp().querySelector("#imageARPreview");
|
|
if (arPreviewRect instanceof HTMLElement) arPreviewRect.style.display = "none";
|
|
const tabImg2img = gradioApp().querySelector("#tab_img2img");
|
|
if (tabImg2img instanceof HTMLElement) {
|
|
const inImg2img = tabImg2img.style.display === "block";
|
|
if (inImg2img) {
|
|
const inputs = gradioApp().querySelectorAll("input");
|
|
inputs.forEach((e) => {
|
|
if (!(e instanceof HTMLInputElement) || !(e.parentElement instanceof HTMLElement)) return;
|
|
const isWidth = e.parentElement.id === "img2img_width";
|
|
const isHeight = e.parentElement.id === "img2img_height";
|
|
if ((isWidth || isHeight) && !e.classList.contains("scrollwatch")) {
|
|
e.addEventListener("input", (evt) => {
|
|
dimensionChange(evt, isWidth, isHeight);
|
|
});
|
|
e.classList.add("scrollwatch");
|
|
}
|
|
if (isWidth) currentWidth = Number(e.value);
|
|
if (isHeight) currentHeight = Number(e.value);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
onAfterUiUpdate(aspectRatioCallback);
|
|
|
|
// ui/resolutionLock.ts
|
|
var RES_DEBOUNCE = 350;
|
|
var AR_DEBOUNCE = 120;
|
|
var timers = /* @__PURE__ */ new WeakMap();
|
|
var busy = /* @__PURE__ */ new WeakSet();
|
|
function parseAR(ar) {
|
|
if (!ar || ar === "AR") return null;
|
|
const parts = ar.split(":");
|
|
if (parts.length !== 2) return null;
|
|
const w = parseInt(parts[0], 10);
|
|
const h = parseInt(parts[1], 10);
|
|
return w > 0 && h > 0 ? [w, h] : null;
|
|
}
|
|
function numberInput(group) {
|
|
const inp = group.querySelector("input[type=number]") || group.querySelector("input");
|
|
return inp instanceof HTMLInputElement ? inp : null;
|
|
}
|
|
function readValue(group) {
|
|
const inp = numberInput(group);
|
|
return inp ? Number(inp.value) : 0;
|
|
}
|
|
function writeValue(group, raw) {
|
|
const inp = numberInput(group);
|
|
if (!inp) return;
|
|
const step = Number(inp.step) || 8;
|
|
const min = inp.min !== "" ? Number(inp.min) : 0;
|
|
const max = inp.max !== "" ? Number(inp.max) : 8192;
|
|
const value = Math.max(min, Math.min(max, Math.round(raw / step) * step));
|
|
if (value === Number(inp.value)) return;
|
|
group.querySelectorAll("input").forEach((el2) => {
|
|
if (!(el2 instanceof HTMLInputElement)) return;
|
|
el2.value = String(value);
|
|
const e = new Event("input", { bubbles: true });
|
|
Object.defineProperty(e, "target", { value: el2 });
|
|
el2.dispatchEvent(e);
|
|
});
|
|
}
|
|
function arValue(arEl) {
|
|
const inp = arEl.querySelector("input");
|
|
return inp instanceof HTMLInputElement ? inp.value : "AR";
|
|
}
|
|
function pairOf(arEl) {
|
|
let container = arEl.parentElement;
|
|
for (let i = 0; i < 6 && container; i++) {
|
|
const width = container.querySelector('[id$="_width"]');
|
|
const height = container.querySelector('[id$="_height"]');
|
|
if (width && height) return { width, height };
|
|
container = container.parentElement;
|
|
}
|
|
return null;
|
|
}
|
|
function settle(arEl, source) {
|
|
const ar = parseAR(arValue(arEl));
|
|
if (!ar) return;
|
|
const pair = pairOf(arEl);
|
|
if (!pair) return;
|
|
const [rw, rh] = ar;
|
|
busy.add(arEl);
|
|
if (source === "height") writeValue(pair.width, readValue(pair.height) * rw / rh);
|
|
else writeValue(pair.height, readValue(pair.width) * rh / rw);
|
|
busy.delete(arEl);
|
|
}
|
|
function schedule(arEl, source, delay2) {
|
|
if (busy.has(arEl)) return;
|
|
clearTimeout(timers.get(arEl));
|
|
timers.set(arEl, setTimeout(() => settle(arEl, source), delay2));
|
|
}
|
|
function flush(arEl, source) {
|
|
if (busy.has(arEl)) return;
|
|
clearTimeout(timers.get(arEl));
|
|
settle(arEl, source);
|
|
}
|
|
function bind(arEl, group, source) {
|
|
group.querySelectorAll("input").forEach((el2) => {
|
|
if (!(el2 instanceof HTMLInputElement) || el2.classList.contains("ar-lock-bound")) return;
|
|
el2.classList.add("ar-lock-bound");
|
|
el2.addEventListener("input", () => schedule(arEl, source, RES_DEBOUNCE));
|
|
el2.addEventListener("change", () => flush(arEl, source));
|
|
});
|
|
}
|
|
function setupResolutionLock() {
|
|
gradioApp().querySelectorAll(".ar-dropdown").forEach((arEl) => {
|
|
const pair = pairOf(arEl);
|
|
if (!pair) return;
|
|
bind(arEl, pair.width, "width");
|
|
bind(arEl, pair.height, "height");
|
|
arEl.querySelectorAll("input").forEach((el2) => {
|
|
if (!(el2 instanceof HTMLInputElement) || el2.classList.contains("ar-lock-bound")) return;
|
|
el2.classList.add("ar-lock-bound");
|
|
el2.addEventListener("change", () => flush(arEl, "width"));
|
|
el2.addEventListener("input", () => schedule(arEl, "width", AR_DEBOUNCE));
|
|
});
|
|
});
|
|
}
|
|
onAfterUiUpdate(setupResolutionLock);
|
|
|
|
// ui/editAttention.ts
|
|
function keyupEditAttention(event2) {
|
|
const target = event2.originalTarget || event2.composedPath()[0];
|
|
if (!(target instanceof HTMLTextAreaElement)) return;
|
|
if (!target.matches("*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea")) return;
|
|
if (!(event2.metaKey || event2.ctrlKey)) return;
|
|
const isPlus = event2.key === "ArrowUp";
|
|
const isMinus = event2.key === "ArrowDown";
|
|
if (!isPlus && !isMinus) return;
|
|
let { selectionStart } = target;
|
|
let { selectionEnd } = target;
|
|
let text = target.value;
|
|
function selectCurrentParenthesisBlock(OPEN, CLOSE) {
|
|
if (selectionStart !== selectionEnd) return false;
|
|
const before = text.substring(0, selectionStart);
|
|
let beforeParen = before.lastIndexOf(OPEN);
|
|
if (beforeParen === -1) return false;
|
|
let beforeParenClose = before.lastIndexOf(CLOSE);
|
|
while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
|
|
beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);
|
|
beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);
|
|
}
|
|
const after = text.substring(selectionStart);
|
|
let afterParen = after.indexOf(CLOSE);
|
|
if (afterParen === -1) return false;
|
|
let afterParenOpen = after.indexOf(OPEN);
|
|
while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
|
|
afterParen = after.indexOf(CLOSE, afterParen + 1);
|
|
afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);
|
|
}
|
|
if (beforeParen === -1 || afterParen === -1) return false;
|
|
const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);
|
|
const lastColon = parenContent.lastIndexOf(":");
|
|
selectionStart = beforeParen + 1;
|
|
selectionEnd = selectionStart + lastColon;
|
|
target.setSelectionRange(selectionStart, selectionEnd);
|
|
return true;
|
|
}
|
|
function selectCurrentWord() {
|
|
if (selectionStart !== selectionEnd) return false;
|
|
const delimiters = `${window.opts.keyedit_delimiters} \r
|
|
`;
|
|
while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) selectionStart--;
|
|
while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) selectionEnd++;
|
|
target.setSelectionRange(selectionStart, selectionEnd);
|
|
return true;
|
|
}
|
|
if (!selectCurrentParenthesisBlock("<", ">") && !selectCurrentParenthesisBlock("(", ")")) selectCurrentWord();
|
|
event2.preventDefault();
|
|
let closeCharacter = ")";
|
|
let delta = window.opts.keyedit_precision_attention;
|
|
if (selectionStart > 0 && text[selectionStart - 1] === "<") {
|
|
closeCharacter = ">";
|
|
delta = window.opts.keyedit_precision_extra;
|
|
} else if (selectionStart === 0 || text[selectionStart - 1] !== "(") {
|
|
while (selectionEnd > selectionStart && text[selectionEnd - 1] === " ") selectionEnd -= 1;
|
|
if (selectionStart === selectionEnd) return;
|
|
text = `${text.slice(0, selectionStart)}(${text.slice(selectionStart, selectionEnd)}:1.0)${text.slice(selectionEnd)}`;
|
|
selectionStart += 1;
|
|
selectionEnd += 1;
|
|
}
|
|
const end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
|
|
let weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));
|
|
if (Number.isNaN(weight)) return;
|
|
weight += isPlus ? delta : -delta;
|
|
weight = parseFloat(weight.toPrecision(12));
|
|
if (String(weight).length === 1) weight += ".0";
|
|
if (closeCharacter === ")" && weight === 1) {
|
|
text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + 5);
|
|
selectionStart--;
|
|
selectionEnd--;
|
|
} else {
|
|
text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1);
|
|
}
|
|
target.focus();
|
|
target.value = text;
|
|
target.selectionStart = selectionStart;
|
|
target.selectionEnd = selectionEnd;
|
|
updateInput2(target);
|
|
}
|
|
addEventListener("keydown", (event2) => keyupEditAttention(event2));
|
|
|
|
// node_modules/.pnpm/jquery-sparkline@2.4.0/node_modules/jquery-sparkline/jquery.sparkline.js
|
|
(function(document2, Math2, undefined2) {
|
|
(function(factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
define(["jquery"], factory);
|
|
} else if (jQuery && !jQuery.fn.sparkline) {
|
|
factory(jQuery);
|
|
}
|
|
})(function($2) {
|
|
"use strict";
|
|
var UNSET_OPTION = {}, getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues, remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap, MouseHandler, Tooltip, barHighlightMixin, line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles, VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
|
|
getDefaults = function() {
|
|
return {
|
|
// Settings common to most/all chart types
|
|
common: {
|
|
type: "line",
|
|
lineColor: "#00f",
|
|
fillColor: "#cdf",
|
|
defaultPixelsPerValue: 3,
|
|
width: "auto",
|
|
height: "auto",
|
|
composite: false,
|
|
tagValuesAttribute: "values",
|
|
tagOptionsPrefix: "spark",
|
|
enableTagOptions: false,
|
|
enableHighlight: true,
|
|
highlightLighten: 1.4,
|
|
tooltipSkipNull: true,
|
|
tooltipPrefix: "",
|
|
tooltipSuffix: "",
|
|
disableHiddenCheck: false,
|
|
numberFormatter: false,
|
|
numberDigitGroupCount: 3,
|
|
numberDigitGroupSep: ",",
|
|
numberDecimalMark: ".",
|
|
disableTooltips: false,
|
|
disableInteraction: false
|
|
},
|
|
// Defaults for line charts
|
|
line: {
|
|
spotColor: "#f80",
|
|
highlightSpotColor: "#5f5",
|
|
highlightLineColor: "#f22",
|
|
spotRadius: 1.5,
|
|
minSpotColor: "#f80",
|
|
maxSpotColor: "#f80",
|
|
lineWidth: 1,
|
|
normalRangeMin: undefined2,
|
|
normalRangeMax: undefined2,
|
|
normalRangeColor: "#ccc",
|
|
drawNormalOnTop: false,
|
|
chartRangeMin: undefined2,
|
|
chartRangeMax: undefined2,
|
|
chartRangeMinX: undefined2,
|
|
chartRangeMaxX: undefined2,
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{prefix}}{{y}}{{suffix}}')
|
|
},
|
|
// Defaults for bar charts
|
|
bar: {
|
|
barColor: "#3366cc",
|
|
negBarColor: "#f44",
|
|
stackedBarColor: [
|
|
"#3366cc",
|
|
"#dc3912",
|
|
"#ff9900",
|
|
"#109618",
|
|
"#66aa00",
|
|
"#dd4477",
|
|
"#0099c6",
|
|
"#990099"
|
|
],
|
|
zeroColor: undefined2,
|
|
nullColor: undefined2,
|
|
zeroAxis: true,
|
|
barWidth: 4,
|
|
barSpacing: 1,
|
|
chartRangeMax: undefined2,
|
|
chartRangeMin: undefined2,
|
|
chartRangeClip: false,
|
|
colorMap: undefined2,
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{prefix}}{{value}}{{suffix}}')
|
|
},
|
|
// Defaults for tristate charts
|
|
tristate: {
|
|
barWidth: 4,
|
|
barSpacing: 1,
|
|
posBarColor: "#6f6",
|
|
negBarColor: "#f44",
|
|
zeroBarColor: "#999",
|
|
colorMap: {},
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{value:map}}'),
|
|
tooltipValueLookups: { map: { "-1": "Loss", "0": "Draw", "1": "Win" } }
|
|
},
|
|
// Defaults for discrete charts
|
|
discrete: {
|
|
lineHeight: "auto",
|
|
thresholdColor: undefined2,
|
|
thresholdValue: 0,
|
|
chartRangeMax: undefined2,
|
|
chartRangeMin: undefined2,
|
|
chartRangeClip: false,
|
|
tooltipFormat: new SPFormat("{{prefix}}{{value}}{{suffix}}")
|
|
},
|
|
// Defaults for bullet charts
|
|
bullet: {
|
|
targetColor: "#f33",
|
|
targetWidth: 3,
|
|
// width of the target bar in pixels
|
|
performanceColor: "#33f",
|
|
rangeColors: ["#d3dafe", "#a8b6ff", "#7f94ff"],
|
|
base: undefined2,
|
|
// set this to a number to change the base start number
|
|
tooltipFormat: new SPFormat("{{fieldkey:fields}} - {{value}}"),
|
|
tooltipValueLookups: { fields: { r: "Range", p: "Performance", t: "Target" } }
|
|
},
|
|
// Defaults for pie charts
|
|
pie: {
|
|
offset: 0,
|
|
sliceColors: [
|
|
"#3366cc",
|
|
"#dc3912",
|
|
"#ff9900",
|
|
"#109618",
|
|
"#66aa00",
|
|
"#dd4477",
|
|
"#0099c6",
|
|
"#990099"
|
|
],
|
|
borderWidth: 0,
|
|
borderColor: "#000",
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{value}} ({{percent.1}}%)')
|
|
},
|
|
// Defaults for box plots
|
|
box: {
|
|
raw: false,
|
|
boxLineColor: "#000",
|
|
boxFillColor: "#cdf",
|
|
whiskerColor: "#000",
|
|
outlierLineColor: "#333",
|
|
outlierFillColor: "#fff",
|
|
medianColor: "#f00",
|
|
showOutliers: true,
|
|
outlierIQR: 1.5,
|
|
spotRadius: 1.5,
|
|
target: undefined2,
|
|
targetColor: "#4a2",
|
|
chartRangeMax: undefined2,
|
|
chartRangeMin: undefined2,
|
|
tooltipFormat: new SPFormat("{{field:fields}}: {{value}}"),
|
|
tooltipFormatFieldlistKey: "field",
|
|
tooltipValueLookups: { fields: {
|
|
lq: "Lower Quartile",
|
|
med: "Median",
|
|
uq: "Upper Quartile",
|
|
lo: "Left Outlier",
|
|
ro: "Right Outlier",
|
|
lw: "Left Whisker",
|
|
rw: "Right Whisker"
|
|
} }
|
|
}
|
|
};
|
|
};
|
|
defaultStyles = '.jqstooltip { position: absolute;left: 0px;top: 0px;visibility: hidden;background: rgb(0, 0, 0) transparent;background-color: rgba(0,0,0,0.6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";color: white;font: 10px arial, san serif;text-align: left;white-space: nowrap;padding: 5px;border: 1px solid white;box-sizing: content-box;z-index: 10000;}.jqsfield { color: white;font: 10px arial, san serif;text-align: left;}';
|
|
createClass = function() {
|
|
var Class, args;
|
|
Class = function() {
|
|
this.init.apply(this, arguments);
|
|
};
|
|
if (arguments.length > 1) {
|
|
if (arguments[0]) {
|
|
Class.prototype = $2.extend(new arguments[0](), arguments[arguments.length - 1]);
|
|
Class._super = arguments[0].prototype;
|
|
} else {
|
|
Class.prototype = arguments[arguments.length - 1];
|
|
}
|
|
if (arguments.length > 2) {
|
|
args = Array.prototype.slice.call(arguments, 1, -1);
|
|
args.unshift(Class.prototype);
|
|
$2.extend.apply($2, args);
|
|
}
|
|
} else {
|
|
Class.prototype = arguments[0];
|
|
}
|
|
Class.prototype.cls = Class;
|
|
return Class;
|
|
};
|
|
$2.SPFormatClass = SPFormat = createClass({
|
|
fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
|
|
precre: /(\w+)\.(\d+)/,
|
|
init: function(format2, fclass) {
|
|
this.format = format2;
|
|
this.fclass = fclass;
|
|
},
|
|
render: function(fieldset, lookups, options) {
|
|
var self2 = this, fields = fieldset, match, token2, lookupkey, fieldvalue, prec;
|
|
return this.format.replace(this.fre, function() {
|
|
var lookup;
|
|
token2 = arguments[1];
|
|
lookupkey = arguments[3];
|
|
match = self2.precre.exec(token2);
|
|
if (match) {
|
|
prec = match[2];
|
|
token2 = match[1];
|
|
} else {
|
|
prec = false;
|
|
}
|
|
fieldvalue = fields[token2];
|
|
if (fieldvalue === undefined2) {
|
|
return "";
|
|
}
|
|
if (lookupkey && lookups && lookups[lookupkey]) {
|
|
lookup = lookups[lookupkey];
|
|
if (lookup.get) {
|
|
return lookups[lookupkey].get(fieldvalue) || fieldvalue;
|
|
} else {
|
|
return lookups[lookupkey][fieldvalue] || fieldvalue;
|
|
}
|
|
}
|
|
if (isNumber(fieldvalue)) {
|
|
if (options.get("numberFormatter")) {
|
|
fieldvalue = options.get("numberFormatter")(fieldvalue);
|
|
} else {
|
|
fieldvalue = formatNumber(
|
|
fieldvalue,
|
|
prec,
|
|
options.get("numberDigitGroupCount"),
|
|
options.get("numberDigitGroupSep"),
|
|
options.get("numberDecimalMark")
|
|
);
|
|
}
|
|
}
|
|
return fieldvalue;
|
|
});
|
|
}
|
|
});
|
|
$2.spformat = function(format2, fclass) {
|
|
return new SPFormat(format2, fclass);
|
|
};
|
|
clipval = function(val, min, max) {
|
|
if (val < min) {
|
|
return min;
|
|
}
|
|
if (val > max) {
|
|
return max;
|
|
}
|
|
return val;
|
|
};
|
|
quartile = function(values, q) {
|
|
var vl;
|
|
if (q === 2) {
|
|
vl = Math2.floor(values.length / 2);
|
|
return values.length % 2 ? values[vl] : (values[vl - 1] + values[vl]) / 2;
|
|
} else {
|
|
if (values.length % 2) {
|
|
vl = (values.length * q + q) / 4;
|
|
return vl % 1 ? (values[Math2.floor(vl)] + values[Math2.floor(vl) - 1]) / 2 : values[vl - 1];
|
|
} else {
|
|
vl = (values.length * q + 2) / 4;
|
|
return vl % 1 ? (values[Math2.floor(vl)] + values[Math2.floor(vl) - 1]) / 2 : values[vl - 1];
|
|
}
|
|
}
|
|
};
|
|
normalizeValue = function(val) {
|
|
var nf;
|
|
switch (val) {
|
|
case "undefined":
|
|
val = undefined2;
|
|
break;
|
|
case "null":
|
|
val = null;
|
|
break;
|
|
case "true":
|
|
val = true;
|
|
break;
|
|
case "false":
|
|
val = false;
|
|
break;
|
|
default:
|
|
nf = parseFloat(val);
|
|
if (val == nf) {
|
|
val = nf;
|
|
}
|
|
}
|
|
return val;
|
|
};
|
|
normalizeValues = function(vals) {
|
|
var i, result = [];
|
|
for (i = vals.length; i--; ) {
|
|
result[i] = normalizeValue(vals[i]);
|
|
}
|
|
return result;
|
|
};
|
|
remove = function(vals, filter) {
|
|
var i, vl, result = [];
|
|
for (i = 0, vl = vals.length; i < vl; i++) {
|
|
if (vals[i] !== filter) {
|
|
result.push(vals[i]);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
isNumber = function(num) {
|
|
return !isNaN(parseFloat(num)) && isFinite(num);
|
|
};
|
|
formatNumber = function(num, prec, groupsize, groupsep, decsep) {
|
|
var p, i;
|
|
num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split("");
|
|
p = (p = $2.inArray(".", num)) < 0 ? num.length : p;
|
|
if (p < num.length) {
|
|
num[p] = decsep;
|
|
}
|
|
for (i = p - groupsize; i > 0; i -= groupsize) {
|
|
num.splice(i, 0, groupsep);
|
|
}
|
|
return num.join("");
|
|
};
|
|
all = function(val, arr, ignoreNull) {
|
|
var i;
|
|
for (i = arr.length; i--; ) {
|
|
if (ignoreNull && arr[i] === null) continue;
|
|
if (arr[i] !== val) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
sum = function(vals) {
|
|
var total = 0, i;
|
|
for (i = vals.length; i--; ) {
|
|
total += typeof vals[i] === "number" ? vals[i] : 0;
|
|
}
|
|
return total;
|
|
};
|
|
ensureArray = function(val) {
|
|
return $2.isArray(val) ? val : [val];
|
|
};
|
|
addCSS = function(css) {
|
|
var tag, iefail;
|
|
if (document2.createStyleSheet) {
|
|
try {
|
|
document2.createStyleSheet().cssText = css;
|
|
return;
|
|
} catch (e) {
|
|
iefail = true;
|
|
}
|
|
}
|
|
tag = document2.createElement("style");
|
|
tag.type = "text/css";
|
|
document2.getElementsByTagName("head")[0].appendChild(tag);
|
|
if (iefail) {
|
|
document2.styleSheets[document2.styleSheets.length - 1].cssText = css;
|
|
} else {
|
|
tag[typeof document2.body.style.WebkitAppearance == "string" ? "innerText" : "innerHTML"] = css;
|
|
}
|
|
};
|
|
$2.fn.simpledraw = function(width, height, useExisting, interact) {
|
|
var target, mhandler;
|
|
if (useExisting && (target = this.data("_jqs_vcanvas"))) {
|
|
return target;
|
|
}
|
|
if ($2.fn.sparkline.canvas === false) {
|
|
return false;
|
|
} else if ($2.fn.sparkline.canvas === undefined2) {
|
|
var el2 = document2.createElement("canvas");
|
|
if (!!(el2.getContext && el2.getContext("2d"))) {
|
|
$2.fn.sparkline.canvas = function(width2, height2, target2, interact2) {
|
|
return new VCanvas_canvas(width2, height2, target2, interact2);
|
|
};
|
|
} else if (document2.namespaces && !document2.namespaces.v) {
|
|
document2.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML");
|
|
$2.fn.sparkline.canvas = function(width2, height2, target2, interact2) {
|
|
return new VCanvas_vml(width2, height2, target2);
|
|
};
|
|
} else {
|
|
$2.fn.sparkline.canvas = false;
|
|
return false;
|
|
}
|
|
}
|
|
if (width === undefined2) {
|
|
width = $2(this).innerWidth();
|
|
}
|
|
if (height === undefined2) {
|
|
height = $2(this).innerHeight();
|
|
}
|
|
target = $2.fn.sparkline.canvas(width, height, this, interact);
|
|
mhandler = $2(this).data("_jqs_mhandler");
|
|
if (mhandler) {
|
|
mhandler.registerCanvas(target);
|
|
}
|
|
return target;
|
|
};
|
|
$2.fn.cleardraw = function() {
|
|
var target = this.data("_jqs_vcanvas");
|
|
if (target) {
|
|
target.reset();
|
|
}
|
|
};
|
|
$2.RangeMapClass = RangeMap = createClass({
|
|
init: function(map) {
|
|
var key, range, rangelist = [];
|
|
for (key in map) {
|
|
if (map.hasOwnProperty(key) && typeof key === "string" && key.indexOf(":") > -1) {
|
|
range = key.split(":");
|
|
range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
|
|
range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
|
|
range[2] = map[key];
|
|
rangelist.push(range);
|
|
}
|
|
}
|
|
this.map = map;
|
|
this.rangelist = rangelist || false;
|
|
},
|
|
get: function(value) {
|
|
var rangelist = this.rangelist, i, range, result;
|
|
if ((result = this.map[value]) !== undefined2) {
|
|
return result;
|
|
}
|
|
if (rangelist) {
|
|
for (i = rangelist.length; i--; ) {
|
|
range = rangelist[i];
|
|
if (range[0] <= value && range[1] >= value) {
|
|
return range[2];
|
|
}
|
|
}
|
|
}
|
|
return undefined2;
|
|
}
|
|
});
|
|
$2.range_map = function(map) {
|
|
return new RangeMap(map);
|
|
};
|
|
MouseHandler = createClass({
|
|
init: function(el2, options) {
|
|
var $el = $2(el2);
|
|
this.$el = $el;
|
|
this.options = options;
|
|
this.currentPageX = 0;
|
|
this.currentPageY = 0;
|
|
this.el = el2;
|
|
this.splist = [];
|
|
this.tooltip = null;
|
|
this.over = false;
|
|
this.displayTooltips = !options.get("disableTooltips");
|
|
this.highlightEnabled = !options.get("disableHighlight");
|
|
},
|
|
registerSparkline: function(sp) {
|
|
this.splist.push(sp);
|
|
if (this.over) {
|
|
this.updateDisplay();
|
|
}
|
|
},
|
|
registerCanvas: function(canvas) {
|
|
var $canvas = $2(canvas.canvas);
|
|
this.canvas = canvas;
|
|
this.$canvas = $canvas;
|
|
$canvas.mouseenter($2.proxy(this.mouseenter, this));
|
|
$canvas.mouseleave($2.proxy(this.mouseleave, this));
|
|
$canvas.click($2.proxy(this.mouseclick, this));
|
|
},
|
|
reset: function(removeTooltip) {
|
|
this.splist = [];
|
|
if (this.tooltip && removeTooltip) {
|
|
this.tooltip.remove();
|
|
this.tooltip = undefined2;
|
|
}
|
|
},
|
|
mouseclick: function(e) {
|
|
var clickEvent = $2.Event("sparklineClick");
|
|
clickEvent.originalEvent = e;
|
|
clickEvent.sparklines = this.splist;
|
|
this.$el.trigger(clickEvent);
|
|
},
|
|
mouseenter: function(e) {
|
|
$2(document2.body).unbind("mousemove.jqs");
|
|
$2(document2.body).bind("mousemove.jqs", $2.proxy(this.mousemove, this));
|
|
this.over = true;
|
|
this.currentPageX = e.pageX;
|
|
this.currentPageY = e.pageY;
|
|
this.currentEl = e.target;
|
|
if (!this.tooltip && this.displayTooltips) {
|
|
this.tooltip = new Tooltip(this.options);
|
|
this.tooltip.updatePosition(e.pageX, e.pageY);
|
|
}
|
|
this.updateDisplay();
|
|
},
|
|
mouseleave: function() {
|
|
$2(document2.body).unbind("mousemove.jqs");
|
|
var splist = this.splist, spcount = splist.length, needsRefresh = false, sp, i;
|
|
this.over = false;
|
|
this.currentEl = null;
|
|
if (this.tooltip) {
|
|
this.tooltip.remove();
|
|
this.tooltip = null;
|
|
}
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
if (sp.clearRegionHighlight()) {
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
if (needsRefresh) {
|
|
this.canvas.render();
|
|
}
|
|
},
|
|
mousemove: function(e) {
|
|
this.currentPageX = e.pageX;
|
|
this.currentPageY = e.pageY;
|
|
this.currentEl = e.target;
|
|
if (this.tooltip) {
|
|
this.tooltip.updatePosition(e.pageX, e.pageY);
|
|
}
|
|
this.updateDisplay();
|
|
},
|
|
updateDisplay: function() {
|
|
var splist = this.splist, spcount = splist.length, needsRefresh = false, offset = this.$canvas.offset(), localX = this.currentPageX - offset.left, localY = this.currentPageY - offset.top, tooltiphtml, sp, i, result, changeEvent;
|
|
if (!this.over) {
|
|
return;
|
|
}
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
result = sp.setRegionHighlight(this.currentEl, localX, localY);
|
|
if (result) {
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
if (needsRefresh) {
|
|
changeEvent = $2.Event("sparklineRegionChange");
|
|
changeEvent.sparklines = this.splist;
|
|
this.$el.trigger(changeEvent);
|
|
if (this.tooltip) {
|
|
tooltiphtml = "";
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
tooltiphtml += sp.getCurrentRegionTooltip();
|
|
}
|
|
this.tooltip.setContent(tooltiphtml);
|
|
}
|
|
if (!this.disableHighlight) {
|
|
this.canvas.render();
|
|
}
|
|
}
|
|
if (result === null) {
|
|
this.mouseleave();
|
|
}
|
|
}
|
|
});
|
|
Tooltip = createClass({
|
|
sizeStyle: "position: static !important;display: block !important;visibility: hidden !important;float: left !important;",
|
|
init: function(options) {
|
|
var tooltipClassname = options.get("tooltipClassname", "jqstooltip"), sizetipStyle = this.sizeStyle, offset;
|
|
this.container = options.get("tooltipContainer") || document2.body;
|
|
this.tooltipOffsetX = options.get("tooltipOffsetX", 10);
|
|
this.tooltipOffsetY = options.get("tooltipOffsetY", 12);
|
|
$2("#jqssizetip").remove();
|
|
$2("#jqstooltip").remove();
|
|
this.sizetip = $2("<div/>", {
|
|
id: "jqssizetip",
|
|
style: sizetipStyle,
|
|
"class": tooltipClassname
|
|
});
|
|
this.tooltip = $2("<div/>", {
|
|
id: "jqstooltip",
|
|
"class": tooltipClassname
|
|
}).appendTo(this.container);
|
|
offset = this.tooltip.offset();
|
|
this.offsetLeft = offset.left;
|
|
this.offsetTop = offset.top;
|
|
this.hidden = true;
|
|
$2(window).unbind("resize.jqs scroll.jqs");
|
|
$2(window).bind("resize.jqs scroll.jqs", $2.proxy(this.updateWindowDims, this));
|
|
this.updateWindowDims();
|
|
},
|
|
updateWindowDims: function() {
|
|
this.scrollTop = $2(window).scrollTop();
|
|
this.scrollLeft = $2(window).scrollLeft();
|
|
this.scrollRight = this.scrollLeft + $2(window).width();
|
|
this.updatePosition();
|
|
},
|
|
getSize: function(content) {
|
|
this.sizetip.html(content).appendTo(this.container);
|
|
this.width = this.sizetip.width() + 1;
|
|
this.height = this.sizetip.height();
|
|
this.sizetip.remove();
|
|
},
|
|
setContent: function(content) {
|
|
if (!content) {
|
|
this.tooltip.css("visibility", "hidden");
|
|
this.hidden = true;
|
|
return;
|
|
}
|
|
this.getSize(content);
|
|
this.tooltip.html(content).css({
|
|
"width": this.width,
|
|
"height": this.height,
|
|
"visibility": "visible"
|
|
});
|
|
if (this.hidden) {
|
|
this.hidden = false;
|
|
this.updatePosition();
|
|
}
|
|
},
|
|
updatePosition: function(x, y) {
|
|
if (x === undefined2) {
|
|
if (this.mousex === undefined2) {
|
|
return;
|
|
}
|
|
x = this.mousex - this.offsetLeft;
|
|
y = this.mousey - this.offsetTop;
|
|
} else {
|
|
this.mousex = x = x - this.offsetLeft;
|
|
this.mousey = y = y - this.offsetTop;
|
|
}
|
|
if (!this.height || !this.width || this.hidden) {
|
|
return;
|
|
}
|
|
y -= this.height + this.tooltipOffsetY;
|
|
x += this.tooltipOffsetX;
|
|
if (y < this.scrollTop) {
|
|
y = this.scrollTop;
|
|
}
|
|
if (x < this.scrollLeft) {
|
|
x = this.scrollLeft;
|
|
} else if (x + this.width > this.scrollRight) {
|
|
x = this.scrollRight - this.width;
|
|
}
|
|
this.tooltip.css({
|
|
"left": x,
|
|
"top": y
|
|
});
|
|
},
|
|
remove: function() {
|
|
this.tooltip.remove();
|
|
this.sizetip.remove();
|
|
this.sizetip = this.tooltip = undefined2;
|
|
$2(window).unbind("resize.jqs scroll.jqs");
|
|
}
|
|
});
|
|
initStyles = function() {
|
|
addCSS(defaultStyles);
|
|
};
|
|
$2(initStyles);
|
|
pending = [];
|
|
$2.fn.sparkline = function(userValues, userOptions) {
|
|
return this.each(function() {
|
|
var options = new $2.fn.sparkline.options(this, userOptions), $this = $2(this), render, i;
|
|
render = function() {
|
|
var values, width, height, tmp, mhandler, sp, vals;
|
|
if (userValues === "html" || userValues === undefined2) {
|
|
vals = this.getAttribute(options.get("tagValuesAttribute"));
|
|
if (vals === undefined2 || vals === null) {
|
|
vals = $this.html();
|
|
}
|
|
values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, "").split(",");
|
|
} else {
|
|
values = userValues;
|
|
}
|
|
width = options.get("width") === "auto" ? values.length * options.get("defaultPixelsPerValue") : options.get("width");
|
|
if (options.get("height") === "auto") {
|
|
if (!options.get("composite") || !$2.data(this, "_jqs_vcanvas")) {
|
|
tmp = document2.createElement("span");
|
|
tmp.innerHTML = "a";
|
|
$this.html(tmp);
|
|
height = $2(tmp).innerHeight() || $2(tmp).height();
|
|
$2(tmp).remove();
|
|
tmp = null;
|
|
}
|
|
} else {
|
|
height = options.get("height");
|
|
}
|
|
if (!options.get("disableInteraction")) {
|
|
mhandler = $2.data(this, "_jqs_mhandler");
|
|
if (!mhandler) {
|
|
mhandler = new MouseHandler(this, options);
|
|
$2.data(this, "_jqs_mhandler", mhandler);
|
|
} else if (!options.get("composite")) {
|
|
mhandler.reset();
|
|
}
|
|
} else {
|
|
mhandler = false;
|
|
}
|
|
if (options.get("composite") && !$2.data(this, "_jqs_vcanvas")) {
|
|
if (!$2.data(this, "_jqs_errnotify")) {
|
|
alert("Attempted to attach a composite sparkline to an element with no existing sparkline");
|
|
$2.data(this, "_jqs_errnotify", true);
|
|
}
|
|
return;
|
|
}
|
|
sp = new $2.fn.sparkline[options.get("type")](this, values, options, width, height);
|
|
sp.render();
|
|
if (mhandler) {
|
|
mhandler.registerSparkline(sp);
|
|
}
|
|
};
|
|
if ($2(this).html() && !options.get("disableHiddenCheck") && $2(this).is(":hidden") || !$2(this).parents("body").length) {
|
|
if (!options.get("composite") && $2.data(this, "_jqs_pending")) {
|
|
for (i = pending.length; i; i--) {
|
|
if (pending[i - 1][0] == this) {
|
|
pending.splice(i - 1, 1);
|
|
}
|
|
}
|
|
}
|
|
pending.push([this, render]);
|
|
$2.data(this, "_jqs_pending", true);
|
|
} else {
|
|
render.call(this);
|
|
}
|
|
});
|
|
};
|
|
$2.fn.sparkline.defaults = getDefaults();
|
|
$2.sparkline_display_visible = function() {
|
|
var el2, i, pl;
|
|
var done = [];
|
|
for (i = 0, pl = pending.length; i < pl; i++) {
|
|
el2 = pending[i][0];
|
|
if ($2(el2).is(":visible") && !$2(el2).parents().is(":hidden")) {
|
|
pending[i][1].call(el2);
|
|
$2.data(pending[i][0], "_jqs_pending", false);
|
|
done.push(i);
|
|
} else if (!$2(el2).closest("html").length && !$2.data(el2, "_jqs_pending")) {
|
|
$2.data(pending[i][0], "_jqs_pending", false);
|
|
done.push(i);
|
|
}
|
|
}
|
|
for (i = done.length; i; i--) {
|
|
pending.splice(done[i - 1], 1);
|
|
}
|
|
};
|
|
$2.fn.sparkline.options = createClass({
|
|
init: function(tag, userOptions) {
|
|
var extendedOptions, defaults, base, tagOptionType;
|
|
this.userOptions = userOptions = userOptions || {};
|
|
this.tag = tag;
|
|
this.tagValCache = {};
|
|
defaults = $2.fn.sparkline.defaults;
|
|
base = defaults.common;
|
|
this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
|
|
tagOptionType = this.getTagSetting("type");
|
|
if (tagOptionType === UNSET_OPTION) {
|
|
extendedOptions = defaults[userOptions.type || base.type];
|
|
} else {
|
|
extendedOptions = defaults[tagOptionType];
|
|
}
|
|
this.mergedOptions = $2.extend({}, base, extendedOptions, userOptions);
|
|
},
|
|
getTagSetting: function(key) {
|
|
var prefix = this.tagOptionsPrefix, val, i, pairs, keyval;
|
|
if (prefix === false || prefix === undefined2) {
|
|
return UNSET_OPTION;
|
|
}
|
|
if (this.tagValCache.hasOwnProperty(key)) {
|
|
val = this.tagValCache.key;
|
|
} else {
|
|
val = this.tag.getAttribute(prefix + key);
|
|
if (val === undefined2 || val === null) {
|
|
val = UNSET_OPTION;
|
|
} else if (val.substr(0, 1) === "[") {
|
|
val = val.substr(1, val.length - 2).split(",");
|
|
for (i = val.length; i--; ) {
|
|
val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ""));
|
|
}
|
|
} else if (val.substr(0, 1) === "{") {
|
|
pairs = val.substr(1, val.length - 2).split(",");
|
|
val = {};
|
|
for (i = pairs.length; i--; ) {
|
|
keyval = pairs[i].split(":", 2);
|
|
val[keyval[0].replace(/(^\s*)|(\s*$)/g, "")] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ""));
|
|
}
|
|
} else {
|
|
val = normalizeValue(val);
|
|
}
|
|
this.tagValCache.key = val;
|
|
}
|
|
return val;
|
|
},
|
|
get: function(key, defaultval) {
|
|
var tagOption = this.getTagSetting(key), result;
|
|
if (tagOption !== UNSET_OPTION) {
|
|
return tagOption;
|
|
}
|
|
return (result = this.mergedOptions[key]) === undefined2 ? defaultval : result;
|
|
}
|
|
});
|
|
$2.fn.sparkline._base = createClass({
|
|
disabled: false,
|
|
init: function(el2, values, options, width, height) {
|
|
this.el = el2;
|
|
this.$el = $2(el2);
|
|
this.values = values;
|
|
this.options = options;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.currentRegion = undefined2;
|
|
},
|
|
/**
|
|
* Setup the canvas
|
|
*/
|
|
initTarget: function() {
|
|
var interactive = !this.options.get("disableInteraction");
|
|
if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get("composite"), interactive))) {
|
|
this.disabled = true;
|
|
} else {
|
|
this.canvasWidth = this.target.pixelWidth;
|
|
this.canvasHeight = this.target.pixelHeight;
|
|
}
|
|
},
|
|
/**
|
|
* Actually render the chart to the canvas
|
|
*/
|
|
render: function() {
|
|
if (this.disabled) {
|
|
this.el.innerHTML = "";
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
/**
|
|
* Return a region id for a given x/y co-ordinate
|
|
*/
|
|
getRegion: function(x, y) {
|
|
},
|
|
/**
|
|
* Highlight an item based on the moused-over x,y co-ordinate
|
|
*/
|
|
setRegionHighlight: function(el2, x, y) {
|
|
var currentRegion = this.currentRegion, highlightEnabled = !this.options.get("disableHighlight"), newRegion;
|
|
if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
|
|
return null;
|
|
}
|
|
newRegion = this.getRegion(el2, x, y);
|
|
if (currentRegion !== newRegion) {
|
|
if (currentRegion !== undefined2 && highlightEnabled) {
|
|
this.removeHighlight();
|
|
}
|
|
this.currentRegion = newRegion;
|
|
if (newRegion !== undefined2 && highlightEnabled) {
|
|
this.renderHighlight();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
/**
|
|
* Reset any currently highlighted item
|
|
*/
|
|
clearRegionHighlight: function() {
|
|
if (this.currentRegion !== undefined2) {
|
|
this.removeHighlight();
|
|
this.currentRegion = undefined2;
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
renderHighlight: function() {
|
|
this.changeHighlight(true);
|
|
},
|
|
removeHighlight: function() {
|
|
this.changeHighlight(false);
|
|
},
|
|
changeHighlight: function(highlight) {
|
|
},
|
|
/**
|
|
* Fetch the HTML to display as a tooltip
|
|
*/
|
|
getCurrentRegionTooltip: function() {
|
|
var options = this.options, header = "", entries = [], fields, formats, formatlen, fclass, text, i, showFields, showFieldsKey, newFields, fv, formatter, format2, fieldlen, j;
|
|
if (this.currentRegion === undefined2) {
|
|
return "";
|
|
}
|
|
fields = this.getCurrentRegionFields();
|
|
formatter = options.get("tooltipFormatter");
|
|
if (formatter) {
|
|
return formatter(this, options, fields);
|
|
}
|
|
if (options.get("tooltipChartTitle")) {
|
|
header += '<div class="jqs jqstitle">' + options.get("tooltipChartTitle") + "</div>\n";
|
|
}
|
|
formats = this.options.get("tooltipFormat");
|
|
if (!formats) {
|
|
return "";
|
|
}
|
|
if (!$2.isArray(formats)) {
|
|
formats = [formats];
|
|
}
|
|
if (!$2.isArray(fields)) {
|
|
fields = [fields];
|
|
}
|
|
showFields = this.options.get("tooltipFormatFieldlist");
|
|
showFieldsKey = this.options.get("tooltipFormatFieldlistKey");
|
|
if (showFields && showFieldsKey) {
|
|
newFields = [];
|
|
for (i = fields.length; i--; ) {
|
|
fv = fields[i][showFieldsKey];
|
|
if ((j = $2.inArray(fv, showFields)) != -1) {
|
|
newFields[j] = fields[i];
|
|
}
|
|
}
|
|
fields = newFields;
|
|
}
|
|
formatlen = formats.length;
|
|
fieldlen = fields.length;
|
|
for (i = 0; i < formatlen; i++) {
|
|
format2 = formats[i];
|
|
if (typeof format2 === "string") {
|
|
format2 = new SPFormat(format2);
|
|
}
|
|
fclass = format2.fclass || "jqsfield";
|
|
for (j = 0; j < fieldlen; j++) {
|
|
if (!fields[j].isNull || !options.get("tooltipSkipNull")) {
|
|
$2.extend(fields[j], {
|
|
prefix: options.get("tooltipPrefix"),
|
|
suffix: options.get("tooltipSuffix")
|
|
});
|
|
text = format2.render(fields[j], options.get("tooltipValueLookups"), options);
|
|
entries.push('<div class="' + fclass + '">' + text + "</div>");
|
|
}
|
|
}
|
|
}
|
|
if (entries.length) {
|
|
return header + entries.join("\n");
|
|
}
|
|
return "";
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
},
|
|
calcHighlightColor: function(color, options) {
|
|
var highlightColor = options.get("highlightColor"), lighten = options.get("highlightLighten"), parse, mult, rgbnew, i;
|
|
if (highlightColor) {
|
|
return highlightColor;
|
|
}
|
|
if (lighten) {
|
|
parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
|
|
if (parse) {
|
|
rgbnew = [];
|
|
mult = color.length === 4 ? 16 : 1;
|
|
for (i = 0; i < 3; i++) {
|
|
rgbnew[i] = clipval(Math2.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
|
|
}
|
|
return "rgb(" + rgbnew.join(",") + ")";
|
|
}
|
|
}
|
|
return color;
|
|
}
|
|
});
|
|
barHighlightMixin = {
|
|
changeHighlight: function(highlight) {
|
|
var currentRegion = this.currentRegion, target = this.target, shapeids = this.regionShapes[currentRegion], newShapes;
|
|
if (shapeids) {
|
|
newShapes = this.renderRegion(currentRegion, highlight);
|
|
if ($2.isArray(newShapes) || $2.isArray(shapeids)) {
|
|
target.replaceWithShapes(shapeids, newShapes);
|
|
this.regionShapes[currentRegion] = $2.map(newShapes, function(newShape) {
|
|
return newShape.id;
|
|
});
|
|
} else {
|
|
target.replaceWithShape(shapeids, newShapes);
|
|
this.regionShapes[currentRegion] = newShapes.id;
|
|
}
|
|
}
|
|
},
|
|
render: function() {
|
|
var values = this.values, target = this.target, regionShapes = this.regionShapes, shapes, ids, i, j;
|
|
if (!this.cls._super.render.call(this)) {
|
|
return;
|
|
}
|
|
for (i = values.length; i--; ) {
|
|
shapes = this.renderRegion(i);
|
|
if (shapes) {
|
|
if ($2.isArray(shapes)) {
|
|
ids = [];
|
|
for (j = shapes.length; j--; ) {
|
|
shapes[j].append();
|
|
ids.push(shapes[j].id);
|
|
}
|
|
regionShapes[i] = ids;
|
|
} else {
|
|
shapes.append();
|
|
regionShapes[i] = shapes.id;
|
|
}
|
|
} else {
|
|
regionShapes[i] = null;
|
|
}
|
|
}
|
|
target.render();
|
|
}
|
|
};
|
|
$2.fn.sparkline.line = line = createClass($2.fn.sparkline._base, {
|
|
type: "line",
|
|
init: function(el2, values, options, width, height) {
|
|
line._super.init.call(this, el2, values, options, width, height);
|
|
this.vertices = [];
|
|
this.regionMap = [];
|
|
this.xvalues = [];
|
|
this.yvalues = [];
|
|
this.yminmax = [];
|
|
this.hightlightSpotId = null;
|
|
this.lastShapeId = null;
|
|
this.initTarget();
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
var i, regionMap = this.regionMap;
|
|
for (i = regionMap.length; i--; ) {
|
|
if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
|
|
return regionMap[i][2];
|
|
}
|
|
}
|
|
return undefined2;
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.yvalues[currentRegion] === null,
|
|
x: this.xvalues[currentRegion],
|
|
y: this.yvalues[currentRegion],
|
|
color: this.options.get("lineColor"),
|
|
fillColor: this.options.get("fillColor"),
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
renderHighlight: function() {
|
|
var currentRegion = this.currentRegion, target = this.target, vertex = this.vertices[currentRegion], options = this.options, spotRadius = options.get("spotRadius"), highlightSpotColor = options.get("highlightSpotColor"), highlightLineColor = options.get("highlightLineColor"), highlightSpot, highlightLine;
|
|
if (!vertex) {
|
|
return;
|
|
}
|
|
if (spotRadius && highlightSpotColor) {
|
|
highlightSpot = target.drawCircle(
|
|
vertex[0],
|
|
vertex[1],
|
|
spotRadius,
|
|
undefined2,
|
|
highlightSpotColor
|
|
);
|
|
this.highlightSpotId = highlightSpot.id;
|
|
target.insertAfterShape(this.lastShapeId, highlightSpot);
|
|
}
|
|
if (highlightLineColor) {
|
|
highlightLine = target.drawLine(
|
|
vertex[0],
|
|
this.canvasTop,
|
|
vertex[0],
|
|
this.canvasTop + this.canvasHeight,
|
|
highlightLineColor
|
|
);
|
|
this.highlightLineId = highlightLine.id;
|
|
target.insertAfterShape(this.lastShapeId, highlightLine);
|
|
}
|
|
},
|
|
removeHighlight: function() {
|
|
var target = this.target;
|
|
if (this.highlightSpotId) {
|
|
target.removeShapeId(this.highlightSpotId);
|
|
this.highlightSpotId = null;
|
|
}
|
|
if (this.highlightLineId) {
|
|
target.removeShapeId(this.highlightLineId);
|
|
this.highlightLineId = null;
|
|
}
|
|
},
|
|
scanValues: function() {
|
|
var values = this.values, valcount = values.length, xvalues = this.xvalues, yvalues = this.yvalues, yminmax = this.yminmax, i, val, isStr, isArray, sp;
|
|
for (i = 0; i < valcount; i++) {
|
|
val = values[i];
|
|
isStr = typeof values[i] === "string";
|
|
isArray = typeof values[i] === "object" && values[i] instanceof Array;
|
|
sp = isStr && values[i].split(":");
|
|
if (isStr && sp.length === 2) {
|
|
xvalues.push(Number(sp[0]));
|
|
yvalues.push(Number(sp[1]));
|
|
yminmax.push(Number(sp[1]));
|
|
} else if (isArray) {
|
|
xvalues.push(val[0]);
|
|
yvalues.push(val[1]);
|
|
yminmax.push(val[1]);
|
|
} else {
|
|
xvalues.push(i);
|
|
if (values[i] === null || values[i] === "null") {
|
|
yvalues.push(null);
|
|
} else {
|
|
yvalues.push(Number(val));
|
|
yminmax.push(Number(val));
|
|
}
|
|
}
|
|
}
|
|
if (this.options.get("xvalues")) {
|
|
xvalues = this.options.get("xvalues");
|
|
}
|
|
this.maxy = this.maxyorg = Math2.max.apply(Math2, yminmax);
|
|
this.miny = this.minyorg = Math2.min.apply(Math2, yminmax);
|
|
this.maxx = Math2.max.apply(Math2, xvalues);
|
|
this.minx = Math2.min.apply(Math2, xvalues);
|
|
this.xvalues = xvalues;
|
|
this.yvalues = yvalues;
|
|
this.yminmax = yminmax;
|
|
},
|
|
processRangeOptions: function() {
|
|
var options = this.options, normalRangeMin = options.get("normalRangeMin"), normalRangeMax = options.get("normalRangeMax");
|
|
if (normalRangeMin !== undefined2) {
|
|
if (normalRangeMin < this.miny) {
|
|
this.miny = normalRangeMin;
|
|
}
|
|
if (normalRangeMax > this.maxy) {
|
|
this.maxy = normalRangeMax;
|
|
}
|
|
}
|
|
if (options.get("chartRangeMin") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMin") < this.miny)) {
|
|
this.miny = options.get("chartRangeMin");
|
|
}
|
|
if (options.get("chartRangeMax") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMax") > this.maxy)) {
|
|
this.maxy = options.get("chartRangeMax");
|
|
}
|
|
if (options.get("chartRangeMinX") !== undefined2 && (options.get("chartRangeClipX") || options.get("chartRangeMinX") < this.minx)) {
|
|
this.minx = options.get("chartRangeMinX");
|
|
}
|
|
if (options.get("chartRangeMaxX") !== undefined2 && (options.get("chartRangeClipX") || options.get("chartRangeMaxX") > this.maxx)) {
|
|
this.maxx = options.get("chartRangeMaxX");
|
|
}
|
|
},
|
|
drawNormalRange: function(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
|
|
var normalRangeMin = this.options.get("normalRangeMin"), normalRangeMax = this.options.get("normalRangeMax"), ytop = canvasTop + Math2.round(canvasHeight - canvasHeight * ((normalRangeMax - this.miny) / rangey)), height = Math2.round(canvasHeight * (normalRangeMax - normalRangeMin) / rangey);
|
|
this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined2, this.options.get("normalRangeColor")).append();
|
|
},
|
|
render: function() {
|
|
var options = this.options, target = this.target, canvasWidth = this.canvasWidth, canvasHeight = this.canvasHeight, vertices = this.vertices, spotRadius = options.get("spotRadius"), regionMap = this.regionMap, rangex, rangey, yvallast, canvasTop, canvasLeft, vertex, path, paths, x, y, xnext, xpos, xposnext, last, next, yvalcount, lineShapes, fillShapes, plen, valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
|
|
if (!line._super.render.call(this)) {
|
|
return;
|
|
}
|
|
this.scanValues();
|
|
this.processRangeOptions();
|
|
xvalues = this.xvalues;
|
|
yvalues = this.yvalues;
|
|
if (!this.yminmax.length || this.yvalues.length < 2) {
|
|
return;
|
|
}
|
|
canvasTop = canvasLeft = 0;
|
|
rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
|
|
rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
|
|
yvallast = this.yvalues.length - 1;
|
|
if (spotRadius && (canvasWidth < spotRadius * 4 || canvasHeight < spotRadius * 4)) {
|
|
spotRadius = 0;
|
|
}
|
|
if (spotRadius) {
|
|
hlSpotsEnabled = options.get("highlightSpotColor") && !options.get("disableInteraction");
|
|
if (hlSpotsEnabled || options.get("minSpotColor") || options.get("spotColor") && yvalues[yvallast] === this.miny) {
|
|
canvasHeight -= Math2.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled || options.get("maxSpotColor") || options.get("spotColor") && yvalues[yvallast] === this.maxy) {
|
|
canvasHeight -= Math2.ceil(spotRadius);
|
|
canvasTop += Math2.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled || (options.get("minSpotColor") || options.get("maxSpotColor")) && (yvalues[0] === this.miny || yvalues[0] === this.maxy)) {
|
|
canvasLeft += Math2.ceil(spotRadius);
|
|
canvasWidth -= Math2.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled || options.get("spotColor") || (options.get("minSpotColor") || options.get("maxSpotColor") && (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
|
|
canvasWidth -= Math2.ceil(spotRadius);
|
|
}
|
|
}
|
|
canvasHeight--;
|
|
if (options.get("normalRangeMin") !== undefined2 && !options.get("drawNormalOnTop")) {
|
|
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
|
|
}
|
|
path = [];
|
|
paths = [path];
|
|
last = next = null;
|
|
yvalcount = yvalues.length;
|
|
for (i = 0; i < yvalcount; i++) {
|
|
x = xvalues[i];
|
|
xnext = xvalues[i + 1];
|
|
y = yvalues[i];
|
|
xpos = canvasLeft + Math2.round((x - this.minx) * (canvasWidth / rangex));
|
|
xposnext = i < yvalcount - 1 ? canvasLeft + Math2.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
|
|
next = xpos + (xposnext - xpos) / 2;
|
|
regionMap[i] = [last || 0, next, i];
|
|
last = next;
|
|
if (y === null) {
|
|
if (i) {
|
|
if (yvalues[i - 1] !== null) {
|
|
path = [];
|
|
paths.push(path);
|
|
}
|
|
vertices.push(null);
|
|
}
|
|
} else {
|
|
if (y < this.miny) {
|
|
y = this.miny;
|
|
}
|
|
if (y > this.maxy) {
|
|
y = this.maxy;
|
|
}
|
|
if (!path.length) {
|
|
path.push([xpos, canvasTop + canvasHeight]);
|
|
}
|
|
vertex = [xpos, canvasTop + Math2.round(canvasHeight - canvasHeight * ((y - this.miny) / rangey))];
|
|
path.push(vertex);
|
|
vertices.push(vertex);
|
|
}
|
|
}
|
|
lineShapes = [];
|
|
fillShapes = [];
|
|
plen = paths.length;
|
|
for (i = 0; i < plen; i++) {
|
|
path = paths[i];
|
|
if (path.length) {
|
|
if (options.get("fillColor")) {
|
|
path.push([path[path.length - 1][0], canvasTop + canvasHeight]);
|
|
fillShapes.push(path.slice(0));
|
|
path.pop();
|
|
}
|
|
if (path.length > 2) {
|
|
path[0] = [path[0][0], path[1][1]];
|
|
}
|
|
lineShapes.push(path);
|
|
}
|
|
}
|
|
plen = fillShapes.length;
|
|
for (i = 0; i < plen; i++) {
|
|
target.drawShape(
|
|
fillShapes[i],
|
|
options.get("fillColor"),
|
|
options.get("fillColor")
|
|
).append();
|
|
}
|
|
if (options.get("normalRangeMin") !== undefined2 && options.get("drawNormalOnTop")) {
|
|
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
|
|
}
|
|
plen = lineShapes.length;
|
|
for (i = 0; i < plen; i++) {
|
|
target.drawShape(
|
|
lineShapes[i],
|
|
options.get("lineColor"),
|
|
undefined2,
|
|
options.get("lineWidth")
|
|
).append();
|
|
}
|
|
if (spotRadius && options.get("valueSpots")) {
|
|
valueSpots = options.get("valueSpots");
|
|
if (valueSpots.get === undefined2) {
|
|
valueSpots = new RangeMap(valueSpots);
|
|
}
|
|
for (i = 0; i < yvalcount; i++) {
|
|
color = valueSpots.get(yvalues[i]);
|
|
if (color) {
|
|
target.drawCircle(
|
|
canvasLeft + Math2.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math2.round(canvasHeight - canvasHeight * ((yvalues[i] - this.miny) / rangey)),
|
|
spotRadius,
|
|
undefined2,
|
|
color
|
|
).append();
|
|
}
|
|
}
|
|
}
|
|
if (spotRadius && options.get("spotColor") && yvalues[yvallast] !== null) {
|
|
target.drawCircle(
|
|
canvasLeft + Math2.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math2.round(canvasHeight - canvasHeight * ((yvalues[yvallast] - this.miny) / rangey)),
|
|
spotRadius,
|
|
undefined2,
|
|
options.get("spotColor")
|
|
).append();
|
|
}
|
|
if (this.maxy !== this.minyorg) {
|
|
if (spotRadius && options.get("minSpotColor")) {
|
|
x = xvalues[$2.inArray(this.minyorg, yvalues)];
|
|
target.drawCircle(
|
|
canvasLeft + Math2.round((x - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math2.round(canvasHeight - canvasHeight * ((this.minyorg - this.miny) / rangey)),
|
|
spotRadius,
|
|
undefined2,
|
|
options.get("minSpotColor")
|
|
).append();
|
|
}
|
|
if (spotRadius && options.get("maxSpotColor")) {
|
|
x = xvalues[$2.inArray(this.maxyorg, yvalues)];
|
|
target.drawCircle(
|
|
canvasLeft + Math2.round((x - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math2.round(canvasHeight - canvasHeight * ((this.maxyorg - this.miny) / rangey)),
|
|
spotRadius,
|
|
undefined2,
|
|
options.get("maxSpotColor")
|
|
).append();
|
|
}
|
|
}
|
|
this.lastShapeId = target.getLastShapeId();
|
|
this.canvasTop = canvasTop;
|
|
target.render();
|
|
}
|
|
});
|
|
$2.fn.sparkline.bar = bar = createClass($2.fn.sparkline._base, barHighlightMixin, {
|
|
type: "bar",
|
|
init: function(el2, values, options, width, height) {
|
|
var barWidth = parseInt(options.get("barWidth"), 10), barSpacing = parseInt(options.get("barSpacing"), 10), chartRangeMin = options.get("chartRangeMin"), chartRangeMax = options.get("chartRangeMax"), chartRangeClip = options.get("chartRangeClip"), stackMin = Infinity, stackMax = -Infinity, isStackString, groupMin, groupMax, stackRanges, numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax, stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
|
|
bar._super.init.call(this, el2, values, options, width, height);
|
|
for (i = 0, vlen = values.length; i < vlen; i++) {
|
|
val = values[i];
|
|
isStackString = typeof val === "string" && val.indexOf(":") > -1;
|
|
if (isStackString || $2.isArray(val)) {
|
|
stacked = true;
|
|
if (isStackString) {
|
|
val = values[i] = normalizeValues(val.split(":"));
|
|
}
|
|
val = remove(val, null);
|
|
groupMin = Math2.min.apply(Math2, val);
|
|
groupMax = Math2.max.apply(Math2, val);
|
|
if (groupMin < stackMin) {
|
|
stackMin = groupMin;
|
|
}
|
|
if (groupMax > stackMax) {
|
|
stackMax = groupMax;
|
|
}
|
|
}
|
|
}
|
|
this.stacked = stacked;
|
|
this.regionShapes = {};
|
|
this.barWidth = barWidth;
|
|
this.barSpacing = barSpacing;
|
|
this.totalBarWidth = barWidth + barSpacing;
|
|
this.width = width = values.length * barWidth + (values.length - 1) * barSpacing;
|
|
this.initTarget();
|
|
if (chartRangeClip) {
|
|
clipMin = chartRangeMin === undefined2 ? -Infinity : chartRangeMin;
|
|
clipMax = chartRangeMax === undefined2 ? Infinity : chartRangeMax;
|
|
}
|
|
numValues = [];
|
|
stackRanges = stacked ? [] : numValues;
|
|
var stackTotals = [];
|
|
var stackRangesNeg = [];
|
|
for (i = 0, vlen = values.length; i < vlen; i++) {
|
|
if (stacked) {
|
|
vlist = values[i];
|
|
values[i] = svals = [];
|
|
stackTotals[i] = 0;
|
|
stackRanges[i] = stackRangesNeg[i] = 0;
|
|
for (j = 0, slen = vlist.length; j < slen; j++) {
|
|
val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
|
|
if (val !== null) {
|
|
if (val > 0) {
|
|
stackTotals[i] += val;
|
|
}
|
|
if (stackMin < 0 && stackMax > 0) {
|
|
if (val < 0) {
|
|
stackRangesNeg[i] += Math2.abs(val);
|
|
} else {
|
|
stackRanges[i] += val;
|
|
}
|
|
} else {
|
|
stackRanges[i] += Math2.abs(val - (val < 0 ? stackMax : stackMin));
|
|
}
|
|
numValues.push(val);
|
|
}
|
|
}
|
|
} else {
|
|
val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
|
|
val = values[i] = normalizeValue(val);
|
|
if (val !== null) {
|
|
numValues.push(val);
|
|
}
|
|
}
|
|
}
|
|
this.max = max = Math2.max.apply(Math2, numValues);
|
|
this.min = min = Math2.min.apply(Math2, numValues);
|
|
this.stackMax = stackMax = stacked ? Math2.max.apply(Math2, stackTotals) : max;
|
|
this.stackMin = stackMin = stacked ? Math2.min.apply(Math2, numValues) : min;
|
|
if (options.get("chartRangeMin") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMin") < min)) {
|
|
min = options.get("chartRangeMin");
|
|
}
|
|
if (options.get("chartRangeMax") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMax") > max)) {
|
|
max = options.get("chartRangeMax");
|
|
}
|
|
this.zeroAxis = zeroAxis = options.get("zeroAxis", true);
|
|
if (min <= 0 && max >= 0 && zeroAxis) {
|
|
xaxisOffset = 0;
|
|
} else if (zeroAxis == false) {
|
|
xaxisOffset = min;
|
|
} else if (min > 0) {
|
|
xaxisOffset = min;
|
|
} else {
|
|
xaxisOffset = max;
|
|
}
|
|
this.xaxisOffset = xaxisOffset;
|
|
range = stacked ? Math2.max.apply(Math2, stackRanges) + Math2.max.apply(Math2, stackRangesNeg) : max - min;
|
|
this.canvasHeightEf = zeroAxis && min < 0 ? this.canvasHeight - 2 : this.canvasHeight - 1;
|
|
if (min < xaxisOffset) {
|
|
yMaxCalc = stacked && max >= 0 ? stackMax : max;
|
|
yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
|
|
if (yoffset !== Math2.ceil(yoffset)) {
|
|
this.canvasHeightEf -= 2;
|
|
yoffset = Math2.ceil(yoffset);
|
|
}
|
|
} else {
|
|
yoffset = this.canvasHeight;
|
|
}
|
|
this.yoffset = yoffset;
|
|
if ($2.isArray(options.get("colorMap"))) {
|
|
this.colorMapByIndex = options.get("colorMap");
|
|
this.colorMapByValue = null;
|
|
} else {
|
|
this.colorMapByIndex = null;
|
|
this.colorMapByValue = options.get("colorMap");
|
|
if (this.colorMapByValue && this.colorMapByValue.get === undefined2) {
|
|
this.colorMapByValue = new RangeMap(this.colorMapByValue);
|
|
}
|
|
}
|
|
this.range = range;
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
var result = Math2.floor(x / this.totalBarWidth);
|
|
return result < 0 || result >= this.values.length ? undefined2 : result;
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion, values = ensureArray(this.values[currentRegion]), result = [], value, i;
|
|
for (i = values.length; i--; ) {
|
|
value = values[i];
|
|
result.push({
|
|
isNull: value === null,
|
|
value,
|
|
color: this.calcColor(i, value, currentRegion),
|
|
offset: currentRegion
|
|
});
|
|
}
|
|
return result;
|
|
},
|
|
calcColor: function(stacknum, value, valuenum) {
|
|
var colorMapByIndex = this.colorMapByIndex, colorMapByValue = this.colorMapByValue, options = this.options, color, newColor;
|
|
if (this.stacked) {
|
|
color = options.get("stackedBarColor");
|
|
} else {
|
|
color = value < 0 ? options.get("negBarColor") : options.get("barColor");
|
|
}
|
|
if (value === 0 && options.get("zeroColor") !== undefined2) {
|
|
color = options.get("zeroColor");
|
|
}
|
|
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
|
|
color = newColor;
|
|
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
|
|
color = colorMapByIndex[valuenum];
|
|
}
|
|
return $2.isArray(color) ? color[stacknum % color.length] : color;
|
|
},
|
|
/**
|
|
* Render bar(s) for a region
|
|
*/
|
|
renderRegion: function(valuenum, highlight) {
|
|
var vals = this.values[valuenum], options = this.options, xaxisOffset = this.xaxisOffset, result = [], range = this.range, stacked = this.stacked, target = this.target, x = valuenum * this.totalBarWidth, canvasHeightEf = this.canvasHeightEf, yoffset = this.yoffset, y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
|
|
vals = $2.isArray(vals) ? vals : [vals];
|
|
valcount = vals.length;
|
|
val = vals[0];
|
|
isNull = all(null, vals);
|
|
allMin = all(xaxisOffset, vals, true);
|
|
if (isNull) {
|
|
if (options.get("nullColor")) {
|
|
color = highlight ? options.get("nullColor") : this.calcHighlightColor(options.get("nullColor"), options);
|
|
y = yoffset > 0 ? yoffset - 1 : yoffset;
|
|
return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
|
|
} else {
|
|
return undefined2;
|
|
}
|
|
}
|
|
yoffsetNeg = yoffset;
|
|
for (i = 0; i < valcount; i++) {
|
|
val = vals[i];
|
|
if (stacked && val === xaxisOffset) {
|
|
if (!allMin || minPlotted) {
|
|
continue;
|
|
}
|
|
minPlotted = true;
|
|
}
|
|
if (range > 0) {
|
|
height = Math2.floor(canvasHeightEf * (Math2.abs(val - xaxisOffset) / range)) + 1;
|
|
} else {
|
|
height = 1;
|
|
}
|
|
if (val < xaxisOffset || val === xaxisOffset && yoffset === 0) {
|
|
y = yoffsetNeg;
|
|
yoffsetNeg += height;
|
|
} else {
|
|
y = yoffset - height;
|
|
yoffset -= height;
|
|
}
|
|
color = this.calcColor(i, val, valuenum);
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
|
|
}
|
|
if (result.length === 1) {
|
|
return result[0];
|
|
}
|
|
return result;
|
|
}
|
|
});
|
|
$2.fn.sparkline.tristate = tristate = createClass($2.fn.sparkline._base, barHighlightMixin, {
|
|
type: "tristate",
|
|
init: function(el2, values, options, width, height) {
|
|
var barWidth = parseInt(options.get("barWidth"), 10), barSpacing = parseInt(options.get("barSpacing"), 10);
|
|
tristate._super.init.call(this, el2, values, options, width, height);
|
|
this.regionShapes = {};
|
|
this.barWidth = barWidth;
|
|
this.barSpacing = barSpacing;
|
|
this.totalBarWidth = barWidth + barSpacing;
|
|
this.values = $2.map(values, Number);
|
|
this.width = width = values.length * barWidth + (values.length - 1) * barSpacing;
|
|
if ($2.isArray(options.get("colorMap"))) {
|
|
this.colorMapByIndex = options.get("colorMap");
|
|
this.colorMapByValue = null;
|
|
} else {
|
|
this.colorMapByIndex = null;
|
|
this.colorMapByValue = options.get("colorMap");
|
|
if (this.colorMapByValue && this.colorMapByValue.get === undefined2) {
|
|
this.colorMapByValue = new RangeMap(this.colorMapByValue);
|
|
}
|
|
}
|
|
this.initTarget();
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
return Math2.floor(x / this.totalBarWidth);
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined2,
|
|
value: this.values[currentRegion],
|
|
color: this.calcColor(this.values[currentRegion], currentRegion),
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
calcColor: function(value, valuenum) {
|
|
var values = this.values, options = this.options, colorMapByIndex = this.colorMapByIndex, colorMapByValue = this.colorMapByValue, color, newColor;
|
|
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
|
|
color = newColor;
|
|
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
|
|
color = colorMapByIndex[valuenum];
|
|
} else if (values[valuenum] < 0) {
|
|
color = options.get("negBarColor");
|
|
} else if (values[valuenum] > 0) {
|
|
color = options.get("posBarColor");
|
|
} else {
|
|
color = options.get("zeroBarColor");
|
|
}
|
|
return color;
|
|
},
|
|
renderRegion: function(valuenum, highlight) {
|
|
var values = this.values, options = this.options, target = this.target, canvasHeight, height, halfHeight, x, y, color;
|
|
canvasHeight = target.pixelHeight;
|
|
halfHeight = Math2.round(canvasHeight / 2);
|
|
x = valuenum * this.totalBarWidth;
|
|
if (values[valuenum] < 0) {
|
|
y = halfHeight;
|
|
height = halfHeight - 1;
|
|
} else if (values[valuenum] > 0) {
|
|
y = 0;
|
|
height = halfHeight - 1;
|
|
} else {
|
|
y = halfHeight - 1;
|
|
height = 2;
|
|
}
|
|
color = this.calcColor(values[valuenum], valuenum);
|
|
if (color === null) {
|
|
return;
|
|
}
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
|
|
}
|
|
});
|
|
$2.fn.sparkline.discrete = discrete = createClass($2.fn.sparkline._base, barHighlightMixin, {
|
|
type: "discrete",
|
|
init: function(el2, values, options, width, height) {
|
|
discrete._super.init.call(this, el2, values, options, width, height);
|
|
this.regionShapes = {};
|
|
this.values = values = $2.map(values, Number);
|
|
this.min = Math2.min.apply(Math2, values);
|
|
this.max = Math2.max.apply(Math2, values);
|
|
this.range = this.max - this.min;
|
|
this.width = width = options.get("width") === "auto" ? values.length * 2 : this.width;
|
|
this.interval = Math2.floor(width / values.length);
|
|
this.itemWidth = width / values.length;
|
|
if (options.get("chartRangeMin") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMin") < this.min)) {
|
|
this.min = options.get("chartRangeMin");
|
|
}
|
|
if (options.get("chartRangeMax") !== undefined2 && (options.get("chartRangeClip") || options.get("chartRangeMax") > this.max)) {
|
|
this.max = options.get("chartRangeMax");
|
|
}
|
|
this.initTarget();
|
|
if (this.target) {
|
|
this.lineHeight = options.get("lineHeight") === "auto" ? Math2.round(this.canvasHeight * 0.3) : options.get("lineHeight");
|
|
}
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
return Math2.floor(x / this.itemWidth);
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined2,
|
|
value: this.values[currentRegion],
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
renderRegion: function(valuenum, highlight) {
|
|
var values = this.values, options = this.options, min = this.min, max = this.max, range = this.range, interval = this.interval, target = this.target, canvasHeight = this.canvasHeight, lineHeight = this.lineHeight, pheight = canvasHeight - lineHeight, ytop, val, color, x;
|
|
val = clipval(values[valuenum], min, max);
|
|
x = valuenum * interval;
|
|
ytop = Math2.round(pheight - pheight * ((val - min) / range));
|
|
color = options.get("thresholdColor") && val < options.get("thresholdValue") ? options.get("thresholdColor") : options.get("lineColor");
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
return target.drawLine(x, ytop, x, ytop + lineHeight, color);
|
|
}
|
|
});
|
|
$2.fn.sparkline.bullet = bullet = createClass($2.fn.sparkline._base, {
|
|
type: "bullet",
|
|
init: function(el2, values, options, width, height) {
|
|
var min, max, vals;
|
|
bullet._super.init.call(this, el2, values, options, width, height);
|
|
this.values = values = normalizeValues(values);
|
|
vals = values.slice();
|
|
vals[0] = vals[0] === null ? vals[2] : vals[0];
|
|
vals[1] = values[1] === null ? vals[2] : vals[1];
|
|
min = Math2.min.apply(Math2, values);
|
|
max = Math2.max.apply(Math2, values);
|
|
if (options.get("base") === undefined2) {
|
|
min = min < 0 ? min : 0;
|
|
} else {
|
|
min = options.get("base");
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
this.range = max - min;
|
|
this.shapes = {};
|
|
this.valueShapes = {};
|
|
this.regiondata = {};
|
|
this.width = width = options.get("width") === "auto" ? "4.0em" : width;
|
|
this.target = this.$el.simpledraw(width, height, options.get("composite"));
|
|
if (!values.length) {
|
|
this.disabled = true;
|
|
}
|
|
this.initTarget();
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
var shapeid = this.target.getShapeAt(el2, x, y);
|
|
return shapeid !== undefined2 && this.shapes[shapeid] !== undefined2 ? this.shapes[shapeid] : undefined2;
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
fieldkey: currentRegion.substr(0, 1),
|
|
value: this.values[currentRegion.substr(1)],
|
|
region: currentRegion
|
|
};
|
|
},
|
|
changeHighlight: function(highlight) {
|
|
var currentRegion = this.currentRegion, shapeid = this.valueShapes[currentRegion], shape;
|
|
delete this.shapes[shapeid];
|
|
switch (currentRegion.substr(0, 1)) {
|
|
case "r":
|
|
shape = this.renderRange(currentRegion.substr(1), highlight);
|
|
break;
|
|
case "p":
|
|
shape = this.renderPerformance(highlight);
|
|
break;
|
|
case "t":
|
|
shape = this.renderTarget(highlight);
|
|
break;
|
|
}
|
|
this.valueShapes[currentRegion] = shape.id;
|
|
this.shapes[shape.id] = currentRegion;
|
|
this.target.replaceWithShape(shapeid, shape);
|
|
},
|
|
renderRange: function(rn, highlight) {
|
|
var rangeval = this.values[rn], rangewidth = Math2.round(this.canvasWidth * ((rangeval - this.min) / this.range)), color = this.options.get("rangeColors")[rn - 2];
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
|
|
},
|
|
renderPerformance: function(highlight) {
|
|
var perfval = this.values[1], perfwidth = Math2.round(this.canvasWidth * ((perfval - this.min) / this.range)), color = this.options.get("performanceColor");
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(
|
|
0,
|
|
Math2.round(this.canvasHeight * 0.3),
|
|
perfwidth - 1,
|
|
Math2.round(this.canvasHeight * 0.4) - 1,
|
|
color,
|
|
color
|
|
);
|
|
},
|
|
renderTarget: function(highlight) {
|
|
var targetval = this.values[0], x = Math2.round(this.canvasWidth * ((targetval - this.min) / this.range) - this.options.get("targetWidth") / 2), targettop = Math2.round(this.canvasHeight * 0.1), targetheight = this.canvasHeight - targettop * 2, color = this.options.get("targetColor");
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(x, targettop, this.options.get("targetWidth") - 1, targetheight - 1, color, color);
|
|
},
|
|
render: function() {
|
|
var vlen = this.values.length, target = this.target, i, shape;
|
|
if (!bullet._super.render.call(this)) {
|
|
return;
|
|
}
|
|
for (i = 2; i < vlen; i++) {
|
|
shape = this.renderRange(i).append();
|
|
this.shapes[shape.id] = "r" + i;
|
|
this.valueShapes["r" + i] = shape.id;
|
|
}
|
|
if (this.values[1] !== null) {
|
|
shape = this.renderPerformance().append();
|
|
this.shapes[shape.id] = "p1";
|
|
this.valueShapes.p1 = shape.id;
|
|
}
|
|
if (this.values[0] !== null) {
|
|
shape = this.renderTarget().append();
|
|
this.shapes[shape.id] = "t0";
|
|
this.valueShapes.t0 = shape.id;
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
$2.fn.sparkline.pie = pie = createClass($2.fn.sparkline._base, {
|
|
type: "pie",
|
|
init: function(el2, values, options, width, height) {
|
|
var total = 0, i;
|
|
pie._super.init.call(this, el2, values, options, width, height);
|
|
this.shapes = {};
|
|
this.valueShapes = {};
|
|
this.values = values = $2.map(values, Number);
|
|
if (options.get("width") === "auto") {
|
|
this.width = this.height;
|
|
}
|
|
if (values.length > 0) {
|
|
for (i = values.length; i--; ) {
|
|
total += values[i];
|
|
}
|
|
}
|
|
this.total = total;
|
|
this.initTarget();
|
|
this.radius = Math2.floor(Math2.min(this.canvasWidth, this.canvasHeight) / 2);
|
|
},
|
|
getRegion: function(el2, x, y) {
|
|
var shapeid = this.target.getShapeAt(el2, x, y);
|
|
return shapeid !== undefined2 && this.shapes[shapeid] !== undefined2 ? this.shapes[shapeid] : undefined2;
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined2,
|
|
value: this.values[currentRegion],
|
|
percent: this.values[currentRegion] / this.total * 100,
|
|
color: this.options.get("sliceColors")[currentRegion % this.options.get("sliceColors").length],
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
changeHighlight: function(highlight) {
|
|
var currentRegion = this.currentRegion, newslice = this.renderSlice(currentRegion, highlight), shapeid = this.valueShapes[currentRegion];
|
|
delete this.shapes[shapeid];
|
|
this.target.replaceWithShape(shapeid, newslice);
|
|
this.valueShapes[currentRegion] = newslice.id;
|
|
this.shapes[newslice.id] = currentRegion;
|
|
},
|
|
renderSlice: function(valuenum, highlight) {
|
|
var target = this.target, options = this.options, radius = this.radius, borderWidth = options.get("borderWidth"), offset = options.get("offset"), circle = 2 * Math2.PI, values = this.values, total = this.total, next = offset ? 2 * Math2.PI * (offset / 360) : 0, start, end, i, vlen, color;
|
|
vlen = values.length;
|
|
for (i = 0; i < vlen; i++) {
|
|
start = next;
|
|
end = next;
|
|
if (total > 0) {
|
|
end = next + circle * (values[i] / total);
|
|
}
|
|
if (valuenum === i) {
|
|
color = options.get("sliceColors")[i % options.get("sliceColors").length];
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined2, color);
|
|
}
|
|
next = end;
|
|
}
|
|
},
|
|
render: function() {
|
|
var target = this.target, values = this.values, options = this.options, radius = this.radius, borderWidth = options.get("borderWidth"), donutWidth = options.get("donutWidth"), shape, i;
|
|
if (!pie._super.render.call(this)) {
|
|
return;
|
|
}
|
|
if (borderWidth) {
|
|
target.drawCircle(
|
|
radius,
|
|
radius,
|
|
Math2.floor(radius - borderWidth / 2),
|
|
options.get("borderColor"),
|
|
undefined2,
|
|
borderWidth
|
|
).append();
|
|
}
|
|
for (i = values.length; i--; ) {
|
|
if (values[i]) {
|
|
shape = this.renderSlice(i).append();
|
|
this.valueShapes[i] = shape.id;
|
|
this.shapes[shape.id] = i;
|
|
}
|
|
}
|
|
if (donutWidth) {
|
|
target.drawCircle(
|
|
radius,
|
|
radius,
|
|
radius - donutWidth,
|
|
options.get("donutColor"),
|
|
options.get("donutColor"),
|
|
0
|
|
).append();
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
$2.fn.sparkline.box = box = createClass($2.fn.sparkline._base, {
|
|
type: "box",
|
|
init: function(el2, values, options, width, height) {
|
|
box._super.init.call(this, el2, values, options, width, height);
|
|
this.values = $2.map(values, Number);
|
|
this.width = options.get("width") === "auto" ? "4.0em" : width;
|
|
this.initTarget();
|
|
if (!this.values.length) {
|
|
this.disabled = 1;
|
|
}
|
|
},
|
|
/**
|
|
* Simulate a single region
|
|
*/
|
|
getRegion: function() {
|
|
return 1;
|
|
},
|
|
getCurrentRegionFields: function() {
|
|
var result = [
|
|
{ field: "lq", value: this.quartiles[0] },
|
|
{ field: "med", value: this.quartiles[1] },
|
|
{ field: "uq", value: this.quartiles[2] }
|
|
];
|
|
if (this.loutlier !== undefined2) {
|
|
result.push({ field: "lo", value: this.loutlier });
|
|
}
|
|
if (this.routlier !== undefined2) {
|
|
result.push({ field: "ro", value: this.routlier });
|
|
}
|
|
if (this.lwhisker !== undefined2) {
|
|
result.push({ field: "lw", value: this.lwhisker });
|
|
}
|
|
if (this.rwhisker !== undefined2) {
|
|
result.push({ field: "rw", value: this.rwhisker });
|
|
}
|
|
return result;
|
|
},
|
|
render: function() {
|
|
var target = this.target, values = this.values, vlen = values.length, options = this.options, canvasWidth = this.canvasWidth, canvasHeight = this.canvasHeight, minValue = options.get("chartRangeMin") === undefined2 ? Math2.min.apply(Math2, values) : options.get("chartRangeMin"), maxValue = options.get("chartRangeMax") === undefined2 ? Math2.max.apply(Math2, values) : options.get("chartRangeMax"), canvasLeft = 0, lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i, size, unitSize;
|
|
if (!box._super.render.call(this)) {
|
|
return;
|
|
}
|
|
if (options.get("raw")) {
|
|
if (options.get("showOutliers") && values.length > 5) {
|
|
loutlier = values[0];
|
|
lwhisker = values[1];
|
|
q1 = values[2];
|
|
q2 = values[3];
|
|
q3 = values[4];
|
|
rwhisker = values[5];
|
|
routlier = values[6];
|
|
} else {
|
|
lwhisker = values[0];
|
|
q1 = values[1];
|
|
q2 = values[2];
|
|
q3 = values[3];
|
|
rwhisker = values[4];
|
|
}
|
|
} else {
|
|
values.sort(function(a, b) {
|
|
return a - b;
|
|
});
|
|
q1 = quartile(values, 1);
|
|
q2 = quartile(values, 2);
|
|
q3 = quartile(values, 3);
|
|
iqr = q3 - q1;
|
|
if (options.get("showOutliers")) {
|
|
lwhisker = rwhisker = undefined2;
|
|
for (i = 0; i < vlen; i++) {
|
|
if (lwhisker === undefined2 && values[i] > q1 - iqr * options.get("outlierIQR")) {
|
|
lwhisker = values[i];
|
|
}
|
|
if (values[i] < q3 + iqr * options.get("outlierIQR")) {
|
|
rwhisker = values[i];
|
|
}
|
|
}
|
|
loutlier = values[0];
|
|
routlier = values[vlen - 1];
|
|
} else {
|
|
lwhisker = values[0];
|
|
rwhisker = values[vlen - 1];
|
|
}
|
|
}
|
|
this.quartiles = [q1, q2, q3];
|
|
this.lwhisker = lwhisker;
|
|
this.rwhisker = rwhisker;
|
|
this.loutlier = loutlier;
|
|
this.routlier = routlier;
|
|
unitSize = canvasWidth / (maxValue - minValue + 1);
|
|
if (options.get("showOutliers")) {
|
|
canvasLeft = Math2.ceil(options.get("spotRadius"));
|
|
canvasWidth -= 2 * Math2.ceil(options.get("spotRadius"));
|
|
unitSize = canvasWidth / (maxValue - minValue + 1);
|
|
if (loutlier < lwhisker) {
|
|
target.drawCircle(
|
|
(loutlier - minValue) * unitSize + canvasLeft,
|
|
canvasHeight / 2,
|
|
options.get("spotRadius"),
|
|
options.get("outlierLineColor"),
|
|
options.get("outlierFillColor")
|
|
).append();
|
|
}
|
|
if (routlier > rwhisker) {
|
|
target.drawCircle(
|
|
(routlier - minValue) * unitSize + canvasLeft,
|
|
canvasHeight / 2,
|
|
options.get("spotRadius"),
|
|
options.get("outlierLineColor"),
|
|
options.get("outlierFillColor")
|
|
).append();
|
|
}
|
|
}
|
|
target.drawRect(
|
|
Math2.round((q1 - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight * 0.1),
|
|
Math2.round((q3 - q1) * unitSize),
|
|
Math2.round(canvasHeight * 0.8),
|
|
options.get("boxLineColor"),
|
|
options.get("boxFillColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2),
|
|
Math2.round((q1 - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2),
|
|
options.get("lineColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 4),
|
|
Math2.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight - canvasHeight / 4),
|
|
options.get("whiskerColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2),
|
|
Math2.round((q3 - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2),
|
|
options.get("lineColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 4),
|
|
Math2.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight - canvasHeight / 4),
|
|
options.get("whiskerColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((q2 - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight * 0.1),
|
|
Math2.round((q2 - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight * 0.9),
|
|
options.get("medianColor")
|
|
).append();
|
|
if (options.get("target")) {
|
|
size = Math2.ceil(options.get("spotRadius"));
|
|
target.drawLine(
|
|
Math2.round((options.get("target") - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2 - size),
|
|
Math2.round((options.get("target") - minValue) * unitSize + canvasLeft),
|
|
Math2.round(canvasHeight / 2 + size),
|
|
options.get("targetColor")
|
|
).append();
|
|
target.drawLine(
|
|
Math2.round((options.get("target") - minValue) * unitSize + canvasLeft - size),
|
|
Math2.round(canvasHeight / 2),
|
|
Math2.round((options.get("target") - minValue) * unitSize + canvasLeft + size),
|
|
Math2.round(canvasHeight / 2),
|
|
options.get("targetColor")
|
|
).append();
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
VShape = createClass({
|
|
init: function(target, id, type, args) {
|
|
this.target = target;
|
|
this.id = id;
|
|
this.type = type;
|
|
this.args = args;
|
|
},
|
|
append: function() {
|
|
this.target.appendShape(this);
|
|
return this;
|
|
}
|
|
});
|
|
VCanvas_base = createClass({
|
|
_pxregex: /(\d+)(px)?\s*$/i,
|
|
init: function(width, height, target) {
|
|
if (!width) {
|
|
return;
|
|
}
|
|
this.width = width;
|
|
this.height = height;
|
|
this.target = target;
|
|
this.lastShapeId = null;
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$2.data(target, "_jqs_vcanvas", this);
|
|
},
|
|
drawLine: function(x1, y1, x2, y2, lineColor, lineWidth) {
|
|
return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
|
|
},
|
|
drawShape: function(path, lineColor, fillColor, lineWidth) {
|
|
return this._genShape("Shape", [path, lineColor, fillColor, lineWidth]);
|
|
},
|
|
drawCircle: function(x, y, radius, lineColor, fillColor, lineWidth) {
|
|
return this._genShape("Circle", [x, y, radius, lineColor, fillColor, lineWidth]);
|
|
},
|
|
drawPieSlice: function(x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
return this._genShape("PieSlice", [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
|
|
},
|
|
drawRect: function(x, y, width, height, lineColor, fillColor) {
|
|
return this._genShape("Rect", [x, y, width, height, lineColor, fillColor]);
|
|
},
|
|
getElement: function() {
|
|
return this.canvas;
|
|
},
|
|
/**
|
|
* Return the most recently inserted shape id
|
|
*/
|
|
getLastShapeId: function() {
|
|
return this.lastShapeId;
|
|
},
|
|
/**
|
|
* Clear and reset the canvas
|
|
*/
|
|
reset: function() {
|
|
alert("reset not implemented");
|
|
},
|
|
_insert: function(el2, target) {
|
|
$2(target).html(el2);
|
|
},
|
|
/**
|
|
* Calculate the pixel dimensions of the canvas
|
|
*/
|
|
_calculatePixelDims: function(width, height, canvas) {
|
|
var match;
|
|
match = this._pxregex.exec(height);
|
|
if (match) {
|
|
this.pixelHeight = match[1];
|
|
} else {
|
|
this.pixelHeight = $2(canvas).height();
|
|
}
|
|
match = this._pxregex.exec(width);
|
|
if (match) {
|
|
this.pixelWidth = match[1];
|
|
} else {
|
|
this.pixelWidth = $2(canvas).width();
|
|
}
|
|
},
|
|
/**
|
|
* Generate a shape object and id for later rendering
|
|
*/
|
|
_genShape: function(shapetype, shapeargs) {
|
|
var id = shapeCount++;
|
|
shapeargs.unshift(id);
|
|
return new VShape(this, id, shapetype, shapeargs);
|
|
},
|
|
/**
|
|
* Add a shape to the end of the render queue
|
|
*/
|
|
appendShape: function(shape) {
|
|
alert("appendShape not implemented");
|
|
},
|
|
/**
|
|
* Replace one shape with another
|
|
*/
|
|
replaceWithShape: function(shapeid, shape) {
|
|
alert("replaceWithShape not implemented");
|
|
},
|
|
/**
|
|
* Insert one shape after another in the render queue
|
|
*/
|
|
insertAfterShape: function(shapeid, shape) {
|
|
alert("insertAfterShape not implemented");
|
|
},
|
|
/**
|
|
* Remove a shape from the queue
|
|
*/
|
|
removeShapeId: function(shapeid) {
|
|
alert("removeShapeId not implemented");
|
|
},
|
|
/**
|
|
* Find a shape at the specified x/y co-ordinates
|
|
*/
|
|
getShapeAt: function(el2, x, y) {
|
|
alert("getShapeAt not implemented");
|
|
},
|
|
/**
|
|
* Render all queued shapes onto the canvas
|
|
*/
|
|
render: function() {
|
|
alert("render not implemented");
|
|
}
|
|
});
|
|
VCanvas_canvas = createClass(VCanvas_base, {
|
|
init: function(width, height, target, interact) {
|
|
VCanvas_canvas._super.init.call(this, width, height, target);
|
|
this.canvas = document2.createElement("canvas");
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$2.data(target, "_jqs_vcanvas", this);
|
|
$2(this.canvas).css({ display: "inline-block", width, height, verticalAlign: "top" });
|
|
this._insert(this.canvas, target);
|
|
this._calculatePixelDims(width, height, this.canvas);
|
|
this.canvas.width = this.pixelWidth;
|
|
this.canvas.height = this.pixelHeight;
|
|
this.interact = interact;
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
this.currentTargetShapeId = undefined2;
|
|
$2(this.canvas).css({ width: this.pixelWidth, height: this.pixelHeight });
|
|
},
|
|
_getContext: function(lineColor, fillColor, lineWidth) {
|
|
var context = this.canvas.getContext("2d");
|
|
if (lineColor !== undefined2) {
|
|
context.strokeStyle = lineColor;
|
|
}
|
|
context.lineWidth = lineWidth === undefined2 ? 1 : lineWidth;
|
|
if (fillColor !== undefined2) {
|
|
context.fillStyle = fillColor;
|
|
}
|
|
return context;
|
|
},
|
|
reset: function() {
|
|
var context = this._getContext();
|
|
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
this.currentTargetShapeId = undefined2;
|
|
},
|
|
_drawShape: function(shapeid, path, lineColor, fillColor, lineWidth) {
|
|
var context = this._getContext(lineColor, fillColor, lineWidth), i, plen;
|
|
context.beginPath();
|
|
context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
|
|
for (i = 1, plen = path.length; i < plen; i++) {
|
|
context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5);
|
|
}
|
|
if (lineColor !== undefined2) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor !== undefined2) {
|
|
context.fill();
|
|
}
|
|
if (this.targetX !== undefined2 && this.targetY !== undefined2 && context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
},
|
|
_drawCircle: function(shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
|
|
var context = this._getContext(lineColor, fillColor, lineWidth);
|
|
context.beginPath();
|
|
context.arc(x, y, radius, 0, 2 * Math2.PI, false);
|
|
if (this.targetX !== undefined2 && this.targetY !== undefined2 && context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
if (lineColor !== undefined2) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor !== undefined2) {
|
|
context.fill();
|
|
}
|
|
},
|
|
_drawPieSlice: function(shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
var context = this._getContext(lineColor, fillColor);
|
|
context.beginPath();
|
|
context.moveTo(x, y);
|
|
context.arc(x, y, radius, startAngle, endAngle, false);
|
|
context.lineTo(x, y);
|
|
context.closePath();
|
|
if (lineColor !== undefined2) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor) {
|
|
context.fill();
|
|
}
|
|
if (this.targetX !== undefined2 && this.targetY !== undefined2 && context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
},
|
|
_drawRect: function(shapeid, x, y, width, height, lineColor, fillColor) {
|
|
return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
|
|
},
|
|
appendShape: function(shape) {
|
|
this.shapes[shape.id] = shape;
|
|
this.shapeseq.push(shape.id);
|
|
this.lastShapeId = shape.id;
|
|
return shape.id;
|
|
},
|
|
replaceWithShape: function(shapeid, shape) {
|
|
var shapeseq = this.shapeseq, i;
|
|
this.shapes[shape.id] = shape;
|
|
for (i = shapeseq.length; i--; ) {
|
|
if (shapeseq[i] == shapeid) {
|
|
shapeseq[i] = shape.id;
|
|
}
|
|
}
|
|
delete this.shapes[shapeid];
|
|
},
|
|
replaceWithShapes: function(shapeids, shapes) {
|
|
var shapeseq = this.shapeseq, shapemap = {}, sid, i, first;
|
|
for (i = shapeids.length; i--; ) {
|
|
shapemap[shapeids[i]] = true;
|
|
}
|
|
for (i = shapeseq.length; i--; ) {
|
|
sid = shapeseq[i];
|
|
if (shapemap[sid]) {
|
|
shapeseq.splice(i, 1);
|
|
delete this.shapes[sid];
|
|
first = i;
|
|
}
|
|
}
|
|
for (i = shapes.length; i--; ) {
|
|
shapeseq.splice(first, 0, shapes[i].id);
|
|
this.shapes[shapes[i].id] = shapes[i];
|
|
}
|
|
},
|
|
insertAfterShape: function(shapeid, shape) {
|
|
var shapeseq = this.shapeseq, i;
|
|
for (i = shapeseq.length; i--; ) {
|
|
if (shapeseq[i] === shapeid) {
|
|
shapeseq.splice(i + 1, 0, shape.id);
|
|
this.shapes[shape.id] = shape;
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
removeShapeId: function(shapeid) {
|
|
var shapeseq = this.shapeseq, i;
|
|
for (i = shapeseq.length; i--; ) {
|
|
if (shapeseq[i] === shapeid) {
|
|
shapeseq.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
delete this.shapes[shapeid];
|
|
},
|
|
getShapeAt: function(el2, x, y) {
|
|
this.targetX = x;
|
|
this.targetY = y;
|
|
this.render();
|
|
return this.currentTargetShapeId;
|
|
},
|
|
render: function() {
|
|
var shapeseq = this.shapeseq, shapes = this.shapes, shapeCount2 = shapeseq.length, context = this._getContext(), shapeid, shape, i;
|
|
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
|
|
for (i = 0; i < shapeCount2; i++) {
|
|
shapeid = shapeseq[i];
|
|
shape = shapes[shapeid];
|
|
this["_draw" + shape.type].apply(this, shape.args);
|
|
}
|
|
if (!this.interact) {
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
}
|
|
}
|
|
});
|
|
VCanvas_vml = createClass(VCanvas_base, {
|
|
init: function(width, height, target) {
|
|
var groupel;
|
|
VCanvas_vml._super.init.call(this, width, height, target);
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$2.data(target, "_jqs_vcanvas", this);
|
|
this.canvas = document2.createElement("span");
|
|
$2(this.canvas).css({ display: "inline-block", position: "relative", overflow: "hidden", width, height, margin: "0px", padding: "0px", verticalAlign: "top" });
|
|
this._insert(this.canvas, target);
|
|
this._calculatePixelDims(width, height, this.canvas);
|
|
this.canvas.width = this.pixelWidth;
|
|
this.canvas.height = this.pixelHeight;
|
|
groupel = '<v:group coordorigin="0 0" coordsize="' + this.pixelWidth + " " + this.pixelHeight + '" style="position:absolute;top:0;left:0;width:' + this.pixelWidth + "px;height=" + this.pixelHeight + 'px;"></v:group>';
|
|
this.canvas.insertAdjacentHTML("beforeEnd", groupel);
|
|
this.group = $2(this.canvas).children()[0];
|
|
this.rendered = false;
|
|
this.prerender = "";
|
|
},
|
|
_drawShape: function(shapeid, path, lineColor, fillColor, lineWidth) {
|
|
var vpath = [], initial, stroke, fill, closed, vel, plen, i;
|
|
for (i = 0, plen = path.length; i < plen; i++) {
|
|
vpath[i] = "" + path[i][0] + "," + path[i][1];
|
|
}
|
|
initial = vpath.splice(0, 1);
|
|
lineWidth = lineWidth === undefined2 ? 1 : lineWidth;
|
|
stroke = lineColor === undefined2 ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined2 ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
closed = vpath[0] === vpath[vpath.length - 1] ? "x " : "";
|
|
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + " " + this.pixelHeight + '" id="jqsshape' + shapeid + '" ' + stroke + fill + ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + "px;width:" + this.pixelWidth + 'px;padding:0px;margin:0px;" path="m ' + initial + " l " + vpath.join(", ") + " " + closed + 'e"> </v:shape>';
|
|
return vel;
|
|
},
|
|
_drawCircle: function(shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
|
|
var stroke, fill, vel;
|
|
x -= radius;
|
|
y -= radius;
|
|
stroke = lineColor === undefined2 ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined2 ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
vel = '<v:oval id="jqsshape' + shapeid + '" ' + stroke + fill + ' style="position:absolute;top:' + y + "px; left:" + x + "px; width:" + radius * 2 + "px; height:" + radius * 2 + 'px"></v:oval>';
|
|
return vel;
|
|
},
|
|
_drawPieSlice: function(shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
var vpath, startx, starty, endx, endy, stroke, fill, vel;
|
|
if (startAngle === endAngle) {
|
|
return "";
|
|
}
|
|
if (endAngle - startAngle === 2 * Math2.PI) {
|
|
startAngle = 0;
|
|
endAngle = 2 * Math2.PI;
|
|
}
|
|
startx = x + Math2.round(Math2.cos(startAngle) * radius);
|
|
starty = y + Math2.round(Math2.sin(startAngle) * radius);
|
|
endx = x + Math2.round(Math2.cos(endAngle) * radius);
|
|
endy = y + Math2.round(Math2.sin(endAngle) * radius);
|
|
if (startx === endx && starty === endy) {
|
|
if (endAngle - startAngle < Math2.PI) {
|
|
return "";
|
|
}
|
|
startx = endx = x + radius;
|
|
starty = endy = y;
|
|
}
|
|
if (startx === endx && starty === endy && endAngle - startAngle < Math2.PI) {
|
|
return "";
|
|
}
|
|
vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
|
|
stroke = lineColor === undefined2 ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined2 ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + " " + this.pixelHeight + '" id="jqsshape' + shapeid + '" ' + stroke + fill + ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + "px;width:" + this.pixelWidth + 'px;padding:0px;margin:0px;" path="m ' + x + "," + y + " wa " + vpath.join(", ") + ' x e"> </v:shape>';
|
|
return vel;
|
|
},
|
|
_drawRect: function(shapeid, x, y, width, height, lineColor, fillColor) {
|
|
return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
|
|
},
|
|
reset: function() {
|
|
this.group.innerHTML = "";
|
|
},
|
|
appendShape: function(shape) {
|
|
var vel = this["_draw" + shape.type].apply(this, shape.args);
|
|
if (this.rendered) {
|
|
this.group.insertAdjacentHTML("beforeEnd", vel);
|
|
} else {
|
|
this.prerender += vel;
|
|
}
|
|
this.lastShapeId = shape.id;
|
|
return shape.id;
|
|
},
|
|
replaceWithShape: function(shapeid, shape) {
|
|
var existing = $2("#jqsshape" + shapeid), vel = this["_draw" + shape.type].apply(this, shape.args);
|
|
existing[0].outerHTML = vel;
|
|
},
|
|
replaceWithShapes: function(shapeids, shapes) {
|
|
var existing = $2("#jqsshape" + shapeids[0]), replace = "", slen = shapes.length, i;
|
|
for (i = 0; i < slen; i++) {
|
|
replace += this["_draw" + shapes[i].type].apply(this, shapes[i].args);
|
|
}
|
|
existing[0].outerHTML = replace;
|
|
for (i = 1; i < shapeids.length; i++) {
|
|
$2("#jqsshape" + shapeids[i]).remove();
|
|
}
|
|
},
|
|
insertAfterShape: function(shapeid, shape) {
|
|
var existing = $2("#jqsshape" + shapeid), vel = this["_draw" + shape.type].apply(this, shape.args);
|
|
existing[0].insertAdjacentHTML("afterEnd", vel);
|
|
},
|
|
removeShapeId: function(shapeid) {
|
|
var existing = $2("#jqsshape" + shapeid);
|
|
this.group.removeChild(existing[0]);
|
|
},
|
|
getShapeAt: function(el2, x, y) {
|
|
var shapeid = el2.id.substr(8);
|
|
return shapeid;
|
|
},
|
|
render: function() {
|
|
if (!this.rendered) {
|
|
this.group.innerHTML = this.prerender;
|
|
this.rendered = true;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
})(document, Math);
|
|
|
|
// ui/gpu.ts
|
|
var gpuInterval = null;
|
|
var chartData = { mem: [], load: [] };
|
|
async function updateGPUChart(mem, load) {
|
|
const maxLen = 120;
|
|
const colorRangeMap = $.range_map({
|
|
"0:5": "#fffafa",
|
|
"6:10": "#fff7ed",
|
|
"11:20": "#fed7aa",
|
|
"21:30": "#fdba74",
|
|
"31:40": "#fb923c",
|
|
"41:50": "#f97316",
|
|
"51:60": "#ea580c",
|
|
"61:70": "#c2410c",
|
|
"71:80": "#9a3412",
|
|
"81:90": "#7c2d12",
|
|
"91:100": "#6c2e12"
|
|
});
|
|
const sparklineConfigLOAD = { type: "bar", height: "128px", barWidth: "3px", barSpacing: "1px", chartRangeMin: 0, chartRangeMax: 100, barColor: "#89007D" };
|
|
const sparklineConfigMEM = { type: "bar", height: "128px", barWidth: "3px", barSpacing: "1px", chartRangeMin: 0, chartRangeMax: 100, colorMap: colorRangeMap, composite: true };
|
|
if (chartData.load.length > maxLen) chartData.load.shift();
|
|
chartData.load.push(load);
|
|
if (chartData.mem.length > maxLen) chartData.mem.shift();
|
|
chartData.mem.push(mem);
|
|
$("#gpuChart").sparkline(chartData.load, sparklineConfigLOAD);
|
|
$("#gpuChart").sparkline(chartData.mem, sparklineConfigMEM);
|
|
}
|
|
async function updateGPU() {
|
|
const gpuEl = document.getElementById("gpu");
|
|
const gpuTable = document.getElementById("gpu-table");
|
|
if (!gpuEl || !gpuTable) return;
|
|
try {
|
|
const res = await authFetch(`${window.api}/gpu-smi`);
|
|
if (!res || !res.ok) {
|
|
clearInterval(gpuInterval);
|
|
gpuEl.style.display = "none";
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
if (!data) {
|
|
clearInterval(gpuInterval);
|
|
gpuEl.style.display = "none";
|
|
return;
|
|
}
|
|
const gpuTbody = gpuTable.querySelector("tbody");
|
|
if (!gpuTbody) return;
|
|
for (const gpu of data) {
|
|
let rows = `<tr><td>GPU</td><td>${gpu.name}</td></tr>`;
|
|
for (const item of Object.entries(gpu.data)) rows += `<tr><td>${item[0]}</td><td>${item[1]}</td></tr>`;
|
|
gpuTbody.innerHTML = rows;
|
|
if (gpu.chart && gpu.chart.length === 2) updateGPUChart(gpu.chart[0], gpu.chart[1]);
|
|
}
|
|
gpuEl.style.display = "block";
|
|
} catch (e) {
|
|
error("updateGPU", e);
|
|
clearInterval(gpuInterval);
|
|
gpuEl.style.display = "none";
|
|
}
|
|
}
|
|
async function startGPU() {
|
|
const gpuEl = document.getElementById("gpu");
|
|
if (!gpuEl) return;
|
|
gpuEl.style.display = "block";
|
|
if (gpuInterval) clearInterval(gpuInterval);
|
|
const interval = window.opts?.gpu_monitor || 3e3;
|
|
log("startGPU", interval);
|
|
gpuInterval = setInterval(updateGPU, interval);
|
|
updateGPU();
|
|
}
|
|
window.startGPU = startGPU;
|
|
async function disableGPU() {
|
|
clearInterval(gpuInterval);
|
|
const gpuEl = document.getElementById("gpu");
|
|
if (gpuEl) gpuEl.style.display = "none";
|
|
}
|
|
window.disableGPU = disableGPU;
|
|
//# sourceMappingURL=sdnext.mjs.map
|