|
|
- const module = "";
- const CONSTANTS = {
- MODULE_NAME: "sequencer",
- FLAG_NAME: "effects",
- COLOR: {
- PRIMARY: 15615023,
- SECONDARY: 6298186,
- TERTIARY: 6298186
- },
- SHAPES: {
- POLY: "polygon",
- RECT: "rectangle",
- CIRC: "circle",
- ELIP: "ellipse",
- RREC: "roundedRect"
- },
- FEET_REGEX: new RegExp(/\.[0-9]+ft\.*/g),
- ARRAY_REGEX: new RegExp(/\.[0-9]$/g),
- STATUS: {
- READY: 0,
- RUNNING: 1,
- COMPLETE: 2,
- SKIPPED: 3,
- ABORTED: 4
- }
- };
- CONSTANTS.INTEGRATIONS = {};
- CONSTANTS.INTEGRATIONS.ISOMETRIC = {};
- CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE = false;
- CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME = "grape_juice-isometrics";
- CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED = `flags.${CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME}.is_isometric`;
- CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_FLAG = `flags.${CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME}.original_image_projection_type`;
- CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_TYPES = {
- TOPDOWN: "topdown",
- TRUE: "true_isometric",
- DIAMETRIC: "diametric"
- };
- CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION = Math.sqrt(3);
- CONSTANTS.INTEGRATIONS.ISOMETRIC.DIMETRIC_CONVERSION = 2 / CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION;
- CONSTANTS.INTEGRATIONS.ISOMETRIC.DUNGEON_BUILDER_CONVERSION = 278 / 154 / CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION;
- CONSTANTS.EFFECTS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.${CONSTANTS.FLAG_NAME}`;
- function registerEase(easeName, easeFunction, overwrite = false) {
- if (typeof easeName !== "string")
- throw custom_error("registerEase", "easeName must be of type string");
- if (!is_function$1(easeFunction))
- throw custom_error(
- "registerEase",
- "easeFunction must be of type function"
- );
- if (easeFunctions[easeName] !== void 0 && !overwrite)
- return;
- debug(`registerEase | Registered ease function: ${easeName}`);
- easeFunctions[easeName] = easeFunction;
- }
- const easeFunctions = {
- linear,
- easeInSine,
- easeOutSine,
- easeInOutSine,
- easeInQuad,
- easeOutQuad,
- easeInOutQuad,
- easeInCubic,
- easeOutCubic,
- easeInOutCubic,
- easeInQuart,
- easeOutQuart,
- easeInOutQuart,
- easeInQuint,
- easeOutQuint,
- easeInOutQuint,
- easeInExpo,
- easeOutExpo,
- easeInOutExpo,
- easeInCirc,
- easeOutCirc,
- easeInOutCirc,
- easeInBack,
- easeOutBack,
- easeInOutBack,
- easeInElastic,
- easeOutElastic,
- easeInOutElastic,
- easeInBounce,
- easeOutBounce,
- easeInOutBounce
- };
- const EASE = {
- LINEAR: "linear",
- SINE_IN: "easeInSine",
- SINE_OUT: "easeOutSine",
- SINE_IN_OUT: "easeInOutSine",
- QUAD_IN: "easeInQuad",
- QUAD_OUT: "easeOutQuad",
- QUAD_IN_OUT: "easeInOutQuad",
- CUBIC_IN: "easeInCubic",
- CUBIC_OUT: "easeOutCubic",
- CUBIC_IN_OUT: "easeInOutCubic",
- QUART_IN: "easeInQuart",
- QUART_OUT: "easeOutQuart",
- QUART_IN_OUT: "easeInOutQuart",
- QUINT_IN: "easeInQuint",
- QUINT_OUT: "easeOutQuint",
- QUINT_IN_OUT: "easeInOutQuint",
- EXPO_IN: "easeInExpo",
- EXPO_OUT: "easeOutExpo",
- EXPO_IN_OUT: "easeInOutExpo",
- CIRC_IN: "easeInCirc",
- CIRC_OUT: "easeOutCirc",
- CIRC_IN_OUT: "easeInOutCirc",
- BACK_IN: "easeInBack",
- BACK_OUT: "easeOutBack",
- BACK_IN_OUT: "easeInOutBack",
- ELASTIC_IN: "easeInElastic",
- ELASTIC_OUT: "easeOutElastic",
- ELASTIC_IN_OUT: "easeInOutElastic",
- BOUNCE_IN: "easeInBounce",
- BOUNCE_OUT: "easeOutBounce",
- BOUNCE_IN_OUT: "easeInOutBounce"
- };
- function linear(x) {
- return x;
- }
- function easeInSine(x) {
- return 1 - Math.cos(x * Math.PI / 2);
- }
- function easeOutSine(x) {
- return Math.sin(x * Math.PI / 2);
- }
- function easeInOutSine(x) {
- return -(Math.cos(Math.PI * x) - 1) / 2;
- }
- function easeInQuad(x) {
- return x * x;
- }
- function easeOutQuad(x) {
- return 1 - (1 - x) * (1 - x);
- }
- function easeInOutQuad(x) {
- return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
- }
- function easeInCubic(x) {
- return x * x * x;
- }
- function easeOutCubic(x) {
- return 1 - Math.pow(1 - x, 3);
- }
- function easeInOutCubic(x) {
- return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
- }
- function easeInQuart(x) {
- return x * x * x * x;
- }
- function easeOutQuart(x) {
- return 1 - Math.pow(1 - x, 4);
- }
- function easeInOutQuart(x) {
- return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
- }
- function easeInQuint(x) {
- return x * x * x * x * x;
- }
- function easeOutQuint(x) {
- return 1 - Math.pow(1 - x, 5);
- }
- function easeInOutQuint(x) {
- return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
- }
- function easeInExpo(x) {
- return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
- }
- function easeOutExpo(x) {
- return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
- }
- function easeInOutExpo(x) {
- return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2;
- }
- function easeInCirc(x) {
- return 1 - Math.sqrt(1 - Math.pow(x, 2));
- }
- function easeOutCirc(x) {
- return Math.sqrt(1 - Math.pow(x - 1, 2));
- }
- function easeInOutCirc(x) {
- return x < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;
- }
- function easeInBack(x) {
- const c1 = 1.70158;
- const c3 = c1 + 1;
- return c3 * x * x * x - c1 * x * x;
- }
- function easeOutBack(x) {
- const c1 = 1.70158;
- const c3 = c1 + 1;
- return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
- }
- function easeInOutBack(x) {
- const c1 = 1.70158;
- const c2 = c1 * 1.525;
- return x < 0.5 ? Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2) / 2 : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
- }
- function easeInElastic(x) {
- const c4 = 2 * Math.PI / 3;
- return x === 0 ? 0 : x === 1 ? 1 : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);
- }
- function easeOutElastic(x) {
- const c4 = 2 * Math.PI / 3;
- return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
- }
- function easeInOutElastic(x) {
- const c5 = 2 * Math.PI / 4.5;
- return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2 : Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5) / 2 + 1;
- }
- function easeInBounce(x) {
- return 1 - easeOutBounce(1 - x);
- }
- function easeOutBounce(x) {
- const n1 = 7.5625;
- const d1 = 2.75;
- if (x < 1 / d1) {
- return n1 * x * x;
- } else if (x < 2 / d1) {
- return n1 * (x -= 1.5 / d1) * x + 0.75;
- } else if (x < 2.5 / d1) {
- return n1 * (x -= 2.25 / d1) * x + 0.9375;
- } else {
- return n1 * (x -= 2.625 / d1) * x + 0.984375;
- }
- }
- function easeInOutBounce(x) {
- return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
- }
- async function getFiles(inFile, { applyWildCard = false, softFail = false } = {}) {
- let source = "data";
- const browseOptions = { wildcard: applyWildCard };
- if (/\.s3\./.test(inFile)) {
- source = "s3";
- const { bucket, keyPrefix } = FilePicker.parseS3URL(inFile);
- if (bucket) {
- browseOptions.bucket = bucket;
- inFile = keyPrefix;
- }
- }
- try {
- return (await FilePicker.browse(source, inFile, browseOptions)).files;
- } catch (err) {
- if (softFail)
- return false;
- throw custom_error("Sequencer", `getFiles | ${err}`);
- }
- }
- function interpolate(p1, p2, t, ease = "linear") {
- const easeFunction = is_function$1(ease) ? ease : easeFunctions[ease];
- return p1 + (p2 - p1) * easeFunction(t);
- }
- function random_float_between(min, max, twister = false) {
- const random = twister ? twister.random() : Math.random();
- const _max = Math.max(max, min);
- const _min = Math.min(max, min);
- return random * (_max - _min) + _min;
- }
- function random_int_between(min, max, twister = false) {
- return Math.floor(random_float_between(min, max, twister));
- }
- function flip_negate(num_1, num_2) {
- if (num_1 > 0) {
- num_1 -= num_2;
- } else {
- num_1 += num_2;
- }
- return num_1;
- }
- function shuffle_array(inArray, twister = false) {
- let shuffled = [...inArray];
- const randomMethod = twister?.random ?? Math.random;
- for (let i = shuffled.length - 1; i > 0; i--) {
- let j = Math.floor(randomMethod() * (i + 1));
- let temp = shuffled[i];
- shuffled[i] = shuffled[j];
- shuffled[j] = temp;
- }
- return shuffled;
- }
- function is_function$1(inFunc) {
- return inFunc && ({}.toString.call(inFunc) === "[object Function]" || {}.toString.call(inFunc) === "[object AsyncFunction]");
- }
- function random_array_element(inArray, { recurse = false, twister = false, index = false } = {}) {
- const chosenIndex = random_int_between(0, inArray.length, twister);
- let choice = inArray[chosenIndex];
- if (recurse && Array.isArray(choice)) {
- return random_array_element(choice, { recurse, twister, index });
- }
- if (index) {
- return chosenIndex;
- }
- return choice;
- }
- function random_object_element(inObject, { recurse = false, twister = false } = {}) {
- let keys = Object.keys(inObject).filter((k) => !k.startsWith("_"));
- let choice = inObject[random_array_element(keys, { twister })];
- if (typeof choice === "object" && recurse) {
- return random_object_element(choice, { recurse: true });
- }
- return choice;
- }
- function is_real_number(inNumber) {
- return !isNaN(inNumber) && typeof inNumber === "number" && isFinite(inNumber);
- }
- function deep_get(obj, path) {
- if (!Array.isArray(path))
- path = path.split(".");
- try {
- let i;
- for (i = 0; i < path.length - 1; i++) {
- obj = obj[path[i]];
- }
- return obj[path[i]];
- } catch (err) {
- }
- }
- function deep_set(obj, path, value) {
- if (!Array.isArray(path))
- path = path.split(".");
- try {
- let i;
- for (i = 0; i < path.length - 1; i++) {
- obj = obj[path[i]];
- }
- if (is_function$1(obj[path[i]])) {
- obj[path[i]](value);
- } else {
- obj[path[i]] = value;
- }
- } catch (err) {
- }
- }
- function flatten_object(obj) {
- let toReturn = [];
- for (let i in obj) {
- if (i.startsWith("_"))
- continue;
- if (!obj.hasOwnProperty(i))
- continue;
- if (typeof obj[i] == "object") {
- let flatObject = flatten_object(obj[i]);
- for (let x in flatObject) {
- if (!flatObject.hasOwnProperty(x))
- continue;
- toReturn[i + "." + x] = flatObject[x];
- }
- } else {
- toReturn[i] = obj[i];
- }
- }
- return toReturn;
- }
- function wait$1(ms) {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
- function clamp(num, min, max) {
- const _max = Math.max(min, max);
- const _min = Math.min(min, max);
- return Math.max(_min, Math.min(_max, num));
- }
- function is_UUID(inId) {
- return typeof inId === "string" && (inId.startsWith("Scene") || inId.startsWith("Actor") || inId.startsWith("Item")) && (inId.match(/\./g) || []).length && !inId.endsWith(".");
- }
- function get_object_from_scene(inObjectId, inSceneId = game.user.viewedScene) {
- let tryUUID = is_UUID(inObjectId);
- if (tryUUID) {
- const obj = fromUuidSync(inObjectId);
- if (obj)
- return obj;
- tryUUID = false;
- }
- return get_all_documents_from_scene(inSceneId).find((obj) => {
- return get_object_identifier(obj, tryUUID) === inObjectId;
- });
- }
- function get_all_documents_from_scene(inSceneId = false) {
- const scene = inSceneId ? game.scenes.get(inSceneId) : game.scenes.get(game.user?.viewedScene);
- if (!scene)
- return [];
- return [
- ...canvas.templates?.preview?.children ?? [],
- ...Array.from(scene?.tokens ?? []),
- ...Array.from(scene?.lights ?? []),
- ...Array.from(scene?.sounds ?? []),
- ...Array.from(scene?.templates ?? []),
- ...Array.from(scene?.tiles ?? []),
- ...Array.from(scene?.walls ?? []),
- ...Array.from(scene?.drawings ?? [])
- ].deepFlatten().filter(Boolean);
- }
- function validate_document(inObject) {
- const document2 = inObject?.document ?? inObject;
- return is_UUID(document2?.uuid) ? document2 : inObject;
- }
- function get_object_identifier(inObject, tryUUID = true) {
- const uuid = tryUUID && is_UUID(inObject?.uuid) ? inObject?.uuid : void 0;
- return uuid ?? inObject?.id ?? inObject?.document?.name ?? inObject?.name ?? (inObject?.tag !== "" ? inObject?.tag : void 0) ?? (inObject?.label !== "" ? inObject?.label : void 0);
- }
- function make_array_unique(inArray) {
- return Array.from(new Set(inArray));
- }
- function debug(msg, args = "") {
- if (game.settings.get(CONSTANTS.MODULE_NAME, "debug"))
- console.log(`DEBUG | Sequencer | ${msg}`, args);
- }
- function debug_error(msg, args) {
- if (game.settings.get(CONSTANTS.MODULE_NAME, "debug"))
- console.error(`DEBUG | Sequencer | ${msg}`, args);
- }
- function custom_warning(inClassName, warning, notify = false) {
- inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
- warning = `${inClassName} | ${warning}`;
- if (notify)
- ui.notifications.warn(warning, { console: false });
- console.warn(warning.replace("<br>", "\n"));
- }
- const throttledWarnings = {};
- function throttled_custom_warning(inClassName, warning, delay = 1e4, notify = false) {
- inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
- warning = `${inClassName} | ${warning}`;
- if (throttledWarnings[warning])
- return;
- throttledWarnings[warning] = true;
- if (notify)
- ui.notifications.warn(warning, { console: false });
- console.warn(warning.replace("<br>", "\n"));
- setTimeout(() => {
- delete throttledWarnings[warning];
- }, delay);
- }
- function custom_error(inClassName, error, notify = true) {
- inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
- error = `${inClassName} | ${error}`;
- if (notify)
- ui.notifications.error(error, { console: false });
- return new Error(error.replace("<br>", "\n"));
- }
- function user_can_do(inSetting) {
- return game.user.role > game.settings.get(CONSTANTS.MODULE_NAME, inSetting);
- }
- function group_by(xs, key) {
- return xs.reduce(function(acc, obj) {
- let property = getProperty(obj, key);
- acc[property] = acc[property] || [];
- acc[property].push(obj);
- return acc;
- }, {});
- }
- function objHasProperty(obj, prop) {
- return obj.constructor.prototype.hasOwnProperty(prop);
- }
- function sequence_proxy_wrap(inSequence) {
- return new Proxy(inSequence, {
- get: function(target, prop) {
- if (!objHasProperty(target, prop)) {
- if (Sequencer.SectionManager.externalSections[prop] === void 0) {
- const section = target.sections[target.sections.length - 1];
- if (section && objHasProperty(section, prop)) {
- const targetProperty = Reflect.get(section, prop);
- return is_function$1(targetProperty) ? targetProperty.bind(section) : targetProperty;
- }
- return Reflect.get(target, prop);
- }
- target.sectionToCreate = Sequencer.SectionManager.externalSections[prop];
- return Reflect.get(target, "_createCustomSection");
- }
- return Reflect.get(target, prop);
- }
- });
- }
- function section_proxy_wrap(inClass) {
- return new Proxy(inClass, {
- get: function(target, prop) {
- if (!objHasProperty(target, prop) && objHasProperty(target.sequence, prop)) {
- const targetProperty = Reflect.get(target.sequence, prop);
- return is_function$1(targetProperty) ? targetProperty.bind(target.sequence) : targetProperty;
- }
- return Reflect.get(target, prop);
- }
- });
- }
- function str_to_search_regex_str(str) {
- return str.trim().replace(/[^A-Za-z0-9 .*_-]/g, "").replace(/\*+/g, ".*?");
- }
- function safe_str(str) {
- return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
- }
- function get_hash(input) {
- let hash2 = 0;
- const len = input.length;
- for (let i = 0; i < len; i++) {
- hash2 = (hash2 << 5) - hash2 + input.charCodeAt(i);
- hash2 |= 0;
- }
- return hash2;
- }
- function parseColor(inColor) {
- return {
- hexadecimal: is_real_number(inColor) ? inColor.toString(16) : inColor,
- decimal: typeof inColor === "string" && inColor.startsWith("#") ? parseInt(inColor.slice(1), 16) : inColor
- };
- }
- function getCanvasMouse() {
- return game.release.generation === 11 ? canvas.app.renderer.plugins.interaction.pointer : canvas.app.renderer.plugins.interaction.mouse;
- }
- function noop() {
- }
- const identity = (x) => x;
- function assign(tar, src) {
- for (const k in src)
- tar[k] = src[k];
- return tar;
- }
- function run(fn) {
- return fn();
- }
- function blank_object() {
- return /* @__PURE__ */ Object.create(null);
- }
- function run_all(fns) {
- fns.forEach(run);
- }
- function is_function(thing) {
- return typeof thing === "function";
- }
- function safe_not_equal(a, b) {
- return a != a ? b == b : a !== b || (a && typeof a === "object" || typeof a === "function");
- }
- let src_url_equal_anchor;
- function src_url_equal(element_src, url) {
- if (!src_url_equal_anchor) {
- src_url_equal_anchor = document.createElement("a");
- }
- src_url_equal_anchor.href = url;
- return element_src === src_url_equal_anchor.href;
- }
- function is_empty(obj) {
- return Object.keys(obj).length === 0;
- }
- function subscribe(store, ...callbacks) {
- if (store == null) {
- return noop;
- }
- const unsub = store.subscribe(...callbacks);
- return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
- }
- function get_store_value(store) {
- let value;
- subscribe(store, (_) => value = _)();
- return value;
- }
- function component_subscribe(component, store, callback) {
- component.$$.on_destroy.push(subscribe(store, callback));
- }
- function create_slot(definition, ctx, $$scope, fn) {
- if (definition) {
- const slot_ctx = get_slot_context(definition, ctx, $$scope, fn);
- return definition[0](slot_ctx);
- }
- }
- function get_slot_context(definition, ctx, $$scope, fn) {
- return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx;
- }
- function get_slot_changes(definition, $$scope, dirty, fn) {
- if (definition[2] && fn) {
- const lets = definition[2](fn(dirty));
- if ($$scope.dirty === void 0) {
- return lets;
- }
- if (typeof lets === "object") {
- const merged = [];
- const len = Math.max($$scope.dirty.length, lets.length);
- for (let i = 0; i < len; i += 1) {
- merged[i] = $$scope.dirty[i] | lets[i];
- }
- return merged;
- }
- return $$scope.dirty | lets;
- }
- return $$scope.dirty;
- }
- function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {
- if (slot_changes) {
- const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
- slot.p(slot_context, slot_changes);
- }
- }
- function get_all_dirty_from_scope($$scope) {
- if ($$scope.ctx.length > 32) {
- const dirty = [];
- const length = $$scope.ctx.length / 32;
- for (let i = 0; i < length; i++) {
- dirty[i] = -1;
- }
- return dirty;
- }
- return -1;
- }
- function exclude_internal_props(props) {
- const result = {};
- for (const k in props)
- if (k[0] !== "$")
- result[k] = props[k];
- return result;
- }
- function compute_slots(slots) {
- const result = {};
- for (const key in slots) {
- result[key] = true;
- }
- return result;
- }
- function set_store_value(store, ret, value) {
- store.set(value);
- return ret;
- }
- function action_destroyer(action_result) {
- return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
- }
- const is_client = typeof window !== "undefined";
- let now = is_client ? () => window.performance.now() : () => Date.now();
- let raf = is_client ? (cb) => requestAnimationFrame(cb) : noop;
- const tasks = /* @__PURE__ */ new Set();
- function run_tasks(now2) {
- tasks.forEach((task) => {
- if (!task.c(now2)) {
- tasks.delete(task);
- task.f();
- }
- });
- if (tasks.size !== 0)
- raf(run_tasks);
- }
- function loop(callback) {
- let task;
- if (tasks.size === 0)
- raf(run_tasks);
- return {
- promise: new Promise((fulfill) => {
- tasks.add(task = { c: callback, f: fulfill });
- }),
- abort() {
- tasks.delete(task);
- }
- };
- }
- function append(target, node) {
- target.appendChild(node);
- }
- function get_root_for_style(node) {
- if (!node)
- return document;
- const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;
- if (root && root.host) {
- return root;
- }
- return node.ownerDocument;
- }
- function append_empty_stylesheet(node) {
- const style_element = element("style");
- append_stylesheet(get_root_for_style(node), style_element);
- return style_element.sheet;
- }
- function append_stylesheet(node, style) {
- append(node.head || node, style);
- return style.sheet;
- }
- function insert(target, node, anchor) {
- target.insertBefore(node, anchor || null);
- }
- function detach(node) {
- if (node.parentNode) {
- node.parentNode.removeChild(node);
- }
- }
- function destroy_each(iterations, detaching) {
- for (let i = 0; i < iterations.length; i += 1) {
- if (iterations[i])
- iterations[i].d(detaching);
- }
- }
- function element(name) {
- return document.createElement(name);
- }
- function svg_element(name) {
- return document.createElementNS("http://www.w3.org/2000/svg", name);
- }
- function text$1(data) {
- return document.createTextNode(data);
- }
- function space() {
- return text$1(" ");
- }
- function empty() {
- return text$1("");
- }
- function listen(node, event, handler, options) {
- node.addEventListener(event, handler, options);
- return () => node.removeEventListener(event, handler, options);
- }
- function prevent_default(fn) {
- return function(event) {
- event.preventDefault();
- return fn.call(this, event);
- };
- }
- function stop_propagation(fn) {
- return function(event) {
- event.stopPropagation();
- return fn.call(this, event);
- };
- }
- function attr(node, attribute, value) {
- if (value == null)
- node.removeAttribute(attribute);
- else if (node.getAttribute(attribute) !== value)
- node.setAttribute(attribute, value);
- }
- function to_number(value) {
- return value === "" ? null : +value;
- }
- function children(element2) {
- return Array.from(element2.childNodes);
- }
- function set_data(text2, data) {
- data = "" + data;
- if (text2.wholeText !== data)
- text2.data = data;
- }
- function set_input_value(input, value) {
- input.value = value == null ? "" : value;
- }
- function set_style(node, key, value, important) {
- if (value === null) {
- node.style.removeProperty(key);
- } else {
- node.style.setProperty(key, value, important ? "important" : "");
- }
- }
- function select_option(select, value) {
- for (let i = 0; i < select.options.length; i += 1) {
- const option = select.options[i];
- if (option.__value === value) {
- option.selected = true;
- return;
- }
- }
- select.selectedIndex = -1;
- }
- function select_options(select, value) {
- for (let i = 0; i < select.options.length; i += 1) {
- const option = select.options[i];
- option.selected = ~value.indexOf(option.__value);
- }
- }
- function select_value(select) {
- const selected_option = select.querySelector(":checked") || select.options[0];
- return selected_option && selected_option.__value;
- }
- function select_multiple_value(select) {
- return [].map.call(select.querySelectorAll(":checked"), (option) => option.__value);
- }
- function toggle_class(element2, name, toggle) {
- element2.classList[toggle ? "add" : "remove"](name);
- }
- function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
- const e = document.createEvent("CustomEvent");
- e.initCustomEvent(type, bubbles, cancelable, detail);
- return e;
- }
- class HtmlTag {
- constructor(is_svg = false) {
- this.is_svg = false;
- this.is_svg = is_svg;
- this.e = this.n = null;
- }
- c(html) {
- this.h(html);
- }
- m(html, target, anchor = null) {
- if (!this.e) {
- if (this.is_svg)
- this.e = svg_element(target.nodeName);
- else
- this.e = element(target.nodeName);
- this.t = target;
- this.c(html);
- }
- this.i(anchor);
- }
- h(html) {
- this.e.innerHTML = html;
- this.n = Array.from(this.e.childNodes);
- }
- i(anchor) {
- for (let i = 0; i < this.n.length; i += 1) {
- insert(this.t, this.n[i], anchor);
- }
- }
- p(html) {
- this.d();
- this.h(html);
- this.i(this.a);
- }
- d() {
- this.n.forEach(detach);
- }
- }
- function construct_svelte_component(component, props) {
- return new component(props);
- }
- const managed_styles = /* @__PURE__ */ new Map();
- let active = 0;
- function hash(str) {
- let hash2 = 5381;
- let i = str.length;
- while (i--)
- hash2 = (hash2 << 5) - hash2 ^ str.charCodeAt(i);
- return hash2 >>> 0;
- }
- function create_style_information(doc, node) {
- const info = { stylesheet: append_empty_stylesheet(node), rules: {} };
- managed_styles.set(doc, info);
- return info;
- }
- function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) {
- const step = 16.666 / duration;
- let keyframes = "{\n";
- for (let p = 0; p <= 1; p += step) {
- const t = a + (b - a) * ease(p);
- keyframes += p * 100 + `%{${fn(t, 1 - t)}}
- `;
- }
- const rule = keyframes + `100% {${fn(b, 1 - b)}}
- }`;
- const name = `__svelte_${hash(rule)}_${uid}`;
- const doc = get_root_for_style(node);
- const { stylesheet, rules } = managed_styles.get(doc) || create_style_information(doc, node);
- if (!rules[name]) {
- rules[name] = true;
- stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
- }
- const animation2 = node.style.animation || "";
- node.style.animation = `${animation2 ? `${animation2}, ` : ""}${name} ${duration}ms linear ${delay}ms 1 both`;
- active += 1;
- return name;
- }
- function delete_rule(node, name) {
- const previous = (node.style.animation || "").split(", ");
- const next = previous.filter(
- name ? (anim) => anim.indexOf(name) < 0 : (anim) => anim.indexOf("__svelte") === -1
- // remove all Svelte animations
- );
- const deleted = previous.length - next.length;
- if (deleted) {
- node.style.animation = next.join(", ");
- active -= deleted;
- if (!active)
- clear_rules();
- }
- }
- function clear_rules() {
- raf(() => {
- if (active)
- return;
- managed_styles.forEach((info) => {
- const { ownerNode } = info.stylesheet;
- if (ownerNode)
- detach(ownerNode);
- });
- managed_styles.clear();
- });
- }
- let current_component;
- function set_current_component(component) {
- current_component = component;
- }
- function get_current_component() {
- if (!current_component)
- throw new Error("Function called outside component initialization");
- return current_component;
- }
- function onMount(fn) {
- get_current_component().$$.on_mount.push(fn);
- }
- function afterUpdate(fn) {
- get_current_component().$$.after_update.push(fn);
- }
- function onDestroy(fn) {
- get_current_component().$$.on_destroy.push(fn);
- }
- function createEventDispatcher() {
- const component = get_current_component();
- return (type, detail, { cancelable = false } = {}) => {
- const callbacks = component.$$.callbacks[type];
- if (callbacks) {
- const event = custom_event(type, detail, { cancelable });
- callbacks.slice().forEach((fn) => {
- fn.call(component, event);
- });
- return !event.defaultPrevented;
- }
- return true;
- };
- }
- function setContext(key, context) {
- get_current_component().$$.context.set(key, context);
- return context;
- }
- function getContext(key) {
- return get_current_component().$$.context.get(key);
- }
- const dirty_components = [];
- const binding_callbacks = [];
- const render_callbacks = [];
- const flush_callbacks = [];
- const resolved_promise = Promise.resolve();
- let update_scheduled = false;
- function schedule_update() {
- if (!update_scheduled) {
- update_scheduled = true;
- resolved_promise.then(flush);
- }
- }
- function add_render_callback(fn) {
- render_callbacks.push(fn);
- }
- function add_flush_callback(fn) {
- flush_callbacks.push(fn);
- }
- const seen_callbacks = /* @__PURE__ */ new Set();
- let flushidx = 0;
- function flush() {
- if (flushidx !== 0) {
- return;
- }
- const saved_component = current_component;
- do {
- try {
- while (flushidx < dirty_components.length) {
- const component = dirty_components[flushidx];
- flushidx++;
- set_current_component(component);
- update(component.$$);
- }
- } catch (e) {
- dirty_components.length = 0;
- flushidx = 0;
- throw e;
- }
- set_current_component(null);
- dirty_components.length = 0;
- flushidx = 0;
- while (binding_callbacks.length)
- binding_callbacks.pop()();
- for (let i = 0; i < render_callbacks.length; i += 1) {
- const callback = render_callbacks[i];
- if (!seen_callbacks.has(callback)) {
- seen_callbacks.add(callback);
- callback();
- }
- }
- render_callbacks.length = 0;
- } while (dirty_components.length);
- while (flush_callbacks.length) {
- flush_callbacks.pop()();
- }
- update_scheduled = false;
- seen_callbacks.clear();
- set_current_component(saved_component);
- }
- function update($$) {
- if ($$.fragment !== null) {
- $$.update();
- run_all($$.before_update);
- const dirty = $$.dirty;
- $$.dirty = [-1];
- $$.fragment && $$.fragment.p($$.ctx, dirty);
- $$.after_update.forEach(add_render_callback);
- }
- }
- let promise;
- function wait() {
- if (!promise) {
- promise = Promise.resolve();
- promise.then(() => {
- promise = null;
- });
- }
- return promise;
- }
- function dispatch(node, direction, kind) {
- node.dispatchEvent(custom_event(`${direction ? "intro" : "outro"}${kind}`));
- }
- const outroing = /* @__PURE__ */ new Set();
- let outros;
- function group_outros() {
- outros = {
- r: 0,
- c: [],
- p: outros
- // parent group
- };
- }
- function check_outros() {
- if (!outros.r) {
- run_all(outros.c);
- }
- outros = outros.p;
- }
- function transition_in(block, local) {
- if (block && block.i) {
- outroing.delete(block);
- block.i(local);
- }
- }
- function transition_out(block, local, detach2, callback) {
- if (block && block.o) {
- if (outroing.has(block))
- return;
- outroing.add(block);
- outros.c.push(() => {
- outroing.delete(block);
- if (callback) {
- if (detach2)
- block.d(1);
- callback();
- }
- });
- block.o(local);
- } else if (callback) {
- callback();
- }
- }
- const null_transition = { duration: 0 };
- function create_in_transition(node, fn, params) {
- const options = { direction: "in" };
- let config = fn(node, params, options);
- let running = false;
- let animation_name;
- let task;
- let uid = 0;
- function cleanup() {
- if (animation_name)
- delete_rule(node, animation_name);
- }
- function go() {
- const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition;
- if (css)
- animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++);
- tick(0, 1);
- const start_time = now() + delay;
- const end_time = start_time + duration;
- if (task)
- task.abort();
- running = true;
- add_render_callback(() => dispatch(node, true, "start"));
- task = loop((now2) => {
- if (running) {
- if (now2 >= end_time) {
- tick(1, 0);
- dispatch(node, true, "end");
- cleanup();
- return running = false;
- }
- if (now2 >= start_time) {
- const t = easing((now2 - start_time) / duration);
- tick(t, 1 - t);
- }
- }
- return running;
- });
- }
- let started = false;
- return {
- start() {
- if (started)
- return;
- started = true;
- delete_rule(node);
- if (is_function(config)) {
- config = config(options);
- wait().then(go);
- } else {
- go();
- }
- },
- invalidate() {
- started = false;
- },
- end() {
- if (running) {
- cleanup();
- running = false;
- }
- }
- };
- }
- function create_out_transition(node, fn, params) {
- const options = { direction: "out" };
- let config = fn(node, params, options);
- let running = true;
- let animation_name;
- const group = outros;
- group.r += 1;
- function go() {
- const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition;
- if (css)
- animation_name = create_rule(node, 1, 0, duration, delay, easing, css);
- const start_time = now() + delay;
- const end_time = start_time + duration;
- add_render_callback(() => dispatch(node, false, "start"));
- loop((now2) => {
- if (running) {
- if (now2 >= end_time) {
- tick(0, 1);
- dispatch(node, false, "end");
- if (!--group.r) {
- run_all(group.c);
- }
- return false;
- }
- if (now2 >= start_time) {
- const t = easing((now2 - start_time) / duration);
- tick(1 - t, t);
- }
- }
- return running;
- });
- }
- if (is_function(config)) {
- wait().then(() => {
- config = config(options);
- go();
- });
- } else {
- go();
- }
- return {
- end(reset) {
- if (reset && config.tick) {
- config.tick(1, 0);
- }
- if (running) {
- if (animation_name)
- delete_rule(node, animation_name);
- running = false;
- }
- }
- };
- }
- function destroy_block(block, lookup) {
- block.d(1);
- lookup.delete(block.key);
- }
- function outro_and_destroy_block(block, lookup) {
- transition_out(block, 1, 1, () => {
- lookup.delete(block.key);
- });
- }
- function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block2, next, get_context) {
- let o = old_blocks.length;
- let n = list.length;
- let i = o;
- const old_indexes = {};
- while (i--)
- old_indexes[old_blocks[i].key] = i;
- const new_blocks = [];
- const new_lookup = /* @__PURE__ */ new Map();
- const deltas = /* @__PURE__ */ new Map();
- i = n;
- while (i--) {
- const child_ctx = get_context(ctx, list, i);
- const key = get_key(child_ctx);
- let block = lookup.get(key);
- if (!block) {
- block = create_each_block2(key, child_ctx);
- block.c();
- } else if (dynamic) {
- block.p(child_ctx, dirty);
- }
- new_lookup.set(key, new_blocks[i] = block);
- if (key in old_indexes)
- deltas.set(key, Math.abs(i - old_indexes[key]));
- }
- const will_move = /* @__PURE__ */ new Set();
- const did_move = /* @__PURE__ */ new Set();
- function insert2(block) {
- transition_in(block, 1);
- block.m(node, next);
- lookup.set(block.key, block);
- next = block.first;
- n--;
- }
- while (o && n) {
- const new_block = new_blocks[n - 1];
- const old_block = old_blocks[o - 1];
- const new_key = new_block.key;
- const old_key = old_block.key;
- if (new_block === old_block) {
- next = new_block.first;
- o--;
- n--;
- } else if (!new_lookup.has(old_key)) {
- destroy(old_block, lookup);
- o--;
- } else if (!lookup.has(new_key) || will_move.has(new_key)) {
- insert2(new_block);
- } else if (did_move.has(old_key)) {
- o--;
- } else if (deltas.get(new_key) > deltas.get(old_key)) {
- did_move.add(new_key);
- insert2(new_block);
- } else {
- will_move.add(old_key);
- o--;
- }
- }
- while (o--) {
- const old_block = old_blocks[o];
- if (!new_lookup.has(old_block.key))
- destroy(old_block, lookup);
- }
- while (n)
- insert2(new_blocks[n - 1]);
- return new_blocks;
- }
- function get_spread_update(levels, updates) {
- const update2 = {};
- const to_null_out = {};
- const accounted_for = { $$scope: 1 };
- let i = levels.length;
- while (i--) {
- const o = levels[i];
- const n = updates[i];
- if (n) {
- for (const key in o) {
- if (!(key in n))
- to_null_out[key] = 1;
- }
- for (const key in n) {
- if (!accounted_for[key]) {
- update2[key] = n[key];
- accounted_for[key] = 1;
- }
- }
- levels[i] = n;
- } else {
- for (const key in o) {
- accounted_for[key] = 1;
- }
- }
- }
- for (const key in to_null_out) {
- if (!(key in update2))
- update2[key] = void 0;
- }
- return update2;
- }
- function get_spread_object(spread_props) {
- return typeof spread_props === "object" && spread_props !== null ? spread_props : {};
- }
- function bind(component, name, callback) {
- const index = component.$$.props[name];
- if (index !== void 0) {
- component.$$.bound[index] = callback;
- callback(component.$$.ctx[index]);
- }
- }
- function create_component(block) {
- block && block.c();
- }
- function mount_component(component, target, anchor, customElement) {
- const { fragment, after_update } = component.$$;
- fragment && fragment.m(target, anchor);
- if (!customElement) {
- add_render_callback(() => {
- const new_on_destroy = component.$$.on_mount.map(run).filter(is_function);
- if (component.$$.on_destroy) {
- component.$$.on_destroy.push(...new_on_destroy);
- } else {
- run_all(new_on_destroy);
- }
- component.$$.on_mount = [];
- });
- }
- after_update.forEach(add_render_callback);
- }
- function destroy_component(component, detaching) {
- const $$ = component.$$;
- if ($$.fragment !== null) {
- run_all($$.on_destroy);
- $$.fragment && $$.fragment.d(detaching);
- $$.on_destroy = $$.fragment = null;
- $$.ctx = [];
- }
- }
- function make_dirty(component, i) {
- if (component.$$.dirty[0] === -1) {
- dirty_components.push(component);
- schedule_update();
- component.$$.dirty.fill(0);
- }
- component.$$.dirty[i / 31 | 0] |= 1 << i % 31;
- }
- function init(component, options, instance2, create_fragment2, not_equal, props, append_styles, dirty = [-1]) {
- const parent_component = current_component;
- set_current_component(component);
- const $$ = component.$$ = {
- fragment: null,
- ctx: [],
- // state
- props,
- update: noop,
- not_equal,
- bound: blank_object(),
- // lifecycle
- on_mount: [],
- on_destroy: [],
- on_disconnect: [],
- before_update: [],
- after_update: [],
- context: new Map(options.context || (parent_component ? parent_component.$$.context : [])),
- // everything else
- callbacks: blank_object(),
- dirty,
- skip_bound: false,
- root: options.target || parent_component.$$.root
- };
- append_styles && append_styles($$.root);
- let ready = false;
- $$.ctx = instance2 ? instance2(component, options.props || {}, (i, ret, ...rest) => {
- const value = rest.length ? rest[0] : ret;
- if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
- if (!$$.skip_bound && $$.bound[i])
- $$.bound[i](value);
- if (ready)
- make_dirty(component, i);
- }
- return ret;
- }) : [];
- $$.update();
- ready = true;
- run_all($$.before_update);
- $$.fragment = create_fragment2 ? create_fragment2($$.ctx) : false;
- if (options.target) {
- if (options.hydrate) {
- const nodes = children(options.target);
- $$.fragment && $$.fragment.l(nodes);
- nodes.forEach(detach);
- } else {
- $$.fragment && $$.fragment.c();
- }
- if (options.intro)
- transition_in(component.$$.fragment);
- mount_component(component, options.target, options.anchor, options.customElement);
- flush();
- }
- set_current_component(parent_component);
- }
- class SvelteComponent {
- $destroy() {
- destroy_component(this, 1);
- this.$destroy = noop;
- }
- $on(type, callback) {
- if (!is_function(callback)) {
- return noop;
- }
- const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
- callbacks.push(callback);
- return () => {
- const index = callbacks.indexOf(callback);
- if (index !== -1)
- callbacks.splice(index, 1);
- };
- }
- $set($$props) {
- if (this.$$set && !is_empty($$props)) {
- this.$$.skip_bound = true;
- this.$$set($$props);
- this.$$.skip_bound = false;
- }
- }
- }
- const s_TAG_OBJECT = "[object Object]";
- function deepMerge(target = {}, ...sourceObj) {
- if (Object.prototype.toString.call(target) !== s_TAG_OBJECT) {
- throw new TypeError(`deepMerge error: 'target' is not an 'object'.`);
- }
- for (let cntr = 0; cntr < sourceObj.length; cntr++) {
- if (Object.prototype.toString.call(sourceObj[cntr]) !== s_TAG_OBJECT) {
- throw new TypeError(`deepMerge error: 'sourceObj[${cntr}]' is not an 'object'.`);
- }
- }
- return _deepMerge(target, ...sourceObj);
- }
- function isIterable(value) {
- if (value === null || value === void 0 || typeof value !== "object") {
- return false;
- }
- return typeof value[Symbol.iterator] === "function";
- }
- function isObject(value) {
- return value !== null && typeof value === "object";
- }
- function isPlainObject(value) {
- if (Object.prototype.toString.call(value) !== s_TAG_OBJECT) {
- return false;
- }
- const prototype = Object.getPrototypeOf(value);
- return prototype === null || prototype === Object.prototype;
- }
- function safeAccess(data, accessor, defaultValue = void 0) {
- if (typeof data !== "object") {
- return defaultValue;
- }
- if (typeof accessor !== "string") {
- return defaultValue;
- }
- const access = accessor.split(".");
- for (let cntr = 0; cntr < access.length; cntr++) {
- if (typeof data[access[cntr]] === "undefined" || data[access[cntr]] === null) {
- return defaultValue;
- }
- data = data[access[cntr]];
- }
- return data;
- }
- function safeSet(data, accessor, value, operation = "set", createMissing = true) {
- if (typeof data !== "object") {
- throw new TypeError(`safeSet Error: 'data' is not an 'object'.`);
- }
- if (typeof accessor !== "string") {
- throw new TypeError(`safeSet Error: 'accessor' is not a 'string'.`);
- }
- const access = accessor.split(".");
- for (let cntr = 0; cntr < access.length; cntr++) {
- if (Array.isArray(data)) {
- const number = +access[cntr];
- if (!Number.isInteger(number) || number < 0) {
- return false;
- }
- }
- if (cntr === access.length - 1) {
- switch (operation) {
- case "add":
- data[access[cntr]] += value;
- break;
- case "div":
- data[access[cntr]] /= value;
- break;
- case "mult":
- data[access[cntr]] *= value;
- break;
- case "set":
- data[access[cntr]] = value;
- break;
- case "set-undefined":
- if (typeof data[access[cntr]] === "undefined") {
- data[access[cntr]] = value;
- }
- break;
- case "sub":
- data[access[cntr]] -= value;
- break;
- }
- } else {
- if (createMissing && typeof data[access[cntr]] === "undefined") {
- data[access[cntr]] = {};
- }
- if (data[access[cntr]] === null || typeof data[access[cntr]] !== "object") {
- return false;
- }
- data = data[access[cntr]];
- }
- }
- return true;
- }
- function _deepMerge(target = {}, ...sourceObj) {
- for (let cntr = 0; cntr < sourceObj.length; cntr++) {
- const obj = sourceObj[cntr];
- for (const prop in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, prop)) {
- if (prop.startsWith("-=")) {
- delete target[prop.slice(2)];
- continue;
- }
- target[prop] = Object.prototype.hasOwnProperty.call(target, prop) && target[prop]?.constructor === Object && obj[prop]?.constructor === Object ? _deepMerge({}, target[prop], obj[prop]) : obj[prop];
- }
- }
- }
- return target;
- }
- class A11yHelper {
- /**
- * Apply focus to the HTMLElement targets in a given A11yFocusSource data object. An iterable list `options.focusEl`
- * can contain HTMLElements or selector strings. If multiple focus targets are provided in a list then the first
- * valid target found will be focused. If focus target is a string then a lookup via `document.querySelector` is
- * performed. In this case you should provide a unique selector for the desired focus target.
- *
- * Note: The body of this method is postponed to the next clock tick to allow any changes in the DOM to occur that
- * might alter focus targets before applying.
- *
- * @param {A11yFocusSource|{ focusSource: A11yFocusSource }} options - The focus options instance to apply.
- */
- static applyFocusSource(options) {
- if (!isObject(options)) {
- return;
- }
- const focusOpts = isObject(options?.focusSource) ? options.focusSource : options;
- setTimeout(() => {
- const debug2 = typeof focusOpts.debug === "boolean" ? focusOpts.debug : false;
- if (isIterable(focusOpts.focusEl)) {
- if (debug2) {
- console.debug(`A11yHelper.applyFocusSource debug - Attempting to apply focus target: `, focusOpts.focusEl);
- }
- for (const target of focusOpts.focusEl) {
- if (target instanceof HTMLElement && target.isConnected) {
- target.focus();
- if (debug2) {
- console.debug(`A11yHelper.applyFocusSource debug - Applied focus to target: `, target);
- }
- break;
- } else if (typeof target === "string") {
- const element2 = document.querySelector(target);
- if (element2 instanceof HTMLElement && element2.isConnected) {
- element2.focus();
- if (debug2) {
- console.debug(`A11yHelper.applyFocusSource debug - Applied focus to target: `, element2);
- }
- break;
- } else if (debug2) {
- console.debug(`A11yHelper.applyFocusSource debug - Could not query selector: `, target);
- }
- }
- }
- } else if (debug2) {
- console.debug(`A11yHelper.applyFocusSource debug - No focus targets defined.`);
- }
- }, 0);
- }
- /**
- * Returns first focusable element within a specified element.
- *
- * @param {HTMLElement|Document} [element=document] - Optional element to start query.
- *
- * @param {object} [options] - Optional parameters.
- *
- * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
- *
- * @param {Set<HTMLElement>} [options.ignoreElements] - Set of elements to ignore.
- *
- * @returns {HTMLElement} First focusable child element
- */
- static getFirstFocusableElement(element2 = document, options) {
- const focusableElements = this.getFocusableElements(element2, options);
- return focusableElements.length > 0 ? focusableElements[0] : void 0;
- }
- /**
- * Returns all focusable elements within a specified element.
- *
- * @param {HTMLElement|Document} [element=document] Optional element to start query.
- *
- * @param {object} [options] - Optional parameters.
- *
- * @param {boolean} [options.anchorHref=true] - When true anchors must have an HREF.
- *
- * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
- *
- * @param {Set<HTMLElement>} [options.ignoreElements] - Set of elements to ignore.
- *
- * @param {string} [options.selectors] - Custom list of focusable selectors for `querySelectorAll`.
- *
- * @returns {Array<HTMLElement>} Child keyboard focusable
- */
- static getFocusableElements(element2 = document, { anchorHref = true, ignoreClasses, ignoreElements, selectors } = {}) {
- if (!(element2 instanceof HTMLElement) && !(element2 instanceof Document)) {
- throw new TypeError(`'element' is not a HTMLElement or Document instance.`);
- }
- if (typeof anchorHref !== "boolean") {
- throw new TypeError(`'anchorHref' is not a boolean.`);
- }
- if (ignoreClasses !== void 0 && !isIterable(ignoreClasses)) {
- throw new TypeError(`'ignoreClasses' is not an iterable list.`);
- }
- if (ignoreElements !== void 0 && !(ignoreElements instanceof Set)) {
- throw new TypeError(`'ignoreElements' is not a Set.`);
- }
- if (selectors !== void 0 && typeof selectors !== "string") {
- throw new TypeError(`'selectors' is not a string.`);
- }
- const selectorQuery = selectors ?? this.#getFocusableSelectors(anchorHref);
- const allElements = [...element2.querySelectorAll(selectorQuery)];
- if (ignoreElements && ignoreClasses) {
- return allElements.filter((el) => {
- let hasIgnoreClass = false;
- for (const ignoreClass of ignoreClasses) {
- if (el.classList.contains(ignoreClass)) {
- hasIgnoreClass = true;
- break;
- }
- }
- return !hasIgnoreClass && !ignoreElements.has(el) && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
- });
- } else if (ignoreClasses) {
- return allElements.filter((el) => {
- let hasIgnoreClass = false;
- for (const ignoreClass of ignoreClasses) {
- if (el.classList.contains(ignoreClass)) {
- hasIgnoreClass = true;
- break;
- }
- }
- return !hasIgnoreClass && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
- });
- } else if (ignoreElements) {
- return allElements.filter((el) => {
- return !ignoreElements.has(el) && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
- });
- } else {
- return allElements.filter((el) => {
- return el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
- });
- }
- }
- /**
- * Returns the default focusable selectors query.
- *
- * @param {boolean} [anchorHref=true] - When true anchors must have an HREF.
- *
- * @returns {string} Focusable selectors for `querySelectorAll`.
- */
- static #getFocusableSelectors(anchorHref = true) {
- return `button, [contenteditable=""], [contenteditable="true"], details summary:not([tabindex="-1"]), embed, a${anchorHref ? "[href]" : ""}, iframe, object, input:not([type=hidden]), select, textarea, [tabindex]:not([tabindex="-1"])`;
- }
- /**
- * Gets a A11yFocusSource object from the given DOM event allowing for optional X / Y screen space overrides.
- * Browsers (Firefox / Chrome) forwards a mouse event for the context menu keyboard button. Provides detection of
- * when the context menu event is from the keyboard. Firefox as of (1/23) does not provide the correct screen space
- * coordinates, so for keyboard context menu presses coordinates are generated from the centroid point of the
- * element.
- *
- * A default fallback element or selector string may be provided to provide the focus target. If the event comes from
- * the keyboard however the source focused element is inserted as the target with the fallback value appended to the
- * list of focus targets. When A11yFocusSource is applied by {@link A11yHelper.applyFocusSource} the target focus
- * list is iterated through until a connected target is found and focus applied.
- *
- * @param {object} options - Options
- *
- * @param {KeyboardEvent|MouseEvent} [options.event] - The source DOM event.
- *
- * @param {boolean} [options.debug] - When true {@link A11yHelper.applyFocusSource} logs focus target data.
- *
- * @param {HTMLElement|string} [options.focusEl] - A specific HTMLElement or selector string as the focus target.
- *
- * @param {number} [options.x] - Used when an event isn't provided; integer of event source in screen space.
- *
- * @param {number} [options.y] - Used when an event isn't provided; integer of event source in screen space.
- *
- * @returns {A11yFocusSource} A A11yFocusSource object.
- *
- * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1426671
- * @see https://bugzilla.mozilla.org/show_bug.cgi?id=314314
- *
- * TODO: Evaluate / test against touch input devices.
- */
- static getFocusSource({ event, x, y, focusEl, debug: debug2 = false }) {
- if (focusEl !== void 0 && !(focusEl instanceof HTMLElement) && typeof focusEl !== "string") {
- throw new TypeError(
- `A11yHelper.getFocusSource error: 'focusEl' is not a HTMLElement or string.`
- );
- }
- if (debug2 !== void 0 && typeof debug2 !== "boolean") {
- throw new TypeError(`A11yHelper.getFocusSource error: 'debug' is not a boolean.`);
- }
- if (event === void 0) {
- if (typeof x !== "number") {
- throw new TypeError(`A11yHelper.getFocusSource error: 'event' not defined and 'x' is not a number.`);
- }
- if (typeof y !== "number") {
- throw new TypeError(`A11yHelper.getFocusSource error: 'event' not defined and 'y' is not a number.`);
- }
- return {
- debug: debug2,
- focusEl: focusEl !== void 0 ? [focusEl] : void 0,
- x,
- y
- };
- }
- if (!(event instanceof KeyboardEvent) && !(event instanceof MouseEvent)) {
- throw new TypeError(`A11yHelper.getFocusSource error: 'event' is not a KeyboardEvent or MouseEvent.`);
- }
- if (x !== void 0 && !Number.isInteger(x)) {
- throw new TypeError(`A11yHelper.getFocusSource error: 'x' is not a number.`);
- }
- if (y !== void 0 && !Number.isInteger(y)) {
- throw new TypeError(`A11yHelper.getFocusSource error: 'y' is not a number.`);
- }
- const targetEl = event.target;
- if (!(targetEl instanceof HTMLElement)) {
- throw new TypeError(`A11yHelper.getFocusSource error: 'event.target' is not an HTMLElement.`);
- }
- const result = { debug: debug2 };
- if (event instanceof MouseEvent) {
- if (event?.button !== 2 && event.type === "contextmenu") {
- const rect = targetEl.getBoundingClientRect();
- result.x = x ?? rect.left + rect.width / 2;
- result.y = y ?? rect.top + rect.height / 2;
- result.focusEl = focusEl !== void 0 ? [targetEl, focusEl] : [targetEl];
- result.source = "keyboard";
- } else {
- result.x = x ?? event.pageX;
- result.y = y ?? event.pageY;
- result.focusEl = focusEl !== void 0 ? [focusEl] : void 0;
- }
- } else {
- const rect = targetEl.getBoundingClientRect();
- result.x = x ?? rect.left + rect.width / 2;
- result.y = y ?? rect.top + rect.height / 2;
- result.focusEl = focusEl !== void 0 ? [targetEl, focusEl] : [targetEl];
- result.source = "keyboard";
- }
- return result;
- }
- /**
- * Returns first focusable element within a specified element.
- *
- * @param {HTMLElement|Document} [element=document] - Optional element to start query.
- *
- * @param {object} [options] - Optional parameters.
- *
- * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
- *
- * @param {Set<HTMLElement>} [options.ignoreElements] - Set of elements to ignore.
- *
- * @returns {HTMLElement} First focusable child element
- */
- static getLastFocusableElement(element2 = document, options) {
- const focusableElements = this.getFocusableElements(element2, options);
- return focusableElements.length > 0 ? focusableElements[focusableElements.length - 1] : void 0;
- }
- /**
- * Tests if the given element is focusable.
- *
- * @param {HTMLElement} [el] - Element to test.
- *
- * @param {object} [options] - Optional parameters.
- *
- * @param {boolean} [options.anchorHref=true] - When true anchors must have an HREF.
- *
- * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
- *
- * @returns {boolean} Element is focusable.
- */
- static isFocusable(el, { anchorHref = true, ignoreClasses } = {}) {
- if (el === void 0 || el === null || !(el instanceof HTMLElement) || el?.hidden || !el?.isConnected) {
- return false;
- }
- if (typeof anchorHref !== "boolean") {
- throw new TypeError(`'anchorHref' is not a boolean.`);
- }
- if (ignoreClasses !== void 0 && !isIterable(ignoreClasses)) {
- throw new TypeError(`'ignoreClasses' is not an iterable list.`);
- }
- const contenteditableAttr = el.getAttribute("contenteditable");
- const contenteditableFocusable = typeof contenteditableAttr === "string" && (contenteditableAttr === "" || contenteditableAttr === "true");
- const tabindexAttr = el.getAttribute("tabindex");
- const tabindexFocusable = typeof tabindexAttr === "string" && tabindexAttr !== "-1";
- const isAnchor = el instanceof HTMLAnchorElement;
- if (contenteditableFocusable || tabindexFocusable || isAnchor || el instanceof HTMLButtonElement || el instanceof HTMLDetailsElement || el instanceof HTMLEmbedElement || el instanceof HTMLIFrameElement || el instanceof HTMLInputElement || el instanceof HTMLObjectElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) {
- if (isAnchor && anchorHref && typeof el.getAttribute("href") !== "string") {
- return false;
- }
- return el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
- }
- return false;
- }
- /**
- * Convenience method to check if the given data is a valid focus source.
- *
- * @param {HTMLElement|string} data - Either an HTMLElement or selector string.
- *
- * @returns {boolean} Is valid focus source.
- */
- static isFocusSource(data) {
- return data instanceof HTMLElement || typeof data === "string";
- }
- }
- class StyleManager {
- /** @type {CSSStyleRule} */
- #cssRule;
- /** @type {string} */
- #docKey;
- /** @type {string} */
- #selector;
- /** @type {HTMLStyleElement} */
- #styleElement;
- /** @type {number} */
- #version;
- /**
- *
- * @param {object} opts - Options.
- *
- * @param {string} opts.docKey - Required key providing a link to a specific style sheet element.
- *
- * @param {string} [opts.selector=:root] - Selector element.
- *
- * @param {Document} [opts.document] - Target document to load styles into.
- *
- * @param {number} [opts.version] - An integer representing the version / level of styles being managed.
- *
- */
- constructor({ docKey, selector = ":root", document: document2 = globalThis.document, version } = {}) {
- if (typeof docKey !== "string") {
- throw new TypeError(`StyleManager error: 'docKey' is not a string.`);
- }
- if (typeof selector !== "string") {
- throw new TypeError(`StyleManager error: 'selector' is not a string.`);
- }
- if (version !== void 0 && !Number.isSafeInteger(version) && version < 1) {
- throw new TypeError(`StyleManager error: 'version' is defined and is not a positive integer >= 1.`);
- }
- this.#selector = selector;
- this.#docKey = docKey;
- this.#version = version;
- if (document2[this.#docKey] === void 0) {
- this.#styleElement = document2.createElement("style");
- document2.head.append(this.#styleElement);
- this.#styleElement._STYLE_MANAGER_VERSION = version;
- this.#styleElement.sheet.insertRule(`${selector} {}`, 0);
- this.#cssRule = this.#styleElement.sheet.cssRules[0];
- document2[docKey] = this.#styleElement;
- } else {
- this.#styleElement = document2[docKey];
- this.#cssRule = this.#styleElement.sheet.cssRules[0];
- if (version) {
- const existingVersion = this.#styleElement._STYLE_MANAGER_VERSION ?? 0;
- if (version > existingVersion) {
- this.#cssRule.style.cssText = "";
- }
- }
- }
- }
- /**
- * @returns {string} Provides an accessor to get the `cssText` for the style sheet.
- */
- get cssText() {
- return this.#cssRule.style.cssText;
- }
- /**
- * @returns {number} Returns the version of this instance.
- */
- get version() {
- return this.#version;
- }
- /**
- * Provides a copy constructor to duplicate an existing StyleManager instance into a new document.
- *
- * Note: This is used to support the `PopOut` module.
- *
- * @param {Document} [document] Target browser document to clone into.
- *
- * @returns {StyleManager} New style manager instance.
- */
- clone(document2 = globalThis.document) {
- const newStyleManager = new StyleManager({
- selector: this.#selector,
- docKey: this.#docKey,
- document: document2,
- version: this.#version
- });
- newStyleManager.#cssRule.style.cssText = this.#cssRule.style.cssText;
- return newStyleManager;
- }
- get() {
- const cssText = this.#cssRule.style.cssText;
- const result = {};
- if (cssText !== "") {
- for (const entry of cssText.split(";")) {
- if (entry !== "") {
- const values = entry.split(":");
- result[values[0].trim()] = values[1];
- }
- }
- }
- return result;
- }
- /**
- * Gets a particular CSS variable.
- *
- * @param {string} key - CSS variable property key.
- *
- * @returns {string} Returns CSS variable value.
- */
- getProperty(key) {
- if (typeof key !== "string") {
- throw new TypeError(`StyleManager error: 'key' is not a string.`);
- }
- return this.#cssRule.style.getPropertyValue(key);
- }
- /**
- * Set rules by property / value; useful for CSS variables.
- *
- * @param {Object<string, string>} rules - An object with property / value string pairs to load.
- *
- * @param {boolean} [overwrite=true] - When true overwrites any existing values.
- */
- setProperties(rules, overwrite = true) {
- if (!isObject(rules)) {
- throw new TypeError(`StyleManager error: 'rules' is not an object.`);
- }
- if (typeof overwrite !== "boolean") {
- throw new TypeError(`StyleManager error: 'overwrite' is not a boolean.`);
- }
- if (overwrite) {
- for (const [key, value] of Object.entries(rules)) {
- this.#cssRule.style.setProperty(key, value);
- }
- } else {
- for (const [key, value] of Object.entries(rules)) {
- if (this.#cssRule.style.getPropertyValue(key) === "") {
- this.#cssRule.style.setProperty(key, value);
- }
- }
- }
- }
- /**
- * Sets a particular property.
- *
- * @param {string} key - CSS variable property key.
- *
- * @param {string} value - CSS variable value.
- *
- * @param {boolean} [overwrite=true] - Overwrite any existing value.
- */
- setProperty(key, value, overwrite = true) {
- if (typeof key !== "string") {
- throw new TypeError(`StyleManager error: 'key' is not a string.`);
- }
- if (typeof value !== "string") {
- throw new TypeError(`StyleManager error: 'value' is not a string.`);
- }
- if (typeof overwrite !== "boolean") {
- throw new TypeError(`StyleManager error: 'overwrite' is not a boolean.`);
- }
- if (overwrite) {
- this.#cssRule.style.setProperty(key, value);
- } else {
- if (this.#cssRule.style.getPropertyValue(key) === "") {
- this.#cssRule.style.setProperty(key, value);
- }
- }
- }
- /**
- * Removes the property keys specified. If `keys` is an iterable list then all property keys in the list are removed.
- *
- * @param {Iterable<string>} keys - The property keys to remove.
- */
- removeProperties(keys) {
- if (!isIterable(keys)) {
- throw new TypeError(`StyleManager error: 'keys' is not an iterable list.`);
- }
- for (const key of keys) {
- if (typeof key === "string") {
- this.#cssRule.style.removeProperty(key);
- }
- }
- }
- /**
- * Removes a particular CSS variable.
- *
- * @param {string} key - CSS variable property key.
- *
- * @returns {string} CSS variable value when removed.
- */
- removeProperty(key) {
- if (typeof key !== "string") {
- throw new TypeError(`StyleManager error: 'key' is not a string.`);
- }
- return this.#cssRule.style.removeProperty(key);
- }
- }
- const s_REGEX = /(\d+)\s*px/;
- function styleParsePixels(value) {
- if (typeof value !== "string") {
- return void 0;
- }
- const isPixels = s_REGEX.test(value);
- const number = parseInt(value);
- return isPixels && Number.isFinite(number) ? number : void 0;
- }
- const applicationShellContract = ["elementRoot"];
- Object.freeze(applicationShellContract);
- function isApplicationShell(component) {
- if (component === null || component === void 0) {
- return false;
- }
- let compHasContract = true;
- let protoHasContract = true;
- for (const accessor of applicationShellContract) {
- const descriptor = Object.getOwnPropertyDescriptor(component, accessor);
- if (descriptor === void 0 || descriptor.get === void 0 || descriptor.set === void 0) {
- compHasContract = false;
- }
- }
- const prototype = Object.getPrototypeOf(component);
- for (const accessor of applicationShellContract) {
- const descriptor = Object.getOwnPropertyDescriptor(prototype, accessor);
- if (descriptor === void 0 || descriptor.get === void 0 || descriptor.set === void 0) {
- protoHasContract = false;
- }
- }
- return compHasContract || protoHasContract;
- }
- function isHMRProxy(comp) {
- const instanceName = comp?.constructor?.name;
- if (typeof instanceName === "string" && (instanceName.startsWith("Proxy<") || instanceName === "ProxyComponent")) {
- return true;
- }
- const prototypeName = comp?.prototype?.constructor?.name;
- return typeof prototypeName === "string" && (prototypeName.startsWith("Proxy<") || prototypeName === "ProxyComponent");
- }
- function isSvelteComponent(comp) {
- if (comp === null || comp === void 0 || typeof comp !== "function") {
- return false;
- }
- const prototypeName = comp?.prototype?.constructor?.name;
- if (typeof prototypeName === "string" && (prototypeName.startsWith("Proxy<") || prototypeName === "ProxyComponent")) {
- return true;
- }
- return typeof window !== void 0 ? typeof comp.prototype.$destroy === "function" && typeof comp.prototype.$on === "function" : (
- // client-side
- typeof comp.render === "function"
- );
- }
- async function outroAndDestroy(instance2) {
- return new Promise((resolve) => {
- if (instance2.$$.fragment && instance2.$$.fragment.o) {
- group_outros();
- transition_out(instance2.$$.fragment, 0, 0, () => {
- instance2.$destroy();
- resolve();
- });
- check_outros();
- } else {
- instance2.$destroy();
- resolve();
- }
- });
- }
- function parseSvelteConfig(config, thisArg = void 0) {
- if (typeof config !== "object") {
- throw new TypeError(`parseSvelteConfig - 'config' is not an object:
- ${JSON.stringify(config)}.`);
- }
- if (!isSvelteComponent(config.class)) {
- throw new TypeError(
- `parseSvelteConfig - 'class' is not a Svelte component constructor for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.hydrate !== void 0 && typeof config.hydrate !== "boolean") {
- throw new TypeError(
- `parseSvelteConfig - 'hydrate' is not a boolean for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.intro !== void 0 && typeof config.intro !== "boolean") {
- throw new TypeError(
- `parseSvelteConfig - 'intro' is not a boolean for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.target !== void 0 && typeof config.target !== "string" && !(config.target instanceof HTMLElement) && !(config.target instanceof ShadowRoot) && !(config.target instanceof DocumentFragment)) {
- throw new TypeError(
- `parseSvelteConfig - 'target' is not a string, HTMLElement, ShadowRoot, or DocumentFragment for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.anchor !== void 0 && typeof config.anchor !== "string" && !(config.anchor instanceof HTMLElement) && !(config.anchor instanceof ShadowRoot) && !(config.anchor instanceof DocumentFragment)) {
- throw new TypeError(
- `parseSvelteConfig - 'anchor' is not a string, HTMLElement, ShadowRoot, or DocumentFragment for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.context !== void 0 && typeof config.context !== "function" && !(config.context instanceof Map) && typeof config.context !== "object") {
- throw new TypeError(
- `parseSvelteConfig - 'context' is not a Map, function or object for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.selectorTarget !== void 0 && typeof config.selectorTarget !== "string") {
- throw new TypeError(
- `parseSvelteConfig - 'selectorTarget' is not a string for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.options !== void 0 && typeof config.options !== "object") {
- throw new TypeError(
- `parseSvelteConfig - 'options' is not an object for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.options !== void 0) {
- if (config.options.injectApp !== void 0 && typeof config.options.injectApp !== "boolean") {
- throw new TypeError(
- `parseSvelteConfig - 'options.injectApp' is not a boolean for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.options.injectEventbus !== void 0 && typeof config.options.injectEventbus !== "boolean") {
- throw new TypeError(
- `parseSvelteConfig - 'options.injectEventbus' is not a boolean for config:
- ${JSON.stringify(config)}.`
- );
- }
- if (config.options.selectorElement !== void 0 && typeof config.options.selectorElement !== "string") {
- throw new TypeError(
- `parseSvelteConfig - 'selectorElement' is not a string for config:
- ${JSON.stringify(config)}.`
- );
- }
- }
- const svelteConfig = { ...config };
- delete svelteConfig.options;
- let externalContext = {};
- if (typeof svelteConfig.context === "function") {
- const contextFunc = svelteConfig.context;
- delete svelteConfig.context;
- const result = contextFunc.call(thisArg);
- if (isObject(result)) {
- externalContext = { ...result };
- } else {
- throw new Error(`parseSvelteConfig - 'context' is a function that did not return an object for config:
- ${JSON.stringify(config)}`);
- }
- } else if (svelteConfig.context instanceof Map) {
- externalContext = Object.fromEntries(svelteConfig.context);
- delete svelteConfig.context;
- } else if (isObject(svelteConfig.context)) {
- externalContext = svelteConfig.context;
- delete svelteConfig.context;
- }
- svelteConfig.props = s_PROCESS_PROPS(svelteConfig.props, thisArg, config);
- if (Array.isArray(svelteConfig.children)) {
- const children2 = [];
- for (let cntr = 0; cntr < svelteConfig.children.length; cntr++) {
- const child = svelteConfig.children[cntr];
- if (!isSvelteComponent(child.class)) {
- throw new Error(`parseSvelteConfig - 'class' is not a Svelte component for child[${cntr}] for config:
- ${JSON.stringify(config)}`);
- }
- child.props = s_PROCESS_PROPS(child.props, thisArg, config);
- children2.push(child);
- }
- if (children2.length > 0) {
- externalContext.children = children2;
- }
- delete svelteConfig.children;
- } else if (isObject(svelteConfig.children)) {
- if (!isSvelteComponent(svelteConfig.children.class)) {
- throw new Error(`parseSvelteConfig - 'class' is not a Svelte component for children object for config:
- ${JSON.stringify(config)}`);
- }
- svelteConfig.children.props = s_PROCESS_PROPS(svelteConfig.children.props, thisArg, config);
- externalContext.children = [svelteConfig.children];
- delete svelteConfig.children;
- }
- if (!(svelteConfig.context instanceof Map)) {
- svelteConfig.context = /* @__PURE__ */ new Map();
- }
- svelteConfig.context.set("#external", externalContext);
- return svelteConfig;
- }
- function s_PROCESS_PROPS(props, thisArg, config) {
- if (typeof props === "function") {
- const result = props.call(thisArg);
- if (isObject(result)) {
- return result;
- } else {
- throw new Error(`parseSvelteConfig - 'props' is a function that did not return an object for config:
- ${JSON.stringify(config)}`);
- }
- } else if (isObject(props)) {
- return props;
- } else if (props !== void 0) {
- throw new Error(
- `parseSvelteConfig - 'props' is not a function or an object for config:
- ${JSON.stringify(config)}`
- );
- }
- return {};
- }
- function hasGetter(object, accessor) {
- if (object === null || object === void 0) {
- return false;
- }
- const iDescriptor = Object.getOwnPropertyDescriptor(object, accessor);
- if (iDescriptor !== void 0 && iDescriptor.get !== void 0) {
- return true;
- }
- for (let o = Object.getPrototypeOf(object); o; o = Object.getPrototypeOf(o)) {
- const descriptor = Object.getOwnPropertyDescriptor(o, accessor);
- if (descriptor !== void 0 && descriptor.get !== void 0) {
- return true;
- }
- }
- return false;
- }
- const subscriber_queue = [];
- function readable(value, start) {
- return {
- subscribe: writable$1(value, start).subscribe
- };
- }
- function writable$1(value, start = noop) {
- let stop;
- const subscribers = /* @__PURE__ */ new Set();
- function set(new_value) {
- if (safe_not_equal(value, new_value)) {
- value = new_value;
- if (stop) {
- const run_queue = !subscriber_queue.length;
- for (const subscriber of subscribers) {
- subscriber[1]();
- subscriber_queue.push(subscriber, value);
- }
- if (run_queue) {
- for (let i = 0; i < subscriber_queue.length; i += 2) {
- subscriber_queue[i][0](subscriber_queue[i + 1]);
- }
- subscriber_queue.length = 0;
- }
- }
- }
- }
- function update2(fn) {
- set(fn(value));
- }
- function subscribe2(run2, invalidate = noop) {
- const subscriber = [run2, invalidate];
- subscribers.add(subscriber);
- if (subscribers.size === 1) {
- stop = start(set) || noop;
- }
- run2(value);
- return () => {
- subscribers.delete(subscriber);
- if (subscribers.size === 0) {
- stop();
- stop = null;
- }
- };
- }
- return { set, update: update2, subscribe: subscribe2 };
- }
- function derived(stores, fn, initial_value) {
- const single = !Array.isArray(stores);
- const stores_array = single ? [stores] : stores;
- const auto = fn.length < 2;
- return readable(initial_value, (set) => {
- let inited = false;
- const values = [];
- let pending = 0;
- let cleanup = noop;
- const sync = () => {
- if (pending) {
- return;
- }
- cleanup();
- const result = fn(single ? values[0] : values, set);
- if (auto) {
- set(result);
- } else {
- cleanup = is_function(result) ? result : noop;
- }
- };
- const unsubscribers = stores_array.map((store, i) => subscribe(store, (value) => {
- values[i] = value;
- pending &= ~(1 << i);
- if (inited) {
- sync();
- }
- }, () => {
- pending |= 1 << i;
- }));
- inited = true;
- sync();
- return function stop() {
- run_all(unsubscribers);
- cleanup();
- };
- });
- }
- function isSimpleDeriver(deriver) {
- return deriver.length < 2;
- }
- function generator(storage2) {
- function readable2(key, value, start) {
- return {
- subscribe: writable2(key, value, start).subscribe
- };
- }
- function writable2(key, value, start = noop) {
- function wrap_start(ogSet) {
- return start(function wrap_set(new_value) {
- if (storage2) {
- storage2.setItem(key, JSON.stringify(new_value));
- }
- return ogSet(new_value);
- });
- }
- if (storage2) {
- const storageValue = storage2.getItem(key);
- try {
- if (storageValue) {
- value = JSON.parse(storageValue);
- }
- } catch (err) {
- }
- storage2.setItem(key, JSON.stringify(value));
- }
- const ogStore = writable$1(value, start ? wrap_start : void 0);
- function set(new_value) {
- if (storage2) {
- storage2.setItem(key, JSON.stringify(new_value));
- }
- ogStore.set(new_value);
- }
- function update2(fn) {
- set(fn(get_store_value(ogStore)));
- }
- function subscribe2(run2, invalidate = noop) {
- return ogStore.subscribe(run2, invalidate);
- }
- return { set, update: update2, subscribe: subscribe2 };
- }
- function derived2(key, stores, fn, initial_value) {
- const single = !Array.isArray(stores);
- const stores_array = single ? [stores] : stores;
- if (storage2 && storage2.getItem(key)) {
- try {
- initial_value = JSON.parse(storage2.getItem(key));
- } catch (err) {
- }
- }
- return readable2(key, initial_value, (set) => {
- let inited = false;
- const values = [];
- let pending = 0;
- let cleanup = noop;
- const sync = () => {
- if (pending) {
- return;
- }
- cleanup();
- const input = single ? values[0] : values;
- if (isSimpleDeriver(fn)) {
- set(fn(input));
- } else {
- const result = fn(input, set);
- cleanup = is_function(result) ? result : noop;
- }
- };
- const unsubscribers = stores_array.map((store, i) => store.subscribe((value) => {
- values[i] = value;
- pending &= ~(1 << i);
- if (inited) {
- sync();
- }
- }, () => {
- pending |= 1 << i;
- }));
- inited = true;
- sync();
- return function stop() {
- run_all(unsubscribers);
- cleanup();
- };
- });
- }
- return {
- readable: readable2,
- writable: writable2,
- derived: derived2,
- get: get_store_value
- };
- }
- var storage = typeof window !== "undefined" ? window.sessionStorage : void 0;
- var g = generator(storage);
- var writable = g.writable;
- class TJSSessionStorage {
- /**
- * @type {Map<string, import('svelte/store').Writable>}
- */
- #stores = /* @__PURE__ */ new Map();
- /**
- * Creates a new store for the given key.
- *
- * @param {string} key - Key to lookup in stores map.
- *
- * @param {boolean} [defaultValue] - A default value to set for the store.
- *
- * @returns {import('svelte/store').Writable} The new store.
- */
- static #createStore(key, defaultValue = void 0) {
- try {
- const value = sessionStorage.getItem(key);
- if (value !== null) {
- defaultValue = value === "undefined" ? void 0 : JSON.parse(value);
- }
- } catch (err) {
- }
- return writable(key, defaultValue);
- }
- /**
- * Gets a store from the `stores` Map or creates a new store for the key and a given default value.
- *
- * @param {string} key - Key to lookup in stores map.
- *
- * @param {boolean} [defaultValue] - A default value to set for the store.
- *
- * @returns {import('svelte/store').Writable} The store for the given key.
- */
- #getStore(key, defaultValue = void 0) {
- let store = this.#stores.get(key);
- if (store === void 0) {
- store = TJSSessionStorage.#createStore(key, defaultValue);
- this.#stores.set(key, store);
- }
- return store;
- }
- /**
- * Get value from the sessionStorage.
- *
- * @param {string} key - Key to lookup in sessionStorage.
- *
- * @param {*} [defaultValue] - A default value to return if key not present in session storage.
- *
- * @returns {*} Value from session storage or if not defined any default value provided.
- */
- getItem(key, defaultValue) {
- let value = defaultValue;
- const storageValue = sessionStorage.getItem(key);
- if (storageValue !== null) {
- try {
- value = storageValue === "undefined" ? void 0 : JSON.parse(storageValue);
- } catch (err) {
- value = defaultValue;
- }
- } else if (defaultValue !== void 0) {
- try {
- const newValue = JSON.stringify(defaultValue);
- sessionStorage.setItem(key, newValue === "undefined" ? void 0 : newValue);
- } catch (err) {
- }
- }
- return value;
- }
- /**
- * Returns the backing Svelte store for the given key; potentially sets a default value if the key
- * is not already set.
- *
- * @param {string} key - Key to lookup in sessionStorage.
- *
- * @param {*} [defaultValue] - A default value to return if key not present in session storage.
- *
- * @returns {import('svelte/store').Writable} The Svelte store for this key.
- */
- getStore(key, defaultValue) {
- return this.#getStore(key, defaultValue);
- }
- /**
- * Sets the value for the given key in sessionStorage.
- *
- * @param {string} key - Key to lookup in sessionStorage.
- *
- * @param {*} value - A value to set for this key.
- */
- setItem(key, value) {
- const store = this.#getStore(key);
- store.set(value);
- }
- /**
- * Convenience method to swap a boolean value stored in session storage.
- *
- * @param {string} key - Key to lookup in sessionStorage.
- *
- * @param {boolean} [defaultValue] - A default value to return if key not present in session storage.
- *
- * @returns {boolean} The boolean swap for the given key.
- */
- swapItemBoolean(key, defaultValue) {
- const store = this.#getStore(key, defaultValue);
- let currentValue = false;
- try {
- currentValue = !!JSON.parse(sessionStorage.getItem(key));
- } catch (err) {
- }
- const newValue = typeof currentValue === "boolean" ? !currentValue : false;
- store.set(newValue);
- return newValue;
- }
- }
- function isUpdatableStore(store) {
- if (store === null || store === void 0) {
- return false;
- }
- switch (typeof store) {
- case "function":
- case "object":
- return typeof store.subscribe === "function" && typeof store.update === "function";
- }
- return false;
- }
- function subscribeIgnoreFirst(store, update2) {
- let firedFirst = false;
- return store.subscribe((value) => {
- if (!firedFirst) {
- firedFirst = true;
- } else {
- update2(value);
- }
- });
- }
- function writableDerived(origins, derive, reflect, initial) {
- var childDerivedSetter, originValues, blockNextDerive = false;
- var reflectOldValues = reflect.length >= 2;
- var wrappedDerive = (got, set) => {
- childDerivedSetter = set;
- if (reflectOldValues) {
- originValues = got;
- }
- if (!blockNextDerive) {
- let returned = derive(got, set);
- if (derive.length < 2) {
- set(returned);
- } else {
- return returned;
- }
- }
- blockNextDerive = false;
- };
- var childDerived = derived(origins, wrappedDerive, initial);
- var singleOrigin = !Array.isArray(origins);
- function doReflect(reflecting) {
- var setWith = reflect(reflecting, originValues);
- if (singleOrigin) {
- blockNextDerive = true;
- origins.set(setWith);
- } else {
- setWith.forEach((value, i) => {
- blockNextDerive = true;
- origins[i].set(value);
- });
- }
- blockNextDerive = false;
- }
- var tryingSet = false;
- function update2(fn) {
- var isUpdated, mutatedBySubscriptions, oldValue, newValue;
- if (tryingSet) {
- newValue = fn(get_store_value(childDerived));
- childDerivedSetter(newValue);
- return;
- }
- var unsubscribe = childDerived.subscribe((value) => {
- if (!tryingSet) {
- oldValue = value;
- } else if (!isUpdated) {
- isUpdated = true;
- } else {
- mutatedBySubscriptions = true;
- }
- });
- newValue = fn(oldValue);
- tryingSet = true;
- childDerivedSetter(newValue);
- unsubscribe();
- tryingSet = false;
- if (mutatedBySubscriptions) {
- newValue = get_store_value(childDerived);
- }
- if (isUpdated) {
- doReflect(newValue);
- }
- }
- return {
- subscribe: childDerived.subscribe,
- set(value) {
- update2(() => value);
- },
- update: update2
- };
- }
- function propertyStore(origin, propName) {
- if (!Array.isArray(propName)) {
- return writableDerived(
- origin,
- (object) => object[propName],
- (reflecting, object) => {
- object[propName] = reflecting;
- return object;
- }
- );
- } else {
- let props = propName.concat();
- return writableDerived(
- origin,
- (value) => {
- for (let i = 0; i < props.length; ++i) {
- value = value[props[i]];
- }
- return value;
- },
- (reflecting, object) => {
- let target = object;
- for (let i = 0; i < props.length - 1; ++i) {
- target = target[props[i]];
- }
- target[props[props.length - 1]] = reflecting;
- return object;
- }
- );
- }
- }
- const storeState = writable$1(void 0);
- ({
- subscribe: storeState.subscribe,
- get: () => game
- });
- Hooks.once("ready", () => storeState.set(game));
- function cubicOut(t) {
- const f = t - 1;
- return f * f * f + 1;
- }
- function lerp$5(start, end, amount) {
- return (1 - amount) * start + amount * end;
- }
- function degToRad(deg) {
- return deg * (Math.PI / 180);
- }
- var EPSILON = 1e-6;
- var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
- var RANDOM = Math.random;
- if (!Math.hypot)
- Math.hypot = function() {
- var y = 0, i = arguments.length;
- while (i--) {
- y += arguments[i] * arguments[i];
- }
- return Math.sqrt(y);
- };
- function create$6() {
- var out = new ARRAY_TYPE(9);
- if (ARRAY_TYPE != Float32Array) {
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[5] = 0;
- out[6] = 0;
- out[7] = 0;
- }
- out[0] = 1;
- out[4] = 1;
- out[8] = 1;
- return out;
- }
- function create$5() {
- var out = new ARRAY_TYPE(16);
- if (ARRAY_TYPE != Float32Array) {
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- }
- out[0] = 1;
- out[5] = 1;
- out[10] = 1;
- out[15] = 1;
- return out;
- }
- function clone$5(a) {
- var out = new ARRAY_TYPE(16);
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- out[3] = a[3];
- out[4] = a[4];
- out[5] = a[5];
- out[6] = a[6];
- out[7] = a[7];
- out[8] = a[8];
- out[9] = a[9];
- out[10] = a[10];
- out[11] = a[11];
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- return out;
- }
- function copy$5(out, a) {
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- out[3] = a[3];
- out[4] = a[4];
- out[5] = a[5];
- out[6] = a[6];
- out[7] = a[7];
- out[8] = a[8];
- out[9] = a[9];
- out[10] = a[10];
- out[11] = a[11];
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- return out;
- }
- function fromValues$5(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- var out = new ARRAY_TYPE(16);
- out[0] = m00;
- out[1] = m01;
- out[2] = m02;
- out[3] = m03;
- out[4] = m10;
- out[5] = m11;
- out[6] = m12;
- out[7] = m13;
- out[8] = m20;
- out[9] = m21;
- out[10] = m22;
- out[11] = m23;
- out[12] = m30;
- out[13] = m31;
- out[14] = m32;
- out[15] = m33;
- return out;
- }
- function set$5(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
- out[0] = m00;
- out[1] = m01;
- out[2] = m02;
- out[3] = m03;
- out[4] = m10;
- out[5] = m11;
- out[6] = m12;
- out[7] = m13;
- out[8] = m20;
- out[9] = m21;
- out[10] = m22;
- out[11] = m23;
- out[12] = m30;
- out[13] = m31;
- out[14] = m32;
- out[15] = m33;
- return out;
- }
- function identity$2(out) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = 1;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function transpose(out, a) {
- if (out === a) {
- var a01 = a[1], a02 = a[2], a03 = a[3];
- var a12 = a[6], a13 = a[7];
- var a23 = a[11];
- out[1] = a[4];
- out[2] = a[8];
- out[3] = a[12];
- out[4] = a01;
- out[6] = a[9];
- out[7] = a[13];
- out[8] = a02;
- out[9] = a12;
- out[11] = a[14];
- out[12] = a03;
- out[13] = a13;
- out[14] = a23;
- } else {
- out[0] = a[0];
- out[1] = a[4];
- out[2] = a[8];
- out[3] = a[12];
- out[4] = a[1];
- out[5] = a[5];
- out[6] = a[9];
- out[7] = a[13];
- out[8] = a[2];
- out[9] = a[6];
- out[10] = a[10];
- out[11] = a[14];
- out[12] = a[3];
- out[13] = a[7];
- out[14] = a[11];
- out[15] = a[15];
- }
- return out;
- }
- function invert$2(out, a) {
- var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
- var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
- var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
- var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
- if (!det) {
- return null;
- }
- det = 1 / det;
- out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
- out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
- out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
- out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
- out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
- out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
- out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
- out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
- out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
- out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
- out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
- out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
- out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
- out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
- out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
- out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
- return out;
- }
- function adjoint(out, a) {
- var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
- var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
- var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
- var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
- out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
- out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
- out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
- out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
- out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
- out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
- out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
- out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
- out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
- out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
- out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
- out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
- out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
- out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
- out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
- out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
- return out;
- }
- function determinant(a) {
- var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
- var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
- var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
- var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
- return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
- }
- function multiply$5(out, a, b) {
- var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
- var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
- var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
- var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
- var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
- out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- b0 = b[4];
- b1 = b[5];
- b2 = b[6];
- b3 = b[7];
- out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- b0 = b[8];
- b1 = b[9];
- b2 = b[10];
- b3 = b[11];
- out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- b0 = b[12];
- b1 = b[13];
- b2 = b[14];
- b3 = b[15];
- out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
- out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
- out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
- out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
- return out;
- }
- function translate$1(out, a, v) {
- var x = v[0], y = v[1], z = v[2];
- var a00, a01, a02, a03;
- var a10, a11, a12, a13;
- var a20, a21, a22, a23;
- if (a === out) {
- out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
- out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
- out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
- out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
- } else {
- a00 = a[0];
- a01 = a[1];
- a02 = a[2];
- a03 = a[3];
- a10 = a[4];
- a11 = a[5];
- a12 = a[6];
- a13 = a[7];
- a20 = a[8];
- a21 = a[9];
- a22 = a[10];
- a23 = a[11];
- out[0] = a00;
- out[1] = a01;
- out[2] = a02;
- out[3] = a03;
- out[4] = a10;
- out[5] = a11;
- out[6] = a12;
- out[7] = a13;
- out[8] = a20;
- out[9] = a21;
- out[10] = a22;
- out[11] = a23;
- out[12] = a00 * x + a10 * y + a20 * z + a[12];
- out[13] = a01 * x + a11 * y + a21 * z + a[13];
- out[14] = a02 * x + a12 * y + a22 * z + a[14];
- out[15] = a03 * x + a13 * y + a23 * z + a[15];
- }
- return out;
- }
- function scale$5(out, a, v) {
- var x = v[0], y = v[1], z = v[2];
- out[0] = a[0] * x;
- out[1] = a[1] * x;
- out[2] = a[2] * x;
- out[3] = a[3] * x;
- out[4] = a[4] * y;
- out[5] = a[5] * y;
- out[6] = a[6] * y;
- out[7] = a[7] * y;
- out[8] = a[8] * z;
- out[9] = a[9] * z;
- out[10] = a[10] * z;
- out[11] = a[11] * z;
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- return out;
- }
- function rotate$1(out, a, rad, axis) {
- var x = axis[0], y = axis[1], z = axis[2];
- var len = Math.hypot(x, y, z);
- var s, c, t;
- var a00, a01, a02, a03;
- var a10, a11, a12, a13;
- var a20, a21, a22, a23;
- var b00, b01, b02;
- var b10, b11, b12;
- var b20, b21, b22;
- if (len < EPSILON) {
- return null;
- }
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
- a00 = a[0];
- a01 = a[1];
- a02 = a[2];
- a03 = a[3];
- a10 = a[4];
- a11 = a[5];
- a12 = a[6];
- a13 = a[7];
- a20 = a[8];
- a21 = a[9];
- a22 = a[10];
- a23 = a[11];
- b00 = x * x * t + c;
- b01 = y * x * t + z * s;
- b02 = z * x * t - y * s;
- b10 = x * y * t - z * s;
- b11 = y * y * t + c;
- b12 = z * y * t + x * s;
- b20 = x * z * t + y * s;
- b21 = y * z * t - x * s;
- b22 = z * z * t + c;
- out[0] = a00 * b00 + a10 * b01 + a20 * b02;
- out[1] = a01 * b00 + a11 * b01 + a21 * b02;
- out[2] = a02 * b00 + a12 * b01 + a22 * b02;
- out[3] = a03 * b00 + a13 * b01 + a23 * b02;
- out[4] = a00 * b10 + a10 * b11 + a20 * b12;
- out[5] = a01 * b10 + a11 * b11 + a21 * b12;
- out[6] = a02 * b10 + a12 * b11 + a22 * b12;
- out[7] = a03 * b10 + a13 * b11 + a23 * b12;
- out[8] = a00 * b20 + a10 * b21 + a20 * b22;
- out[9] = a01 * b20 + a11 * b21 + a21 * b22;
- out[10] = a02 * b20 + a12 * b21 + a22 * b22;
- out[11] = a03 * b20 + a13 * b21 + a23 * b22;
- if (a !== out) {
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- }
- return out;
- }
- function rotateX$3(out, a, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- var a10 = a[4];
- var a11 = a[5];
- var a12 = a[6];
- var a13 = a[7];
- var a20 = a[8];
- var a21 = a[9];
- var a22 = a[10];
- var a23 = a[11];
- if (a !== out) {
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- out[3] = a[3];
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- }
- out[4] = a10 * c + a20 * s;
- out[5] = a11 * c + a21 * s;
- out[6] = a12 * c + a22 * s;
- out[7] = a13 * c + a23 * s;
- out[8] = a20 * c - a10 * s;
- out[9] = a21 * c - a11 * s;
- out[10] = a22 * c - a12 * s;
- out[11] = a23 * c - a13 * s;
- return out;
- }
- function rotateY$3(out, a, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- var a00 = a[0];
- var a01 = a[1];
- var a02 = a[2];
- var a03 = a[3];
- var a20 = a[8];
- var a21 = a[9];
- var a22 = a[10];
- var a23 = a[11];
- if (a !== out) {
- out[4] = a[4];
- out[5] = a[5];
- out[6] = a[6];
- out[7] = a[7];
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- }
- out[0] = a00 * c - a20 * s;
- out[1] = a01 * c - a21 * s;
- out[2] = a02 * c - a22 * s;
- out[3] = a03 * c - a23 * s;
- out[8] = a00 * s + a20 * c;
- out[9] = a01 * s + a21 * c;
- out[10] = a02 * s + a22 * c;
- out[11] = a03 * s + a23 * c;
- return out;
- }
- function rotateZ$3(out, a, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- var a00 = a[0];
- var a01 = a[1];
- var a02 = a[2];
- var a03 = a[3];
- var a10 = a[4];
- var a11 = a[5];
- var a12 = a[6];
- var a13 = a[7];
- if (a !== out) {
- out[8] = a[8];
- out[9] = a[9];
- out[10] = a[10];
- out[11] = a[11];
- out[12] = a[12];
- out[13] = a[13];
- out[14] = a[14];
- out[15] = a[15];
- }
- out[0] = a00 * c + a10 * s;
- out[1] = a01 * c + a11 * s;
- out[2] = a02 * c + a12 * s;
- out[3] = a03 * c + a13 * s;
- out[4] = a10 * c - a00 * s;
- out[5] = a11 * c - a01 * s;
- out[6] = a12 * c - a02 * s;
- out[7] = a13 * c - a03 * s;
- return out;
- }
- function fromTranslation$1(out, v) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = 1;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = v[0];
- out[13] = v[1];
- out[14] = v[2];
- out[15] = 1;
- return out;
- }
- function fromScaling(out, v) {
- out[0] = v[0];
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = v[1];
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = v[2];
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function fromRotation$1(out, rad, axis) {
- var x = axis[0], y = axis[1], z = axis[2];
- var len = Math.hypot(x, y, z);
- var s, c, t;
- if (len < EPSILON) {
- return null;
- }
- len = 1 / len;
- x *= len;
- y *= len;
- z *= len;
- s = Math.sin(rad);
- c = Math.cos(rad);
- t = 1 - c;
- out[0] = x * x * t + c;
- out[1] = y * x * t + z * s;
- out[2] = z * x * t - y * s;
- out[3] = 0;
- out[4] = x * y * t - z * s;
- out[5] = y * y * t + c;
- out[6] = z * y * t + x * s;
- out[7] = 0;
- out[8] = x * z * t + y * s;
- out[9] = y * z * t - x * s;
- out[10] = z * z * t + c;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function fromXRotation(out, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = c;
- out[6] = s;
- out[7] = 0;
- out[8] = 0;
- out[9] = -s;
- out[10] = c;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function fromYRotation(out, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- out[0] = c;
- out[1] = 0;
- out[2] = -s;
- out[3] = 0;
- out[4] = 0;
- out[5] = 1;
- out[6] = 0;
- out[7] = 0;
- out[8] = s;
- out[9] = 0;
- out[10] = c;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function fromZRotation(out, rad) {
- var s = Math.sin(rad);
- var c = Math.cos(rad);
- out[0] = c;
- out[1] = s;
- out[2] = 0;
- out[3] = 0;
- out[4] = -s;
- out[5] = c;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 1;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function fromRotationTranslation$1(out, q, v) {
- var x = q[0], y = q[1], z = q[2], w = q[3];
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- out[0] = 1 - (yy + zz);
- out[1] = xy + wz;
- out[2] = xz - wy;
- out[3] = 0;
- out[4] = xy - wz;
- out[5] = 1 - (xx + zz);
- out[6] = yz + wx;
- out[7] = 0;
- out[8] = xz + wy;
- out[9] = yz - wx;
- out[10] = 1 - (xx + yy);
- out[11] = 0;
- out[12] = v[0];
- out[13] = v[1];
- out[14] = v[2];
- out[15] = 1;
- return out;
- }
- function fromQuat2(out, a) {
- var translation = new ARRAY_TYPE(3);
- var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7];
- var magnitude = bx * bx + by * by + bz * bz + bw * bw;
- if (magnitude > 0) {
- translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
- translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
- translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
- } else {
- translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
- translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
- translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
- }
- fromRotationTranslation$1(out, a, translation);
- return out;
- }
- function getTranslation$1(out, mat) {
- out[0] = mat[12];
- out[1] = mat[13];
- out[2] = mat[14];
- return out;
- }
- function getScaling(out, mat) {
- var m11 = mat[0];
- var m12 = mat[1];
- var m13 = mat[2];
- var m21 = mat[4];
- var m22 = mat[5];
- var m23 = mat[6];
- var m31 = mat[8];
- var m32 = mat[9];
- var m33 = mat[10];
- out[0] = Math.hypot(m11, m12, m13);
- out[1] = Math.hypot(m21, m22, m23);
- out[2] = Math.hypot(m31, m32, m33);
- return out;
- }
- function getRotation(out, mat) {
- var scaling = new ARRAY_TYPE(3);
- getScaling(scaling, mat);
- var is1 = 1 / scaling[0];
- var is2 = 1 / scaling[1];
- var is3 = 1 / scaling[2];
- var sm11 = mat[0] * is1;
- var sm12 = mat[1] * is2;
- var sm13 = mat[2] * is3;
- var sm21 = mat[4] * is1;
- var sm22 = mat[5] * is2;
- var sm23 = mat[6] * is3;
- var sm31 = mat[8] * is1;
- var sm32 = mat[9] * is2;
- var sm33 = mat[10] * is3;
- var trace = sm11 + sm22 + sm33;
- var S = 0;
- if (trace > 0) {
- S = Math.sqrt(trace + 1) * 2;
- out[3] = 0.25 * S;
- out[0] = (sm23 - sm32) / S;
- out[1] = (sm31 - sm13) / S;
- out[2] = (sm12 - sm21) / S;
- } else if (sm11 > sm22 && sm11 > sm33) {
- S = Math.sqrt(1 + sm11 - sm22 - sm33) * 2;
- out[3] = (sm23 - sm32) / S;
- out[0] = 0.25 * S;
- out[1] = (sm12 + sm21) / S;
- out[2] = (sm31 + sm13) / S;
- } else if (sm22 > sm33) {
- S = Math.sqrt(1 + sm22 - sm11 - sm33) * 2;
- out[3] = (sm31 - sm13) / S;
- out[0] = (sm12 + sm21) / S;
- out[1] = 0.25 * S;
- out[2] = (sm23 + sm32) / S;
- } else {
- S = Math.sqrt(1 + sm33 - sm11 - sm22) * 2;
- out[3] = (sm12 - sm21) / S;
- out[0] = (sm31 + sm13) / S;
- out[1] = (sm23 + sm32) / S;
- out[2] = 0.25 * S;
- }
- return out;
- }
- function fromRotationTranslationScale(out, q, v, s) {
- var x = q[0], y = q[1], z = q[2], w = q[3];
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- var sx = s[0];
- var sy = s[1];
- var sz = s[2];
- out[0] = (1 - (yy + zz)) * sx;
- out[1] = (xy + wz) * sx;
- out[2] = (xz - wy) * sx;
- out[3] = 0;
- out[4] = (xy - wz) * sy;
- out[5] = (1 - (xx + zz)) * sy;
- out[6] = (yz + wx) * sy;
- out[7] = 0;
- out[8] = (xz + wy) * sz;
- out[9] = (yz - wx) * sz;
- out[10] = (1 - (xx + yy)) * sz;
- out[11] = 0;
- out[12] = v[0];
- out[13] = v[1];
- out[14] = v[2];
- out[15] = 1;
- return out;
- }
- function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
- var x = q[0], y = q[1], z = q[2], w = q[3];
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- var sx = s[0];
- var sy = s[1];
- var sz = s[2];
- var ox = o[0];
- var oy = o[1];
- var oz = o[2];
- var out0 = (1 - (yy + zz)) * sx;
- var out1 = (xy + wz) * sx;
- var out2 = (xz - wy) * sx;
- var out4 = (xy - wz) * sy;
- var out5 = (1 - (xx + zz)) * sy;
- var out6 = (yz + wx) * sy;
- var out8 = (xz + wy) * sz;
- var out9 = (yz - wx) * sz;
- var out10 = (1 - (xx + yy)) * sz;
- out[0] = out0;
- out[1] = out1;
- out[2] = out2;
- out[3] = 0;
- out[4] = out4;
- out[5] = out5;
- out[6] = out6;
- out[7] = 0;
- out[8] = out8;
- out[9] = out9;
- out[10] = out10;
- out[11] = 0;
- out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
- out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
- out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
- out[15] = 1;
- return out;
- }
- function fromQuat(out, q) {
- var x = q[0], y = q[1], z = q[2], w = q[3];
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
- var xx = x * x2;
- var yx = y * x2;
- var yy = y * y2;
- var zx = z * x2;
- var zy = z * y2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
- out[0] = 1 - yy - zz;
- out[1] = yx + wz;
- out[2] = zx - wy;
- out[3] = 0;
- out[4] = yx - wz;
- out[5] = 1 - xx - zz;
- out[6] = zy + wx;
- out[7] = 0;
- out[8] = zx + wy;
- out[9] = zy - wx;
- out[10] = 1 - xx - yy;
- out[11] = 0;
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- out[15] = 1;
- return out;
- }
- function frustum(out, left, right, bottom, top, near, far) {
- var rl = 1 / (right - left);
- var tb = 1 / (top - bottom);
- var nf = 1 / (near - far);
- out[0] = near * 2 * rl;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = near * 2 * tb;
- out[6] = 0;
- out[7] = 0;
- out[8] = (right + left) * rl;
- out[9] = (top + bottom) * tb;
- out[10] = (far + near) * nf;
- out[11] = -1;
- out[12] = 0;
- out[13] = 0;
- out[14] = far * near * 2 * nf;
- out[15] = 0;
- return out;
- }
- function perspectiveNO(out, fovy, aspect, near, far) {
- var f = 1 / Math.tan(fovy / 2), nf;
- out[0] = f / aspect;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = f;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[11] = -1;
- out[12] = 0;
- out[13] = 0;
- out[15] = 0;
- if (far != null && far !== Infinity) {
- nf = 1 / (near - far);
- out[10] = (far + near) * nf;
- out[14] = 2 * far * near * nf;
- } else {
- out[10] = -1;
- out[14] = -2 * near;
- }
- return out;
- }
- var perspective = perspectiveNO;
- function perspectiveZO(out, fovy, aspect, near, far) {
- var f = 1 / Math.tan(fovy / 2), nf;
- out[0] = f / aspect;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = f;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[11] = -1;
- out[12] = 0;
- out[13] = 0;
- out[15] = 0;
- if (far != null && far !== Infinity) {
- nf = 1 / (near - far);
- out[10] = far * nf;
- out[14] = far * near * nf;
- } else {
- out[10] = -1;
- out[14] = -near;
- }
- return out;
- }
- function perspectiveFromFieldOfView(out, fov, near, far) {
- var upTan = Math.tan(fov.upDegrees * Math.PI / 180);
- var downTan = Math.tan(fov.downDegrees * Math.PI / 180);
- var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180);
- var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180);
- var xScale = 2 / (leftTan + rightTan);
- var yScale = 2 / (upTan + downTan);
- out[0] = xScale;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = yScale;
- out[6] = 0;
- out[7] = 0;
- out[8] = -((leftTan - rightTan) * xScale * 0.5);
- out[9] = (upTan - downTan) * yScale * 0.5;
- out[10] = far / (near - far);
- out[11] = -1;
- out[12] = 0;
- out[13] = 0;
- out[14] = far * near / (near - far);
- out[15] = 0;
- return out;
- }
- function orthoNO(out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right);
- var bt = 1 / (bottom - top);
- var nf = 1 / (near - far);
- out[0] = -2 * lr;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = -2 * bt;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = 2 * nf;
- out[11] = 0;
- out[12] = (left + right) * lr;
- out[13] = (top + bottom) * bt;
- out[14] = (far + near) * nf;
- out[15] = 1;
- return out;
- }
- var ortho = orthoNO;
- function orthoZO(out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right);
- var bt = 1 / (bottom - top);
- var nf = 1 / (near - far);
- out[0] = -2 * lr;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 0;
- out[5] = -2 * bt;
- out[6] = 0;
- out[7] = 0;
- out[8] = 0;
- out[9] = 0;
- out[10] = nf;
- out[11] = 0;
- out[12] = (left + right) * lr;
- out[13] = (top + bottom) * bt;
- out[14] = near * nf;
- out[15] = 1;
- return out;
- }
- function lookAt(out, eye, center, up) {
- var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
- var eyex = eye[0];
- var eyey = eye[1];
- var eyez = eye[2];
- var upx = up[0];
- var upy = up[1];
- var upz = up[2];
- var centerx = center[0];
- var centery = center[1];
- var centerz = center[2];
- if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
- return identity$2(out);
- }
- z0 = eyex - centerx;
- z1 = eyey - centery;
- z2 = eyez - centerz;
- len = 1 / Math.hypot(z0, z1, z2);
- z0 *= len;
- z1 *= len;
- z2 *= len;
- x0 = upy * z2 - upz * z1;
- x1 = upz * z0 - upx * z2;
- x2 = upx * z1 - upy * z0;
- len = Math.hypot(x0, x1, x2);
- if (!len) {
- x0 = 0;
- x1 = 0;
- x2 = 0;
- } else {
- len = 1 / len;
- x0 *= len;
- x1 *= len;
- x2 *= len;
- }
- y0 = z1 * x2 - z2 * x1;
- y1 = z2 * x0 - z0 * x2;
- y2 = z0 * x1 - z1 * x0;
- len = Math.hypot(y0, y1, y2);
- if (!len) {
- y0 = 0;
- y1 = 0;
- y2 = 0;
- } else {
- len = 1 / len;
- y0 *= len;
- y1 *= len;
- y2 *= len;
- }
- out[0] = x0;
- out[1] = y0;
- out[2] = z0;
- out[3] = 0;
- out[4] = x1;
- out[5] = y1;
- out[6] = z1;
- out[7] = 0;
- out[8] = x2;
- out[9] = y2;
- out[10] = z2;
- out[11] = 0;
- out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
- out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
- out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
- out[15] = 1;
- return out;
- }
- function targetTo(out, eye, target, up) {
- var eyex = eye[0], eyey = eye[1], eyez = eye[2], upx = up[0], upy = up[1], upz = up[2];
- var z0 = eyex - target[0], z1 = eyey - target[1], z2 = eyez - target[2];
- var len = z0 * z0 + z1 * z1 + z2 * z2;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- z0 *= len;
- z1 *= len;
- z2 *= len;
- }
- var x0 = upy * z2 - upz * z1, x1 = upz * z0 - upx * z2, x2 = upx * z1 - upy * z0;
- len = x0 * x0 + x1 * x1 + x2 * x2;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- x0 *= len;
- x1 *= len;
- x2 *= len;
- }
- out[0] = x0;
- out[1] = x1;
- out[2] = x2;
- out[3] = 0;
- out[4] = z1 * x2 - z2 * x1;
- out[5] = z2 * x0 - z0 * x2;
- out[6] = z0 * x1 - z1 * x0;
- out[7] = 0;
- out[8] = z0;
- out[9] = z1;
- out[10] = z2;
- out[11] = 0;
- out[12] = eyex;
- out[13] = eyey;
- out[14] = eyez;
- out[15] = 1;
- return out;
- }
- function str$5(a) {
- return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
- }
- function frob(a) {
- return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
- }
- function add$5(out, a, b) {
- out[0] = a[0] + b[0];
- out[1] = a[1] + b[1];
- out[2] = a[2] + b[2];
- out[3] = a[3] + b[3];
- out[4] = a[4] + b[4];
- out[5] = a[5] + b[5];
- out[6] = a[6] + b[6];
- out[7] = a[7] + b[7];
- out[8] = a[8] + b[8];
- out[9] = a[9] + b[9];
- out[10] = a[10] + b[10];
- out[11] = a[11] + b[11];
- out[12] = a[12] + b[12];
- out[13] = a[13] + b[13];
- out[14] = a[14] + b[14];
- out[15] = a[15] + b[15];
- return out;
- }
- function subtract$3(out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- out[2] = a[2] - b[2];
- out[3] = a[3] - b[3];
- out[4] = a[4] - b[4];
- out[5] = a[5] - b[5];
- out[6] = a[6] - b[6];
- out[7] = a[7] - b[7];
- out[8] = a[8] - b[8];
- out[9] = a[9] - b[9];
- out[10] = a[10] - b[10];
- out[11] = a[11] - b[11];
- out[12] = a[12] - b[12];
- out[13] = a[13] - b[13];
- out[14] = a[14] - b[14];
- out[15] = a[15] - b[15];
- return out;
- }
- function multiplyScalar(out, a, b) {
- out[0] = a[0] * b;
- out[1] = a[1] * b;
- out[2] = a[2] * b;
- out[3] = a[3] * b;
- out[4] = a[4] * b;
- out[5] = a[5] * b;
- out[6] = a[6] * b;
- out[7] = a[7] * b;
- out[8] = a[8] * b;
- out[9] = a[9] * b;
- out[10] = a[10] * b;
- out[11] = a[11] * b;
- out[12] = a[12] * b;
- out[13] = a[13] * b;
- out[14] = a[14] * b;
- out[15] = a[15] * b;
- return out;
- }
- function multiplyScalarAndAdd(out, a, b, scale2) {
- out[0] = a[0] + b[0] * scale2;
- out[1] = a[1] + b[1] * scale2;
- out[2] = a[2] + b[2] * scale2;
- out[3] = a[3] + b[3] * scale2;
- out[4] = a[4] + b[4] * scale2;
- out[5] = a[5] + b[5] * scale2;
- out[6] = a[6] + b[6] * scale2;
- out[7] = a[7] + b[7] * scale2;
- out[8] = a[8] + b[8] * scale2;
- out[9] = a[9] + b[9] * scale2;
- out[10] = a[10] + b[10] * scale2;
- out[11] = a[11] + b[11] * scale2;
- out[12] = a[12] + b[12] * scale2;
- out[13] = a[13] + b[13] * scale2;
- out[14] = a[14] + b[14] * scale2;
- out[15] = a[15] + b[15] * scale2;
- return out;
- }
- function exactEquals$5(a, b) {
- return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
- }
- function equals$5(a, b) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
- var a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];
- var a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];
- var a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];
- var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
- var b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];
- var b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];
- var b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
- return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1, Math.abs(a15), Math.abs(b15));
- }
- var mul$5 = multiply$5;
- var sub$3 = subtract$3;
- const mat4 = /* @__PURE__ */ Object.freeze({
- __proto__: null,
- add: add$5,
- adjoint,
- clone: clone$5,
- copy: copy$5,
- create: create$5,
- determinant,
- equals: equals$5,
- exactEquals: exactEquals$5,
- frob,
- fromQuat,
- fromQuat2,
- fromRotation: fromRotation$1,
- fromRotationTranslation: fromRotationTranslation$1,
- fromRotationTranslationScale,
- fromRotationTranslationScaleOrigin,
- fromScaling,
- fromTranslation: fromTranslation$1,
- fromValues: fromValues$5,
- fromXRotation,
- fromYRotation,
- fromZRotation,
- frustum,
- getRotation,
- getScaling,
- getTranslation: getTranslation$1,
- identity: identity$2,
- invert: invert$2,
- lookAt,
- mul: mul$5,
- multiply: multiply$5,
- multiplyScalar,
- multiplyScalarAndAdd,
- ortho,
- orthoNO,
- orthoZO,
- perspective,
- perspectiveFromFieldOfView,
- perspectiveNO,
- perspectiveZO,
- rotate: rotate$1,
- rotateX: rotateX$3,
- rotateY: rotateY$3,
- rotateZ: rotateZ$3,
- scale: scale$5,
- set: set$5,
- str: str$5,
- sub: sub$3,
- subtract: subtract$3,
- targetTo,
- translate: translate$1,
- transpose
- });
- function create$4() {
- var out = new ARRAY_TYPE(3);
- if (ARRAY_TYPE != Float32Array) {
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- }
- return out;
- }
- function clone$4(a) {
- var out = new ARRAY_TYPE(3);
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- return out;
- }
- function length$4(a) {
- var x = a[0];
- var y = a[1];
- var z = a[2];
- return Math.hypot(x, y, z);
- }
- function fromValues$4(x, y, z) {
- var out = new ARRAY_TYPE(3);
- out[0] = x;
- out[1] = y;
- out[2] = z;
- return out;
- }
- function copy$4(out, a) {
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- return out;
- }
- function set$4(out, x, y, z) {
- out[0] = x;
- out[1] = y;
- out[2] = z;
- return out;
- }
- function add$4(out, a, b) {
- out[0] = a[0] + b[0];
- out[1] = a[1] + b[1];
- out[2] = a[2] + b[2];
- return out;
- }
- function subtract$2(out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- out[2] = a[2] - b[2];
- return out;
- }
- function multiply$4(out, a, b) {
- out[0] = a[0] * b[0];
- out[1] = a[1] * b[1];
- out[2] = a[2] * b[2];
- return out;
- }
- function divide$2(out, a, b) {
- out[0] = a[0] / b[0];
- out[1] = a[1] / b[1];
- out[2] = a[2] / b[2];
- return out;
- }
- function ceil$2(out, a) {
- out[0] = Math.ceil(a[0]);
- out[1] = Math.ceil(a[1]);
- out[2] = Math.ceil(a[2]);
- return out;
- }
- function floor$2(out, a) {
- out[0] = Math.floor(a[0]);
- out[1] = Math.floor(a[1]);
- out[2] = Math.floor(a[2]);
- return out;
- }
- function min$2(out, a, b) {
- out[0] = Math.min(a[0], b[0]);
- out[1] = Math.min(a[1], b[1]);
- out[2] = Math.min(a[2], b[2]);
- return out;
- }
- function max$2(out, a, b) {
- out[0] = Math.max(a[0], b[0]);
- out[1] = Math.max(a[1], b[1]);
- out[2] = Math.max(a[2], b[2]);
- return out;
- }
- function round$2(out, a) {
- out[0] = Math.round(a[0]);
- out[1] = Math.round(a[1]);
- out[2] = Math.round(a[2]);
- return out;
- }
- function scale$4(out, a, b) {
- out[0] = a[0] * b;
- out[1] = a[1] * b;
- out[2] = a[2] * b;
- return out;
- }
- function scaleAndAdd$2(out, a, b, scale2) {
- out[0] = a[0] + b[0] * scale2;
- out[1] = a[1] + b[1] * scale2;
- out[2] = a[2] + b[2] * scale2;
- return out;
- }
- function distance$2(a, b) {
- var x = b[0] - a[0];
- var y = b[1] - a[1];
- var z = b[2] - a[2];
- return Math.hypot(x, y, z);
- }
- function squaredDistance$2(a, b) {
- var x = b[0] - a[0];
- var y = b[1] - a[1];
- var z = b[2] - a[2];
- return x * x + y * y + z * z;
- }
- function squaredLength$4(a) {
- var x = a[0];
- var y = a[1];
- var z = a[2];
- return x * x + y * y + z * z;
- }
- function negate$2(out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- out[2] = -a[2];
- return out;
- }
- function inverse$2(out, a) {
- out[0] = 1 / a[0];
- out[1] = 1 / a[1];
- out[2] = 1 / a[2];
- return out;
- }
- function normalize$4(out, a) {
- var x = a[0];
- var y = a[1];
- var z = a[2];
- var len = x * x + y * y + z * z;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- }
- out[0] = a[0] * len;
- out[1] = a[1] * len;
- out[2] = a[2] * len;
- return out;
- }
- function dot$4(a, b) {
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
- }
- function cross$2(out, a, b) {
- var ax = a[0], ay = a[1], az = a[2];
- var bx = b[0], by = b[1], bz = b[2];
- out[0] = ay * bz - az * by;
- out[1] = az * bx - ax * bz;
- out[2] = ax * by - ay * bx;
- return out;
- }
- function lerp$4(out, a, b, t) {
- var ax = a[0];
- var ay = a[1];
- var az = a[2];
- out[0] = ax + t * (b[0] - ax);
- out[1] = ay + t * (b[1] - ay);
- out[2] = az + t * (b[2] - az);
- return out;
- }
- function hermite(out, a, b, c, d, t) {
- var factorTimes2 = t * t;
- var factor1 = factorTimes2 * (2 * t - 3) + 1;
- var factor2 = factorTimes2 * (t - 2) + t;
- var factor3 = factorTimes2 * (t - 1);
- var factor4 = factorTimes2 * (3 - 2 * t);
- out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
- out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
- out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
- return out;
- }
- function bezier(out, a, b, c, d, t) {
- var inverseFactor = 1 - t;
- var inverseFactorTimesTwo = inverseFactor * inverseFactor;
- var factorTimes2 = t * t;
- var factor1 = inverseFactorTimesTwo * inverseFactor;
- var factor2 = 3 * t * inverseFactorTimesTwo;
- var factor3 = 3 * factorTimes2 * inverseFactor;
- var factor4 = factorTimes2 * t;
- out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
- out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
- out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
- return out;
- }
- function random$3(out, scale2) {
- scale2 = scale2 || 1;
- var r = RANDOM() * 2 * Math.PI;
- var z = RANDOM() * 2 - 1;
- var zScale = Math.sqrt(1 - z * z) * scale2;
- out[0] = Math.cos(r) * zScale;
- out[1] = Math.sin(r) * zScale;
- out[2] = z * scale2;
- return out;
- }
- function transformMat4$2(out, a, m) {
- var x = a[0], y = a[1], z = a[2];
- var w = m[3] * x + m[7] * y + m[11] * z + m[15];
- w = w || 1;
- out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
- out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
- out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
- return out;
- }
- function transformMat3$1(out, a, m) {
- var x = a[0], y = a[1], z = a[2];
- out[0] = x * m[0] + y * m[3] + z * m[6];
- out[1] = x * m[1] + y * m[4] + z * m[7];
- out[2] = x * m[2] + y * m[5] + z * m[8];
- return out;
- }
- function transformQuat$1(out, a, q) {
- var qx = q[0], qy = q[1], qz = q[2], qw = q[3];
- var x = a[0], y = a[1], z = a[2];
- var uvx = qy * z - qz * y, uvy = qz * x - qx * z, uvz = qx * y - qy * x;
- var uuvx = qy * uvz - qz * uvy, uuvy = qz * uvx - qx * uvz, uuvz = qx * uvy - qy * uvx;
- var w2 = qw * 2;
- uvx *= w2;
- uvy *= w2;
- uvz *= w2;
- uuvx *= 2;
- uuvy *= 2;
- uuvz *= 2;
- out[0] = x + uvx + uuvx;
- out[1] = y + uvy + uuvy;
- out[2] = z + uvz + uuvz;
- return out;
- }
- function rotateX$2(out, a, b, rad) {
- var p = [], r = [];
- p[0] = a[0] - b[0];
- p[1] = a[1] - b[1];
- p[2] = a[2] - b[2];
- r[0] = p[0];
- r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
- r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad);
- out[0] = r[0] + b[0];
- out[1] = r[1] + b[1];
- out[2] = r[2] + b[2];
- return out;
- }
- function rotateY$2(out, a, b, rad) {
- var p = [], r = [];
- p[0] = a[0] - b[0];
- p[1] = a[1] - b[1];
- p[2] = a[2] - b[2];
- r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
- r[1] = p[1];
- r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad);
- out[0] = r[0] + b[0];
- out[1] = r[1] + b[1];
- out[2] = r[2] + b[2];
- return out;
- }
- function rotateZ$2(out, a, b, rad) {
- var p = [], r = [];
- p[0] = a[0] - b[0];
- p[1] = a[1] - b[1];
- p[2] = a[2] - b[2];
- r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
- r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
- r[2] = p[2];
- out[0] = r[0] + b[0];
- out[1] = r[1] + b[1];
- out[2] = r[2] + b[2];
- return out;
- }
- function angle$1(a, b) {
- var ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2], mag1 = Math.sqrt(ax * ax + ay * ay + az * az), mag2 = Math.sqrt(bx * bx + by * by + bz * bz), mag = mag1 * mag2, cosine = mag && dot$4(a, b) / mag;
- return Math.acos(Math.min(Math.max(cosine, -1), 1));
- }
- function zero$2(out) {
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- return out;
- }
- function str$4(a) {
- return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
- }
- function exactEquals$4(a, b) {
- return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
- }
- function equals$4(a, b) {
- var a0 = a[0], a1 = a[1], a2 = a[2];
- var b0 = b[0], b1 = b[1], b2 = b[2];
- return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2));
- }
- var sub$2 = subtract$2;
- var mul$4 = multiply$4;
- var div$2 = divide$2;
- var dist$2 = distance$2;
- var sqrDist$2 = squaredDistance$2;
- var len$4 = length$4;
- var sqrLen$4 = squaredLength$4;
- var forEach$2 = function() {
- var vec = create$4();
- return function(a, stride, offset2, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 3;
- }
- if (!offset2) {
- offset2 = 0;
- }
- if (count) {
- l = Math.min(count * stride + offset2, a.length);
- } else {
- l = a.length;
- }
- for (i = offset2; i < l; i += stride) {
- vec[0] = a[i];
- vec[1] = a[i + 1];
- vec[2] = a[i + 2];
- fn(vec, vec, arg);
- a[i] = vec[0];
- a[i + 1] = vec[1];
- a[i + 2] = vec[2];
- }
- return a;
- };
- }();
- const vec3 = /* @__PURE__ */ Object.freeze({
- __proto__: null,
- add: add$4,
- angle: angle$1,
- bezier,
- ceil: ceil$2,
- clone: clone$4,
- copy: copy$4,
- create: create$4,
- cross: cross$2,
- dist: dist$2,
- distance: distance$2,
- div: div$2,
- divide: divide$2,
- dot: dot$4,
- equals: equals$4,
- exactEquals: exactEquals$4,
- floor: floor$2,
- forEach: forEach$2,
- fromValues: fromValues$4,
- hermite,
- inverse: inverse$2,
- len: len$4,
- length: length$4,
- lerp: lerp$4,
- max: max$2,
- min: min$2,
- mul: mul$4,
- multiply: multiply$4,
- negate: negate$2,
- normalize: normalize$4,
- random: random$3,
- rotateX: rotateX$2,
- rotateY: rotateY$2,
- rotateZ: rotateZ$2,
- round: round$2,
- scale: scale$4,
- scaleAndAdd: scaleAndAdd$2,
- set: set$4,
- sqrDist: sqrDist$2,
- sqrLen: sqrLen$4,
- squaredDistance: squaredDistance$2,
- squaredLength: squaredLength$4,
- str: str$4,
- sub: sub$2,
- subtract: subtract$2,
- transformMat3: transformMat3$1,
- transformMat4: transformMat4$2,
- transformQuat: transformQuat$1,
- zero: zero$2
- });
- function create$3() {
- var out = new ARRAY_TYPE(4);
- if (ARRAY_TYPE != Float32Array) {
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- }
- return out;
- }
- function normalize$3(out, a) {
- var x = a[0];
- var y = a[1];
- var z = a[2];
- var w = a[3];
- var len = x * x + y * y + z * z + w * w;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- }
- out[0] = x * len;
- out[1] = y * len;
- out[2] = z * len;
- out[3] = w * len;
- return out;
- }
- (function() {
- var vec = create$3();
- return function(a, stride, offset2, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 4;
- }
- if (!offset2) {
- offset2 = 0;
- }
- if (count) {
- l = Math.min(count * stride + offset2, a.length);
- } else {
- l = a.length;
- }
- for (i = offset2; i < l; i += stride) {
- vec[0] = a[i];
- vec[1] = a[i + 1];
- vec[2] = a[i + 2];
- vec[3] = a[i + 3];
- fn(vec, vec, arg);
- a[i] = vec[0];
- a[i + 1] = vec[1];
- a[i + 2] = vec[2];
- a[i + 3] = vec[3];
- }
- return a;
- };
- })();
- function create$2() {
- var out = new ARRAY_TYPE(4);
- if (ARRAY_TYPE != Float32Array) {
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- }
- out[3] = 1;
- return out;
- }
- function setAxisAngle(out, axis, rad) {
- rad = rad * 0.5;
- var s = Math.sin(rad);
- out[0] = s * axis[0];
- out[1] = s * axis[1];
- out[2] = s * axis[2];
- out[3] = Math.cos(rad);
- return out;
- }
- function slerp(out, a, b, t) {
- var ax = a[0], ay = a[1], az = a[2], aw = a[3];
- var bx = b[0], by = b[1], bz = b[2], bw = b[3];
- var omega, cosom, sinom, scale0, scale1;
- cosom = ax * bx + ay * by + az * bz + aw * bw;
- if (cosom < 0) {
- cosom = -cosom;
- bx = -bx;
- by = -by;
- bz = -bz;
- bw = -bw;
- }
- if (1 - cosom > EPSILON) {
- omega = Math.acos(cosom);
- sinom = Math.sin(omega);
- scale0 = Math.sin((1 - t) * omega) / sinom;
- scale1 = Math.sin(t * omega) / sinom;
- } else {
- scale0 = 1 - t;
- scale1 = t;
- }
- out[0] = scale0 * ax + scale1 * bx;
- out[1] = scale0 * ay + scale1 * by;
- out[2] = scale0 * az + scale1 * bz;
- out[3] = scale0 * aw + scale1 * bw;
- return out;
- }
- function fromMat3(out, m) {
- var fTrace = m[0] + m[4] + m[8];
- var fRoot;
- if (fTrace > 0) {
- fRoot = Math.sqrt(fTrace + 1);
- out[3] = 0.5 * fRoot;
- fRoot = 0.5 / fRoot;
- out[0] = (m[5] - m[7]) * fRoot;
- out[1] = (m[6] - m[2]) * fRoot;
- out[2] = (m[1] - m[3]) * fRoot;
- } else {
- var i = 0;
- if (m[4] > m[0])
- i = 1;
- if (m[8] > m[i * 3 + i])
- i = 2;
- var j = (i + 1) % 3;
- var k = (i + 2) % 3;
- fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1);
- out[i] = 0.5 * fRoot;
- fRoot = 0.5 / fRoot;
- out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
- out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
- out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
- }
- return out;
- }
- var normalize$2 = normalize$3;
- (function() {
- var tmpvec3 = create$4();
- var xUnitVec3 = fromValues$4(1, 0, 0);
- var yUnitVec3 = fromValues$4(0, 1, 0);
- return function(out, a, b) {
- var dot = dot$4(a, b);
- if (dot < -0.999999) {
- cross$2(tmpvec3, xUnitVec3, a);
- if (len$4(tmpvec3) < 1e-6)
- cross$2(tmpvec3, yUnitVec3, a);
- normalize$4(tmpvec3, tmpvec3);
- setAxisAngle(out, tmpvec3, Math.PI);
- return out;
- } else if (dot > 0.999999) {
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- return out;
- } else {
- cross$2(tmpvec3, a, b);
- out[0] = tmpvec3[0];
- out[1] = tmpvec3[1];
- out[2] = tmpvec3[2];
- out[3] = 1 + dot;
- return normalize$2(out, out);
- }
- };
- })();
- (function() {
- var temp1 = create$2();
- var temp2 = create$2();
- return function(out, a, b, c, d, t) {
- slerp(temp1, a, d, t);
- slerp(temp2, b, c, t);
- slerp(out, temp1, temp2, 2 * t * (1 - t));
- return out;
- };
- })();
- (function() {
- var matr = create$6();
- return function(out, view, right, up) {
- matr[0] = right[0];
- matr[3] = right[1];
- matr[6] = right[2];
- matr[1] = up[0];
- matr[4] = up[1];
- matr[7] = up[2];
- matr[2] = -view[0];
- matr[5] = -view[1];
- matr[8] = -view[2];
- return normalize$2(out, fromMat3(out, matr));
- };
- })();
- function create() {
- var out = new ARRAY_TYPE(2);
- if (ARRAY_TYPE != Float32Array) {
- out[0] = 0;
- out[1] = 0;
- }
- return out;
- }
- (function() {
- var vec = create();
- return function(a, stride, offset2, count, fn, arg) {
- var i, l;
- if (!stride) {
- stride = 2;
- }
- if (!offset2) {
- offset2 = 0;
- }
- if (count) {
- l = Math.min(count * stride + offset2, a.length);
- } else {
- l = a.length;
- }
- for (i = offset2; i < l; i += stride) {
- vec[0] = a[i];
- vec[1] = a[i + 1];
- fn(vec, vec, arg);
- a[i] = vec[0];
- a[i + 1] = vec[1];
- }
- return a;
- };
- })();
- class AnimationControl {
- /** @type {object} */
- #animationData;
- /** @type {Promise<void>} */
- #finishedPromise;
- #willFinish;
- /**
- * Defines a static empty / void animation control.
- *
- * @type {AnimationControl}
- */
- static #voidControl = new AnimationControl(null);
- /**
- * Provides a static void / undefined AnimationControl that is automatically resolved.
- *
- * @returns {AnimationControl} Void AnimationControl
- */
- static get voidControl() {
- return this.#voidControl;
- }
- /**
- * @param {object|null} [animationData] - Animation data from {@link AnimationAPI}.
- *
- * @param {boolean} [willFinish] - Promise that tracks animation finished state.
- */
- constructor(animationData, willFinish = false) {
- this.#animationData = animationData;
- this.#willFinish = willFinish;
- if (isObject(animationData)) {
- animationData.control = this;
- }
- }
- /**
- * Get a promise that resolves when animation is finished.
- *
- * @returns {Promise<void>}
- */
- get finished() {
- if (!(this.#finishedPromise instanceof Promise)) {
- this.#finishedPromise = this.#willFinish ? new Promise((resolve) => this.#animationData.resolve = resolve) : Promise.resolve();
- }
- return this.#finishedPromise;
- }
- /**
- * Returns whether this animation is currently active / animating.
- *
- * Note: a delayed animation may not be started / active yet. Use {@link AnimationControl.isFinished} to determine
- * if an animation is actually finished.
- *
- * @returns {boolean} Animation active state.
- */
- get isActive() {
- return this.#animationData.active;
- }
- /**
- * Returns whether this animation is completely finished.
- *
- * @returns {boolean} Animation finished state.
- */
- get isFinished() {
- return this.#animationData.finished;
- }
- /**
- * Cancels the animation.
- */
- cancel() {
- const animationData = this.#animationData;
- if (animationData === null || animationData === void 0) {
- return;
- }
- animationData.cancelled = true;
- }
- }
- class AnimationManager {
- /**
- * @type {object[]}
- */
- static activeList = [];
- /**
- * @type {object[]}
- */
- static newList = [];
- /**
- * @type {number}
- */
- static current;
- /**
- * Add animation data.
- *
- * @param {object} data -
- */
- static add(data) {
- const now2 = performance.now();
- data.start = now2 + (AnimationManager.current - now2);
- AnimationManager.newList.push(data);
- }
- /**
- * Manage all animation
- */
- static animate() {
- const current = AnimationManager.current = performance.now();
- if (AnimationManager.activeList.length === 0 && AnimationManager.newList.length === 0) {
- globalThis.requestAnimationFrame(AnimationManager.animate);
- return;
- }
- if (AnimationManager.newList.length) {
- for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
- const data = AnimationManager.newList[cntr];
- if (data.cancelled) {
- AnimationManager.newList.splice(cntr, 1);
- data.cleanup(data);
- }
- if (data.active) {
- AnimationManager.newList.splice(cntr, 1);
- AnimationManager.activeList.push(data);
- }
- }
- }
- for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
- const data = AnimationManager.activeList[cntr];
- if (data.cancelled || data.el !== void 0 && !data.el.isConnected) {
- AnimationManager.activeList.splice(cntr, 1);
- data.cleanup(data);
- continue;
- }
- data.current = current - data.start;
- if (data.current >= data.duration) {
- for (let dataCntr = data.keys.length; --dataCntr >= 0; ) {
- const key = data.keys[dataCntr];
- data.newData[key] = data.destination[key];
- }
- data.position.set(data.newData);
- AnimationManager.activeList.splice(cntr, 1);
- data.cleanup(data);
- continue;
- }
- const easedTime = data.ease(data.current / data.duration);
- for (let dataCntr = data.keys.length; --dataCntr >= 0; ) {
- const key = data.keys[dataCntr];
- data.newData[key] = data.interpolate(data.initial[key], data.destination[key], easedTime);
- }
- data.position.set(data.newData);
- }
- globalThis.requestAnimationFrame(AnimationManager.animate);
- }
- /**
- * Cancels all animations for given Position instance.
- *
- * @param {Position} position - Position instance.
- */
- static cancel(position) {
- for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
- const data = AnimationManager.activeList[cntr];
- if (data.position === position) {
- AnimationManager.activeList.splice(cntr, 1);
- data.cancelled = true;
- data.cleanup(data);
- }
- }
- for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
- const data = AnimationManager.newList[cntr];
- if (data.position === position) {
- AnimationManager.newList.splice(cntr, 1);
- data.cancelled = true;
- data.cleanup(data);
- }
- }
- }
- /**
- * Cancels all active and delayed animations.
- */
- static cancelAll() {
- for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
- const data = AnimationManager.activeList[cntr];
- data.cancelled = true;
- data.cleanup(data);
- }
- for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
- const data = AnimationManager.newList[cntr];
- data.cancelled = true;
- data.cleanup(data);
- }
- AnimationManager.activeList.length = 0;
- AnimationManager.newList.length = 0;
- }
- /**
- * Gets all {@link AnimationControl} instances for a given Position instance.
- *
- * @param {Position} position - Position instance.
- *
- * @returns {AnimationControl[]} All scheduled AnimationControl instances for the given Position instance.
- */
- static getScheduled(position) {
- const results = [];
- for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
- const data = AnimationManager.activeList[cntr];
- if (data.position === position) {
- results.push(data.control);
- }
- }
- for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
- const data = AnimationManager.newList[cntr];
- if (data.position === position) {
- results.push(data.control);
- }
- }
- return results;
- }
- }
- AnimationManager.animate();
- const animateKeys = /* @__PURE__ */ new Set([
- // Main keys
- "left",
- "top",
- "maxWidth",
- "maxHeight",
- "minWidth",
- "minHeight",
- "width",
- "height",
- "rotateX",
- "rotateY",
- "rotateZ",
- "scale",
- "translateX",
- "translateY",
- "translateZ",
- "zIndex",
- // Aliases
- "rotation"
- ]);
- const transformKeys = ["rotateX", "rotateY", "rotateZ", "scale", "translateX", "translateY", "translateZ"];
- Object.freeze(transformKeys);
- const relativeRegex = /^([-+*])=(-?[\d]*\.?[\d]+)$/;
- const numericDefaults = {
- // Other keys
- height: 0,
- left: 0,
- maxHeight: null,
- maxWidth: null,
- minHeight: null,
- minWidth: null,
- top: 0,
- transformOrigin: null,
- width: 0,
- zIndex: null,
- rotateX: 0,
- rotateY: 0,
- rotateZ: 0,
- scale: 1,
- translateX: 0,
- translateY: 0,
- translateZ: 0,
- rotation: 0
- };
- Object.freeze(numericDefaults);
- function setNumericDefaults(data) {
- if (data.rotateX === null) {
- data.rotateX = 0;
- }
- if (data.rotateY === null) {
- data.rotateY = 0;
- }
- if (data.rotateZ === null) {
- data.rotateZ = 0;
- }
- if (data.translateX === null) {
- data.translateX = 0;
- }
- if (data.translateY === null) {
- data.translateY = 0;
- }
- if (data.translateZ === null) {
- data.translateZ = 0;
- }
- if (data.scale === null) {
- data.scale = 1;
- }
- if (data.rotation === null) {
- data.rotation = 0;
- }
- }
- const transformKeysBitwise = {
- rotateX: 1,
- rotateY: 2,
- rotateZ: 4,
- scale: 8,
- translateX: 16,
- translateY: 32,
- translateZ: 64
- };
- Object.freeze(transformKeysBitwise);
- const transformOriginDefault = "top left";
- const transformOrigins = [
- "top left",
- "top center",
- "top right",
- "center left",
- "center",
- "center right",
- "bottom left",
- "bottom center",
- "bottom right"
- ];
- Object.freeze(transformOrigins);
- function convertRelative(positionData, position) {
- for (const key in positionData) {
- if (animateKeys.has(key)) {
- const value = positionData[key];
- if (typeof value !== "string") {
- continue;
- }
- if (value === "auto" || value === "inherit") {
- continue;
- }
- const regexResults = relativeRegex.exec(value);
- if (!regexResults) {
- throw new Error(
- `convertRelative error: malformed relative key (${key}) with value (${value})`
- );
- }
- const current = position[key];
- switch (regexResults[1]) {
- case "-":
- positionData[key] = current - parseFloat(regexResults[2]);
- break;
- case "+":
- positionData[key] = current + parseFloat(regexResults[2]);
- break;
- case "*":
- positionData[key] = current * parseFloat(regexResults[2]);
- break;
- }
- }
- }
- }
- class AnimationAPI {
- /** @type {PositionData} */
- #data;
- /** @type {Position} */
- #position;
- /**
- * Tracks the number of animation control instances that are active.
- *
- * @type {number}
- */
- #instanceCount = 0;
- /**
- * Provides a bound function to pass as data to AnimationManager to invoke
- *
- * @type {Function}
- * @see {AnimationAPI.#cleanupInstance}
- */
- #cleanup;
- constructor(position, data) {
- this.#position = position;
- this.#data = data;
- this.#cleanup = this.#cleanupInstance.bind(this);
- }
- /**
- * Returns whether there are scheduled animations whether active or delayed for this Position.
- *
- * @returns {boolean} Are there active animation instances.
- */
- get isScheduled() {
- return this.#instanceCount > 0;
- }
- /**
- * Adds / schedules an animation w/ the AnimationManager. This contains the final steps common to all tweens.
- *
- * @param {object} initial -
- *
- * @param {object} destination -
- *
- * @param {number} duration -
- *
- * @param {HTMLElement} el -
- *
- * @param {number} delay -
- *
- * @param {Function} ease -
- *
- * @param {Function} interpolate -
- *
- * @returns {AnimationControl} The associated animation control.
- */
- #addAnimation(initial, destination, duration, el, delay, ease, interpolate2) {
- setNumericDefaults(initial);
- setNumericDefaults(destination);
- for (const key in initial) {
- if (!Number.isFinite(initial[key])) {
- delete initial[key];
- }
- }
- const keys = Object.keys(initial);
- const newData = Object.assign({ immediateElementUpdate: true }, initial);
- if (keys.length === 0) {
- return AnimationControl.voidControl;
- }
- const animationData = {
- active: true,
- cleanup: this.#cleanup,
- cancelled: false,
- control: void 0,
- current: 0,
- destination,
- duration: duration * 1e3,
- // Internally the AnimationManager works in ms.
- ease,
- el,
- finished: false,
- initial,
- interpolate: interpolate2,
- keys,
- newData,
- position: this.#position,
- resolve: void 0,
- start: void 0
- };
- if (delay > 0) {
- animationData.active = false;
- setTimeout(() => {
- if (!animationData.cancelled) {
- animationData.active = true;
- const now2 = performance.now();
- animationData.start = now2 + (AnimationManager.current - now2);
- }
- }, delay * 1e3);
- }
- this.#instanceCount++;
- AnimationManager.add(animationData);
- return new AnimationControl(animationData, true);
- }
- /**
- * Cancels all animation instances for this Position instance.
- */
- cancel() {
- AnimationManager.cancel(this.#position);
- }
- /**
- * Cleans up an animation instance.
- *
- * @param {object} data - Animation data for an animation instance.
- */
- #cleanupInstance(data) {
- this.#instanceCount--;
- data.active = false;
- data.finished = true;
- if (typeof data.resolve === "function") {
- data.resolve(data.cancelled);
- }
- }
- /**
- * Returns all currently scheduled AnimationControl instances for this Position instance.
- *
- * @returns {AnimationControl[]} All currently scheduled animation controls for this Position instance.
- */
- getScheduled() {
- return AnimationManager.getScheduled(this.#position);
- }
- /**
- * Provides a tween from given position data to the current position.
- *
- * @param {PositionDataExtended} fromData - The starting position.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {number} [opts.delay=0] - Delay in seconds before animation starts.
- *
- * @param {number} [opts.duration=1] - Duration in seconds.
- *
- * @param {Function} [opts.ease=cubicOut] - Easing function.
- *
- * @param {Function} [opts.interpolate=lerp] - Interpolation function.
- *
- * @returns {AnimationControl} A control object that can cancel animation and provides a `finished` Promise.
- */
- from(fromData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
- if (!isObject(fromData)) {
- throw new TypeError(`AnimationAPI.from error: 'fromData' is not an object.`);
- }
- const position = this.#position;
- const parent = position.parent;
- if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
- return AnimationControl.voidControl;
- }
- const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
- const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
- if (!Number.isFinite(delay) || delay < 0) {
- throw new TypeError(`AnimationAPI.from error: 'delay' is not a positive number.`);
- }
- if (!Number.isFinite(duration) || duration < 0) {
- throw new TypeError(`AnimationAPI.from error: 'duration' is not a positive number.`);
- }
- if (typeof ease !== "function") {
- throw new TypeError(`AnimationAPI.from error: 'ease' is not a function.`);
- }
- if (typeof interpolate2 !== "function") {
- throw new TypeError(`AnimationAPI.from error: 'interpolate' is not a function.`);
- }
- const initial = {};
- const destination = {};
- const data = this.#data;
- for (const key in fromData) {
- if (data[key] !== void 0 && fromData[key] !== data[key]) {
- initial[key] = fromData[key];
- destination[key] = data[key];
- }
- }
- convertRelative(initial, data);
- return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
- }
- /**
- * Provides a tween from given position data to the current position.
- *
- * @param {PositionDataExtended} fromData - The starting position.
- *
- * @param {PositionDataExtended} toData - The ending position.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {number} [opts.delay=0] - Delay in seconds before animation starts.
- *
- * @param {number} [opts.duration=1] - Duration in seconds.
- *
- * @param {Function} [opts.ease=cubicOut] - Easing function.
- *
- * @param {Function} [opts.interpolate=lerp] - Interpolation function.
- *
- * @returns {AnimationControl} A control object that can cancel animation and provides a `finished` Promise.
- */
- fromTo(fromData, toData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
- if (!isObject(fromData)) {
- throw new TypeError(`AnimationAPI.fromTo error: 'fromData' is not an object.`);
- }
- if (!isObject(toData)) {
- throw new TypeError(`AnimationAPI.fromTo error: 'toData' is not an object.`);
- }
- const parent = this.#position.parent;
- if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
- return AnimationControl.voidControl;
- }
- const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
- const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
- if (!Number.isFinite(delay) || delay < 0) {
- throw new TypeError(`AnimationAPI.fromTo error: 'delay' is not a positive number.`);
- }
- if (!Number.isFinite(duration) || duration < 0) {
- throw new TypeError(`AnimationAPI.fromTo error: 'duration' is not a positive number.`);
- }
- if (typeof ease !== "function") {
- throw new TypeError(`AnimationAPI.fromTo error: 'ease' is not a function.`);
- }
- if (typeof interpolate2 !== "function") {
- throw new TypeError(`AnimationAPI.fromTo error: 'interpolate' is not a function.`);
- }
- const initial = {};
- const destination = {};
- const data = this.#data;
- for (const key in fromData) {
- if (toData[key] === void 0) {
- console.warn(
- `AnimationAPI.fromTo warning: key ('${key}') from 'fromData' missing in 'toData'; skipping this key.`
- );
- continue;
- }
- if (data[key] !== void 0) {
- initial[key] = fromData[key];
- destination[key] = toData[key];
- }
- }
- convertRelative(initial, data);
- convertRelative(destination, data);
- return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
- }
- /**
- * Provides a tween to given position data from the current position.
- *
- * @param {PositionDataExtended} toData - The destination position.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {number} [opts.delay=0] - Delay in seconds before animation starts.
- *
- * @param {number} [opts.duration=1] - Duration in seconds.
- *
- * @param {Function} [opts.ease=cubicOut] - Easing function.
- *
- * @param {Function} [opts.interpolate=lerp] - Interpolation function.
- *
- * @returns {AnimationControl} A control object that can cancel animation and provides a `finished` Promise.
- */
- to(toData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
- if (!isObject(toData)) {
- throw new TypeError(`AnimationAPI.to error: 'toData' is not an object.`);
- }
- const parent = this.#position.parent;
- if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
- return AnimationControl.voidControl;
- }
- const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
- const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
- if (!Number.isFinite(delay) || delay < 0) {
- throw new TypeError(`AnimationAPI.to error: 'delay' is not a positive number.`);
- }
- if (!Number.isFinite(duration) || duration < 0) {
- throw new TypeError(`AnimationAPI.to error: 'duration' is not a positive number.`);
- }
- if (typeof ease !== "function") {
- throw new TypeError(`AnimationAPI.to error: 'ease' is not a function.`);
- }
- if (typeof interpolate2 !== "function") {
- throw new TypeError(`AnimationAPI.to error: 'interpolate' is not a function.`);
- }
- const initial = {};
- const destination = {};
- const data = this.#data;
- for (const key in toData) {
- if (data[key] !== void 0 && toData[key] !== data[key]) {
- destination[key] = toData[key];
- initial[key] = data[key];
- }
- }
- convertRelative(destination, data);
- return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
- }
- /**
- * Returns a function that provides an optimized way to constantly update a to-tween.
- *
- * @param {Iterable<string>} keys - The keys for quickTo.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {number} [opts.duration=1] - Duration in seconds.
- *
- * @param {Function} [opts.ease=cubicOut] - Easing function.
- *
- * @param {Function} [opts.interpolate=lerp] - Interpolation function.
- *
- * @returns {quickToCallback} quick-to tween function.
- */
- quickTo(keys, { duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
- if (!isIterable(keys)) {
- throw new TypeError(`AnimationAPI.quickTo error: 'keys' is not an iterable list.`);
- }
- const parent = this.#position.parent;
- if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
- throw new Error(`AnimationAPI.quickTo error: 'parent' is not positionable.`);
- }
- if (!Number.isFinite(duration) || duration < 0) {
- throw new TypeError(`AnimationAPI.quickTo error: 'duration' is not a positive number.`);
- }
- if (typeof ease !== "function") {
- throw new TypeError(`AnimationAPI.quickTo error: 'ease' is not a function.`);
- }
- if (typeof interpolate2 !== "function") {
- throw new TypeError(`AnimationAPI.quickTo error: 'interpolate' is not a function.`);
- }
- const initial = {};
- const destination = {};
- const data = this.#data;
- for (const key of keys) {
- if (typeof key !== "string") {
- throw new TypeError(`AnimationAPI.quickTo error: key is not a string.`);
- }
- if (!animateKeys.has(key)) {
- throw new Error(`AnimationAPI.quickTo error: key ('${key}') is not animatable.`);
- }
- if (data[key] !== void 0) {
- destination[key] = data[key];
- initial[key] = data[key];
- }
- }
- const keysArray = [...keys];
- Object.freeze(keysArray);
- const newData = Object.assign({ immediateElementUpdate: true }, initial);
- const animationData = {
- active: true,
- cleanup: this.#cleanup,
- cancelled: false,
- control: void 0,
- current: 0,
- destination,
- duration: duration * 1e3,
- // Internally the AnimationManager works in ms.
- ease,
- el: void 0,
- finished: true,
- // Note: start in finished state to add to AnimationManager on first callback.
- initial,
- interpolate: interpolate2,
- keys,
- newData,
- position: this.#position,
- resolve: void 0,
- start: void 0
- };
- const quickToCB = (...args) => {
- const argsLength = args.length;
- if (argsLength === 0) {
- return;
- }
- for (let cntr = keysArray.length; --cntr >= 0; ) {
- const key = keysArray[cntr];
- if (data[key] !== void 0) {
- initial[key] = data[key];
- }
- }
- if (isObject(args[0])) {
- const objData = args[0];
- for (const key in objData) {
- if (destination[key] !== void 0) {
- destination[key] = objData[key];
- }
- }
- } else {
- for (let cntr = 0; cntr < argsLength && cntr < keysArray.length; cntr++) {
- const key = keysArray[cntr];
- if (destination[key] !== void 0) {
- destination[key] = args[cntr];
- }
- }
- }
- convertRelative(destination, data);
- setNumericDefaults(initial);
- setNumericDefaults(destination);
- const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
- animationData.el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
- if (animationData.finished) {
- animationData.finished = false;
- animationData.active = true;
- animationData.current = 0;
- this.#instanceCount++;
- AnimationManager.add(animationData);
- } else {
- const now2 = performance.now();
- animationData.start = now2 + (AnimationManager.current - now2);
- animationData.current = 0;
- }
- };
- quickToCB.keys = keysArray;
- quickToCB.options = ({ duration: duration2, ease: ease2, interpolate: interpolate3 } = {}) => {
- if (duration2 !== void 0 && (!Number.isFinite(duration2) || duration2 < 0)) {
- throw new TypeError(`AnimationAPI.quickTo.options error: 'duration' is not a positive number.`);
- }
- if (ease2 !== void 0 && typeof ease2 !== "function") {
- throw new TypeError(`AnimationAPI.quickTo.options error: 'ease' is not a function.`);
- }
- if (interpolate3 !== void 0 && typeof interpolate3 !== "function") {
- throw new TypeError(`AnimationAPI.quickTo.options error: 'interpolate' is not a function.`);
- }
- if (duration2 >= 0) {
- animationData.duration = duration2 * 1e3;
- }
- if (ease2) {
- animationData.ease = ease2;
- }
- if (interpolate3) {
- animationData.interpolate = interpolate3;
- }
- return quickToCB;
- };
- return quickToCB;
- }
- }
- class AnimationGroupControl {
- /** @type {AnimationControl[]} */
- #animationControls;
- /** @type {Promise<Awaited<unknown>[]>} */
- #finishedPromise;
- /**
- * Defines a static empty / void animation control.
- *
- * @type {AnimationGroupControl}
- */
- static #voidControl = new AnimationGroupControl(null);
- /**
- * Provides a static void / undefined AnimationGroupControl that is automatically resolved.
- *
- * @returns {AnimationGroupControl} Void AnimationGroupControl
- */
- static get voidControl() {
- return this.#voidControl;
- }
- /**
- * @param {AnimationControl[]} animationControls - An array of AnimationControl instances.
- */
- constructor(animationControls) {
- this.#animationControls = animationControls;
- }
- /**
- * Get a promise that resolves when all animations are finished.
- *
- * @returns {Promise<Awaited<unknown>[]>|Promise<void>} Finished Promise for all animations.
- */
- get finished() {
- const animationControls = this.#animationControls;
- if (animationControls === null || animationControls === void 0) {
- return Promise.resolve();
- }
- if (!(this.#finishedPromise instanceof Promise)) {
- const promises = [];
- for (let cntr = animationControls.length; --cntr >= 0; ) {
- promises.push(animationControls[cntr].finished);
- }
- this.#finishedPromise = Promise.all(promises);
- }
- return this.#finishedPromise;
- }
- /**
- * Returns whether there are active animation instances for this group.
- *
- * Note: a delayed animation may not be started / active yet. Use {@link AnimationGroupControl.isFinished} to
- * determine if all animations in the group are finished.
- *
- * @returns {boolean} Are there active animation instances.
- */
- get isActive() {
- const animationControls = this.#animationControls;
- if (animationControls === null || animationControls === void 0) {
- return false;
- }
- for (let cntr = animationControls.length; --cntr >= 0; ) {
- if (animationControls[cntr].isActive) {
- return true;
- }
- }
- return false;
- }
- /**
- * Returns whether all animations in the group are finished.
- *
- * @returns {boolean} Are all animation instances finished.
- */
- get isFinished() {
- const animationControls = this.#animationControls;
- if (animationControls === null || animationControls === void 0) {
- return true;
- }
- for (let cntr = animationControls.length; --cntr >= 0; ) {
- if (!animationControls[cntr].isFinished) {
- return false;
- }
- }
- return false;
- }
- /**
- * Cancels the all animations.
- */
- cancel() {
- const animationControls = this.#animationControls;
- if (animationControls === null || animationControls === void 0) {
- return;
- }
- for (let cntr = this.#animationControls.length; --cntr >= 0; ) {
- this.#animationControls[cntr].cancel();
- }
- }
- }
- class AnimationGroupAPI {
- /**
- * Checks of the given object is a Position instance by checking for AnimationAPI.
- *
- * @param {*} object - Any data.
- *
- * @returns {boolean} Is Position.
- */
- static #isPosition(object) {
- return isObject(object) && object.animate instanceof AnimationAPI;
- }
- /**
- * Cancels any animation for given Position data.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- */
- static cancel(position) {
- if (isIterable(position)) {
- let index = -1;
- for (const entry of position) {
- index++;
- const actualPosition = this.#isPosition(entry) ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.cancel warning: No Position instance found at index: ${index}.`);
- continue;
- }
- AnimationManager.cancel(actualPosition);
- }
- } else {
- const actualPosition = this.#isPosition(position) ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.cancel warning: No Position instance found.`);
- return;
- }
- AnimationManager.cancel(actualPosition);
- }
- }
- /**
- * Cancels all Position animation.
- */
- static cancelAll() {
- AnimationManager.cancelAll();
- }
- /**
- * Gets all animation controls for the given position data.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- *
- * @returns {{position: Position, data: object|void, controls: AnimationControl[]}[]} Results array.
- */
- static getScheduled(position) {
- const results = [];
- if (isIterable(position)) {
- let index = -1;
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.getScheduled warning: No Position instance found at index: ${index}.`);
- continue;
- }
- const controls = AnimationManager.getScheduled(actualPosition);
- results.push({ position: actualPosition, data: isPosition ? void 0 : entry, controls });
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.getScheduled warning: No Position instance found.`);
- return results;
- }
- const controls = AnimationManager.getScheduled(actualPosition);
- results.push({ position: actualPosition, data: isPosition ? void 0 : position, controls });
- }
- return results;
- }
- /**
- * Provides the `from` animation tween for one or more Position instances as a group.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- *
- * @param {object|Function} fromData -
- *
- * @param {object|Function} options -
- *
- * @returns {TJSBasicAnimation} Basic animation control.
- */
- static from(position, fromData, options) {
- if (!isObject(fromData) && typeof fromData !== "function") {
- throw new TypeError(`AnimationGroupAPI.from error: 'fromData' is not an object or function.`);
- }
- if (options !== void 0 && !isObject(options) && typeof options !== "function") {
- throw new TypeError(`AnimationGroupAPI.from error: 'options' is not an object or function.`);
- }
- const animationControls = [];
- let index = -1;
- let callbackOptions;
- const hasDataCallback = typeof fromData === "function";
- const hasOptionCallback = typeof options === "function";
- const hasCallback = hasDataCallback || hasOptionCallback;
- if (hasCallback) {
- callbackOptions = { index, position: void 0, data: void 0 };
- }
- let actualFromData = fromData;
- let actualOptions = options;
- if (isIterable(position)) {
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.from warning: No Position instance found at index: ${index}.`);
- continue;
- }
- if (hasCallback) {
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- }
- if (hasDataCallback) {
- actualFromData = fromData(callbackOptions);
- if (actualFromData === null || actualFromData === void 0) {
- continue;
- }
- if (typeof actualFromData !== "object") {
- throw new TypeError(`AnimationGroupAPI.from error: fromData callback function iteration(${index}) failed to return an object.`);
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (actualOptions === null || actualOptions === void 0) {
- continue;
- }
- if (typeof actualOptions !== "object") {
- throw new TypeError(`AnimationGroupAPI.from error: options callback function iteration(${index}) failed to return an object.`);
- }
- }
- animationControls.push(actualPosition.animate.from(actualFromData, actualOptions));
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.from warning: No Position instance found.`);
- return AnimationGroupControl.voidControl;
- }
- if (hasCallback) {
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- }
- if (hasDataCallback) {
- actualFromData = fromData(callbackOptions);
- if (typeof actualFromData !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.from error: fromData callback function failed to return an object.`
- );
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.from error: options callback function failed to return an object.`
- );
- }
- }
- animationControls.push(actualPosition.animate.from(actualFromData, actualOptions));
- }
- return new AnimationGroupControl(animationControls);
- }
- /**
- * Provides the `fromTo` animation tween for one or more Position instances as a group.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- *
- * @param {object|Function} fromData -
- *
- * @param {object|Function} toData -
- *
- * @param {object|Function} options -
- *
- * @returns {TJSBasicAnimation} Basic animation control.
- */
- static fromTo(position, fromData, toData, options) {
- if (!isObject(fromData) && typeof fromData !== "function") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: 'fromData' is not an object or function.`);
- }
- if (!isObject(toData) && typeof toData !== "function") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: 'toData' is not an object or function.`);
- }
- if (options !== void 0 && !isObject(options) && typeof options !== "function") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: 'options' is not an object or function.`);
- }
- const animationControls = [];
- let index = -1;
- let callbackOptions;
- const hasFromCallback = typeof fromData === "function";
- const hasToCallback = typeof toData === "function";
- const hasOptionCallback = typeof options === "function";
- const hasCallback = hasFromCallback || hasToCallback || hasOptionCallback;
- if (hasCallback) {
- callbackOptions = { index, position: void 0, data: void 0 };
- }
- let actualFromData = fromData;
- let actualToData = toData;
- let actualOptions = options;
- if (isIterable(position)) {
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.fromTo warning: No Position instance found at index: ${index}.`);
- continue;
- }
- if (hasCallback) {
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- }
- if (hasFromCallback) {
- actualFromData = fromData(callbackOptions);
- if (actualFromData === null || actualFromData === void 0) {
- continue;
- }
- if (typeof actualFromData !== "object") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: fromData callback function iteration(${index}) failed to return an object.`);
- }
- }
- if (hasToCallback) {
- actualToData = toData(callbackOptions);
- if (actualToData === null || actualToData === void 0) {
- continue;
- }
- if (typeof actualToData !== "object") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: toData callback function iteration(${index}) failed to return an object.`);
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (actualOptions === null || actualOptions === void 0) {
- continue;
- }
- if (typeof actualOptions !== "object") {
- throw new TypeError(`AnimationGroupAPI.fromTo error: options callback function iteration(${index}) failed to return an object.`);
- }
- }
- animationControls.push(actualPosition.animate.fromTo(actualFromData, actualToData, actualOptions));
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.fromTo warning: No Position instance found.`);
- return AnimationGroupControl.voidControl;
- }
- if (hasCallback) {
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- }
- if (hasFromCallback) {
- actualFromData = fromData(callbackOptions);
- if (typeof actualFromData !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.fromTo error: fromData callback function failed to return an object.`
- );
- }
- }
- if (hasToCallback) {
- actualToData = toData(callbackOptions);
- if (typeof actualToData !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.fromTo error: toData callback function failed to return an object.`
- );
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.fromTo error: options callback function failed to return an object.`
- );
- }
- }
- animationControls.push(actualPosition.animate.fromTo(actualFromData, actualToData, actualOptions));
- }
- return new AnimationGroupControl(animationControls);
- }
- /**
- * Provides the `to` animation tween for one or more Position instances as a group.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- *
- * @param {object|Function} toData -
- *
- * @param {object|Function} options -
- *
- * @returns {TJSBasicAnimation} Basic animation control.
- */
- static to(position, toData, options) {
- if (!isObject(toData) && typeof toData !== "function") {
- throw new TypeError(`AnimationGroupAPI.to error: 'toData' is not an object or function.`);
- }
- if (options !== void 0 && !isObject(options) && typeof options !== "function") {
- throw new TypeError(`AnimationGroupAPI.to error: 'options' is not an object or function.`);
- }
- const animationControls = [];
- let index = -1;
- let callbackOptions;
- const hasDataCallback = typeof toData === "function";
- const hasOptionCallback = typeof options === "function";
- const hasCallback = hasDataCallback || hasOptionCallback;
- if (hasCallback) {
- callbackOptions = { index, position: void 0, data: void 0 };
- }
- let actualToData = toData;
- let actualOptions = options;
- if (isIterable(position)) {
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.to warning: No Position instance found at index: ${index}.`);
- continue;
- }
- if (hasCallback) {
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- }
- if (hasDataCallback) {
- actualToData = toData(callbackOptions);
- if (actualToData === null || actualToData === void 0) {
- continue;
- }
- if (typeof actualToData !== "object") {
- throw new TypeError(`AnimationGroupAPI.to error: toData callback function iteration(${index}) failed to return an object.`);
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (actualOptions === null || actualOptions === void 0) {
- continue;
- }
- if (typeof actualOptions !== "object") {
- throw new TypeError(`AnimationGroupAPI.to error: options callback function iteration(${index}) failed to return an object.`);
- }
- }
- animationControls.push(actualPosition.animate.to(actualToData, actualOptions));
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.to warning: No Position instance found.`);
- return AnimationGroupControl.voidControl;
- }
- if (hasCallback) {
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- }
- if (hasDataCallback) {
- actualToData = toData(callbackOptions);
- if (typeof actualToData !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.to error: toData callback function failed to return an object.`
- );
- }
- }
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.to error: options callback function failed to return an object.`
- );
- }
- }
- animationControls.push(actualPosition.animate.to(actualToData, actualOptions));
- }
- return new AnimationGroupControl(animationControls);
- }
- /**
- * Provides the `to` animation tween for one or more Position instances as a group.
- *
- * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
- *
- * @param {Iterable<string>} keys -
- *
- * @param {object|Function} options -
- *
- * @returns {quickToCallback} Basic animation control.
- */
- static quickTo(position, keys, options) {
- if (!isIterable(keys)) {
- throw new TypeError(`AnimationGroupAPI.quickTo error: 'keys' is not an iterable list.`);
- }
- if (options !== void 0 && !isObject(options) && typeof options !== "function") {
- throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' is not an object or function.`);
- }
- const quickToCallbacks = [];
- let index = -1;
- const hasOptionCallback = typeof options === "function";
- const callbackOptions = { index, position: void 0, data: void 0 };
- let actualOptions = options;
- if (isIterable(position)) {
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.quickTo warning: No Position instance found at index: ${index}.`);
- continue;
- }
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (actualOptions === null || actualOptions === void 0) {
- continue;
- }
- if (typeof actualOptions !== "object") {
- throw new TypeError(`AnimationGroupAPI.quickTo error: options callback function iteration(${index}) failed to return an object.`);
- }
- }
- quickToCallbacks.push(actualPosition.animate.quickTo(keys, actualOptions));
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.quickTo warning: No Position instance found.`);
- return () => null;
- }
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- if (hasOptionCallback) {
- actualOptions = options(callbackOptions);
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.quickTo error: options callback function failed to return an object.`
- );
- }
- }
- quickToCallbacks.push(actualPosition.animate.quickTo(keys, actualOptions));
- }
- const keysArray = [...keys];
- Object.freeze(keysArray);
- const quickToCB = (...args) => {
- const argsLength = args.length;
- if (argsLength === 0) {
- return;
- }
- if (typeof args[0] === "function") {
- const dataCallback = args[0];
- index = -1;
- let cntr = 0;
- if (isIterable(position)) {
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- continue;
- }
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- const toData = dataCallback(callbackOptions);
- if (toData === null || toData === void 0) {
- continue;
- }
- const toDataIterable = isIterable(toData);
- if (!Number.isFinite(toData) && !toDataIterable && typeof toData !== "object") {
- throw new TypeError(`AnimationGroupAPI.quickTo error: toData callback function iteration(${index}) failed to return a finite number, iterable list, or object.`);
- }
- if (toDataIterable) {
- quickToCallbacks[cntr++](...toData);
- } else {
- quickToCallbacks[cntr++](toData);
- }
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- return;
- }
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- const toData = dataCallback(callbackOptions);
- if (toData === null || toData === void 0) {
- return;
- }
- const toDataIterable = isIterable(toData);
- if (!Number.isFinite(toData) && !toDataIterable && typeof toData !== "object") {
- throw new TypeError(`AnimationGroupAPI.quickTo error: toData callback function iteration(${index}) failed to return a finite number, iterable list, or object.`);
- }
- if (toDataIterable) {
- quickToCallbacks[cntr++](...toData);
- } else {
- quickToCallbacks[cntr++](toData);
- }
- }
- } else {
- for (let cntr = quickToCallbacks.length; --cntr >= 0; ) {
- quickToCallbacks[cntr](...args);
- }
- }
- };
- quickToCB.keys = keysArray;
- quickToCB.options = (options2) => {
- if (options2 !== void 0 && !isObject(options2) && typeof options2 !== "function") {
- throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' is not an object or function.`);
- }
- if (isObject(options2)) {
- for (let cntr = quickToCallbacks.length; --cntr >= 0; ) {
- quickToCallbacks[cntr].options(options2);
- }
- } else if (typeof options2 === "function") {
- if (isIterable(position)) {
- index = -1;
- let cntr = 0;
- for (const entry of position) {
- index++;
- const isPosition = this.#isPosition(entry);
- const actualPosition = isPosition ? entry : entry.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(
- `AnimationGroupAPI.quickTo.options warning: No Position instance found at index: ${index}.`
- );
- continue;
- }
- callbackOptions.index = index;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : entry;
- actualOptions = options2(callbackOptions);
- if (actualOptions === null || actualOptions === void 0) {
- continue;
- }
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.quickTo.options error: options callback function iteration(${index}) failed to return an object.`
- );
- }
- quickToCallbacks[cntr++].options(actualOptions);
- }
- } else {
- const isPosition = this.#isPosition(position);
- const actualPosition = isPosition ? position : position.position;
- if (!this.#isPosition(actualPosition)) {
- console.warn(`AnimationGroupAPI.quickTo.options warning: No Position instance found.`);
- return quickToCB;
- }
- callbackOptions.index = 0;
- callbackOptions.position = position;
- callbackOptions.data = isPosition ? void 0 : position;
- actualOptions = options2(callbackOptions);
- if (typeof actualOptions !== "object") {
- throw new TypeError(
- `AnimationGroupAPI.quickTo error: options callback function failed to return an object.`
- );
- }
- quickToCallbacks[0].options(actualOptions);
- }
- }
- return quickToCB;
- };
- return quickToCB;
- }
- }
- class Centered {
- /**
- * @type {HTMLElement}
- */
- #element;
- /**
- * Provides a manual setting of the element height. As things go `offsetHeight` causes a browser layout and is not
- * performance oriented. If manually set this height is used instead of `offsetHeight`.
- *
- * @type {number}
- */
- #height;
- /**
- * Set from an optional value in the constructor to lock accessors preventing modification.
- */
- #lock;
- /**
- * Provides a manual setting of the element width. As things go `offsetWidth` causes a browser layout and is not
- * performance oriented. If manually set this width is used instead of `offsetWidth`.
- *
- * @type {number}
- */
- #width;
- constructor({ element: element2, lock = false, width: width2, height } = {}) {
- this.element = element2;
- this.width = width2;
- this.height = height;
- this.#lock = typeof lock === "boolean" ? lock : false;
- }
- get element() {
- return this.#element;
- }
- get height() {
- return this.#height;
- }
- get width() {
- return this.#width;
- }
- set element(element2) {
- if (this.#lock) {
- return;
- }
- if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
- this.#element = element2;
- } else {
- throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
- }
- }
- set height(height) {
- if (this.#lock) {
- return;
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- set width(width2) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- }
- setDimension(width2, height) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- getLeft(width2) {
- const boundsWidth = this.#width ?? this.#element?.offsetWidth ?? globalThis.innerWidth;
- return (boundsWidth - width2) / 2;
- }
- getTop(height) {
- const boundsHeight = this.#height ?? this.#element?.offsetHeight ?? globalThis.innerHeight;
- return (boundsHeight - height) / 2;
- }
- }
- const browserCentered = new Centered();
- const positionInitial = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- Centered,
- browserCentered
- }, Symbol.toStringTag, { value: "Module" }));
- class PositionChangeSet {
- constructor() {
- this.left = false;
- this.top = false;
- this.width = false;
- this.height = false;
- this.maxHeight = false;
- this.maxWidth = false;
- this.minHeight = false;
- this.minWidth = false;
- this.zIndex = false;
- this.transform = false;
- this.transformOrigin = false;
- }
- hasChange() {
- return this.left || this.top || this.width || this.height || this.maxHeight || this.maxWidth || this.minHeight || this.minWidth || this.zIndex || this.transform || this.transformOrigin;
- }
- set(value) {
- this.left = value;
- this.top = value;
- this.width = value;
- this.height = value;
- this.maxHeight = value;
- this.maxWidth = value;
- this.minHeight = value;
- this.minWidth = value;
- this.zIndex = value;
- this.transform = value;
- this.transformOrigin = value;
- }
- }
- class PositionData {
- constructor({
- height = null,
- left = null,
- maxHeight = null,
- maxWidth = null,
- minHeight = null,
- minWidth = null,
- rotateX = null,
- rotateY = null,
- rotateZ = null,
- scale: scale2 = null,
- translateX = null,
- translateY = null,
- translateZ = null,
- top = null,
- transformOrigin = null,
- width: width2 = null,
- zIndex = null
- } = {}) {
- this.height = height;
- this.left = left;
- this.maxHeight = maxHeight;
- this.maxWidth = maxWidth;
- this.minHeight = minHeight;
- this.minWidth = minWidth;
- this.rotateX = rotateX;
- this.rotateY = rotateY;
- this.rotateZ = rotateZ;
- this.scale = scale2;
- this.top = top;
- this.transformOrigin = transformOrigin;
- this.translateX = translateX;
- this.translateY = translateY;
- this.translateZ = translateZ;
- this.width = width2;
- this.zIndex = zIndex;
- Object.seal(this);
- }
- /**
- * Copies given data to this instance.
- *
- * @param {PositionData} data - Copy from this instance.
- *
- * @returns {PositionData} This instance.
- */
- copy(data) {
- this.height = data.height;
- this.left = data.left;
- this.maxHeight = data.maxHeight;
- this.maxWidth = data.maxWidth;
- this.minHeight = data.minHeight;
- this.minWidth = data.minWidth;
- this.rotateX = data.rotateX;
- this.rotateY = data.rotateY;
- this.rotateZ = data.rotateZ;
- this.scale = data.scale;
- this.top = data.top;
- this.transformOrigin = data.transformOrigin;
- this.translateX = data.translateX;
- this.translateY = data.translateY;
- this.translateZ = data.translateZ;
- this.width = data.width;
- this.zIndex = data.zIndex;
- return this;
- }
- }
- class PositionStateAPI {
- /** @type {PositionData} */
- #data;
- /**
- * @type {Map<string, PositionDataExtended>}
- */
- #dataSaved = /* @__PURE__ */ new Map();
- /** @type {Position} */
- #position;
- /** @type {Transforms} */
- #transforms;
- constructor(position, data, transforms) {
- this.#position = position;
- this.#data = data;
- this.#transforms = transforms;
- }
- /**
- * Returns any stored save state by name.
- *
- * @param {string} name - Saved data set name.
- *
- * @returns {PositionDataExtended} The saved data set.
- */
- get({ name }) {
- if (typeof name !== "string") {
- throw new TypeError(`Position - getSave error: 'name' is not a string.`);
- }
- return this.#dataSaved.get(name);
- }
- /**
- * Returns any associated default data.
- *
- * @returns {PositionDataExtended} Associated default data.
- */
- getDefault() {
- return this.#dataSaved.get("#defaultData");
- }
- /**
- * Removes and returns any position state by name.
- *
- * @param {object} options - Options.
- *
- * @param {string} options.name - Name to remove and retrieve.
- *
- * @returns {PositionDataExtended} Saved position data.
- */
- remove({ name }) {
- if (typeof name !== "string") {
- throw new TypeError(`Position - remove: 'name' is not a string.`);
- }
- const data = this.#dataSaved.get(name);
- this.#dataSaved.delete(name);
- return data;
- }
- /**
- * Resets data to default values and invokes set.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {boolean} [opts.keepZIndex=false] - When true keeps current z-index.
- *
- * @param {boolean} [opts.invokeSet=true] - When true invokes set method.
- *
- * @returns {boolean} Operation successful.
- */
- reset({ keepZIndex = false, invokeSet = true } = {}) {
- const defaultData = this.#dataSaved.get("#defaultData");
- if (typeof defaultData !== "object") {
- return false;
- }
- if (this.#position.animate.isScheduled) {
- this.#position.animate.cancel();
- }
- const zIndex = this.#position.zIndex;
- const data = Object.assign({}, defaultData);
- if (keepZIndex) {
- data.zIndex = zIndex;
- }
- this.#transforms.reset(data);
- if (this.#position.parent?.reactive?.minimized) {
- this.#position.parent?.maximize?.({ animate: false, duration: 0 });
- }
- if (invokeSet) {
- setTimeout(() => this.#position.set(data), 0);
- }
- return true;
- }
- /**
- * Restores a saved positional state returning the data. Several optional parameters are available
- * to control whether the restore action occurs silently (no store / inline styles updates), animates
- * to the stored data, or simply sets the stored data. Restoring via {@link AnimationAPI.to} allows
- * specification of the duration, easing, and interpolate functions along with configuring a Promise to be
- * returned if awaiting the end of the animation.
- *
- * @param {object} params - Parameters
- *
- * @param {string} params.name - Saved data set name.
- *
- * @param {boolean} [params.remove=false] - Remove data set.
- *
- * @param {Iterable<string>} [params.properties] - Specific properties to set / animate.
- *
- * @param {boolean} [params.silent] - Set position data directly; no store or style updates.
- *
- * @param {boolean} [params.async=false] - If animating return a Promise that resolves with any saved data.
- *
- * @param {boolean} [params.animateTo=false] - Animate to restore data.
- *
- * @param {number} [params.duration=0.1] - Duration in seconds.
- *
- * @param {Function} [params.ease=linear] - Easing function.
- *
- * @param {Function} [params.interpolate=lerp] - Interpolation function.
- *
- * @returns {PositionDataExtended|Promise<PositionDataExtended>} Saved position data.
- */
- restore({
- name,
- remove = false,
- properties,
- silent = false,
- async = false,
- animateTo = false,
- duration = 0.1,
- ease = identity,
- interpolate: interpolate2 = lerp$5
- }) {
- if (typeof name !== "string") {
- throw new TypeError(`Position - restore error: 'name' is not a string.`);
- }
- const dataSaved = this.#dataSaved.get(name);
- if (dataSaved) {
- if (remove) {
- this.#dataSaved.delete(name);
- }
- let data = dataSaved;
- if (isIterable(properties)) {
- data = {};
- for (const property of properties) {
- data[property] = dataSaved[property];
- }
- }
- if (silent) {
- for (const property in data) {
- this.#data[property] = data[property];
- }
- return dataSaved;
- } else if (animateTo) {
- if (data.transformOrigin !== this.#position.transformOrigin) {
- this.#position.transformOrigin = data.transformOrigin;
- }
- if (async) {
- return this.#position.animate.to(data, { duration, ease, interpolate: interpolate2 }).finished.then(() => dataSaved);
- } else {
- this.#position.animate.to(data, { duration, ease, interpolate: interpolate2 });
- }
- } else {
- this.#position.set(data);
- }
- }
- return dataSaved;
- }
- /**
- * Saves current position state with the opportunity to add extra data to the saved state.
- *
- * @param {object} opts - Options.
- *
- * @param {string} opts.name - name to index this saved data.
- *
- * @param {...*} [opts.extra] - Extra data to add to saved data.
- *
- * @returns {PositionData} Current position data
- */
- save({ name, ...extra }) {
- if (typeof name !== "string") {
- throw new TypeError(`Position - save error: 'name' is not a string.`);
- }
- const data = this.#position.get(extra);
- this.#dataSaved.set(name, data);
- return data;
- }
- /**
- * Directly sets a position state.
- *
- * @param {object} opts - Options.
- *
- * @param {string} opts.name - name to index this saved data.
- *
- * @param {...*} [opts.data] - Position data to set.
- */
- set({ name, ...data }) {
- if (typeof name !== "string") {
- throw new TypeError(`Position - set error: 'name' is not a string.`);
- }
- this.#dataSaved.set(name, data);
- }
- }
- class StyleCache {
- constructor() {
- this.el = void 0;
- this.computed = void 0;
- this.marginLeft = void 0;
- this.marginTop = void 0;
- this.maxHeight = void 0;
- this.maxWidth = void 0;
- this.minHeight = void 0;
- this.minWidth = void 0;
- this.hasWillChange = false;
- this.resizeObserved = {
- contentHeight: void 0,
- contentWidth: void 0,
- offsetHeight: void 0,
- offsetWidth: void 0
- };
- const storeResizeObserved = writable$1(this.resizeObserved);
- this.stores = {
- element: writable$1(this.el),
- resizeContentHeight: propertyStore(storeResizeObserved, "contentHeight"),
- resizeContentWidth: propertyStore(storeResizeObserved, "contentWidth"),
- resizeObserved: storeResizeObserved,
- resizeOffsetHeight: propertyStore(storeResizeObserved, "offsetHeight"),
- resizeOffsetWidth: propertyStore(storeResizeObserved, "offsetWidth")
- };
- }
- /**
- * Returns the cached offsetHeight from any attached `resizeObserver` action otherwise gets the offsetHeight from
- * the element directly. The more optimized path is using `resizeObserver` as getting it from the element
- * directly is more expensive and alters the execution order of an animation frame.
- *
- * @returns {number} The element offsetHeight.
- */
- get offsetHeight() {
- if (this.el instanceof HTMLElement) {
- return this.resizeObserved.offsetHeight !== void 0 ? this.resizeObserved.offsetHeight : this.el.offsetHeight;
- }
- throw new Error(`StyleCache - get offsetHeight error: no element assigned.`);
- }
- /**
- * Returns the cached offsetWidth from any attached `resizeObserver` action otherwise gets the offsetWidth from
- * the element directly. The more optimized path is using `resizeObserver` as getting it from the element
- * directly is more expensive and alters the execution order of an animation frame.
- *
- * @returns {number} The element offsetHeight.
- */
- get offsetWidth() {
- if (this.el instanceof HTMLElement) {
- return this.resizeObserved.offsetWidth !== void 0 ? this.resizeObserved.offsetWidth : this.el.offsetWidth;
- }
- throw new Error(`StyleCache - get offsetWidth error: no element assigned.`);
- }
- /**
- * @param {HTMLElement} el -
- *
- * @returns {boolean} Does element match cached element.
- */
- hasData(el) {
- return this.el === el;
- }
- /**
- * Resets the style cache.
- */
- reset() {
- if (this.el instanceof HTMLElement && this.el.isConnected && !this.hasWillChange) {
- this.el.style.willChange = null;
- }
- this.el = void 0;
- this.computed = void 0;
- this.marginLeft = void 0;
- this.marginTop = void 0;
- this.maxHeight = void 0;
- this.maxWidth = void 0;
- this.minHeight = void 0;
- this.minWidth = void 0;
- this.hasWillChange = false;
- this.resizeObserved.contentHeight = void 0;
- this.resizeObserved.contentWidth = void 0;
- this.resizeObserved.offsetHeight = void 0;
- this.resizeObserved.offsetWidth = void 0;
- this.stores.element.set(void 0);
- }
- /**
- * Updates the style cache with new data from the given element.
- *
- * @param {HTMLElement} el - An HTML element.
- */
- update(el) {
- this.el = el;
- this.computed = globalThis.getComputedStyle(el);
- this.marginLeft = styleParsePixels(el.style.marginLeft) ?? styleParsePixels(this.computed.marginLeft);
- this.marginTop = styleParsePixels(el.style.marginTop) ?? styleParsePixels(this.computed.marginTop);
- this.maxHeight = styleParsePixels(el.style.maxHeight) ?? styleParsePixels(this.computed.maxHeight);
- this.maxWidth = styleParsePixels(el.style.maxWidth) ?? styleParsePixels(this.computed.maxWidth);
- this.minHeight = styleParsePixels(el.style.minHeight) ?? styleParsePixels(this.computed.minHeight);
- this.minWidth = styleParsePixels(el.style.minWidth) ?? styleParsePixels(this.computed.minWidth);
- const willChange = el.style.willChange !== "" ? el.style.willChange : this.computed.willChange;
- this.hasWillChange = willChange !== "" && willChange !== "auto";
- this.stores.element.set(el);
- }
- }
- class TransformData {
- constructor() {
- Object.seal(this);
- }
- /**
- * Stores the calculated bounding rectangle.
- *
- * @type {DOMRect}
- */
- #boundingRect = new DOMRect();
- /**
- * Stores the individual transformed corner points of the window in screenspace clockwise from:
- * top left -> top right -> bottom right -> bottom left.
- *
- * @type {Vector3[]}
- */
- #corners = [vec3.create(), vec3.create(), vec3.create(), vec3.create()];
- /**
- * Stores the current gl-matrix mat4 data.
- *
- * @type {Matrix4}
- */
- #mat4 = mat4.create();
- /**
- * Stores the pre & post origin translations to apply to matrix transforms.
- *
- * @type {Matrix4[]}
- */
- #originTranslations = [mat4.create(), mat4.create()];
- /**
- * @returns {DOMRect} The bounding rectangle.
- */
- get boundingRect() {
- return this.#boundingRect;
- }
- /**
- * @returns {Vector3[]} The transformed corner points as vec3 in screen space.
- */
- get corners() {
- return this.#corners;
- }
- /**
- * @returns {string} Returns the CSS style string for the transform matrix.
- */
- get css() {
- return `matrix3d(${this.mat4.join(",")})`;
- }
- /**
- * @returns {Matrix4} The transform matrix.
- */
- get mat4() {
- return this.#mat4;
- }
- /**
- * @returns {Matrix4[]} The pre / post translation matrices for origin translation.
- */
- get originTranslations() {
- return this.#originTranslations;
- }
- }
- class AdapterValidators {
- /** @type {boolean} */
- #enabled = true;
- /**
- * @type {ValidatorData[]}
- */
- #validatorData;
- #mapUnsubscribe = /* @__PURE__ */ new Map();
- /**
- * @returns {[AdapterValidators, ValidatorData[]]} Returns this and internal storage for validator adapter.
- */
- constructor() {
- this.#validatorData = [];
- Object.seal(this);
- return [this, this.#validatorData];
- }
- /**
- * @returns {boolean} Returns the enabled state.s
- */
- get enabled() {
- return this.#enabled;
- }
- /**
- * @returns {number} Returns the length of the validators array.
- */
- get length() {
- return this.#validatorData.length;
- }
- /**
- * @param {boolean} enabled - Sets enabled state.
- */
- set enabled(enabled) {
- if (typeof enabled !== "boolean") {
- throw new TypeError(`'enabled' is not a boolean.`);
- }
- this.#enabled = enabled;
- }
- /**
- * Provides an iterator for validators.
- *
- * @returns {Generator<ValidatorData|undefined>} Generator / iterator of validators.
- * @yields {ValidatorData}
- */
- *[Symbol.iterator]() {
- if (this.#validatorData.length === 0) {
- return;
- }
- for (const entry of this.#validatorData) {
- yield { ...entry };
- }
- }
- /**
- * @param {...(ValidatorFn|ValidatorData)} validators -
- */
- add(...validators) {
- for (const validator of validators) {
- const validatorType = typeof validator;
- if (validatorType !== "function" && validatorType !== "object" || validator === null) {
- throw new TypeError(`AdapterValidator error: 'validator' is not a function or object.`);
- }
- let data = void 0;
- let subscribeFn = void 0;
- switch (validatorType) {
- case "function":
- data = {
- id: void 0,
- validator,
- weight: 1
- };
- subscribeFn = validator.subscribe;
- break;
- case "object":
- if (typeof validator.validator !== "function") {
- throw new TypeError(`AdapterValidator error: 'validator' attribute is not a function.`);
- }
- if (validator.weight !== void 0 && typeof validator.weight !== "number" || (validator.weight < 0 || validator.weight > 1)) {
- throw new TypeError(
- `AdapterValidator error: 'weight' attribute is not a number between '0 - 1' inclusive.`
- );
- }
- data = {
- id: validator.id !== void 0 ? validator.id : void 0,
- validator: validator.validator.bind(validator),
- weight: validator.weight || 1,
- instance: validator
- };
- subscribeFn = validator.validator.subscribe ?? validator.subscribe;
- break;
- }
- const index = this.#validatorData.findIndex((value) => {
- return data.weight < value.weight;
- });
- if (index >= 0) {
- this.#validatorData.splice(index, 0, data);
- } else {
- this.#validatorData.push(data);
- }
- if (typeof subscribeFn === "function") {
- const unsubscribe = subscribeFn();
- if (typeof unsubscribe !== "function") {
- throw new TypeError(
- "AdapterValidator error: Filter has subscribe function, but no unsubscribe function is returned."
- );
- }
- if (this.#mapUnsubscribe.has(data.validator)) {
- throw new Error(
- "AdapterValidator error: Filter added already has an unsubscribe function registered."
- );
- }
- this.#mapUnsubscribe.set(data.validator, unsubscribe);
- }
- }
- }
- clear() {
- this.#validatorData.length = 0;
- for (const unsubscribe of this.#mapUnsubscribe.values()) {
- unsubscribe();
- }
- this.#mapUnsubscribe.clear();
- }
- /**
- * @param {...(ValidatorFn|ValidatorData)} validators -
- */
- remove(...validators) {
- const length = this.#validatorData.length;
- if (length === 0) {
- return;
- }
- for (const data of validators) {
- const actualValidator = typeof data === "function" ? data : isObject(data) ? data.validator : void 0;
- if (!actualValidator) {
- continue;
- }
- for (let cntr = this.#validatorData.length; --cntr >= 0; ) {
- if (this.#validatorData[cntr].validator === actualValidator) {
- this.#validatorData.splice(cntr, 1);
- let unsubscribe = void 0;
- if (typeof (unsubscribe = this.#mapUnsubscribe.get(actualValidator)) === "function") {
- unsubscribe();
- this.#mapUnsubscribe.delete(actualValidator);
- }
- }
- }
- }
- }
- /**
- * Remove validators by the provided callback. The callback takes 3 parameters: `id`, `validator`, and `weight`.
- * Any truthy value returned will remove that validator.
- *
- * @param {function(*, ValidatorFn, number): boolean} callback - Callback function to evaluate each validator
- * entry.
- */
- removeBy(callback) {
- const length = this.#validatorData.length;
- if (length === 0) {
- return;
- }
- if (typeof callback !== "function") {
- throw new TypeError(`AdapterValidator error: 'callback' is not a function.`);
- }
- this.#validatorData = this.#validatorData.filter((data) => {
- const remove = callback.call(callback, { ...data });
- if (remove) {
- let unsubscribe;
- if (typeof (unsubscribe = this.#mapUnsubscribe.get(data.validator)) === "function") {
- unsubscribe();
- this.#mapUnsubscribe.delete(data.validator);
- }
- }
- return !remove;
- });
- }
- removeById(...ids) {
- const length = this.#validatorData.length;
- if (length === 0) {
- return;
- }
- this.#validatorData = this.#validatorData.filter((data) => {
- let remove = false;
- for (const id of ids) {
- remove |= data.id === id;
- }
- if (remove) {
- let unsubscribe;
- if (typeof (unsubscribe = this.#mapUnsubscribe.get(data.validator)) === "function") {
- unsubscribe();
- this.#mapUnsubscribe.delete(data.validator);
- }
- }
- return !remove;
- });
- }
- }
- class BasicBounds {
- /**
- * When true constrains the min / max width or height to element.
- *
- * @type {boolean}
- */
- #constrain;
- /**
- * @type {HTMLElement}
- */
- #element;
- /**
- * When true the validator is active.
- *
- * @type {boolean}
- */
- #enabled;
- /**
- * Provides a manual setting of the element height. As things go `offsetHeight` causes a browser layout and is not
- * performance oriented. If manually set this height is used instead of `offsetHeight`.
- *
- * @type {number}
- */
- #height;
- /**
- * Set from an optional value in the constructor to lock accessors preventing modification.
- */
- #lock;
- /**
- * Provides a manual setting of the element width. As things go `offsetWidth` causes a browser layout and is not
- * performance oriented. If manually set this width is used instead of `offsetWidth`.
- *
- * @type {number}
- */
- #width;
- constructor({ constrain = true, element: element2, enabled = true, lock = false, width: width2, height } = {}) {
- this.element = element2;
- this.constrain = constrain;
- this.enabled = enabled;
- this.width = width2;
- this.height = height;
- this.#lock = typeof lock === "boolean" ? lock : false;
- }
- get constrain() {
- return this.#constrain;
- }
- get element() {
- return this.#element;
- }
- get enabled() {
- return this.#enabled;
- }
- get height() {
- return this.#height;
- }
- get width() {
- return this.#width;
- }
- set constrain(constrain) {
- if (this.#lock) {
- return;
- }
- if (typeof constrain !== "boolean") {
- throw new TypeError(`'constrain' is not a boolean.`);
- }
- this.#constrain = constrain;
- }
- set element(element2) {
- if (this.#lock) {
- return;
- }
- if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
- this.#element = element2;
- } else {
- throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
- }
- }
- set enabled(enabled) {
- if (this.#lock) {
- return;
- }
- if (typeof enabled !== "boolean") {
- throw new TypeError(`'enabled' is not a boolean.`);
- }
- this.#enabled = enabled;
- }
- set height(height) {
- if (this.#lock) {
- return;
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- set width(width2) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- }
- setDimension(width2, height) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- /**
- * Provides a validator that respects transforms in positional data constraining the position to within the target
- * elements bounds.
- *
- * @param {ValidationData} valData - The associated validation data for position updates.
- *
- * @returns {PositionData} Potentially adjusted position data.
- */
- validator(valData) {
- if (!this.#enabled) {
- return valData.position;
- }
- const boundsWidth = this.#width ?? this.#element?.offsetWidth ?? globalThis.innerWidth;
- const boundsHeight = this.#height ?? this.#element?.offsetHeight ?? globalThis.innerHeight;
- if (typeof valData.position.width === "number") {
- const maxW = valData.maxWidth ?? (this.#constrain ? boundsWidth : Number.MAX_SAFE_INTEGER);
- valData.position.width = valData.width = Math.clamped(valData.position.width, valData.minWidth, maxW);
- if (valData.width + valData.position.left + valData.marginLeft > boundsWidth) {
- valData.position.left = boundsWidth - valData.width - valData.marginLeft;
- }
- }
- if (typeof valData.position.height === "number") {
- const maxH = valData.maxHeight ?? (this.#constrain ? boundsHeight : Number.MAX_SAFE_INTEGER);
- valData.position.height = valData.height = Math.clamped(valData.position.height, valData.minHeight, maxH);
- if (valData.height + valData.position.top + valData.marginTop > boundsHeight) {
- valData.position.top = boundsHeight - valData.height - valData.marginTop;
- }
- }
- const maxL = Math.max(boundsWidth - valData.width - valData.marginLeft, 0);
- valData.position.left = Math.round(Math.clamped(valData.position.left, 0, maxL));
- const maxT = Math.max(boundsHeight - valData.height - valData.marginTop, 0);
- valData.position.top = Math.round(Math.clamped(valData.position.top, 0, maxT));
- return valData.position;
- }
- }
- const s_TRANSFORM_DATA = new TransformData();
- class TransformBounds {
- /**
- * When true constrains the min / max width or height to element.
- *
- * @type {boolean}
- */
- #constrain;
- /**
- * @type {HTMLElement}
- */
- #element;
- /**
- * When true the validator is active.
- *
- * @type {boolean}
- */
- #enabled;
- /**
- * Provides a manual setting of the element height. As things go `offsetHeight` causes a browser layout and is not
- * performance oriented. If manually set this height is used instead of `offsetHeight`.
- *
- * @type {number}
- */
- #height;
- /**
- * Set from an optional value in the constructor to lock accessors preventing modification.
- */
- #lock;
- /**
- * Provides a manual setting of the element width. As things go `offsetWidth` causes a browser layout and is not
- * performance oriented. If manually set this width is used instead of `offsetWidth`.
- *
- * @type {number}
- */
- #width;
- constructor({ constrain = true, element: element2, enabled = true, lock = false, width: width2, height } = {}) {
- this.element = element2;
- this.constrain = constrain;
- this.enabled = enabled;
- this.width = width2;
- this.height = height;
- this.#lock = typeof lock === "boolean" ? lock : false;
- }
- get constrain() {
- return this.#constrain;
- }
- get element() {
- return this.#element;
- }
- get enabled() {
- return this.#enabled;
- }
- get height() {
- return this.#height;
- }
- get width() {
- return this.#width;
- }
- set constrain(constrain) {
- if (this.#lock) {
- return;
- }
- if (typeof constrain !== "boolean") {
- throw new TypeError(`'constrain' is not a boolean.`);
- }
- this.#constrain = constrain;
- }
- set element(element2) {
- if (this.#lock) {
- return;
- }
- if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
- this.#element = element2;
- } else {
- throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
- }
- }
- set enabled(enabled) {
- if (this.#lock) {
- return;
- }
- if (typeof enabled !== "boolean") {
- throw new TypeError(`'enabled' is not a boolean.`);
- }
- this.#enabled = enabled;
- }
- set height(height) {
- if (this.#lock) {
- return;
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- set width(width2) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- }
- setDimension(width2, height) {
- if (this.#lock) {
- return;
- }
- if (width2 === void 0 || Number.isFinite(width2)) {
- this.#width = width2;
- } else {
- throw new TypeError(`'width' is not a finite number or undefined.`);
- }
- if (height === void 0 || Number.isFinite(height)) {
- this.#height = height;
- } else {
- throw new TypeError(`'height' is not a finite number or undefined.`);
- }
- }
- /**
- * Provides a validator that respects transforms in positional data constraining the position to within the target
- * elements bounds.
- *
- * @param {ValidationData} valData - The associated validation data for position updates.
- *
- * @returns {PositionData} Potentially adjusted position data.
- */
- validator(valData) {
- if (!this.#enabled) {
- return valData.position;
- }
- const boundsWidth = this.#width ?? this.#element?.offsetWidth ?? globalThis.innerWidth;
- const boundsHeight = this.#height ?? this.#element?.offsetHeight ?? globalThis.innerHeight;
- if (typeof valData.position.width === "number") {
- const maxW = valData.maxWidth ?? (this.#constrain ? boundsWidth : Number.MAX_SAFE_INTEGER);
- valData.position.width = Math.clamped(valData.width, valData.minWidth, maxW);
- }
- if (typeof valData.position.height === "number") {
- const maxH = valData.maxHeight ?? (this.#constrain ? boundsHeight : Number.MAX_SAFE_INTEGER);
- valData.position.height = Math.clamped(valData.height, valData.minHeight, maxH);
- }
- const data = valData.transforms.getData(valData.position, s_TRANSFORM_DATA, valData);
- const initialX = data.boundingRect.x;
- const initialY = data.boundingRect.y;
- if (data.boundingRect.bottom + valData.marginTop > boundsHeight) {
- data.boundingRect.y += boundsHeight - data.boundingRect.bottom - valData.marginTop;
- }
- if (data.boundingRect.right + valData.marginLeft > boundsWidth) {
- data.boundingRect.x += boundsWidth - data.boundingRect.right - valData.marginLeft;
- }
- if (data.boundingRect.top - valData.marginTop < 0) {
- data.boundingRect.y += Math.abs(data.boundingRect.top - valData.marginTop);
- }
- if (data.boundingRect.left - valData.marginLeft < 0) {
- data.boundingRect.x += Math.abs(data.boundingRect.left - valData.marginLeft);
- }
- valData.position.left -= initialX - data.boundingRect.x;
- valData.position.top -= initialY - data.boundingRect.y;
- return valData.position;
- }
- }
- const basicWindow = new BasicBounds({ lock: true });
- const transformWindow = new TransformBounds({ lock: true });
- const positionValidators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- BasicBounds,
- TransformBounds,
- basicWindow,
- transformWindow
- }, Symbol.toStringTag, { value: "Module" }));
- const s_SCALE_VECTOR = [1, 1, 1];
- const s_TRANSLATE_VECTOR = [0, 0, 0];
- const s_MAT4_RESULT = mat4.create();
- const s_MAT4_TEMP = mat4.create();
- const s_VEC3_TEMP = vec3.create();
- class Transforms {
- /**
- * Stores the transform keys in the order added.
- *
- * @type {string[]}
- */
- #orderList = [];
- constructor() {
- this._data = {};
- }
- /**
- * @returns {boolean} Whether there are active transforms in local data.
- */
- get isActive() {
- return this.#orderList.length > 0;
- }
- /**
- * @returns {number|undefined} Any local rotateX data.
- */
- get rotateX() {
- return this._data.rotateX;
- }
- /**
- * @returns {number|undefined} Any local rotateY data.
- */
- get rotateY() {
- return this._data.rotateY;
- }
- /**
- * @returns {number|undefined} Any local rotateZ data.
- */
- get rotateZ() {
- return this._data.rotateZ;
- }
- /**
- * @returns {number|undefined} Any local rotateZ scale.
- */
- get scale() {
- return this._data.scale;
- }
- /**
- * @returns {number|undefined} Any local translateZ data.
- */
- get translateX() {
- return this._data.translateX;
- }
- /**
- * @returns {number|undefined} Any local translateZ data.
- */
- get translateY() {
- return this._data.translateY;
- }
- /**
- * @returns {number|undefined} Any local translateZ data.
- */
- get translateZ() {
- return this._data.translateZ;
- }
- /**
- * Sets the local rotateX data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set rotateX(value) {
- if (Number.isFinite(value)) {
- if (this._data.rotateX === void 0) {
- this.#orderList.push("rotateX");
- }
- this._data.rotateX = value;
- } else {
- if (this._data.rotateX !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "rotateX");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.rotateX;
- }
- }
- /**
- * Sets the local rotateY data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set rotateY(value) {
- if (Number.isFinite(value)) {
- if (this._data.rotateY === void 0) {
- this.#orderList.push("rotateY");
- }
- this._data.rotateY = value;
- } else {
- if (this._data.rotateY !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "rotateY");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.rotateY;
- }
- }
- /**
- * Sets the local rotateZ data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set rotateZ(value) {
- if (Number.isFinite(value)) {
- if (this._data.rotateZ === void 0) {
- this.#orderList.push("rotateZ");
- }
- this._data.rotateZ = value;
- } else {
- if (this._data.rotateZ !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "rotateZ");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.rotateZ;
- }
- }
- /**
- * Sets the local scale data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set scale(value) {
- if (Number.isFinite(value)) {
- if (this._data.scale === void 0) {
- this.#orderList.push("scale");
- }
- this._data.scale = value;
- } else {
- if (this._data.scale !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "scale");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.scale;
- }
- }
- /**
- * Sets the local translateX data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set translateX(value) {
- if (Number.isFinite(value)) {
- if (this._data.translateX === void 0) {
- this.#orderList.push("translateX");
- }
- this._data.translateX = value;
- } else {
- if (this._data.translateX !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "translateX");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.translateX;
- }
- }
- /**
- * Sets the local translateY data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set translateY(value) {
- if (Number.isFinite(value)) {
- if (this._data.translateY === void 0) {
- this.#orderList.push("translateY");
- }
- this._data.translateY = value;
- } else {
- if (this._data.translateY !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "translateY");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.translateY;
- }
- }
- /**
- * Sets the local translateZ data if the value is a finite number otherwise removes the local data.
- *
- * @param {number|null|undefined} value - A value to set.
- */
- set translateZ(value) {
- if (Number.isFinite(value)) {
- if (this._data.translateZ === void 0) {
- this.#orderList.push("translateZ");
- }
- this._data.translateZ = value;
- } else {
- if (this._data.translateZ !== void 0) {
- const index = this.#orderList.findIndex((entry) => entry === "translateZ");
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- }
- delete this._data.translateZ;
- }
- }
- /**
- * Returns the matrix3d CSS transform for the given position / transform data.
- *
- * @param {object} [data] - Optional position data otherwise use local stored transform data.
- *
- * @returns {string} The CSS matrix3d string.
- */
- getCSS(data = this._data) {
- return `matrix3d(${this.getMat4(data, s_MAT4_RESULT).join(",")})`;
- }
- /**
- * Returns the matrix3d CSS transform for the given position / transform data.
- *
- * @param {object} [data] - Optional position data otherwise use local stored transform data.
- *
- * @returns {string} The CSS matrix3d string.
- */
- getCSSOrtho(data = this._data) {
- return `matrix3d(${this.getMat4Ortho(data, s_MAT4_RESULT).join(",")})`;
- }
- /**
- * Collects all data including a bounding rect, transform matrix, and points array of the given {@link PositionData}
- * instance with the applied local transform data.
- *
- * @param {PositionData} position - The position data to process.
- *
- * @param {TransformData} [output] - Optional TransformData output instance.
- *
- * @param {object} [validationData] - Optional validation data for adjustment parameters.
- *
- * @returns {TransformData} The output TransformData instance.
- */
- getData(position, output = new TransformData(), validationData = {}) {
- const valWidth = validationData.width ?? 0;
- const valHeight = validationData.height ?? 0;
- const valOffsetTop = validationData.offsetTop ?? validationData.marginTop ?? 0;
- const valOffsetLeft = validationData.offsetLeft ?? validationData.offsetLeft ?? 0;
- position.top += valOffsetTop;
- position.left += valOffsetLeft;
- const width2 = Number.isFinite(position.width) ? position.width : valWidth;
- const height = Number.isFinite(position.height) ? position.height : valHeight;
- const rect = output.corners;
- if (this.hasTransform(position)) {
- rect[0][0] = rect[0][1] = rect[0][2] = 0;
- rect[1][0] = width2;
- rect[1][1] = rect[1][2] = 0;
- rect[2][0] = width2;
- rect[2][1] = height;
- rect[2][2] = 0;
- rect[3][0] = 0;
- rect[3][1] = height;
- rect[3][2] = 0;
- const matrix = this.getMat4(position, output.mat4);
- const translate = s_GET_ORIGIN_TRANSLATION(position.transformOrigin, width2, height, output.originTranslations);
- if (transformOriginDefault === position.transformOrigin) {
- vec3.transformMat4(rect[0], rect[0], matrix);
- vec3.transformMat4(rect[1], rect[1], matrix);
- vec3.transformMat4(rect[2], rect[2], matrix);
- vec3.transformMat4(rect[3], rect[3], matrix);
- } else {
- vec3.transformMat4(rect[0], rect[0], translate[0]);
- vec3.transformMat4(rect[0], rect[0], matrix);
- vec3.transformMat4(rect[0], rect[0], translate[1]);
- vec3.transformMat4(rect[1], rect[1], translate[0]);
- vec3.transformMat4(rect[1], rect[1], matrix);
- vec3.transformMat4(rect[1], rect[1], translate[1]);
- vec3.transformMat4(rect[2], rect[2], translate[0]);
- vec3.transformMat4(rect[2], rect[2], matrix);
- vec3.transformMat4(rect[2], rect[2], translate[1]);
- vec3.transformMat4(rect[3], rect[3], translate[0]);
- vec3.transformMat4(rect[3], rect[3], matrix);
- vec3.transformMat4(rect[3], rect[3], translate[1]);
- }
- rect[0][0] = position.left + rect[0][0];
- rect[0][1] = position.top + rect[0][1];
- rect[1][0] = position.left + rect[1][0];
- rect[1][1] = position.top + rect[1][1];
- rect[2][0] = position.left + rect[2][0];
- rect[2][1] = position.top + rect[2][1];
- rect[3][0] = position.left + rect[3][0];
- rect[3][1] = position.top + rect[3][1];
- } else {
- rect[0][0] = position.left;
- rect[0][1] = position.top;
- rect[1][0] = position.left + width2;
- rect[1][1] = position.top;
- rect[2][0] = position.left + width2;
- rect[2][1] = position.top + height;
- rect[3][0] = position.left;
- rect[3][1] = position.top + height;
- mat4.identity(output.mat4);
- }
- let maxX = Number.MIN_SAFE_INTEGER;
- let maxY = Number.MIN_SAFE_INTEGER;
- let minX = Number.MAX_SAFE_INTEGER;
- let minY = Number.MAX_SAFE_INTEGER;
- for (let cntr = 4; --cntr >= 0; ) {
- if (rect[cntr][0] > maxX) {
- maxX = rect[cntr][0];
- }
- if (rect[cntr][0] < minX) {
- minX = rect[cntr][0];
- }
- if (rect[cntr][1] > maxY) {
- maxY = rect[cntr][1];
- }
- if (rect[cntr][1] < minY) {
- minY = rect[cntr][1];
- }
- }
- const boundingRect = output.boundingRect;
- boundingRect.x = minX;
- boundingRect.y = minY;
- boundingRect.width = maxX - minX;
- boundingRect.height = maxY - minY;
- position.top -= valOffsetTop;
- position.left -= valOffsetLeft;
- return output;
- }
- /**
- * Creates a transform matrix based on local data applied in order it was added.
- *
- * If no data object is provided then the source is the local transform data. If another data object is supplied
- * then the stored local transform order is applied then all remaining transform keys are applied. This allows the
- * construction of a transform matrix in advance of setting local data and is useful in collision detection.
- *
- * @param {object} [data] - PositionData instance or local transform data.
- *
- * @param {Matrix4} [output] - The output mat4 instance.
- *
- * @returns {Matrix4} Transform matrix.
- */
- getMat4(data = this._data, output = mat4.create()) {
- const matrix = mat4.identity(output);
- let seenKeys = 0;
- const orderList = this.#orderList;
- for (let cntr = 0; cntr < orderList.length; cntr++) {
- const key = orderList[cntr];
- switch (key) {
- case "rotateX":
- seenKeys |= transformKeysBitwise.rotateX;
- mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateY":
- seenKeys |= transformKeysBitwise.rotateY;
- mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateZ":
- seenKeys |= transformKeysBitwise.rotateZ;
- mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "scale":
- seenKeys |= transformKeysBitwise.scale;
- s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data[key];
- mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
- break;
- case "translateX":
- seenKeys |= transformKeysBitwise.translateX;
- s_TRANSLATE_VECTOR[0] = data.translateX;
- s_TRANSLATE_VECTOR[1] = 0;
- s_TRANSLATE_VECTOR[2] = 0;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- case "translateY":
- seenKeys |= transformKeysBitwise.translateY;
- s_TRANSLATE_VECTOR[0] = 0;
- s_TRANSLATE_VECTOR[1] = data.translateY;
- s_TRANSLATE_VECTOR[2] = 0;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- case "translateZ":
- seenKeys |= transformKeysBitwise.translateZ;
- s_TRANSLATE_VECTOR[0] = 0;
- s_TRANSLATE_VECTOR[1] = 0;
- s_TRANSLATE_VECTOR[2] = data.translateZ;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- }
- }
- if (data !== this._data) {
- for (let cntr = 0; cntr < transformKeys.length; cntr++) {
- const key = transformKeys[cntr];
- if (data[key] === null || (seenKeys & transformKeysBitwise[key]) > 0) {
- continue;
- }
- switch (key) {
- case "rotateX":
- mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateY":
- mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateZ":
- mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "scale":
- s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data[key];
- mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
- break;
- case "translateX":
- s_TRANSLATE_VECTOR[0] = data[key];
- s_TRANSLATE_VECTOR[1] = 0;
- s_TRANSLATE_VECTOR[2] = 0;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- case "translateY":
- s_TRANSLATE_VECTOR[0] = 0;
- s_TRANSLATE_VECTOR[1] = data[key];
- s_TRANSLATE_VECTOR[2] = 0;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- case "translateZ":
- s_TRANSLATE_VECTOR[0] = 0;
- s_TRANSLATE_VECTOR[1] = 0;
- s_TRANSLATE_VECTOR[2] = data[key];
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- break;
- }
- }
- }
- return matrix;
- }
- /**
- * Provides an orthographic enhancement to convert left / top positional data to a translate operation.
- *
- * This transform matrix takes into account that the remaining operations are , but adds any left / top attributes from passed in data to
- * translate X / Y.
- *
- * If no data object is provided then the source is the local transform data. If another data object is supplied
- * then the stored local transform order is applied then all remaining transform keys are applied. This allows the
- * construction of a transform matrix in advance of setting local data and is useful in collision detection.
- *
- * @param {object} [data] - PositionData instance or local transform data.
- *
- * @param {Matrix4} [output] - The output mat4 instance.
- *
- * @returns {Matrix4} Transform matrix.
- */
- getMat4Ortho(data = this._data, output = mat4.create()) {
- const matrix = mat4.identity(output);
- s_TRANSLATE_VECTOR[0] = (data.left ?? 0) + (data.translateX ?? 0);
- s_TRANSLATE_VECTOR[1] = (data.top ?? 0) + (data.translateY ?? 0);
- s_TRANSLATE_VECTOR[2] = data.translateZ ?? 0;
- mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
- if (data.scale !== null) {
- s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data.scale;
- mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
- }
- if (data.rotateX === null && data.rotateY === null && data.rotateZ === null) {
- return matrix;
- }
- let seenKeys = 0;
- const orderList = this.#orderList;
- for (let cntr = 0; cntr < orderList.length; cntr++) {
- const key = orderList[cntr];
- switch (key) {
- case "rotateX":
- seenKeys |= transformKeysBitwise.rotateX;
- mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateY":
- seenKeys |= transformKeysBitwise.rotateY;
- mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateZ":
- seenKeys |= transformKeysBitwise.rotateZ;
- mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- }
- }
- if (data !== this._data) {
- for (let cntr = 0; cntr < transformKeys.length; cntr++) {
- const key = transformKeys[cntr];
- if (data[key] === null || (seenKeys & transformKeysBitwise[key]) > 0) {
- continue;
- }
- switch (key) {
- case "rotateX":
- mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateY":
- mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- case "rotateZ":
- mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
- break;
- }
- }
- }
- return matrix;
- }
- /**
- * Tests an object if it contains transform keys and the values are finite numbers.
- *
- * @param {object} data - An object to test for transform data.
- *
- * @returns {boolean} Whether the given PositionData has transforms.
- */
- hasTransform(data) {
- for (const key of transformKeys) {
- if (Number.isFinite(data[key])) {
- return true;
- }
- }
- return false;
- }
- /**
- * Resets internal data from the given object containing valid transform keys.
- *
- * @param {object} data - An object with transform data.
- */
- reset(data) {
- for (const key in data) {
- if (transformKeys.includes(key)) {
- if (Number.isFinite(data[key])) {
- this._data[key] = data[key];
- } else {
- const index = this.#orderList.findIndex((entry) => entry === key);
- if (index >= 0) {
- this.#orderList.splice(index, 1);
- }
- delete this._data[key];
- }
- }
- }
- }
- }
- function s_GET_ORIGIN_TRANSLATION(transformOrigin, width2, height, output) {
- const vector = s_VEC3_TEMP;
- switch (transformOrigin) {
- case "top left":
- vector[0] = vector[1] = 0;
- mat4.fromTranslation(output[0], vector);
- mat4.fromTranslation(output[1], vector);
- break;
- case "top center":
- vector[0] = -width2 * 0.5;
- vector[1] = 0;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2 * 0.5;
- mat4.fromTranslation(output[1], vector);
- break;
- case "top right":
- vector[0] = -width2;
- vector[1] = 0;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2;
- mat4.fromTranslation(output[1], vector);
- break;
- case "center left":
- vector[0] = 0;
- vector[1] = -height * 0.5;
- mat4.fromTranslation(output[0], vector);
- vector[1] = height * 0.5;
- mat4.fromTranslation(output[1], vector);
- break;
- case null:
- case "center":
- vector[0] = -width2 * 0.5;
- vector[1] = -height * 0.5;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2 * 0.5;
- vector[1] = height * 0.5;
- mat4.fromTranslation(output[1], vector);
- break;
- case "center right":
- vector[0] = -width2;
- vector[1] = -height * 0.5;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2;
- vector[1] = height * 0.5;
- mat4.fromTranslation(output[1], vector);
- break;
- case "bottom left":
- vector[0] = 0;
- vector[1] = -height;
- mat4.fromTranslation(output[0], vector);
- vector[1] = height;
- mat4.fromTranslation(output[1], vector);
- break;
- case "bottom center":
- vector[0] = -width2 * 0.5;
- vector[1] = -height;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2 * 0.5;
- vector[1] = height;
- mat4.fromTranslation(output[1], vector);
- break;
- case "bottom right":
- vector[0] = -width2;
- vector[1] = -height;
- mat4.fromTranslation(output[0], vector);
- vector[0] = width2;
- vector[1] = height;
- mat4.fromTranslation(output[1], vector);
- break;
- default:
- mat4.identity(output[0]);
- mat4.identity(output[1]);
- break;
- }
- return output;
- }
- class UpdateElementData {
- constructor() {
- this.data = void 0;
- this.dataSubscribers = new PositionData();
- this.dimensionData = { width: 0, height: 0 };
- this.changeSet = void 0;
- this.options = void 0;
- this.queued = false;
- this.styleCache = void 0;
- this.transforms = void 0;
- this.transformData = new TransformData();
- this.subscriptions = void 0;
- this.storeDimension = writable$1(this.dimensionData);
- this.storeTransform = writable$1(this.transformData, () => {
- this.options.transformSubscribed = true;
- return () => this.options.transformSubscribed = false;
- });
- this.queued = false;
- Object.seal(this.dimensionData);
- }
- }
- async function nextAnimationFrame(cntr = 1) {
- if (!Number.isInteger(cntr) || cntr < 1) {
- throw new TypeError(`nextAnimationFrame error: 'cntr' must be a positive integer greater than 0.`);
- }
- let currentTime = performance.now();
- for (; --cntr >= 0; ) {
- currentTime = await new Promise((resolve) => requestAnimationFrame(resolve));
- }
- return currentTime;
- }
- class UpdateElementManager {
- static list = [];
- static listCntr = 0;
- static updatePromise;
- static get promise() {
- return this.updatePromise;
- }
- /**
- * Potentially adds the given element and internal updateData instance to the list.
- *
- * @param {HTMLElement} el - An HTMLElement instance.
- *
- * @param {UpdateElementData} updateData - An UpdateElementData instance.
- *
- * @returns {Promise<number>} The unified next frame update promise. Returns `currentTime`.
- */
- static add(el, updateData) {
- if (this.listCntr < this.list.length) {
- const entry = this.list[this.listCntr];
- entry[0] = el;
- entry[1] = updateData;
- } else {
- this.list.push([el, updateData]);
- }
- this.listCntr++;
- updateData.queued = true;
- if (!this.updatePromise) {
- this.updatePromise = this.wait();
- }
- return this.updatePromise;
- }
- /**
- * Await on `nextAnimationFrame` and iterate over list map invoking callback functions.
- *
- * @returns {Promise<number>} The next frame Promise / currentTime from nextAnimationFrame.
- */
- static async wait() {
- const currentTime = await nextAnimationFrame();
- this.updatePromise = void 0;
- for (let cntr = this.listCntr; --cntr >= 0; ) {
- const entry = this.list[cntr];
- const el = entry[0];
- const updateData = entry[1];
- entry[0] = void 0;
- entry[1] = void 0;
- updateData.queued = false;
- if (!el.isConnected) {
- continue;
- }
- if (updateData.options.ortho) {
- s_UPDATE_ELEMENT_ORTHO(el, updateData);
- } else {
- s_UPDATE_ELEMENT(el, updateData);
- }
- if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
- s_UPDATE_TRANSFORM(el, updateData);
- }
- this.updateSubscribers(updateData);
- }
- this.listCntr = 0;
- return currentTime;
- }
- /**
- * Potentially immediately updates the given element.
- *
- * @param {HTMLElement} el - An HTMLElement instance.
- *
- * @param {UpdateElementData} updateData - An UpdateElementData instance.
- */
- static immediate(el, updateData) {
- if (!el.isConnected) {
- return;
- }
- if (updateData.options.ortho) {
- s_UPDATE_ELEMENT_ORTHO(el, updateData);
- } else {
- s_UPDATE_ELEMENT(el, updateData);
- }
- if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
- s_UPDATE_TRANSFORM(el, updateData);
- }
- this.updateSubscribers(updateData);
- }
- /**
- * @param {UpdateElementData} updateData - Data change set.
- */
- static updateSubscribers(updateData) {
- const data = updateData.data;
- const changeSet = updateData.changeSet;
- if (!changeSet.hasChange()) {
- return;
- }
- const output = updateData.dataSubscribers.copy(data);
- const subscriptions = updateData.subscriptions;
- if (subscriptions.length > 0) {
- for (let cntr = 0; cntr < subscriptions.length; cntr++) {
- subscriptions[cntr](output);
- }
- }
- if (changeSet.width || changeSet.height) {
- updateData.dimensionData.width = data.width;
- updateData.dimensionData.height = data.height;
- updateData.storeDimension.set(updateData.dimensionData);
- }
- changeSet.set(false);
- }
- }
- function s_UPDATE_ELEMENT(el, updateData) {
- const changeSet = updateData.changeSet;
- const data = updateData.data;
- if (changeSet.left) {
- el.style.left = `${data.left}px`;
- }
- if (changeSet.top) {
- el.style.top = `${data.top}px`;
- }
- if (changeSet.zIndex) {
- el.style.zIndex = typeof data.zIndex === "number" ? `${data.zIndex}` : null;
- }
- if (changeSet.width) {
- el.style.width = typeof data.width === "number" ? `${data.width}px` : data.width;
- }
- if (changeSet.height) {
- el.style.height = typeof data.height === "number" ? `${data.height}px` : data.height;
- }
- if (changeSet.transformOrigin) {
- el.style.transformOrigin = data.transformOrigin === "center" ? null : data.transformOrigin;
- }
- if (changeSet.transform) {
- el.style.transform = updateData.transforms.isActive ? updateData.transforms.getCSS() : null;
- }
- }
- function s_UPDATE_ELEMENT_ORTHO(el, updateData) {
- const changeSet = updateData.changeSet;
- const data = updateData.data;
- if (changeSet.zIndex) {
- el.style.zIndex = typeof data.zIndex === "number" ? `${data.zIndex}` : null;
- }
- if (changeSet.width) {
- el.style.width = typeof data.width === "number" ? `${data.width}px` : data.width;
- }
- if (changeSet.height) {
- el.style.height = typeof data.height === "number" ? `${data.height}px` : data.height;
- }
- if (changeSet.transformOrigin) {
- el.style.transformOrigin = data.transformOrigin === "center" ? null : data.transformOrigin;
- }
- if (changeSet.left || changeSet.top || changeSet.transform) {
- el.style.transform = updateData.transforms.getCSSOrtho(data);
- }
- }
- function s_UPDATE_TRANSFORM(el, updateData) {
- s_VALIDATION_DATA$1.height = updateData.data.height !== "auto" ? updateData.data.height : updateData.styleCache.offsetHeight;
- s_VALIDATION_DATA$1.width = updateData.data.width !== "auto" ? updateData.data.width : updateData.styleCache.offsetWidth;
- s_VALIDATION_DATA$1.marginLeft = updateData.styleCache.marginLeft;
- s_VALIDATION_DATA$1.marginTop = updateData.styleCache.marginTop;
- updateData.transforms.getData(updateData.data, updateData.transformData, s_VALIDATION_DATA$1);
- updateData.storeTransform.set(updateData.transformData);
- }
- const s_VALIDATION_DATA$1 = {
- height: void 0,
- width: void 0,
- marginLeft: void 0,
- marginTop: void 0
- };
- class Position {
- /**
- * @type {PositionData}
- */
- #data = new PositionData();
- /**
- * Provides the animation API.
- *
- * @type {AnimationAPI}
- */
- #animate = new AnimationAPI(this, this.#data);
- /**
- * Provides a way to turn on / off the position handling.
- *
- * @type {boolean}
- */
- #enabled = true;
- /**
- * Stores the style attributes that changed on update.
- *
- * @type {PositionChangeSet}
- */
- #positionChangeSet = new PositionChangeSet();
- /**
- * Stores ongoing options that are set in the constructor or by transform store subscription.
- *
- * @type {PositionOptions}
- */
- #options = {
- calculateTransform: false,
- initialHelper: void 0,
- ortho: true,
- transformSubscribed: false
- };
- /**
- * The associated parent for positional data tracking. Used in validators.
- *
- * @type {PositionParent}
- */
- #parent;
- /**
- * @type {StorePosition}
- */
- #stores;
- /**
- * Stores an instance of the computer styles for the target element.
- *
- * @type {StyleCache}
- */
- #styleCache;
- /**
- * Stores the subscribers.
- *
- * @type {(function(PositionData): void)[]}
- */
- #subscriptions = [];
- /**
- * @type {Transforms}
- */
- #transforms = new Transforms();
- /**
- * @type {UpdateElementData}
- */
- #updateElementData;
- /**
- * Stores the UpdateElementManager wait promise.
- *
- * @type {Promise}
- */
- #updateElementPromise;
- /**
- * @type {AdapterValidators}
- */
- #validators;
- /**
- * @type {ValidatorData[]}
- */
- #validatorData;
- /**
- * @type {PositionStateAPI}
- */
- #state = new PositionStateAPI(this, this.#data, this.#transforms);
- /**
- * @returns {AnimationGroupAPI} Public Animation API.
- */
- static get Animate() {
- return AnimationGroupAPI;
- }
- /**
- * @returns {{browserCentered?: Centered, Centered?: *}} Initial position helpers.
- */
- static get Initial() {
- return positionInitial;
- }
- /**
- * Returns TransformData class / constructor.
- *
- * @returns {TransformData} TransformData class / constructor.
- */
- static get TransformData() {
- return TransformData;
- }
- /**
- * Returns default validators.
- *
- * Note: `basicWindow` and `BasicBounds` will eventually be removed.
- *
- * @returns {{basicWindow?: BasicBounds, transformWindow?: TransformBounds, TransformBounds?: *, BasicBounds?: *}}
- * Available validators.
- */
- static get Validators() {
- return positionValidators;
- }
- /**
- * Returns a duplicate of a given position instance copying any options and validators.
- *
- * // TODO: Consider more safety over options processing.
- *
- * @param {Position} position - A position instance.
- *
- * @param {PositionOptions} options - Position options.
- *
- * @returns {Position} A duplicate position instance.
- */
- static duplicate(position, options) {
- if (!(position instanceof Position)) {
- throw new TypeError(`'position' is not an instance of Position.`);
- }
- const newPosition = new Position(options);
- newPosition.#options = Object.assign({}, position.#options, options);
- newPosition.#validators.add(...position.#validators);
- newPosition.set(position.#data);
- return newPosition;
- }
- /**
- * @param {PositionParent|PositionOptionsAll} [parent] - A potential parent element or object w/ `elementTarget`
- * getter. May also be the PositionOptions object w/ 1 argument.
- *
- * @param {PositionOptionsAll} [options] - Default values.
- */
- constructor(parent, options) {
- if (isPlainObject(parent)) {
- options = parent;
- } else {
- this.#parent = parent;
- }
- const data = this.#data;
- const transforms = this.#transforms;
- this.#styleCache = new StyleCache();
- const updateData = new UpdateElementData();
- updateData.changeSet = this.#positionChangeSet;
- updateData.data = this.#data;
- updateData.options = this.#options;
- updateData.styleCache = this.#styleCache;
- updateData.subscriptions = this.#subscriptions;
- updateData.transforms = this.#transforms;
- this.#updateElementData = updateData;
- if (isObject(options)) {
- if (typeof options.calculateTransform === "boolean") {
- this.#options.calculateTransform = options.calculateTransform;
- }
- if (typeof options.ortho === "boolean") {
- this.#options.ortho = options.ortho;
- }
- if (Number.isFinite(options.height) || options.height === "auto" || options.height === "inherit" || options.height === null) {
- data.height = updateData.dimensionData.height = typeof options.height === "number" ? Math.round(options.height) : options.height;
- }
- if (Number.isFinite(options.left) || options.left === null) {
- data.left = typeof options.left === "number" ? Math.round(options.left) : options.left;
- }
- if (Number.isFinite(options.maxHeight) || options.maxHeight === null) {
- data.maxHeight = typeof options.maxHeight === "number" ? Math.round(options.maxHeight) : options.maxHeight;
- }
- if (Number.isFinite(options.maxWidth) || options.maxWidth === null) {
- data.maxWidth = typeof options.maxWidth === "number" ? Math.round(options.maxWidth) : options.maxWidth;
- }
- if (Number.isFinite(options.minHeight) || options.minHeight === null) {
- data.minHeight = typeof options.minHeight === "number" ? Math.round(options.minHeight) : options.minHeight;
- }
- if (Number.isFinite(options.minWidth) || options.minWidth === null) {
- data.minWidth = typeof options.minWidth === "number" ? Math.round(options.minWidth) : options.minWidth;
- }
- if (Number.isFinite(options.rotateX) || options.rotateX === null) {
- transforms.rotateX = data.rotateX = options.rotateX;
- }
- if (Number.isFinite(options.rotateY) || options.rotateY === null) {
- transforms.rotateY = data.rotateY = options.rotateY;
- }
- if (Number.isFinite(options.rotateZ) || options.rotateZ === null) {
- transforms.rotateZ = data.rotateZ = options.rotateZ;
- }
- if (Number.isFinite(options.scale) || options.scale === null) {
- transforms.scale = data.scale = options.scale;
- }
- if (Number.isFinite(options.top) || options.top === null) {
- data.top = typeof options.top === "number" ? Math.round(options.top) : options.top;
- }
- if (typeof options.transformOrigin === "string" || options.transformOrigin === null) {
- data.transformOrigin = transformOrigins.includes(options.transformOrigin) ? options.transformOrigin : null;
- }
- if (Number.isFinite(options.translateX) || options.translateX === null) {
- transforms.translateX = data.translateX = options.translateX;
- }
- if (Number.isFinite(options.translateY) || options.translateY === null) {
- transforms.translateY = data.translateY = options.translateY;
- }
- if (Number.isFinite(options.translateZ) || options.translateZ === null) {
- transforms.translateZ = data.translateZ = options.translateZ;
- }
- if (Number.isFinite(options.width) || options.width === "auto" || options.width === "inherit" || options.width === null) {
- data.width = updateData.dimensionData.width = typeof options.width === "number" ? Math.round(options.width) : options.width;
- }
- if (Number.isFinite(options.zIndex) || options.zIndex === null) {
- data.zIndex = typeof options.zIndex === "number" ? Math.round(options.zIndex) : options.zIndex;
- }
- }
- this.#stores = {
- // The main properties for manipulating Position.
- height: propertyStore(this, "height"),
- left: propertyStore(this, "left"),
- rotateX: propertyStore(this, "rotateX"),
- rotateY: propertyStore(this, "rotateY"),
- rotateZ: propertyStore(this, "rotateZ"),
- scale: propertyStore(this, "scale"),
- top: propertyStore(this, "top"),
- transformOrigin: propertyStore(this, "transformOrigin"),
- translateX: propertyStore(this, "translateX"),
- translateY: propertyStore(this, "translateY"),
- translateZ: propertyStore(this, "translateZ"),
- width: propertyStore(this, "width"),
- zIndex: propertyStore(this, "zIndex"),
- // Stores that control validation when width / height is not `auto`.
- maxHeight: propertyStore(this, "maxHeight"),
- maxWidth: propertyStore(this, "maxWidth"),
- minHeight: propertyStore(this, "minHeight"),
- minWidth: propertyStore(this, "minWidth"),
- // Readable stores based on updates or from resize observer changes.
- dimension: { subscribe: updateData.storeDimension.subscribe },
- element: { subscribe: this.#styleCache.stores.element.subscribe },
- resizeContentHeight: { subscribe: this.#styleCache.stores.resizeContentHeight.subscribe },
- resizeContentWidth: { subscribe: this.#styleCache.stores.resizeContentWidth.subscribe },
- resizeOffsetHeight: { subscribe: this.#styleCache.stores.resizeOffsetHeight.subscribe },
- resizeOffsetWidth: { subscribe: this.#styleCache.stores.resizeOffsetWidth.subscribe },
- transform: { subscribe: updateData.storeTransform.subscribe },
- // Protected store that should only be set by resizeObserver action.
- resizeObserved: this.#styleCache.stores.resizeObserved
- };
- subscribeIgnoreFirst(this.#stores.resizeObserved, (resizeData) => {
- const parent2 = this.#parent;
- const el = parent2 instanceof HTMLElement ? parent2 : parent2?.elementTarget;
- if (el instanceof HTMLElement && Number.isFinite(resizeData?.offsetWidth) && Number.isFinite(resizeData?.offsetHeight)) {
- this.set(data);
- }
- });
- this.#stores.transformOrigin.values = transformOrigins;
- [this.#validators, this.#validatorData] = new AdapterValidators();
- if (options?.initial || options?.positionInitial) {
- const initialHelper = options.initial ?? options.positionInitial;
- if (typeof initialHelper?.getLeft !== "function" || typeof initialHelper?.getTop !== "function") {
- throw new Error(
- `'options.initial' position helper does not contain 'getLeft' and / or 'getTop' functions.`
- );
- }
- this.#options.initialHelper = options.initial;
- }
- if (options?.validator) {
- if (isIterable(options?.validator)) {
- this.validators.add(...options.validator);
- } else {
- this.validators.add(options.validator);
- }
- }
- }
- /**
- * Returns the animation API.
- *
- * @returns {AnimationAPI} Animation API.
- */
- get animate() {
- return this.#animate;
- }
- /**
- * Returns the dimension data for the readable store.
- *
- * @returns {{width: number | 'auto', height: number | 'auto'}} Dimension data.
- */
- get dimension() {
- return this.#updateElementData.dimensionData;
- }
- /**
- * Returns the enabled state.
- *
- * @returns {boolean} Enabled state.
- */
- get enabled() {
- return this.#enabled;
- }
- /**
- * Returns the current HTMLElement being positioned.
- *
- * @returns {HTMLElement|undefined} Current HTMLElement being positioned.
- */
- get element() {
- return this.#styleCache.el;
- }
- /**
- * Returns a promise that is resolved on the next element update with the time of the update.
- *
- * @returns {Promise<number>} Promise resolved on element update.
- */
- get elementUpdated() {
- return this.#updateElementPromise;
- }
- /**
- * Returns the associated {@link PositionParent} instance.
- *
- * @returns {PositionParent} The PositionParent instance.
- */
- get parent() {
- return this.#parent;
- }
- /**
- * Returns the state API.
- *
- * @returns {PositionStateAPI} Position state API.
- */
- get state() {
- return this.#state;
- }
- /**
- * Returns the derived writable stores for individual data variables.
- *
- * @returns {StorePosition} Derived / writable stores.
- */
- get stores() {
- return this.#stores;
- }
- /**
- * Returns the transform data for the readable store.
- *
- * @returns {TransformData} Transform Data.
- */
- get transform() {
- return this.#updateElementData.transformData;
- }
- /**
- * Returns the validators.
- *
- * @returns {AdapterValidators} validators.
- */
- get validators() {
- return this.#validators;
- }
- /**
- * Sets the enabled state.
- *
- * @param {boolean} enabled - New enabled state.
- */
- set enabled(enabled) {
- if (typeof enabled !== "boolean") {
- throw new TypeError(`'enabled' is not a boolean.`);
- }
- this.#enabled = enabled;
- }
- /**
- * Sets the associated {@link PositionParent} instance. Resets the style cache and default data.
- *
- * @param {PositionParent|void} parent - A PositionParent instance.
- */
- set parent(parent) {
- if (parent !== void 0 && !(parent instanceof HTMLElement) && !isObject(parent)) {
- throw new TypeError(`'parent' is not an HTMLElement, object, or undefined.`);
- }
- this.#parent = parent;
- this.#state.remove({ name: "#defaultData" });
- this.#styleCache.reset();
- if (parent) {
- this.set(this.#data);
- }
- }
- // Data accessors ----------------------------------------------------------------------------------------------------
- /**
- * @returns {number|'auto'|'inherit'|null} height
- */
- get height() {
- return this.#data.height;
- }
- /**
- * @returns {number|null} left
- */
- get left() {
- return this.#data.left;
- }
- /**
- * @returns {number|null} maxHeight
- */
- get maxHeight() {
- return this.#data.maxHeight;
- }
- /**
- * @returns {number|null} maxWidth
- */
- get maxWidth() {
- return this.#data.maxWidth;
- }
- /**
- * @returns {number|null} minHeight
- */
- get minHeight() {
- return this.#data.minHeight;
- }
- /**
- * @returns {number|null} minWidth
- */
- get minWidth() {
- return this.#data.minWidth;
- }
- /**
- * @returns {number|null} rotateX
- */
- get rotateX() {
- return this.#data.rotateX;
- }
- /**
- * @returns {number|null} rotateY
- */
- get rotateY() {
- return this.#data.rotateY;
- }
- /**
- * @returns {number|null} rotateZ
- */
- get rotateZ() {
- return this.#data.rotateZ;
- }
- /**
- * @returns {number|null} alias for rotateZ
- */
- get rotation() {
- return this.#data.rotateZ;
- }
- /**
- * @returns {number|null} scale
- */
- get scale() {
- return this.#data.scale;
- }
- /**
- * @returns {number|null} top
- */
- get top() {
- return this.#data.top;
- }
- /**
- * @returns {string} transformOrigin
- */
- get transformOrigin() {
- return this.#data.transformOrigin;
- }
- /**
- * @returns {number|null} translateX
- */
- get translateX() {
- return this.#data.translateX;
- }
- /**
- * @returns {number|null} translateY
- */
- get translateY() {
- return this.#data.translateY;
- }
- /**
- * @returns {number|null} translateZ
- */
- get translateZ() {
- return this.#data.translateZ;
- }
- /**
- * @returns {number|'auto'|'inherit'|null} width
- */
- get width() {
- return this.#data.width;
- }
- /**
- * @returns {number|null} z-index
- */
- get zIndex() {
- return this.#data.zIndex;
- }
- /**
- * @param {number|string|null} height -
- */
- set height(height) {
- this.#stores.height.set(height);
- }
- /**
- * @param {number|string|null} left -
- */
- set left(left) {
- this.#stores.left.set(left);
- }
- /**
- * @param {number|string|null} maxHeight -
- */
- set maxHeight(maxHeight) {
- this.#stores.maxHeight.set(maxHeight);
- }
- /**
- * @param {number|string|null} maxWidth -
- */
- set maxWidth(maxWidth) {
- this.#stores.maxWidth.set(maxWidth);
- }
- /**
- * @param {number|string|null} minHeight -
- */
- set minHeight(minHeight) {
- this.#stores.minHeight.set(minHeight);
- }
- /**
- * @param {number|string|null} minWidth -
- */
- set minWidth(minWidth) {
- this.#stores.minWidth.set(minWidth);
- }
- /**
- * @param {number|string|null} rotateX -
- */
- set rotateX(rotateX) {
- this.#stores.rotateX.set(rotateX);
- }
- /**
- * @param {number|string|null} rotateY -
- */
- set rotateY(rotateY) {
- this.#stores.rotateY.set(rotateY);
- }
- /**
- * @param {number|string|null} rotateZ -
- */
- set rotateZ(rotateZ) {
- this.#stores.rotateZ.set(rotateZ);
- }
- /**
- * @param {number|string|null} rotateZ - alias for rotateZ
- */
- set rotation(rotateZ) {
- this.#stores.rotateZ.set(rotateZ);
- }
- /**
- * @param {number|string|null} scale -
- */
- set scale(scale2) {
- this.#stores.scale.set(scale2);
- }
- /**
- * @param {number|string|null} top -
- */
- set top(top) {
- this.#stores.top.set(top);
- }
- /**
- * @param {string} transformOrigin -
- */
- set transformOrigin(transformOrigin) {
- if (transformOrigins.includes(transformOrigin)) {
- this.#stores.transformOrigin.set(transformOrigin);
- }
- }
- /**
- * @param {number|string|null} translateX -
- */
- set translateX(translateX) {
- this.#stores.translateX.set(translateX);
- }
- /**
- * @param {number|string|null} translateY -
- */
- set translateY(translateY) {
- this.#stores.translateY.set(translateY);
- }
- /**
- * @param {number|string|null} translateZ -
- */
- set translateZ(translateZ) {
- this.#stores.translateZ.set(translateZ);
- }
- /**
- * @param {number|string|null} width -
- */
- set width(width2) {
- this.#stores.width.set(width2);
- }
- /**
- * @param {number|string|null} zIndex -
- */
- set zIndex(zIndex) {
- this.#stores.zIndex.set(zIndex);
- }
- /**
- * Assigns current position to object passed into method.
- *
- * @param {object|PositionData} [position] - Target to assign current position data.
- *
- * @param {PositionGetOptions} [options] - Defines options for specific keys and substituting null for numeric
- * default values.
- *
- * @returns {PositionData} Passed in object with current position data.
- */
- get(position = {}, options) {
- const keys = options?.keys;
- const excludeKeys = options?.exclude;
- const numeric = options?.numeric ?? false;
- if (isIterable(keys)) {
- if (numeric) {
- for (const key of keys) {
- position[key] = this[key] ?? numericDefaults[key];
- }
- } else {
- for (const key of keys) {
- position[key] = this[key];
- }
- }
- if (isIterable(excludeKeys)) {
- for (const key of excludeKeys) {
- delete position[key];
- }
- }
- return position;
- } else {
- const data = Object.assign(position, this.#data);
- if (isIterable(excludeKeys)) {
- for (const key of excludeKeys) {
- delete data[key];
- }
- }
- if (numeric) {
- setNumericDefaults(data);
- }
- return data;
- }
- }
- /**
- * @returns {PositionData} Current position data.
- */
- toJSON() {
- return Object.assign({}, this.#data);
- }
- /**
- * All calculation and updates of position are implemented in {@link Position}. This allows position to be fully
- * reactive and in control of updating inline styles for the application.
- *
- * Note: the logic for updating position is improved and changes a few aspects from the default
- * {@link Application.setPosition}. The gate on `popOut` is removed, so to ensure no positional application occurs
- * popOut applications can set `this.options.positionable` to false ensuring no positional inline styles are
- * applied.
- *
- * The initial set call on an application with a target element will always set width / height as this is
- * necessary for correct calculations.
- *
- * When a target element is present updated styles are applied after validation. To modify the behavior of set
- * implement one or more validator functions and add them from the application via
- * `this.position.validators.add(<Function>)`.
- *
- * Updates to any target element are decoupled from the underlying Position data. This method returns this instance
- * that you can then await on the target element inline style update by using {@link Position.elementUpdated}.
- *
- * @param {PositionDataExtended} [position] - Position data to set.
- *
- * @returns {Position} This Position instance.
- */
- set(position = {}) {
- if (typeof position !== "object") {
- throw new TypeError(`Position - set error: 'position' is not an object.`);
- }
- const parent = this.#parent;
- if (!this.#enabled) {
- return this;
- }
- if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
- return this;
- }
- const immediateElementUpdate = position.immediateElementUpdate === true;
- const data = this.#data;
- const transforms = this.#transforms;
- const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
- const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
- const changeSet = this.#positionChangeSet;
- const styleCache = this.#styleCache;
- if (el) {
- if (!styleCache.hasData(el)) {
- styleCache.update(el);
- if (!styleCache.hasWillChange)
- ;
- changeSet.set(true);
- this.#updateElementData.queued = false;
- }
- convertRelative(position, this);
- position = this.#updatePosition(position, parent, el, styleCache);
- if (position === null) {
- return this;
- }
- }
- if (Number.isFinite(position.left)) {
- position.left = Math.round(position.left);
- if (data.left !== position.left) {
- data.left = position.left;
- changeSet.left = true;
- }
- }
- if (Number.isFinite(position.top)) {
- position.top = Math.round(position.top);
- if (data.top !== position.top) {
- data.top = position.top;
- changeSet.top = true;
- }
- }
- if (Number.isFinite(position.maxHeight) || position.maxHeight === null) {
- position.maxHeight = typeof position.maxHeight === "number" ? Math.round(position.maxHeight) : null;
- if (data.maxHeight !== position.maxHeight) {
- data.maxHeight = position.maxHeight;
- changeSet.maxHeight = true;
- }
- }
- if (Number.isFinite(position.maxWidth) || position.maxWidth === null) {
- position.maxWidth = typeof position.maxWidth === "number" ? Math.round(position.maxWidth) : null;
- if (data.maxWidth !== position.maxWidth) {
- data.maxWidth = position.maxWidth;
- changeSet.maxWidth = true;
- }
- }
- if (Number.isFinite(position.minHeight) || position.minHeight === null) {
- position.minHeight = typeof position.minHeight === "number" ? Math.round(position.minHeight) : null;
- if (data.minHeight !== position.minHeight) {
- data.minHeight = position.minHeight;
- changeSet.minHeight = true;
- }
- }
- if (Number.isFinite(position.minWidth) || position.minWidth === null) {
- position.minWidth = typeof position.minWidth === "number" ? Math.round(position.minWidth) : null;
- if (data.minWidth !== position.minWidth) {
- data.minWidth = position.minWidth;
- changeSet.minWidth = true;
- }
- }
- if (Number.isFinite(position.rotateX) || position.rotateX === null) {
- if (data.rotateX !== position.rotateX) {
- data.rotateX = transforms.rotateX = position.rotateX;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.rotateY) || position.rotateY === null) {
- if (data.rotateY !== position.rotateY) {
- data.rotateY = transforms.rotateY = position.rotateY;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.rotateZ) || position.rotateZ === null) {
- if (data.rotateZ !== position.rotateZ) {
- data.rotateZ = transforms.rotateZ = position.rotateZ;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.scale) || position.scale === null) {
- position.scale = typeof position.scale === "number" ? Math.max(0, Math.min(position.scale, 1e3)) : null;
- if (data.scale !== position.scale) {
- data.scale = transforms.scale = position.scale;
- changeSet.transform = true;
- }
- }
- if (typeof position.transformOrigin === "string" && transformOrigins.includes(
- position.transformOrigin
- ) || position.transformOrigin === null) {
- if (data.transformOrigin !== position.transformOrigin) {
- data.transformOrigin = position.transformOrigin;
- changeSet.transformOrigin = true;
- }
- }
- if (Number.isFinite(position.translateX) || position.translateX === null) {
- if (data.translateX !== position.translateX) {
- data.translateX = transforms.translateX = position.translateX;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.translateY) || position.translateY === null) {
- if (data.translateY !== position.translateY) {
- data.translateY = transforms.translateY = position.translateY;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.translateZ) || position.translateZ === null) {
- if (data.translateZ !== position.translateZ) {
- data.translateZ = transforms.translateZ = position.translateZ;
- changeSet.transform = true;
- }
- }
- if (Number.isFinite(position.zIndex)) {
- position.zIndex = Math.round(position.zIndex);
- if (data.zIndex !== position.zIndex) {
- data.zIndex = position.zIndex;
- changeSet.zIndex = true;
- }
- }
- if (Number.isFinite(position.width) || position.width === "auto" || position.width === "inherit" || position.width === null) {
- position.width = typeof position.width === "number" ? Math.round(position.width) : position.width;
- if (data.width !== position.width) {
- data.width = position.width;
- changeSet.width = true;
- }
- }
- if (Number.isFinite(position.height) || position.height === "auto" || position.height === "inherit" || position.height === null) {
- position.height = typeof position.height === "number" ? Math.round(position.height) : position.height;
- if (data.height !== position.height) {
- data.height = position.height;
- changeSet.height = true;
- }
- }
- if (el) {
- const defaultData = this.#state.getDefault();
- if (typeof defaultData !== "object") {
- this.#state.save({ name: "#defaultData", ...Object.assign({}, data) });
- }
- if (immediateElementUpdate) {
- UpdateElementManager.immediate(el, this.#updateElementData);
- this.#updateElementPromise = Promise.resolve(performance.now());
- } else if (!this.#updateElementData.queued) {
- this.#updateElementPromise = UpdateElementManager.add(el, this.#updateElementData);
- }
- } else {
- UpdateElementManager.updateSubscribers(this.#updateElementData);
- }
- return this;
- }
- /**
- *
- * @param {function(PositionData): void} handler - Callback function that is invoked on update / changes. Receives
- * a copy of the PositionData.
- *
- * @returns {(function(): void)} Unsubscribe function.
- */
- subscribe(handler) {
- this.#subscriptions.push(handler);
- handler(Object.assign({}, this.#data));
- return () => {
- const index = this.#subscriptions.findIndex((sub) => sub === handler);
- if (index >= 0) {
- this.#subscriptions.splice(index, 1);
- }
- };
- }
- /**
- * @param {PositionDataExtended} opts -
- *
- * @param {number|null} opts.left -
- *
- * @param {number|null} opts.top -
- *
- * @param {number|null} opts.maxHeight -
- *
- * @param {number|null} opts.maxWidth -
- *
- * @param {number|null} opts.minHeight -
- *
- * @param {number|null} opts.minWidth -
- *
- * @param {number|'auto'|null} opts.width -
- *
- * @param {number|'auto'|null} opts.height -
- *
- * @param {number|null} opts.rotateX -
- *
- * @param {number|null} opts.rotateY -
- *
- * @param {number|null} opts.rotateZ -
- *
- * @param {number|null} opts.scale -
- *
- * @param {string} opts.transformOrigin -
- *
- * @param {number|null} opts.translateX -
- *
- * @param {number|null} opts.translateY -
- *
- * @param {number|null} opts.translateZ -
- *
- * @param {number|null} opts.zIndex -
- *
- * @param {number|null} opts.rotation - alias for rotateZ
- *
- * @param {*} opts.rest -
- *
- * @param {object} parent -
- *
- * @param {HTMLElement} el -
- *
- * @param {StyleCache} styleCache -
- *
- * @returns {null|PositionData} Updated position data or null if validation fails.
- */
- #updatePosition({
- // Directly supported parameters
- left,
- top,
- maxWidth,
- maxHeight,
- minWidth,
- minHeight,
- width: width2,
- height,
- rotateX,
- rotateY,
- rotateZ,
- scale: scale2,
- transformOrigin,
- translateX,
- translateY,
- translateZ,
- zIndex,
- // Aliased parameters
- rotation: rotation2,
- ...rest
- } = {}, parent, el, styleCache) {
- let currentPosition = s_DATA_UPDATE.copy(this.#data);
- if (el.style.width === "" || width2 !== void 0) {
- if (width2 === "auto" || currentPosition.width === "auto" && width2 !== null) {
- currentPosition.width = "auto";
- width2 = styleCache.offsetWidth;
- } else if (width2 === "inherit" || currentPosition.width === "inherit" && width2 !== null) {
- currentPosition.width = "inherit";
- width2 = styleCache.offsetWidth;
- } else {
- const newWidth = Number.isFinite(width2) ? width2 : currentPosition.width;
- currentPosition.width = width2 = Number.isFinite(newWidth) ? Math.round(newWidth) : styleCache.offsetWidth;
- }
- } else {
- width2 = Number.isFinite(currentPosition.width) ? currentPosition.width : styleCache.offsetWidth;
- }
- if (el.style.height === "" || height !== void 0) {
- if (height === "auto" || currentPosition.height === "auto" && height !== null) {
- currentPosition.height = "auto";
- height = styleCache.offsetHeight;
- } else if (height === "inherit" || currentPosition.height === "inherit" && height !== null) {
- currentPosition.height = "inherit";
- height = styleCache.offsetHeight;
- } else {
- const newHeight = Number.isFinite(height) ? height : currentPosition.height;
- currentPosition.height = height = Number.isFinite(newHeight) ? Math.round(newHeight) : styleCache.offsetHeight;
- }
- } else {
- height = Number.isFinite(currentPosition.height) ? currentPosition.height : styleCache.offsetHeight;
- }
- if (Number.isFinite(left)) {
- currentPosition.left = left;
- } else if (!Number.isFinite(currentPosition.left)) {
- currentPosition.left = typeof this.#options.initialHelper?.getLeft === "function" ? this.#options.initialHelper.getLeft(width2) : 0;
- }
- if (Number.isFinite(top)) {
- currentPosition.top = top;
- } else if (!Number.isFinite(currentPosition.top)) {
- currentPosition.top = typeof this.#options.initialHelper?.getTop === "function" ? this.#options.initialHelper.getTop(height) : 0;
- }
- if (Number.isFinite(maxHeight) || maxHeight === null) {
- currentPosition.maxHeight = Number.isFinite(maxHeight) ? Math.round(maxHeight) : null;
- }
- if (Number.isFinite(maxWidth) || maxWidth === null) {
- currentPosition.maxWidth = Number.isFinite(maxWidth) ? Math.round(maxWidth) : null;
- }
- if (Number.isFinite(minHeight) || minHeight === null) {
- currentPosition.minHeight = Number.isFinite(minHeight) ? Math.round(minHeight) : null;
- }
- if (Number.isFinite(minWidth) || minWidth === null) {
- currentPosition.minWidth = Number.isFinite(minWidth) ? Math.round(minWidth) : null;
- }
- if (Number.isFinite(rotateX) || rotateX === null) {
- currentPosition.rotateX = rotateX;
- }
- if (Number.isFinite(rotateY) || rotateY === null) {
- currentPosition.rotateY = rotateY;
- }
- if (rotateZ !== currentPosition.rotateZ && (Number.isFinite(rotateZ) || rotateZ === null)) {
- currentPosition.rotateZ = rotateZ;
- } else if (rotation2 !== currentPosition.rotateZ && (Number.isFinite(rotation2) || rotation2 === null)) {
- currentPosition.rotateZ = rotation2;
- }
- if (Number.isFinite(translateX) || translateX === null) {
- currentPosition.translateX = translateX;
- }
- if (Number.isFinite(translateY) || translateY === null) {
- currentPosition.translateY = translateY;
- }
- if (Number.isFinite(translateZ) || translateZ === null) {
- currentPosition.translateZ = translateZ;
- }
- if (Number.isFinite(scale2) || scale2 === null) {
- currentPosition.scale = typeof scale2 === "number" ? Math.max(0, Math.min(scale2, 1e3)) : null;
- }
- if (typeof transformOrigin === "string" || transformOrigin === null) {
- currentPosition.transformOrigin = transformOrigins.includes(transformOrigin) ? transformOrigin : null;
- }
- if (Number.isFinite(zIndex) || zIndex === null) {
- currentPosition.zIndex = typeof zIndex === "number" ? Math.round(zIndex) : zIndex;
- }
- const validatorData = this.#validatorData;
- if (this.#validators.enabled && validatorData.length) {
- s_VALIDATION_DATA.parent = parent;
- s_VALIDATION_DATA.el = el;
- s_VALIDATION_DATA.computed = styleCache.computed;
- s_VALIDATION_DATA.transforms = this.#transforms;
- s_VALIDATION_DATA.height = height;
- s_VALIDATION_DATA.width = width2;
- s_VALIDATION_DATA.marginLeft = styleCache.marginLeft;
- s_VALIDATION_DATA.marginTop = styleCache.marginTop;
- s_VALIDATION_DATA.maxHeight = styleCache.maxHeight ?? currentPosition.maxHeight;
- s_VALIDATION_DATA.maxWidth = styleCache.maxWidth ?? currentPosition.maxWidth;
- const isMinimized = parent?.reactive?.minimized ?? false;
- s_VALIDATION_DATA.minHeight = isMinimized ? currentPosition.minHeight ?? 0 : styleCache.minHeight || (currentPosition.minHeight ?? 0);
- s_VALIDATION_DATA.minWidth = isMinimized ? currentPosition.minWidth ?? 0 : styleCache.minWidth || (currentPosition.minWidth ?? 0);
- for (let cntr = 0; cntr < validatorData.length; cntr++) {
- s_VALIDATION_DATA.position = currentPosition;
- s_VALIDATION_DATA.rest = rest;
- currentPosition = validatorData[cntr].validator(s_VALIDATION_DATA);
- if (currentPosition === null) {
- return null;
- }
- }
- }
- return currentPosition;
- }
- }
- const s_DATA_UPDATE = new PositionData();
- const s_VALIDATION_DATA = {
- position: void 0,
- parent: void 0,
- el: void 0,
- computed: void 0,
- transforms: void 0,
- height: void 0,
- width: void 0,
- marginLeft: void 0,
- marginTop: void 0,
- maxHeight: void 0,
- maxWidth: void 0,
- minHeight: void 0,
- minWidth: void 0,
- rest: void 0
- };
- Object.seal(s_VALIDATION_DATA);
- class ApplicationState {
- /** @type {ApplicationShellExt} */
- #application;
- /** @type {Map<string, ApplicationStateData>} */
- #dataSaved = /* @__PURE__ */ new Map();
- /**
- * @param {ApplicationShellExt} application - The application.
- */
- constructor(application) {
- this.#application = application;
- Object.seal(this);
- }
- /**
- * Returns current application state along with any extra data passed into method.
- *
- * @param {object} [extra] - Extra data to add to application state.
- *
- * @returns {ApplicationStateData} Passed in object with current application state.
- */
- get(extra = {}) {
- return Object.assign(extra, {
- position: this.#application?.position?.get(),
- beforeMinimized: this.#application?.position?.state.get({ name: "#beforeMinimized" }),
- options: Object.assign({}, this.#application?.options),
- ui: { minimized: this.#application?.reactive?.minimized }
- });
- }
- /**
- * Returns any stored save state by name.
- *
- * @param {string} name - Saved data set name.
- *
- * @returns {ApplicationStateData} The saved data set.
- */
- getSave({ name }) {
- if (typeof name !== "string") {
- throw new TypeError(`ApplicationState - getSave error: 'name' is not a string.`);
- }
- return this.#dataSaved.get(name);
- }
- /**
- * Removes and returns any application state by name.
- *
- * @param {object} options - Options.
- *
- * @param {string} options.name - Name to remove and retrieve.
- *
- * @returns {ApplicationStateData} Saved application data.
- */
- remove({ name }) {
- if (typeof name !== "string") {
- throw new TypeError(`ApplicationState - remove: 'name' is not a string.`);
- }
- const data = this.#dataSaved.get(name);
- this.#dataSaved.delete(name);
- return data;
- }
- /**
- * Restores a saved application state returning the data. Several optional parameters are available
- * to control whether the restore action occurs silently (no store / inline styles updates), animates
- * to the stored data, or simply sets the stored data. Restoring via {@link AnimationAPI.to} allows
- * specification of the duration, easing, and interpolate functions along with configuring a Promise to be
- * returned if awaiting the end of the animation.
- *
- * @param {object} params - Parameters
- *
- * @param {string} params.name - Saved data set name.
- *
- * @param {boolean} [params.remove=false] - Remove data set.
- *
- * @param {boolean} [params.async=false] - If animating return a Promise that resolves with any saved data.
- *
- * @param {boolean} [params.animateTo=false] - Animate to restore data.
- *
- * @param {number} [params.duration=0.1] - Duration in seconds.
- *
- * @param {Function} [params.ease=linear] - Easing function.
- *
- * @param {Function} [params.interpolate=lerp] - Interpolation function.
- *
- * @returns {ApplicationStateData|Promise<ApplicationStateData>} Saved application data.
- */
- restore({
- name,
- remove = false,
- async = false,
- animateTo = false,
- duration = 0.1,
- ease = identity,
- interpolate: interpolate2 = lerp$5
- }) {
- if (typeof name !== "string") {
- throw new TypeError(`ApplicationState - restore error: 'name' is not a string.`);
- }
- const dataSaved = this.#dataSaved.get(name);
- if (dataSaved) {
- if (remove) {
- this.#dataSaved.delete(name);
- }
- if (async) {
- return this.set(dataSaved, { async, animateTo, duration, ease, interpolate: interpolate2 }).then(() => dataSaved);
- } else {
- this.set(dataSaved, { async, animateTo, duration, ease, interpolate: interpolate2 });
- }
- }
- return dataSaved;
- }
- /**
- * Saves current application state with the opportunity to add extra data to the saved state.
- *
- * @param {object} options - Options.
- *
- * @param {string} options.name - name to index this saved data.
- *
- * @param {...*} [options.extra] - Extra data to add to saved data.
- *
- * @returns {ApplicationStateData} Current application data
- */
- save({ name, ...extra }) {
- if (typeof name !== "string") {
- throw new TypeError(`ApplicationState - save error: 'name' is not a string.`);
- }
- const data = this.get(extra);
- this.#dataSaved.set(name, data);
- return data;
- }
- /**
- * Restores a saved application state returning the data. Several optional parameters are available
- * to control whether the restore action occurs silently (no store / inline styles updates), animates
- * to the stored data, or simply sets the stored data. Restoring via {@link AnimationAPI.to} allows
- * specification of the duration, easing, and interpolate functions along with configuring a Promise to be
- * returned if awaiting the end of the animation.
- *
- * Note: If serializing application state any minimized apps will use the before minimized state on initial render
- * of the app as it is currently not possible to render apps with Foundry VTT core API in the minimized state.
- *
- * TODO: THIS METHOD NEEDS TO BE REFACTORED WHEN TRL IS MADE INTO A STANDALONE FRAMEWORK.
- *
- * @param {ApplicationStateData} data - Saved data set name.
- *
- * @param {object} [opts] - Optional parameters
- *
- * @param {boolean} [opts.async=false] - If animating return a Promise that resolves with any saved data.
- *
- * @param {boolean} [opts.animateTo=false] - Animate to restore data.
- *
- * @param {number} [opts.duration=0.1] - Duration in seconds.
- *
- * @param {Function} [opts.ease=linear] - Easing function.
- *
- * @param {Function} [opts.interpolate=lerp] - Interpolation function.
- *
- * @returns {ApplicationShellExt|Promise<ApplicationShellExt>} When synchronous the application or Promise when
- * animating resolving with application.
- */
- set(data, { async = false, animateTo = false, duration = 0.1, ease = identity, interpolate: interpolate2 = lerp$5 } = {}) {
- if (!isObject(data)) {
- throw new TypeError(`ApplicationState - restore error: 'data' is not an object.`);
- }
- const application = this.#application;
- if (!isObject(data?.position)) {
- console.warn(`ApplicationState.set warning: 'data.position' is not an object.`);
- return application;
- }
- const rendered = application.rendered;
- if (animateTo && !rendered) {
- console.warn(`ApplicationState.set warning: Application is not rendered and 'animateTo' is true.`);
- return application;
- }
- if (animateTo) {
- if (data.position.transformOrigin !== application.position.transformOrigin) {
- application.position.transformOrigin = data.position.transformOrigin;
- }
- if (isObject(data?.ui)) {
- const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
- if (application?.reactive?.minimized && !minimized) {
- application.maximize({ animate: false, duration: 0 });
- }
- }
- const promise2 = application.position.animate.to(
- data.position,
- { duration, ease, interpolate: interpolate2 }
- ).finished.then((cancelled) => {
- if (cancelled) {
- return application;
- }
- if (isObject(data?.options)) {
- application?.reactive.mergeOptions(data.options);
- }
- if (isObject(data?.ui)) {
- const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
- if (!application?.reactive?.minimized && minimized) {
- application.minimize({ animate: false, duration: 0 });
- }
- }
- if (isObject(data?.beforeMinimized)) {
- application.position.state.set({ name: "#beforeMinimized", ...data.beforeMinimized });
- }
- return application;
- });
- if (async) {
- return promise2;
- }
- } else {
- if (rendered) {
- if (isObject(data?.options)) {
- application?.reactive.mergeOptions(data.options);
- }
- if (isObject(data?.ui)) {
- const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
- if (application?.reactive?.minimized && !minimized) {
- application.maximize({ animate: false, duration: 0 });
- } else if (!application?.reactive?.minimized && minimized) {
- application.minimize({ animate: false, duration });
- }
- }
- if (isObject(data?.beforeMinimized)) {
- application.position.state.set({ name: "#beforeMinimized", ...data.beforeMinimized });
- }
- application.position.set(data.position);
- } else {
- let positionData = data.position;
- if (isObject(data.beforeMinimized)) {
- positionData = data.beforeMinimized;
- positionData.left = data.position.left;
- positionData.top = data.position.top;
- }
- application.position.set(positionData);
- }
- }
- return application;
- }
- }
- class GetSvelteData {
- /**
- * @type {MountedAppShell[]|null[]}
- */
- #applicationShellHolder;
- /**
- * @type {SvelteData[]}
- */
- #svelteData;
- /**
- * Keep a direct reference to the SvelteData array in an associated {@link SvelteApplication}.
- *
- * @param {MountedAppShell[]|null[]} applicationShellHolder - A reference to the MountedAppShell array.
- *
- * @param {SvelteData[]} svelteData - A reference to the SvelteData array of mounted components.
- */
- constructor(applicationShellHolder, svelteData) {
- this.#applicationShellHolder = applicationShellHolder;
- this.#svelteData = svelteData;
- }
- /**
- * Returns any mounted {@link MountedAppShell}.
- *
- * @returns {MountedAppShell|null} Any mounted application shell.
- */
- get applicationShell() {
- return this.#applicationShellHolder[0];
- }
- /**
- * Returns the indexed Svelte component.
- *
- * @param {number} index -
- *
- * @returns {object} The loaded Svelte component.
- */
- component(index) {
- const data = this.#svelteData[index];
- return isObject(data) ? data?.component : void 0;
- }
- /**
- * Returns the Svelte component entries iterator.
- *
- * @returns {Generator<Array<number|SvelteComponent>>} Svelte component entries iterator.
- * @yields
- */
- *componentEntries() {
- for (let cntr = 0; cntr < this.#svelteData.length; cntr++) {
- yield [cntr, this.#svelteData[cntr].component];
- }
- }
- /**
- * Returns the Svelte component values iterator.
- *
- * @returns {Generator<SvelteComponent>} Svelte component values iterator.
- * @yields
- */
- *componentValues() {
- for (let cntr = 0; cntr < this.#svelteData.length; cntr++) {
- yield this.#svelteData[cntr].component;
- }
- }
- /**
- * Returns the indexed SvelteData entry.
- *
- * @param {number} index -
- *
- * @returns {SvelteData} The loaded Svelte config + component.
- */
- data(index) {
- return this.#svelteData[index];
- }
- /**
- * Returns the {@link SvelteData} instance for a given component.
- *
- * @param {object} component - Svelte component.
- *
- * @returns {SvelteData} - The loaded Svelte config + component.
- */
- dataByComponent(component) {
- for (const data of this.#svelteData) {
- if (data.component === component) {
- return data;
- }
- }
- return void 0;
- }
- /**
- * Returns the SvelteData entries iterator.
- *
- * @returns {IterableIterator<[number, SvelteData]>} SvelteData entries iterator.
- */
- dataEntries() {
- return this.#svelteData.entries();
- }
- /**
- * Returns the SvelteData values iterator.
- *
- * @returns {IterableIterator<SvelteData>} SvelteData values iterator.
- */
- dataValues() {
- return this.#svelteData.values();
- }
- /**
- * Returns the length of the mounted Svelte component list.
- *
- * @returns {number} Length of mounted Svelte component list.
- */
- get length() {
- return this.#svelteData.length;
- }
- }
- function loadSvelteConfig({ app, template, config, elementRootUpdate } = {}) {
- const svelteOptions = isObject(config.options) ? config.options : {};
- let target;
- if (config.target instanceof HTMLElement) {
- target = config.target;
- } else if (template instanceof HTMLElement && typeof config.target === "string") {
- target = template.querySelector(config.target);
- } else {
- target = document.createDocumentFragment();
- }
- if (target === void 0) {
- console.log(
- `%c[TRL] loadSvelteConfig error - could not find target selector, '${config.target}', for config:
- `,
- "background: rgb(57,34,34)",
- config
- );
- throw new Error();
- }
- const NewSvelteComponent = config.class;
- const svelteConfig = parseSvelteConfig({ ...config, target }, app);
- const externalContext = svelteConfig.context.get("#external");
- externalContext.application = app;
- externalContext.elementRootUpdate = elementRootUpdate;
- externalContext.sessionStorage = app.reactive.sessionStorage;
- let eventbus;
- if (isObject(app._eventbus) && typeof app._eventbus.createProxy === "function") {
- eventbus = app._eventbus.createProxy();
- externalContext.eventbus = eventbus;
- }
- Object.seal(externalContext);
- svelteConfig.context.set("external", new Proxy({}, {
- get(targetUnused, prop) {
- console.warn(`[TRL] Deprecation warning: Please change getContext('external') to getContext('#external').`);
- return externalContext[prop];
- }
- }));
- const component = new NewSvelteComponent(svelteConfig);
- svelteConfig.eventbus = eventbus;
- let element2;
- if (isApplicationShell(component)) {
- element2 = component.elementRoot;
- }
- if (target instanceof DocumentFragment && target.firstElementChild) {
- if (element2 === void 0) {
- element2 = target.firstElementChild;
- }
- template.append(target);
- } else if (config.target instanceof HTMLElement && element2 === void 0) {
- if (config.target instanceof HTMLElement && typeof svelteOptions.selectorElement !== "string") {
- console.log(
- `%c[TRL] loadSvelteConfig error - HTMLElement target with no 'selectorElement' defined.
-
- Note: If configuring an application shell and directly targeting a HTMLElement did you bind an'elementRoot' and include '<svelte:options accessors={true}/>'?
-
- Offending config:
- `,
- "background: rgb(57,34,34)",
- config
- );
- throw new Error();
- }
- element2 = target.querySelector(svelteOptions.selectorElement);
- if (element2 === null || element2 === void 0) {
- console.log(
- `%c[TRL] loadSvelteConfig error - HTMLElement target with 'selectorElement', '${svelteOptions.selectorElement}', not found for config:
- `,
- "background: rgb(57,34,34)",
- config
- );
- throw new Error();
- }
- }
- const injectHTML = !(config.target instanceof HTMLElement);
- return { config: svelteConfig, component, element: element2, injectHTML };
- }
- class SvelteReactive {
- /**
- * @type {SvelteApplication}
- */
- #application;
- /**
- * @type {boolean}
- */
- #initialized = false;
- /** @type {TJSSessionStorage} */
- #sessionStorage;
- /**
- * The Application option store which is injected into mounted Svelte component context under the `external` key.
- *
- * @type {StoreAppOptions}
- */
- #storeAppOptions;
- /**
- * Stores the update function for `#storeAppOptions`.
- *
- * @type {import('svelte/store').Writable.update}
- */
- #storeAppOptionsUpdate;
- /**
- * Stores the UI state data to make it accessible via getters.
- *
- * @type {object}
- */
- #dataUIState;
- /**
- * The UI option store which is injected into mounted Svelte component context under the `external` key.
- *
- * @type {StoreUIOptions}
- */
- #storeUIState;
- /**
- * Stores the update function for `#storeUIState`.
- *
- * @type {import('svelte/store').Writable.update}
- */
- #storeUIStateUpdate;
- /**
- * Stores the unsubscribe functions from local store subscriptions.
- *
- * @type {import('svelte/store').Unsubscriber[]}
- */
- #storeUnsubscribe = [];
- /**
- * @param {SvelteApplication} application - The host Foundry application.
- */
- constructor(application) {
- this.#application = application;
- const optionsSessionStorage = application?.options?.sessionStorage;
- if (optionsSessionStorage !== void 0 && !(optionsSessionStorage instanceof TJSSessionStorage)) {
- throw new TypeError(`'options.sessionStorage' is not an instance of TJSSessionStorage.`);
- }
- this.#sessionStorage = optionsSessionStorage !== void 0 ? optionsSessionStorage : new TJSSessionStorage();
- }
- /**
- * Initializes reactive support. Package private for internal use.
- *
- * @returns {SvelteStores|void} Internal methods to interact with Svelte stores.
- * @package
- */
- initialize() {
- if (this.#initialized) {
- return;
- }
- this.#initialized = true;
- this.#storesInitialize();
- return {
- appOptionsUpdate: this.#storeAppOptionsUpdate,
- uiOptionsUpdate: this.#storeUIStateUpdate,
- subscribe: this.#storesSubscribe.bind(this),
- unsubscribe: this.#storesUnsubscribe.bind(this)
- };
- }
- // Store getters -----------------------------------------------------------------------------------------------------
- /**
- * @returns {TJSSessionStorage} Returns TJSSessionStorage instance.
- */
- get sessionStorage() {
- return this.#sessionStorage;
- }
- /**
- * Returns the store for app options.
- *
- * @returns {StoreAppOptions} App options store.
- */
- get storeAppOptions() {
- return this.#storeAppOptions;
- }
- /**
- * Returns the store for UI options.
- *
- * @returns {StoreUIOptions} UI options store.
- */
- get storeUIState() {
- return this.#storeUIState;
- }
- // Only reactive getters ---------------------------------------------------------------------------------------------
- /**
- * Returns the current dragging UI state.
- *
- * @returns {boolean} Dragging UI state.
- */
- get dragging() {
- return this.#dataUIState.dragging;
- }
- /**
- * Returns the current minimized UI state.
- *
- * @returns {boolean} Minimized UI state.
- */
- get minimized() {
- return this.#dataUIState.minimized;
- }
- /**
- * Returns the current resizing UI state.
- *
- * @returns {boolean} Resizing UI state.
- */
- get resizing() {
- return this.#dataUIState.resizing;
- }
- // Reactive getter / setters -----------------------------------------------------------------------------------------
- /**
- * Returns the draggable app option.
- *
- * @returns {boolean} Draggable app option.
- */
- get draggable() {
- return this.#application?.options?.draggable;
- }
- /**
- * Returns the focusAuto app option.
- *
- * @returns {boolean} When true auto-management of app focus is enabled.
- */
- get focusAuto() {
- return this.#application?.options?.focusAuto;
- }
- /**
- * Returns the focusKeep app option.
- *
- * @returns {boolean} When `focusAuto` and `focusKeep` is true; keeps internal focus.
- */
- get focusKeep() {
- return this.#application?.options?.focusKeep;
- }
- /**
- * Returns the focusTrap app option.
- *
- * @returns {boolean} When true focus trapping / wrapping is enabled keeping focus inside app.
- */
- get focusTrap() {
- return this.#application?.options?.focusTrap;
- }
- /**
- * Returns the headerButtonNoClose app option.
- *
- * @returns {boolean} Remove the close the button in header app option.
- */
- get headerButtonNoClose() {
- return this.#application?.options?.headerButtonNoClose;
- }
- /**
- * Returns the headerButtonNoLabel app option.
- *
- * @returns {boolean} Remove the labels from buttons in header app option.
- */
- get headerButtonNoLabel() {
- return this.#application?.options?.headerButtonNoLabel;
- }
- /**
- * Returns the headerIcon app option.
- *
- * @returns {string|void} URL for header app icon.
- */
- get headerIcon() {
- return this.#application?.options?.headerIcon;
- }
- /**
- * Returns the headerNoTitleMinimized app option.
- *
- * @returns {boolean} When true removes the header title when minimized.
- */
- get headerNoTitleMinimized() {
- return this.#application?.options?.headerNoTitleMinimized;
- }
- /**
- * Returns the minimizable app option.
- *
- * @returns {boolean} Minimizable app option.
- */
- get minimizable() {
- return this.#application?.options?.minimizable;
- }
- /**
- * Returns the Foundry popOut state; {@link Application.popOut}
- *
- * @returns {boolean} Positionable app option.
- */
- get popOut() {
- return this.#application.popOut;
- }
- /**
- * Returns the positionable app option; {@link SvelteApplicationOptions.positionable}
- *
- * @returns {boolean} Positionable app option.
- */
- get positionable() {
- return this.#application?.options?.positionable;
- }
- /**
- * Returns the resizable option.
- *
- * @returns {boolean} Resizable app option.
- */
- get resizable() {
- return this.#application?.options?.resizable;
- }
- /**
- * Returns the title accessor from the parent Application class; {@link Application.title}
- * TODO: Application v2; note that super.title localizes `this.options.title`; IMHO it shouldn't.
- *
- * @returns {string} Title.
- */
- get title() {
- return this.#application.title;
- }
- /**
- * Sets `this.options.draggable` which is reactive for application shells.
- *
- * @param {boolean} draggable - Sets the draggable option.
- */
- set draggable(draggable2) {
- if (typeof draggable2 === "boolean") {
- this.setOptions("draggable", draggable2);
- }
- }
- /**
- * Sets `this.options.focusAuto` which is reactive for application shells.
- *
- * @param {boolean} focusAuto - Sets the focusAuto option.
- */
- set focusAuto(focusAuto) {
- if (typeof focusAuto === "boolean") {
- this.setOptions("focusAuto", focusAuto);
- }
- }
- /**
- * Sets `this.options.focusKeep` which is reactive for application shells.
- *
- * @param {boolean} focusKeep - Sets the focusKeep option.
- */
- set focusKeep(focusKeep) {
- if (typeof focusKeep === "boolean") {
- this.setOptions("focusKeep", focusKeep);
- }
- }
- /**
- * Sets `this.options.focusTrap` which is reactive for application shells.
- *
- * @param {boolean} focusTrap - Sets the focusTrap option.
- */
- set focusTrap(focusTrap) {
- if (typeof focusTrap === "boolean") {
- this.setOptions("focusTrap", focusTrap);
- }
- }
- /**
- * Sets `this.options.headerButtonNoClose` which is reactive for application shells.
- *
- * @param {boolean} headerButtonNoClose - Sets the headerButtonNoClose option.
- */
- set headerButtonNoClose(headerButtonNoClose) {
- if (typeof headerButtonNoClose === "boolean") {
- this.setOptions("headerButtonNoClose", headerButtonNoClose);
- }
- }
- /**
- * Sets `this.options.headerButtonNoLabel` which is reactive for application shells.
- *
- * @param {boolean} headerButtonNoLabel - Sets the headerButtonNoLabel option.
- */
- set headerButtonNoLabel(headerButtonNoLabel) {
- if (typeof headerButtonNoLabel === "boolean") {
- this.setOptions("headerButtonNoLabel", headerButtonNoLabel);
- }
- }
- /**
- * Sets `this.options.headerIcon` which is reactive for application shells.
- *
- * @param {string|void} headerIcon - Sets the headerButtonNoLabel option.
- */
- set headerIcon(headerIcon) {
- if (headerIcon === void 0 || typeof headerIcon === "string") {
- this.setOptions("headerIcon", headerIcon);
- }
- }
- /**
- * Sets `this.options.headerNoTitleMinimized` which is reactive for application shells.
- *
- * @param {boolean} headerNoTitleMinimized - Sets the headerNoTitleMinimized option.
- */
- set headerNoTitleMinimized(headerNoTitleMinimized) {
- if (typeof headerNoTitleMinimized === "boolean") {
- this.setOptions("headerNoTitleMinimized", headerNoTitleMinimized);
- }
- }
- /**
- * Sets `this.options.minimizable` which is reactive for application shells that are also pop out.
- *
- * @param {boolean} minimizable - Sets the minimizable option.
- */
- set minimizable(minimizable) {
- if (typeof minimizable === "boolean") {
- this.setOptions("minimizable", minimizable);
- }
- }
- /**
- * Sets `this.options.popOut` which is reactive for application shells. This will add / remove this application
- * from `ui.windows`.
- *
- * @param {boolean} popOut - Sets the popOut option.
- */
- set popOut(popOut) {
- if (typeof popOut === "boolean") {
- this.setOptions("popOut", popOut);
- }
- }
- /**
- * Sets `this.options.positionable` enabling / disabling {@link SvelteApplication.position.set}.
- *
- * @param {boolean} positionable - Sets the positionable option.
- */
- set positionable(positionable) {
- if (typeof positionable === "boolean") {
- this.setOptions("positionable", positionable);
- }
- }
- /**
- * Sets `this.options.resizable` which is reactive for application shells.
- *
- * @param {boolean} resizable - Sets the resizable option.
- */
- set resizable(resizable) {
- if (typeof resizable === "boolean") {
- this.setOptions("resizable", resizable);
- }
- }
- /**
- * Sets `this.options.title` which is reactive for application shells.
- *
- * Note: Will set empty string if title is undefined or null.
- *
- * @param {string|undefined|null} title - Application title; will be localized, so a translation key is fine.
- */
- set title(title) {
- if (typeof title === "string") {
- this.setOptions("title", title);
- } else if (title === void 0 || title === null) {
- this.setOptions("title", "");
- }
- }
- // Reactive Options API -------------------------------------------------------------------------------------------
- /**
- * Provides a way to safely get this applications options given an accessor string which describes the
- * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
- * to walk.
- *
- * // TODO DOCUMENT the accessor in more detail.
- *
- * @param {string} accessor - The path / key to set. You can set multiple levels.
- *
- * @param {*} [defaultValue] - A default value returned if the accessor is not found.
- *
- * @returns {*} Value at the accessor.
- */
- getOptions(accessor, defaultValue) {
- return safeAccess(this.#application.options, accessor, defaultValue);
- }
- /**
- * Provides a way to merge `options` into this applications options and update the appOptions store.
- *
- * @param {object} options - The options object to merge with `this.options`.
- */
- mergeOptions(options) {
- this.#storeAppOptionsUpdate((instanceOptions) => deepMerge(instanceOptions, options));
- }
- /**
- * Provides a way to safely set this applications options given an accessor string which describes the
- * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
- * to walk.
- *
- * Additionally if an application shell Svelte component is mounted and exports the `appOptions` property then
- * the application options is set to `appOptions` potentially updating the application shell / Svelte component.
- *
- * // TODO DOCUMENT the accessor in more detail.
- *
- * @param {string} accessor - The path / key to set. You can set multiple levels.
- *
- * @param {*} value - Value to set.
- */
- setOptions(accessor, value) {
- const success = safeSet(this.#application.options, accessor, value);
- if (success) {
- this.#storeAppOptionsUpdate(() => this.#application.options);
- }
- }
- /**
- * Initializes the Svelte stores and derived stores for the application options and UI state.
- *
- * While writable stores are created the update method is stored in private variables locally and derived Readable
- * stores are provided for essential options which are commonly used.
- *
- * These stores are injected into all Svelte components mounted under the `external` context: `storeAppOptions` and
- * ` storeUIState`.
- */
- #storesInitialize() {
- const writableAppOptions = writable$1(this.#application.options);
- this.#storeAppOptionsUpdate = writableAppOptions.update;
- const storeAppOptions = {
- subscribe: writableAppOptions.subscribe,
- draggable: propertyStore(writableAppOptions, "draggable"),
- focusAuto: propertyStore(writableAppOptions, "focusAuto"),
- focusKeep: propertyStore(writableAppOptions, "focusKeep"),
- focusTrap: propertyStore(writableAppOptions, "focusTrap"),
- headerButtonNoClose: propertyStore(writableAppOptions, "headerButtonNoClose"),
- headerButtonNoLabel: propertyStore(writableAppOptions, "headerButtonNoLabel"),
- headerIcon: propertyStore(writableAppOptions, "headerIcon"),
- headerNoTitleMinimized: propertyStore(writableAppOptions, "headerNoTitleMinimized"),
- minimizable: propertyStore(writableAppOptions, "minimizable"),
- popOut: propertyStore(writableAppOptions, "popOut"),
- positionable: propertyStore(writableAppOptions, "positionable"),
- resizable: propertyStore(writableAppOptions, "resizable"),
- title: propertyStore(writableAppOptions, "title")
- };
- Object.freeze(storeAppOptions);
- this.#storeAppOptions = storeAppOptions;
- this.#dataUIState = {
- dragging: false,
- headerButtons: [],
- minimized: this.#application._minimized,
- resizing: false
- };
- const writableUIOptions = writable$1(this.#dataUIState);
- this.#storeUIStateUpdate = writableUIOptions.update;
- const storeUIState = {
- subscribe: writableUIOptions.subscribe,
- dragging: propertyStore(writableUIOptions, "dragging"),
- headerButtons: derived(writableUIOptions, ($options, set) => set($options.headerButtons)),
- minimized: derived(writableUIOptions, ($options, set) => set($options.minimized)),
- resizing: propertyStore(writableUIOptions, "resizing")
- };
- Object.freeze(storeUIState);
- this.#storeUIState = storeUIState;
- }
- /**
- * Registers local store subscriptions for app options. `popOut` controls registering this app with `ui.windows`.
- *
- * @see SvelteApplication._injectHTML
- */
- #storesSubscribe() {
- this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.headerButtonNoClose, (value) => {
- this.updateHeaderButtons({ headerButtonNoClose: value });
- }));
- this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.headerButtonNoLabel, (value) => {
- this.updateHeaderButtons({ headerButtonNoLabel: value });
- }));
- this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.popOut, (value) => {
- if (value && this.#application.rendered) {
- globalThis.ui.windows[this.#application.appId] = this.#application;
- } else {
- delete globalThis.ui.windows[this.#application.appId];
- }
- }));
- }
- /**
- * Unsubscribes from any locally monitored stores.
- *
- * @see SvelteApplication.close
- */
- #storesUnsubscribe() {
- this.#storeUnsubscribe.forEach((unsubscribe) => unsubscribe());
- this.#storeUnsubscribe = [];
- }
- /**
- * Updates the UI Options store with the current header buttons. You may dynamically add / remove header buttons
- * if using an application shell Svelte component. In either overriding `_getHeaderButtons` or responding to the
- * Hooks fired return a new button array and the uiOptions store is updated and the application shell will render
- * the new buttons.
- *
- * Optionally you can set in the SvelteApplication app options {@link SvelteApplicationOptions.headerButtonNoClose}
- * to remove the close button and {@link SvelteApplicationOptions.headerButtonNoLabel} to true and labels will be
- * removed from the header buttons.
- *
- * @param {object} opts - Optional parameters (for internal use)
- *
- * @param {boolean} opts.headerButtonNoClose - The value for `headerButtonNoClose`.
- *
- * @param {boolean} opts.headerButtonNoLabel - The value for `headerButtonNoLabel`.
- */
- updateHeaderButtons({
- headerButtonNoClose = this.#application.options.headerButtonNoClose,
- headerButtonNoLabel = this.#application.options.headerButtonNoLabel
- } = {}) {
- let buttons = this.#application._getHeaderButtons();
- if (typeof headerButtonNoClose === "boolean" && headerButtonNoClose) {
- buttons = buttons.filter((button) => button.class !== "close");
- }
- if (typeof headerButtonNoLabel === "boolean" && headerButtonNoLabel) {
- for (const button of buttons) {
- button.label = void 0;
- }
- }
- this.#storeUIStateUpdate((options) => {
- options.headerButtons = buttons;
- return options;
- });
- }
- }
- class SvelteApplication extends Application {
- /**
- * Stores the first mounted component which follows the application shell contract.
- *
- * @type {MountedAppShell[]|null[]} Application shell.
- */
- #applicationShellHolder = [null];
- /**
- * Stores and manages application state for saving / restoring / serializing.
- *
- * @type {ApplicationState}
- */
- #applicationState;
- /**
- * Stores the target element which may not necessarily be the main element.
- *
- * @type {HTMLElement}
- */
- #elementTarget = null;
- /**
- * Stores the content element which is set for application shells.
- *
- * @type {HTMLElement}
- */
- #elementContent = null;
- /**
- * Stores initial z-index from `_renderOuter` to set to target element / Svelte component.
- *
- * @type {number}
- */
- #initialZIndex = 95;
- /**
- * Stores on mount state which is checked in _render to trigger onSvelteMount callback.
- *
- * @type {boolean}
- */
- #onMount = false;
- /**
- * The position store.
- *
- * @type {Position}
- */
- #position;
- /**
- * Contains the Svelte stores and reactive accessors.
- *
- * @type {SvelteReactive}
- */
- #reactive;
- /**
- * Stores SvelteData entries with instantiated Svelte components.
- *
- * @type {SvelteData[]}
- */
- #svelteData = [];
- /**
- * Provides a helper class that combines multiple methods for interacting with the mounted components tracked in
- * {@link SvelteData}.
- *
- * @type {GetSvelteData}
- */
- #getSvelteData = new GetSvelteData(this.#applicationShellHolder, this.#svelteData);
- /**
- * Contains methods to interact with the Svelte stores.
- *
- * @type {SvelteStores}
- */
- #stores;
- /**
- * @param {SvelteApplicationOptions} options - The options for the application.
- *
- * @inheritDoc
- */
- constructor(options = {}) {
- super(options);
- this.#applicationState = new ApplicationState(this);
- this.#position = new Position(this, {
- ...this.position,
- ...this.options,
- initial: this.options.positionInitial,
- ortho: this.options.positionOrtho,
- validator: this.options.positionValidator
- });
- delete this.position;
- Object.defineProperty(this, "position", {
- get: () => this.#position,
- set: (position) => {
- if (isObject(position)) {
- this.#position.set(position);
- }
- }
- });
- this.#reactive = new SvelteReactive(this);
- this.#stores = this.#reactive.initialize();
- }
- /**
- * Specifies the default options that SvelteApplication supports.
- *
- * @returns {SvelteApplicationOptions} options - Application options.
- * @see https://foundryvtt.com/api/interfaces/client.ApplicationOptions.html
- */
- static get defaultOptions() {
- return deepMerge(super.defaultOptions, {
- defaultCloseAnimation: true,
- // If false the default slide close animation is not run.
- draggable: true,
- // If true then application shells are draggable.
- focusAuto: true,
- // When true auto-management of app focus is enabled.
- focusKeep: false,
- // When `focusAuto` and `focusKeep` is true; keeps internal focus.
- focusSource: void 0,
- // Stores any A11yFocusSource data that is applied when app is closed.
- focusTrap: true,
- // When true focus trapping / wrapping is enabled keeping focus inside app.
- headerButtonNoClose: false,
- // If true then the close header button is removed.
- headerButtonNoLabel: false,
- // If true then header button labels are removed for application shells.
- headerIcon: void 0,
- // Sets a header icon given an image URL.
- headerNoTitleMinimized: false,
- // If true then header title is hidden when application is minimized.
- minHeight: MIN_WINDOW_HEIGHT,
- // Assigned to position. Number specifying minimum window height.
- minWidth: MIN_WINDOW_WIDTH,
- // Assigned to position. Number specifying minimum window width.
- positionable: true,
- // If false then `position.set` does not take effect.
- positionInitial: Position.Initial.browserCentered,
- // A helper for initial position placement.
- positionOrtho: true,
- // When true Position is optimized for orthographic use.
- positionValidator: Position.Validators.transformWindow,
- // A function providing the default validator.
- sessionStorage: void 0,
- // An instance of SessionStorage to share across SvelteApplications.
- svelte: void 0,
- // A Svelte configuration object.
- transformOrigin: "top left"
- // By default, 'top / left' respects rotation when minimizing.
- });
- }
- /**
- * Returns the content element if an application shell is mounted.
- *
- * @returns {HTMLElement} Content element.
- */
- get elementContent() {
- return this.#elementContent;
- }
- /**
- * Returns the target element or main element if no target defined.
- *
- * @returns {HTMLElement} Target element.
- */
- get elementTarget() {
- return this.#elementTarget;
- }
- /**
- * Returns the reactive accessors & Svelte stores for SvelteApplication.
- *
- * @returns {SvelteReactive} The reactive accessors & Svelte stores.
- */
- get reactive() {
- return this.#reactive;
- }
- /**
- * Returns the application state manager.
- *
- * @returns {ApplicationState} The application state manager.
- */
- get state() {
- return this.#applicationState;
- }
- /**
- * Returns the Svelte helper class w/ various methods to access mounted Svelte components.
- *
- * @returns {GetSvelteData} GetSvelteData
- */
- get svelte() {
- return this.#getSvelteData;
- }
- /**
- * In this case of when a template is defined in app options `html` references the inner HTML / template. However,
- * to activate classic v1 tabs for a Svelte component the element target is passed as an array simulating JQuery as
- * the element is retrieved immediately and the core listeners use standard DOM queries.
- *
- * @inheritDoc
- * @protected
- * @ignore
- */
- _activateCoreListeners(html) {
- super._activateCoreListeners(typeof this.options.template === "string" ? html : [this.#elementTarget]);
- }
- /**
- * Provide an override to set this application as the active window regardless of z-index. Changes behaviour from
- * Foundry core. This is important / used for instance in dialog key handling for left / right button selection.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {boolean} [opts.force=false] - Force bring to top; will increment z-index by popOut order.
- *
- */
- bringToTop({ force = false } = {}) {
- if (force || this.popOut) {
- super.bringToTop();
- }
- if (document.activeElement !== document.body && !this.elementTarget.contains(document.activeElement)) {
- if (document.activeElement instanceof HTMLElement) {
- document.activeElement.blur();
- }
- document.body.focus();
- }
- globalThis.ui.activeWindow = this;
- }
- /**
- * Note: This method is fully overridden and duplicated as Svelte components need to be destroyed manually and the
- * best visual result is to destroy them after the default slide up animation occurs, but before the element
- * is removed from the DOM.
- *
- * If you destroy the Svelte components before the slide up animation the Svelte elements are removed immediately
- * from the DOM. The purpose of overriding ensures the slide up animation is always completed before
- * the Svelte components are destroyed and then the element is removed from the DOM.
- *
- * Close the application and un-register references to it within UI mappings.
- * This function returns a Promise which resolves once the window closing animation concludes
- *
- * @param {object} [options] - Optional parameters.
- *
- * @param {boolean} [options.force] - Force close regardless of render state.
- *
- * @returns {Promise<void>} A Promise which resolves once the application is closed.
- * @ignore
- */
- async close(options = {}) {
- const states = Application.RENDER_STATES;
- if (!options.force && ![states.RENDERED, states.ERROR].includes(this._state)) {
- return;
- }
- this.#stores.unsubscribe();
- this._state = states.CLOSING;
- const el = this.#elementTarget;
- if (!el) {
- return this._state = states.CLOSED;
- }
- const content = el.querySelector(".window-content");
- if (content) {
- content.style.overflow = "hidden";
- for (let cntr = content.children.length; --cntr >= 0; ) {
- content.children[cntr].style.overflow = "hidden";
- }
- }
- for (const cls of this.constructor._getInheritanceChain()) {
- Hooks.call(`close${cls.name}`, this, el);
- }
- const animate = typeof this.options.defaultCloseAnimation === "boolean" ? this.options.defaultCloseAnimation : true;
- if (animate) {
- el.style.minHeight = "0";
- const { paddingBottom, paddingTop } = globalThis.getComputedStyle(el);
- await el.animate([
- { maxHeight: `${el.clientHeight}px`, paddingTop, paddingBottom },
- { maxHeight: 0, paddingTop: 0, paddingBottom: 0 }
- ], { duration: 250, easing: "ease-in", fill: "forwards" }).finished;
- }
- const svelteDestroyPromises = [];
- for (const entry of this.#svelteData) {
- svelteDestroyPromises.push(outroAndDestroy(entry.component));
- const eventbus = entry.config.eventbus;
- if (isObject(eventbus) && typeof eventbus.off === "function") {
- eventbus.off();
- entry.config.eventbus = void 0;
- }
- }
- await Promise.all(svelteDestroyPromises);
- this.#svelteData.length = 0;
- el.remove();
- this.position.state.restore({
- name: "#beforeMinimized",
- properties: ["width", "height"],
- silent: true,
- remove: true
- });
- this.#applicationShellHolder[0] = null;
- this._element = null;
- this.#elementContent = null;
- this.#elementTarget = null;
- delete globalThis.ui.windows[this.appId];
- this._minimized = false;
- this._scrollPositions = null;
- this._state = states.CLOSED;
- this.#onMount = false;
- this.#stores.uiOptionsUpdate((storeOptions) => deepMerge(storeOptions, { minimized: this._minimized }));
- A11yHelper.applyFocusSource(this.options.focusSource);
- delete this.options.focusSource;
- }
- /**
- * Inject the Svelte components defined in `this.options.svelte`. The Svelte component can attach to the existing
- * pop-out of Application or provide no template and render into a document fragment which is then attached to the
- * DOM.
- *
- * @param {JQuery} html -
- *
- * @inheritDoc
- * @ignore
- */
- _injectHTML(html) {
- if (this.popOut && html.length === 0 && Array.isArray(this.options.svelte)) {
- throw new Error(
- "SvelteApplication - _injectHTML - A popout app with no template can only support one Svelte component."
- );
- }
- this.reactive.updateHeaderButtons();
- const elementRootUpdate = () => {
- let cntr = 0;
- return (elementRoot) => {
- if (elementRoot !== null && elementRoot !== void 0 && cntr++ > 0) {
- this.#updateApplicationShell();
- return true;
- }
- return false;
- };
- };
- if (Array.isArray(this.options.svelte)) {
- for (const svelteConfig of this.options.svelte) {
- const svelteData = loadSvelteConfig({
- app: this,
- template: html[0],
- config: svelteConfig,
- elementRootUpdate
- });
- if (isApplicationShell(svelteData.component)) {
- if (this.svelte.applicationShell !== null) {
- throw new Error(
- `SvelteApplication - _injectHTML - An application shell is already mounted; offending config:
- ${JSON.stringify(svelteConfig)}`
- );
- }
- this.#applicationShellHolder[0] = svelteData.component;
- if (isHMRProxy(svelteData.component) && Array.isArray(svelteData.component?.$$?.on_hmr)) {
- svelteData.component.$$.on_hmr.push(() => () => this.#updateApplicationShell());
- }
- }
- this.#svelteData.push(svelteData);
- }
- } else if (isObject(this.options.svelte)) {
- const svelteData = loadSvelteConfig({
- app: this,
- template: html[0],
- config: this.options.svelte,
- elementRootUpdate
- });
- if (isApplicationShell(svelteData.component)) {
- if (this.svelte.applicationShell !== null) {
- throw new Error(
- `SvelteApplication - _injectHTML - An application shell is already mounted; offending config:
- ${JSON.stringify(this.options.svelte)}`
- );
- }
- this.#applicationShellHolder[0] = svelteData.component;
- if (isHMRProxy(svelteData.component) && Array.isArray(svelteData.component?.$$?.on_hmr)) {
- svelteData.component.$$.on_hmr.push(() => () => this.#updateApplicationShell());
- }
- }
- this.#svelteData.push(svelteData);
- }
- const isDocumentFragment = html.length && html[0] instanceof DocumentFragment;
- let injectHTML = true;
- for (const svelteData of this.#svelteData) {
- if (!svelteData.injectHTML) {
- injectHTML = false;
- break;
- }
- }
- if (injectHTML) {
- super._injectHTML(html);
- }
- if (this.svelte.applicationShell !== null) {
- this._element = $(this.svelte.applicationShell.elementRoot);
- this.#elementContent = hasGetter(this.svelte.applicationShell, "elementContent") ? this.svelte.applicationShell.elementContent : null;
- this.#elementTarget = hasGetter(this.svelte.applicationShell, "elementTarget") ? this.svelte.applicationShell.elementTarget : null;
- } else if (isDocumentFragment) {
- for (const svelteData of this.#svelteData) {
- if (svelteData.element instanceof HTMLElement) {
- this._element = $(svelteData.element);
- break;
- }
- }
- }
- if (this.#elementTarget === null) {
- this.#elementTarget = typeof this.options.selectorTarget === "string" ? this._element[0].querySelector(this.options.selectorTarget) : this._element[0];
- }
- if (this.#elementTarget === null || this.#elementTarget === void 0) {
- throw new Error(`SvelteApplication - _injectHTML: Target element '${this.options.selectorTarget}' not found.`);
- }
- if (typeof this.options.positionable === "boolean" && this.options.positionable) {
- this.#elementTarget.style.zIndex = typeof this.options.zIndex === "number" ? this.options.zIndex : this.#initialZIndex ?? 95;
- }
- this.#stores.subscribe();
- }
- /**
- * Provides a mechanism to update the UI options store for maximized.
- *
- * Note: the sanity check is duplicated from {@link Application.maximize} the store is updated _before_
- * performing the rest of animations. This allows application shells to remove / show any resize handlers
- * correctly. Extra constraint data is stored in a saved position state in {@link SvelteApplication.minimize}
- * to animate the content area.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {boolean} [opts.animate=true] - When true perform default maximizing animation.
- *
- * @param {number} [opts.duration=0.1] - Controls content area animation duration in seconds.
- */
- async maximize({ animate = true, duration = 0.1 } = {}) {
- if (!this.popOut || [false, null].includes(this._minimized)) {
- return;
- }
- this._minimized = null;
- const durationMS = duration * 1e3;
- const element2 = this.elementTarget;
- const header = element2.querySelector(".window-header");
- const content = element2.querySelector(".window-content");
- const positionBefore = this.position.state.get({ name: "#beforeMinimized" });
- if (animate) {
- await this.position.state.restore({
- name: "#beforeMinimized",
- async: true,
- animateTo: true,
- properties: ["width"],
- duration: 0.1
- });
- }
- element2.classList.remove("minimized");
- for (let cntr = header.children.length; --cntr >= 0; ) {
- header.children[cntr].style.display = null;
- }
- content.style.display = null;
- let constraints;
- if (animate) {
- ({ constraints } = this.position.state.restore({
- name: "#beforeMinimized",
- animateTo: true,
- properties: ["height"],
- remove: true,
- duration
- }));
- } else {
- ({ constraints } = this.position.state.remove({ name: "#beforeMinimized" }));
- }
- await content.animate([
- { maxHeight: 0, paddingTop: 0, paddingBottom: 0, offset: 0 },
- { ...constraints, offset: 1 },
- { maxHeight: "100%", offset: 1 }
- ], { duration: durationMS, fill: "forwards" }).finished;
- this.position.set({
- minHeight: positionBefore.minHeight ?? this.options?.minHeight ?? MIN_WINDOW_HEIGHT,
- minWidth: positionBefore.minWidth ?? this.options?.minWidth ?? MIN_WINDOW_WIDTH
- });
- element2.style.minWidth = null;
- element2.style.minHeight = null;
- this._minimized = false;
- setTimeout(() => {
- content.style.overflow = null;
- for (let cntr = content.children.length; --cntr >= 0; ) {
- content.children[cntr].style.overflow = null;
- }
- }, 50);
- this.#stores.uiOptionsUpdate((options) => deepMerge(options, { minimized: false }));
- }
- /**
- * Provides a mechanism to update the UI options store for minimized.
- *
- * Note: the sanity check is duplicated from {@link Application.minimize} the store is updated _before_
- * performing the rest of animations. This allows application shells to remove / show any resize handlers
- * correctly. Extra constraint data is stored in a saved position state in {@link SvelteApplication.minimize}
- * to animate the content area.
- *
- * @param {object} [opts] - Optional parameters
- *
- * @param {boolean} [opts.animate=true] - When true perform default minimizing animation.
- *
- * @param {number} [opts.duration=0.1] - Controls content area animation duration in seconds.
- */
- async minimize({ animate = true, duration = 0.1 } = {}) {
- if (!this.rendered || !this.popOut || [true, null].includes(this._minimized)) {
- return;
- }
- this.#stores.uiOptionsUpdate((options) => deepMerge(options, { minimized: true }));
- this._minimized = null;
- const durationMS = duration * 1e3;
- const element2 = this.elementTarget;
- const header = element2.querySelector(".window-header");
- const content = element2.querySelector(".window-content");
- const beforeMinWidth = this.position.minWidth;
- const beforeMinHeight = this.position.minHeight;
- this.position.set({ minWidth: 100, minHeight: 30 });
- element2.style.minWidth = "100px";
- element2.style.minHeight = "30px";
- if (content) {
- content.style.overflow = "hidden";
- for (let cntr = content.children.length; --cntr >= 0; ) {
- content.children[cntr].style.overflow = "hidden";
- }
- }
- const { paddingBottom, paddingTop } = globalThis.getComputedStyle(content);
- const constraints = {
- maxHeight: `${content.clientHeight}px`,
- paddingTop,
- paddingBottom
- };
- if (animate) {
- const animation2 = content.animate([
- constraints,
- { maxHeight: 0, paddingTop: 0, paddingBottom: 0 }
- ], { duration: durationMS, fill: "forwards" });
- animation2.finished.then(() => content.style.display = "none");
- } else {
- setTimeout(() => content.style.display = "none", durationMS);
- }
- const saved = this.position.state.save({ name: "#beforeMinimized", constraints });
- saved.minWidth = beforeMinWidth;
- saved.minHeight = beforeMinHeight;
- const headerOffsetHeight = header.offsetHeight;
- this.position.minHeight = headerOffsetHeight;
- if (animate) {
- await this.position.animate.to({ height: headerOffsetHeight }, { duration }).finished;
- }
- for (let cntr = header.children.length; --cntr >= 0; ) {
- const className = header.children[cntr].className;
- if (className.includes("window-title") || className.includes("close")) {
- continue;
- }
- if (className.includes("keep-minimized")) {
- header.children[cntr].style.display = "block";
- continue;
- }
- header.children[cntr].style.display = "none";
- }
- if (animate) {
- await this.position.animate.to({ width: MIN_WINDOW_WIDTH }, { duration: 0.1 }).finished;
- }
- element2.classList.add("minimized");
- this._minimized = true;
- }
- /**
- * Provides a callback after all Svelte components are initialized.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {HTMLElement} [opts.element] - HTMLElement container for main application element.
- *
- * @param {HTMLElement} [opts.elementContent] - HTMLElement container for content area of application shells.
- *
- * @param {HTMLElement} [opts.elementTarget] - HTMLElement container for main application target element.
- */
- onSvelteMount({ element: element2, elementContent, elementTarget } = {}) {
- }
- // eslint-disable-line no-unused-vars
- /**
- * Provides a callback after the main application shell is remounted. This may occur during HMR / hot module
- * replacement or directly invoked from the `elementRootUpdate` callback passed to the application shell component
- * context.
- *
- * @param {object} [opts] - Optional parameters.
- *
- * @param {HTMLElement} [opts.element] - HTMLElement container for main application element.
- *
- * @param {HTMLElement} [opts.elementContent] - HTMLElement container for content area of application shells.
- *
- * @param {HTMLElement} [opts.elementTarget] - HTMLElement container for main application target element.
- */
- onSvelteRemount({ element: element2, elementContent, elementTarget } = {}) {
- }
- // eslint-disable-line no-unused-vars
- /**
- * Override replacing HTML as Svelte components control the rendering process. Only potentially change the outer
- * application frame / title for pop-out applications.
- *
- * @inheritDoc
- * @ignore
- */
- _replaceHTML(element2, html) {
- if (!element2.length) {
- return;
- }
- this.reactive.updateHeaderButtons();
- }
- /**
- * Provides an override verifying that a new Application being rendered for the first time doesn't have a
- * corresponding DOM element already loaded. This is a check that only occurs when `this._state` is
- * `Application.RENDER_STATES.NONE`. It is useful in particular when SvelteApplication has a static ID
- * explicitly set in `this.options.id` and long intro / outro transitions are assigned. If a new application
- * sharing this static ID attempts to open / render for the first time while an existing DOM element sharing
- * this static ID exists then the initial render is cancelled below rather than crashing later in the render
- * cycle {@link Position.set}.
- *
- * @inheritDoc
- * @protected
- * @ignore
- */
- async _render(force = false, options = {}) {
- if (isObject(options?.focusSource)) {
- this.options.focusSource = options.focusSource;
- }
- if (this._state === Application.RENDER_STATES.NONE && document.querySelector(`#${this.id}`) instanceof HTMLElement) {
- console.warn(`SvelteApplication - _render: A DOM element already exists for CSS ID '${this.id}'. Cancelling initial render for new application with appId '${this.appId}'.`);
- return;
- }
- await super._render(force, options);
- if (!this.#onMount) {
- this.onSvelteMount({ element: this._element[0], elementContent: this.#elementContent, elementTarget: this.#elementTarget });
- this.#onMount = true;
- }
- }
- /**
- * Render the inner application content. Only render a template if one is defined otherwise provide an empty
- * JQuery element per the core Foundry API.
- *
- * @param {object} data The data used to render the inner template
- *
- * @returns {Promise.<JQuery>} A promise resolving to the constructed jQuery object
- *
- * @protected
- * @ignore
- */
- async _renderInner(data) {
- const html = typeof this.template === "string" ? await renderTemplate(this.template, data) : document.createDocumentFragment();
- return $(html);
- }
- /**
- * Stores the initial z-index set in `_renderOuter` which is used in `_injectHTML` to set the target element
- * z-index after the Svelte component is mounted.
- *
- * @returns {Promise<JQuery>} Outer frame / unused.
- * @protected
- * @ignore
- */
- async _renderOuter() {
- const html = await super._renderOuter();
- this.#initialZIndex = html[0].style.zIndex;
- return html;
- }
- /**
- * All calculation and updates of position are implemented in {@link Position.set}. This allows position to be fully
- * reactive and in control of updating inline styles for the application.
- *
- * This method remains for backward compatibility with Foundry. If you have a custom override quite likely you need
- * to update to using the {@link Position.validators} functionality.
- *
- * @param {PositionDataExtended} [position] - Position data.
- *
- * @returns {Position} The updated position object for the application containing the new values
- */
- setPosition(position) {
- return this.position.set(position);
- }
- /**
- * This method is invoked by the `elementRootUpdate` callback that is added to the external context passed to
- * Svelte components. When invoked it updates the local element roots tracked by SvelteApplication.
- *
- * This method may also be invoked by HMR / hot module replacement via `svelte-hmr`.
- */
- #updateApplicationShell() {
- const applicationShell = this.svelte.applicationShell;
- if (applicationShell !== null) {
- this._element = $(applicationShell.elementRoot);
- this.#elementContent = hasGetter(applicationShell, "elementContent") ? applicationShell.elementContent : null;
- this.#elementTarget = hasGetter(applicationShell, "elementTarget") ? applicationShell.elementTarget : null;
- if (this.#elementTarget === null) {
- this.#elementTarget = typeof this.options.selectorTarget === "string" ? this._element[0].querySelector(this.options.selectorTarget) : this._element[0];
- }
- if (typeof this.options.positionable === "boolean" && this.options.positionable) {
- this.#elementTarget.style.zIndex = typeof this.options.zIndex === "number" ? this.options.zIndex : this.#initialZIndex ?? 95;
- super.bringToTop();
- this.position.set(this.position.get());
- }
- super._activateCoreListeners([this.#elementTarget]);
- this.onSvelteRemount({ element: this._element[0], elementContent: this.#elementContent, elementTarget: this.#elementTarget });
- }
- }
- }
- const s_STYLE_KEY = "#__trl-root-styles";
- const cssVariables = new StyleManager({ docKey: s_STYLE_KEY, version: 1 });
- const TJSContainer_svelte_svelte_type_style_lang = "";
- function resizeObserver(node, target) {
- ResizeObserverManager.add(node, target);
- return {
- update: (newTarget) => {
- ResizeObserverManager.remove(node, target);
- target = newTarget;
- ResizeObserverManager.add(node, target);
- },
- destroy: () => {
- ResizeObserverManager.remove(node, target);
- }
- };
- }
- resizeObserver.updateCache = function(el) {
- if (!(el instanceof HTMLElement)) {
- throw new TypeError(`resizeObserverUpdate error: 'el' is not an HTMLElement.`);
- }
- const subscribers = s_MAP.get(el);
- if (Array.isArray(subscribers)) {
- const computed = globalThis.getComputedStyle(el);
- const borderBottom = styleParsePixels(el.style.borderBottom) ?? styleParsePixels(computed.borderBottom) ?? 0;
- const borderLeft = styleParsePixels(el.style.borderLeft) ?? styleParsePixels(computed.borderLeft) ?? 0;
- const borderRight = styleParsePixels(el.style.borderRight) ?? styleParsePixels(computed.borderRight) ?? 0;
- const borderTop = styleParsePixels(el.style.borderTop) ?? styleParsePixels(computed.borderTop) ?? 0;
- const paddingBottom = styleParsePixels(el.style.paddingBottom) ?? styleParsePixels(computed.paddingBottom) ?? 0;
- const paddingLeft = styleParsePixels(el.style.paddingLeft) ?? styleParsePixels(computed.paddingLeft) ?? 0;
- const paddingRight = styleParsePixels(el.style.paddingRight) ?? styleParsePixels(computed.paddingRight) ?? 0;
- const paddingTop = styleParsePixels(el.style.paddingTop) ?? styleParsePixels(computed.paddingTop) ?? 0;
- const additionalWidth = borderLeft + borderRight + paddingLeft + paddingRight;
- const additionalHeight = borderTop + borderBottom + paddingTop + paddingBottom;
- for (const subscriber of subscribers) {
- subscriber.styles.additionalWidth = additionalWidth;
- subscriber.styles.additionalHeight = additionalHeight;
- s_UPDATE_SUBSCRIBER(subscriber, subscriber.contentWidth, subscriber.contentHeight);
- }
- }
- };
- const s_MAP = /* @__PURE__ */ new Map();
- class ResizeObserverManager {
- /**
- * Add an HTMLElement and ResizeObserverTarget instance for monitoring. Create cached style attributes for the
- * given element include border & padding dimensions for offset width / height calculations.
- *
- * @param {HTMLElement} el - The element to observe.
- *
- * @param {ResizeObserverTarget} target - A target that contains one of several mechanisms for updating resize data.
- */
- static add(el, target) {
- const updateType = s_GET_UPDATE_TYPE(target);
- if (updateType === 0) {
- throw new Error(`'target' does not match supported ResizeObserverManager update mechanisms.`);
- }
- const computed = globalThis.getComputedStyle(el);
- const borderBottom = styleParsePixels(el.style.borderBottom) ?? styleParsePixels(computed.borderBottom) ?? 0;
- const borderLeft = styleParsePixels(el.style.borderLeft) ?? styleParsePixels(computed.borderLeft) ?? 0;
- const borderRight = styleParsePixels(el.style.borderRight) ?? styleParsePixels(computed.borderRight) ?? 0;
- const borderTop = styleParsePixels(el.style.borderTop) ?? styleParsePixels(computed.borderTop) ?? 0;
- const paddingBottom = styleParsePixels(el.style.paddingBottom) ?? styleParsePixels(computed.paddingBottom) ?? 0;
- const paddingLeft = styleParsePixels(el.style.paddingLeft) ?? styleParsePixels(computed.paddingLeft) ?? 0;
- const paddingRight = styleParsePixels(el.style.paddingRight) ?? styleParsePixels(computed.paddingRight) ?? 0;
- const paddingTop = styleParsePixels(el.style.paddingTop) ?? styleParsePixels(computed.paddingTop) ?? 0;
- const data = {
- updateType,
- target,
- // Stores most recent contentRect.width and contentRect.height values from ResizeObserver.
- contentWidth: 0,
- contentHeight: 0,
- // Convenience data for total border & padding for offset width & height calculations.
- styles: {
- additionalWidth: borderLeft + borderRight + paddingLeft + paddingRight,
- additionalHeight: borderTop + borderBottom + paddingTop + paddingBottom
- }
- };
- if (s_MAP.has(el)) {
- const subscribers = s_MAP.get(el);
- subscribers.push(data);
- } else {
- s_MAP.set(el, [data]);
- }
- s_RESIZE_OBSERVER.observe(el);
- }
- /**
- * Removes all targets from monitoring when just an element is provided otherwise removes a specific target
- * from the monitoring map. If no more targets remain then the element is removed from monitoring.
- *
- * @param {HTMLElement} el - Element to remove from monitoring.
- *
- * @param {ResizeObserverTarget} [target] - A specific target to remove from monitoring.
- */
- static remove(el, target = void 0) {
- const subscribers = s_MAP.get(el);
- if (Array.isArray(subscribers)) {
- const index = subscribers.findIndex((entry) => entry.target === target);
- if (index >= 0) {
- s_UPDATE_SUBSCRIBER(subscribers[index], void 0, void 0);
- subscribers.splice(index, 1);
- }
- if (subscribers.length === 0) {
- s_MAP.delete(el);
- s_RESIZE_OBSERVER.unobserve(el);
- }
- }
- }
- }
- const s_UPDATE_TYPES = {
- none: 0,
- attribute: 1,
- function: 2,
- resizeObserved: 3,
- setContentBounds: 4,
- setDimension: 5,
- storeObject: 6,
- storesObject: 7
- };
- const s_RESIZE_OBSERVER = new ResizeObserver((entries) => {
- for (const entry of entries) {
- const subscribers = s_MAP.get(entry?.target);
- if (Array.isArray(subscribers)) {
- const contentWidth = entry.contentRect.width;
- const contentHeight = entry.contentRect.height;
- for (const subscriber of subscribers) {
- s_UPDATE_SUBSCRIBER(subscriber, contentWidth, contentHeight);
- }
- }
- }
- });
- function s_GET_UPDATE_TYPE(target) {
- if (target?.resizeObserved instanceof Function) {
- return s_UPDATE_TYPES.resizeObserved;
- }
- if (target?.setDimension instanceof Function) {
- return s_UPDATE_TYPES.setDimension;
- }
- if (target?.setContentBounds instanceof Function) {
- return s_UPDATE_TYPES.setContentBounds;
- }
- const targetType = typeof target;
- if (targetType !== null && (targetType === "object" || targetType === "function")) {
- if (isUpdatableStore(target.resizeObserved)) {
- return s_UPDATE_TYPES.storeObject;
- }
- const stores = target?.stores;
- if (isObject(stores) || typeof stores === "function") {
- if (isUpdatableStore(stores.resizeObserved)) {
- return s_UPDATE_TYPES.storesObject;
- }
- }
- }
- if (targetType !== null && targetType === "object") {
- return s_UPDATE_TYPES.attribute;
- }
- if (targetType === "function") {
- return s_UPDATE_TYPES.function;
- }
- return s_UPDATE_TYPES.none;
- }
- function s_UPDATE_SUBSCRIBER(subscriber, contentWidth, contentHeight) {
- const styles = subscriber.styles;
- subscriber.contentWidth = contentWidth;
- subscriber.contentHeight = contentHeight;
- const offsetWidth = Number.isFinite(contentWidth) ? contentWidth + styles.additionalWidth : void 0;
- const offsetHeight = Number.isFinite(contentHeight) ? contentHeight + styles.additionalHeight : void 0;
- const target = subscriber.target;
- switch (subscriber.updateType) {
- case s_UPDATE_TYPES.attribute:
- target.contentWidth = contentWidth;
- target.contentHeight = contentHeight;
- target.offsetWidth = offsetWidth;
- target.offsetHeight = offsetHeight;
- break;
- case s_UPDATE_TYPES.function:
- target?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
- break;
- case s_UPDATE_TYPES.resizeObserved:
- target.resizeObserved?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
- break;
- case s_UPDATE_TYPES.setContentBounds:
- target.setContentBounds?.(contentWidth, contentHeight);
- break;
- case s_UPDATE_TYPES.setDimension:
- target.setDimension?.(offsetWidth, offsetHeight);
- break;
- case s_UPDATE_TYPES.storeObject:
- target.resizeObserved.update((object) => {
- object.contentHeight = contentHeight;
- object.contentWidth = contentWidth;
- object.offsetHeight = offsetHeight;
- object.offsetWidth = offsetWidth;
- return object;
- });
- break;
- case s_UPDATE_TYPES.storesObject:
- target.stores.resizeObserved.update((object) => {
- object.contentHeight = contentHeight;
- object.contentWidth = contentWidth;
- object.offsetHeight = offsetHeight;
- object.offsetWidth = offsetWidth;
- return object;
- });
- break;
- }
- }
- function applyStyles(node, properties) {
- function setProperties() {
- if (typeof properties !== "object") {
- return;
- }
- for (const prop of Object.keys(properties)) {
- node.style.setProperty(`${prop}`, properties[prop]);
- }
- }
- setProperties();
- return {
- update(newProperties) {
- properties = newProperties;
- setProperties();
- }
- };
- }
- function draggable(node, {
- position,
- active: active2 = true,
- button = 0,
- storeDragging = void 0,
- ease = false,
- easeOptions = { duration: 0.1, ease: cubicOut },
- hasTargetClassList,
- ignoreTargetClassList
- }) {
- if (hasTargetClassList !== void 0 && !isIterable(hasTargetClassList)) {
- throw new TypeError(`'hasTargetClassList' is not iterable.`);
- }
- if (ignoreTargetClassList !== void 0 && !isIterable(ignoreTargetClassList)) {
- throw new TypeError(`'ignoreTargetClassList' is not iterable.`);
- }
- let initialPosition = null;
- let initialDragPoint = {};
- let dragging = false;
- let quickTo = position.animate.quickTo(["top", "left"], easeOptions);
- const handlers = {
- dragDown: ["pointerdown", (e) => onDragPointerDown(e), false],
- dragMove: ["pointermove", (e) => onDragPointerChange(e), false],
- dragUp: ["pointerup", (e) => onDragPointerUp(e), false]
- };
- function activateListeners() {
- node.addEventListener(...handlers.dragDown);
- node.classList.add("draggable");
- }
- function removeListeners() {
- if (typeof storeDragging?.set === "function") {
- storeDragging.set(false);
- }
- node.removeEventListener(...handlers.dragDown);
- node.removeEventListener(...handlers.dragMove);
- node.removeEventListener(...handlers.dragUp);
- node.classList.remove("draggable");
- }
- if (active2) {
- activateListeners();
- }
- function onDragPointerDown(event) {
- if (event.button !== button || !event.isPrimary) {
- return;
- }
- if (!position.enabled) {
- return;
- }
- if (ignoreTargetClassList !== void 0 && event.target instanceof HTMLElement) {
- for (const targetClass of ignoreTargetClassList) {
- if (event.target.classList.contains(targetClass)) {
- return;
- }
- }
- }
- if (hasTargetClassList !== void 0 && event.target instanceof HTMLElement) {
- let foundTarget = false;
- for (const targetClass of hasTargetClassList) {
- if (event.target.classList.contains(targetClass)) {
- foundTarget = true;
- break;
- }
- }
- if (!foundTarget) {
- return;
- }
- }
- event.preventDefault();
- dragging = false;
- initialPosition = position.get();
- initialDragPoint = { x: event.clientX, y: event.clientY };
- node.addEventListener(...handlers.dragMove);
- node.addEventListener(...handlers.dragUp);
- node.setPointerCapture(event.pointerId);
- }
- function onDragPointerChange(event) {
- if ((event.buttons & 1) === 0) {
- onDragPointerUp(event);
- return;
- }
- if (event.button !== -1 || !event.isPrimary) {
- return;
- }
- event.preventDefault();
- if (!dragging && typeof storeDragging?.set === "function") {
- dragging = true;
- storeDragging.set(true);
- }
- const newLeft = initialPosition.left + (event.clientX - initialDragPoint.x);
- const newTop = initialPosition.top + (event.clientY - initialDragPoint.y);
- if (ease) {
- quickTo(newTop, newLeft);
- } else {
- s_POSITION_DATA.left = newLeft;
- s_POSITION_DATA.top = newTop;
- position.set(s_POSITION_DATA);
- }
- }
- function onDragPointerUp(event) {
- event.preventDefault();
- dragging = false;
- if (typeof storeDragging?.set === "function") {
- storeDragging.set(false);
- }
- node.removeEventListener(...handlers.dragMove);
- node.removeEventListener(...handlers.dragUp);
- }
- return {
- // The default of active being true won't automatically add listeners twice.
- update: (options) => {
- if (typeof options.active === "boolean") {
- active2 = options.active;
- if (active2) {
- activateListeners();
- } else {
- removeListeners();
- }
- }
- if (typeof options.button === "number") {
- button = options.button;
- }
- if (options.position !== void 0 && options.position !== position) {
- position = options.position;
- quickTo = position.animate.quickTo(["top", "left"], easeOptions);
- }
- if (typeof options.ease === "boolean") {
- ease = options.ease;
- }
- if (isObject(options.easeOptions)) {
- easeOptions = options.easeOptions;
- quickTo.options(easeOptions);
- }
- if (options.hasTargetClassList !== void 0) {
- if (!isIterable(options.hasTargetClassList)) {
- throw new TypeError(`'hasTargetClassList' is not iterable.`);
- } else {
- hasTargetClassList = options.hasTargetClassList;
- }
- }
- if (options.ignoreTargetClassList !== void 0) {
- if (!isIterable(options.ignoreTargetClassList)) {
- throw new TypeError(`'ignoreTargetClassList' is not iterable.`);
- } else {
- ignoreTargetClassList = options.ignoreTargetClassList;
- }
- }
- },
- destroy: () => removeListeners()
- };
- }
- class DraggableOptions {
- #ease = false;
- #easeOptions = { duration: 0.1, ease: cubicOut };
- /**
- * Stores the subscribers.
- *
- * @type {(function(DraggableOptions): void)[]}
- */
- #subscriptions = [];
- constructor({ ease, easeOptions } = {}) {
- Object.defineProperty(this, "ease", {
- get: () => {
- return this.#ease;
- },
- set: (newEase) => {
- if (typeof newEase !== "boolean") {
- throw new TypeError(`'ease' is not a boolean.`);
- }
- this.#ease = newEase;
- this.#updateSubscribers();
- },
- enumerable: true
- });
- Object.defineProperty(this, "easeOptions", {
- get: () => {
- return this.#easeOptions;
- },
- set: (newEaseOptions) => {
- if (newEaseOptions === null || typeof newEaseOptions !== "object") {
- throw new TypeError(`'easeOptions' is not an object.`);
- }
- if (newEaseOptions.duration !== void 0) {
- if (!Number.isFinite(newEaseOptions.duration)) {
- throw new TypeError(`'easeOptions.duration' is not a finite number.`);
- }
- if (newEaseOptions.duration < 0) {
- throw new Error(`'easeOptions.duration' is less than 0.`);
- }
- this.#easeOptions.duration = newEaseOptions.duration;
- }
- if (newEaseOptions.ease !== void 0) {
- if (typeof newEaseOptions.ease !== "function" && typeof newEaseOptions.ease !== "string") {
- throw new TypeError(`'easeOptions.ease' is not a function or string.`);
- }
- this.#easeOptions.ease = newEaseOptions.ease;
- }
- this.#updateSubscribers();
- },
- enumerable: true
- });
- if (ease !== void 0) {
- this.ease = ease;
- }
- if (easeOptions !== void 0) {
- this.easeOptions = easeOptions;
- }
- }
- /**
- * @returns {number} Get ease duration
- */
- get easeDuration() {
- return this.#easeOptions.duration;
- }
- /**
- * @returns {string|Function} Get easing function value.
- */
- get easeValue() {
- return this.#easeOptions.ease;
- }
- /**
- * @param {number} duration - Set ease duration.
- */
- set easeDuration(duration) {
- if (!Number.isFinite(duration)) {
- throw new TypeError(`'duration' is not a finite number.`);
- }
- if (duration < 0) {
- throw new Error(`'duration' is less than 0.`);
- }
- this.#easeOptions.duration = duration;
- this.#updateSubscribers();
- }
- /**
- * @param {string|Function} value - Get easing function value.
- */
- set easeValue(value) {
- if (typeof value !== "function" && typeof value !== "string") {
- throw new TypeError(`'value' is not a function or string.`);
- }
- this.#easeOptions.ease = value;
- this.#updateSubscribers();
- }
- /**
- * Resets all options data to default values.
- */
- reset() {
- this.#ease = false;
- this.#easeOptions = { duration: 0.1, ease: cubicOut };
- this.#updateSubscribers();
- }
- /**
- * Resets easing options to default values.
- */
- resetEase() {
- this.#easeOptions = { duration: 0.1, ease: cubicOut };
- this.#updateSubscribers();
- }
- /**
- *
- * @param {function(DraggableOptions): void} handler - Callback function that is invoked on update / changes.
- * Receives the DraggableOptions object / instance.
- *
- * @returns {(function(): void)} Unsubscribe function.
- */
- subscribe(handler) {
- this.#subscriptions.push(handler);
- handler(this);
- return () => {
- const index = this.#subscriptions.findIndex((sub) => sub === handler);
- if (index >= 0) {
- this.#subscriptions.splice(index, 1);
- }
- };
- }
- #updateSubscribers() {
- const subscriptions = this.#subscriptions;
- if (subscriptions.length > 0) {
- for (let cntr = 0; cntr < subscriptions.length; cntr++) {
- subscriptions[cntr](this);
- }
- }
- }
- }
- draggable.options = (options) => new DraggableOptions(options);
- const s_POSITION_DATA = { left: 0, top: 0 };
- const s_DEFAULT_TRANSITION_OPTIONS = {};
- const TJSGlassPane_svelte_svelte_type_style_lang = "";
- class AppShellContextInternal {
- /** @type {InternalAppStores} */
- #stores;
- constructor() {
- this.#stores = {
- elementContent: writable$1(void 0),
- elementRoot: writable$1(void 0)
- };
- Object.freeze(this.#stores);
- Object.seal(this);
- }
- /**
- * @returns {InternalAppStores} The internal context stores for elementContent / elementRoot
- */
- get stores() {
- return this.#stores;
- }
- }
- function localize(stringId, data) {
- const result = typeof data !== "object" ? globalThis.game.i18n.localize(stringId) : globalThis.game.i18n.format(stringId, data);
- return result !== void 0 ? result : "";
- }
- const TJSHeaderButton_svelte_svelte_type_style_lang = "";
- function create_if_block$a(ctx) {
- let span;
- let t;
- return {
- c() {
- span = element("span");
- t = text$1(
- /*label*/
- ctx[3]
- );
- attr(span, "class", "svelte-ese-166l8wd");
- toggle_class(
- span,
- "has-icon",
- /*icon*/
- ctx[4] !== void 0
- );
- },
- m(target, anchor) {
- insert(target, span, anchor);
- append(span, t);
- },
- p(ctx2, dirty) {
- if (dirty & /*label*/
- 8)
- set_data(
- t,
- /*label*/
- ctx2[3]
- );
- if (dirty & /*icon*/
- 16) {
- toggle_class(
- span,
- "has-icon",
- /*icon*/
- ctx2[4] !== void 0
- );
- }
- },
- d(detaching) {
- if (detaching)
- detach(span);
- }
- };
- }
- function create_fragment$p(ctx) {
- let a;
- let html_tag;
- let html_anchor;
- let a_class_value;
- let applyStyles_action;
- let mounted;
- let dispose;
- let if_block = (
- /*label*/
- ctx[3] && create_if_block$a(ctx)
- );
- return {
- c() {
- a = element("a");
- html_tag = new HtmlTag(false);
- html_anchor = empty();
- if (if_block)
- if_block.c();
- html_tag.a = html_anchor;
- attr(a, "class", a_class_value = "header-button " + /*button*/
- ctx[0].class + " svelte-ese-166l8wd");
- attr(
- a,
- "aria-label",
- /*label*/
- ctx[3]
- );
- attr(a, "tabindex", "0");
- attr(a, "role", "button");
- toggle_class(
- a,
- "keep-minimized",
- /*keepMinimized*/
- ctx[2]
- );
- },
- m(target, anchor) {
- insert(target, a, anchor);
- html_tag.m(
- /*icon*/
- ctx[4],
- a
- );
- append(a, html_anchor);
- if (if_block)
- if_block.m(a, null);
- if (!mounted) {
- dispose = [
- listen(a, "click", stop_propagation(prevent_default(
- /*onClick*/
- ctx[5]
- ))),
- listen(a, "contextmenu", stop_propagation(prevent_default(
- /*onContextMenu*/
- ctx[6]
- ))),
- listen(
- a,
- "keydown",
- /*onKeydown*/
- ctx[7]
- ),
- listen(
- a,
- "keyup",
- /*onKeyup*/
- ctx[8]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- a,
- /*styles*/
- ctx[1]
- ))
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*icon*/
- 16)
- html_tag.p(
- /*icon*/
- ctx2[4]
- );
- if (
- /*label*/
- ctx2[3]
- ) {
- if (if_block) {
- if_block.p(ctx2, dirty);
- } else {
- if_block = create_if_block$a(ctx2);
- if_block.c();
- if_block.m(a, null);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- if (dirty & /*button*/
- 1 && a_class_value !== (a_class_value = "header-button " + /*button*/
- ctx2[0].class + " svelte-ese-166l8wd")) {
- attr(a, "class", a_class_value);
- }
- if (dirty & /*label*/
- 8) {
- attr(
- a,
- "aria-label",
- /*label*/
- ctx2[3]
- );
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
- 2)
- applyStyles_action.update.call(
- null,
- /*styles*/
- ctx2[1]
- );
- if (dirty & /*button, keepMinimized*/
- 5) {
- toggle_class(
- a,
- "keep-minimized",
- /*keepMinimized*/
- ctx2[2]
- );
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(a);
- if (if_block)
- if_block.d();
- mounted = false;
- run_all(dispose);
- }
- };
- }
- const s_REGEX_HTML = /^\s*<.*>$/;
- function instance$p($$self, $$props, $$invalidate) {
- let title;
- let icon;
- let label;
- let keepMinimized;
- let keyCode;
- let styles;
- let { button = void 0 } = $$props;
- function onClick(event) {
- const invoke = button?.onPress ?? button?.onclick;
- if (typeof invoke === "function") {
- invoke.call(button, event);
- $$invalidate(0, button);
- }
- }
- function onContextMenu(event) {
- const invoke = button?.onContextMenu;
- if (typeof invoke === "function") {
- invoke.call(button, event);
- $$invalidate(0, button);
- }
- }
- function onKeydown(event) {
- if (event.code === keyCode) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- function onKeyup(event) {
- if (event.code === keyCode) {
- const invoke = button.onPress ?? button.onclick;
- if (typeof invoke === "function") {
- invoke.call(button, event);
- $$invalidate(0, button);
- }
- event.preventDefault();
- event.stopPropagation();
- }
- }
- $$self.$$set = ($$props2) => {
- if ("button" in $$props2)
- $$invalidate(0, button = $$props2.button);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*button*/
- 1) {
- $$invalidate(9, title = isObject(button) && typeof button.title === "string" ? localize(button.title) : "");
- }
- if ($$self.$$.dirty & /*button, title*/
- 513) {
- $$invalidate(4, icon = isObject(button) && typeof button.icon !== "string" ? void 0 : s_REGEX_HTML.test(button.icon) ? button.icon : `<i class="${button.icon}" title="${title}"></i>`);
- }
- if ($$self.$$.dirty & /*button*/
- 1) {
- $$invalidate(3, label = isObject(button) && typeof button.label === "string" ? localize(button.label) : void 0);
- }
- if ($$self.$$.dirty & /*button*/
- 1) {
- $$invalidate(2, keepMinimized = isObject(button) && typeof button.keepMinimized === "boolean" ? button.keepMinimized : false);
- }
- if ($$self.$$.dirty & /*button*/
- 1) {
- keyCode = isObject(button) && typeof button.keyCode === "string" ? button.keyCode : "Enter";
- }
- if ($$self.$$.dirty & /*button*/
- 1) {
- $$invalidate(1, styles = isObject(button) && isObject(button.styles) ? button.styles : void 0);
- }
- };
- return [
- button,
- styles,
- keepMinimized,
- label,
- icon,
- onClick,
- onContextMenu,
- onKeydown,
- onKeyup,
- title
- ];
- }
- class TJSHeaderButton extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$p, create_fragment$p, safe_not_equal, { button: 0 });
- }
- get button() {
- return this.$$.ctx[0];
- }
- set button(button) {
- this.$$set({ button });
- flush();
- }
- }
- const TJSApplicationHeader_svelte_svelte_type_style_lang = "";
- function get_each_context$7(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[31] = list[i];
- return child_ctx;
- }
- function get_each_context_1$2(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[31] = list[i];
- return child_ctx;
- }
- function create_if_block$9(ctx) {
- let img;
- let img_src_value;
- return {
- c() {
- img = element("img");
- attr(img, "class", "tjs-app-icon keep-minimized svelte-ese-1wviwl9");
- if (!src_url_equal(img.src, img_src_value = /*$storeHeaderIcon*/
- ctx[6]))
- attr(img, "src", img_src_value);
- attr(img, "alt", "icon");
- },
- m(target, anchor) {
- insert(target, img, anchor);
- },
- p(ctx2, dirty) {
- if (dirty[0] & /*$storeHeaderIcon*/
- 64 && !src_url_equal(img.src, img_src_value = /*$storeHeaderIcon*/
- ctx2[6])) {
- attr(img, "src", img_src_value);
- }
- },
- d(detaching) {
- if (detaching)
- detach(img);
- }
- };
- }
- function create_each_block_1$2(ctx) {
- let switch_instance;
- let switch_instance_anchor;
- let current;
- const switch_instance_spread_levels = [
- /*button*/
- ctx[31].props
- ];
- var switch_value = (
- /*button*/
- ctx[31].class
- );
- function switch_props(ctx2) {
- let switch_instance_props = {};
- for (let i = 0; i < switch_instance_spread_levels.length; i += 1) {
- switch_instance_props = assign(switch_instance_props, switch_instance_spread_levels[i]);
- }
- return { props: switch_instance_props };
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- }
- return {
- c() {
- if (switch_instance)
- create_component(switch_instance.$$.fragment);
- switch_instance_anchor = empty();
- },
- m(target, anchor) {
- if (switch_instance)
- mount_component(switch_instance, target, anchor);
- insert(target, switch_instance_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const switch_instance_changes = dirty[0] & /*buttonsLeft*/
- 2 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
- /*button*/
- ctx2[31].props
- )]) : {};
- if (switch_value !== (switch_value = /*button*/
- ctx2[31].class)) {
- if (switch_instance) {
- group_outros();
- const old_component = switch_instance;
- transition_out(old_component.$$.fragment, 1, 0, () => {
- destroy_component(old_component, 1);
- });
- check_outros();
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- create_component(switch_instance.$$.fragment);
- transition_in(switch_instance.$$.fragment, 1);
- mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
- } else {
- switch_instance = null;
- }
- } else if (switch_value) {
- switch_instance.$set(switch_instance_changes);
- }
- },
- i(local) {
- if (current)
- return;
- if (switch_instance)
- transition_in(switch_instance.$$.fragment, local);
- current = true;
- },
- o(local) {
- if (switch_instance)
- transition_out(switch_instance.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(switch_instance_anchor);
- if (switch_instance)
- destroy_component(switch_instance, detaching);
- }
- };
- }
- function create_each_block$7(ctx) {
- let switch_instance;
- let switch_instance_anchor;
- let current;
- const switch_instance_spread_levels = [
- /*button*/
- ctx[31].props
- ];
- var switch_value = (
- /*button*/
- ctx[31].class
- );
- function switch_props(ctx2) {
- let switch_instance_props = {};
- for (let i = 0; i < switch_instance_spread_levels.length; i += 1) {
- switch_instance_props = assign(switch_instance_props, switch_instance_spread_levels[i]);
- }
- return { props: switch_instance_props };
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- }
- return {
- c() {
- if (switch_instance)
- create_component(switch_instance.$$.fragment);
- switch_instance_anchor = empty();
- },
- m(target, anchor) {
- if (switch_instance)
- mount_component(switch_instance, target, anchor);
- insert(target, switch_instance_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const switch_instance_changes = dirty[0] & /*buttonsRight*/
- 4 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
- /*button*/
- ctx2[31].props
- )]) : {};
- if (switch_value !== (switch_value = /*button*/
- ctx2[31].class)) {
- if (switch_instance) {
- group_outros();
- const old_component = switch_instance;
- transition_out(old_component.$$.fragment, 1, 0, () => {
- destroy_component(old_component, 1);
- });
- check_outros();
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- create_component(switch_instance.$$.fragment);
- transition_in(switch_instance.$$.fragment, 1);
- mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
- } else {
- switch_instance = null;
- }
- } else if (switch_value) {
- switch_instance.$set(switch_instance_changes);
- }
- },
- i(local) {
- if (current)
- return;
- if (switch_instance)
- transition_in(switch_instance.$$.fragment, local);
- current = true;
- },
- o(local) {
- if (switch_instance)
- transition_out(switch_instance.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(switch_instance_anchor);
- if (switch_instance)
- destroy_component(switch_instance, detaching);
- }
- };
- }
- function create_key_block(ctx) {
- let header;
- let t0;
- let h4;
- let t1_value = localize(
- /*$storeTitle*/
- ctx[7]
- ) + "";
- let t1;
- let t2;
- let t3;
- let span;
- let t4;
- let draggable_action;
- let minimizable_action;
- let current;
- let mounted;
- let dispose;
- let if_block = typeof /*$storeHeaderIcon*/
- ctx[6] === "string" && create_if_block$9(ctx);
- let each_value_1 = (
- /*buttonsLeft*/
- ctx[1]
- );
- let each_blocks_1 = [];
- for (let i = 0; i < each_value_1.length; i += 1) {
- each_blocks_1[i] = create_each_block_1$2(get_each_context_1$2(ctx, each_value_1, i));
- }
- const out = (i) => transition_out(each_blocks_1[i], 1, 1, () => {
- each_blocks_1[i] = null;
- });
- let each_value = (
- /*buttonsRight*/
- ctx[2]
- );
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$7(get_each_context$7(ctx, each_value, i));
- }
- const out_1 = (i) => transition_out(each_blocks[i], 1, 1, () => {
- each_blocks[i] = null;
- });
- return {
- c() {
- header = element("header");
- if (if_block)
- if_block.c();
- t0 = space();
- h4 = element("h4");
- t1 = text$1(t1_value);
- t2 = space();
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].c();
- }
- t3 = space();
- span = element("span");
- t4 = space();
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(h4, "class", "window-title svelte-ese-1wviwl9");
- set_style(
- h4,
- "display",
- /*displayHeaderTitle*/
- ctx[4]
- );
- attr(span, "class", "tjs-window-header-spacer keep-minimized svelte-ese-1wviwl9");
- attr(header, "class", "window-header flexrow svelte-ese-1wviwl9");
- },
- m(target, anchor) {
- insert(target, header, anchor);
- if (if_block)
- if_block.m(header, null);
- append(header, t0);
- append(header, h4);
- append(h4, t1);
- append(header, t2);
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].m(header, null);
- }
- append(header, t3);
- append(header, span);
- append(header, t4);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(header, null);
- }
- current = true;
- if (!mounted) {
- dispose = [
- action_destroyer(draggable_action = /*draggable*/
- ctx[0].call(
- null,
- header,
- /*dragOptions*/
- ctx[3]
- )),
- action_destroyer(minimizable_action = /*minimizable*/
- ctx[18].call(
- null,
- header,
- /*$storeMinimizable*/
- ctx[5]
- )),
- listen(
- header,
- "pointerdown",
- /*onPointerdown*/
- ctx[19]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (typeof /*$storeHeaderIcon*/
- ctx2[6] === "string") {
- if (if_block) {
- if_block.p(ctx2, dirty);
- } else {
- if_block = create_if_block$9(ctx2);
- if_block.c();
- if_block.m(header, t0);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- if ((!current || dirty[0] & /*$storeTitle*/
- 128) && t1_value !== (t1_value = localize(
- /*$storeTitle*/
- ctx2[7]
- ) + ""))
- set_data(t1, t1_value);
- if (dirty[0] & /*displayHeaderTitle*/
- 16) {
- set_style(
- h4,
- "display",
- /*displayHeaderTitle*/
- ctx2[4]
- );
- }
- if (dirty[0] & /*buttonsLeft*/
- 2) {
- each_value_1 = /*buttonsLeft*/
- ctx2[1];
- let i;
- for (i = 0; i < each_value_1.length; i += 1) {
- const child_ctx = get_each_context_1$2(ctx2, each_value_1, i);
- if (each_blocks_1[i]) {
- each_blocks_1[i].p(child_ctx, dirty);
- transition_in(each_blocks_1[i], 1);
- } else {
- each_blocks_1[i] = create_each_block_1$2(child_ctx);
- each_blocks_1[i].c();
- transition_in(each_blocks_1[i], 1);
- each_blocks_1[i].m(header, t3);
- }
- }
- group_outros();
- for (i = each_value_1.length; i < each_blocks_1.length; i += 1) {
- out(i);
- }
- check_outros();
- }
- if (dirty[0] & /*buttonsRight*/
- 4) {
- each_value = /*buttonsRight*/
- ctx2[2];
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$7(ctx2, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- transition_in(each_blocks[i], 1);
- } else {
- each_blocks[i] = create_each_block$7(child_ctx);
- each_blocks[i].c();
- transition_in(each_blocks[i], 1);
- each_blocks[i].m(header, null);
- }
- }
- group_outros();
- for (i = each_value.length; i < each_blocks.length; i += 1) {
- out_1(i);
- }
- check_outros();
- }
- if (draggable_action && is_function(draggable_action.update) && dirty[0] & /*dragOptions*/
- 8)
- draggable_action.update.call(
- null,
- /*dragOptions*/
- ctx2[3]
- );
- if (minimizable_action && is_function(minimizable_action.update) && dirty[0] & /*$storeMinimizable*/
- 32)
- minimizable_action.update.call(
- null,
- /*$storeMinimizable*/
- ctx2[5]
- );
- },
- i(local) {
- if (current)
- return;
- for (let i = 0; i < each_value_1.length; i += 1) {
- transition_in(each_blocks_1[i]);
- }
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- each_blocks_1 = each_blocks_1.filter(Boolean);
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- transition_out(each_blocks_1[i]);
- }
- each_blocks = each_blocks.filter(Boolean);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(header);
- if (if_block)
- if_block.d();
- destroy_each(each_blocks_1, detaching);
- destroy_each(each_blocks, detaching);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_fragment$o(ctx) {
- let previous_key = (
- /*draggable*/
- ctx[0]
- );
- let key_block_anchor;
- let current;
- let key_block = create_key_block(ctx);
- return {
- c() {
- key_block.c();
- key_block_anchor = empty();
- },
- m(target, anchor) {
- key_block.m(target, anchor);
- insert(target, key_block_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- if (dirty[0] & /*draggable*/
- 1 && safe_not_equal(previous_key, previous_key = /*draggable*/
- ctx2[0])) {
- group_outros();
- transition_out(key_block, 1, 1, noop);
- check_outros();
- key_block = create_key_block(ctx2);
- key_block.c();
- transition_in(key_block, 1);
- key_block.m(key_block_anchor.parentNode, key_block_anchor);
- } else {
- key_block.p(ctx2, dirty);
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(key_block);
- current = true;
- },
- o(local) {
- transition_out(key_block);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(key_block_anchor);
- key_block.d(detaching);
- }
- };
- }
- function instance$o($$self, $$props, $$invalidate) {
- let $focusKeep;
- let $focusAuto;
- let $elementRoot;
- let $storeHeaderButtons;
- let $storeMinimized;
- let $storeHeaderNoTitleMinimized;
- let $storeDraggable;
- let $storeMinimizable;
- let $storeHeaderIcon;
- let $storeTitle;
- let { draggable: draggable$1 = void 0 } = $$props;
- let { draggableOptions = void 0 } = $$props;
- const { application } = getContext("#external");
- const { focusAuto, focusKeep } = application.reactive.storeAppOptions;
- component_subscribe($$self, focusAuto, (value) => $$invalidate(26, $focusAuto = value));
- component_subscribe($$self, focusKeep, (value) => $$invalidate(25, $focusKeep = value));
- const { elementRoot } = getContext("#internal").stores;
- component_subscribe($$self, elementRoot, (value) => $$invalidate(27, $elementRoot = value));
- const storeTitle = application.reactive.storeAppOptions.title;
- component_subscribe($$self, storeTitle, (value) => $$invalidate(7, $storeTitle = value));
- const storeDraggable = application.reactive.storeAppOptions.draggable;
- component_subscribe($$self, storeDraggable, (value) => $$invalidate(24, $storeDraggable = value));
- const storeDragging = application.reactive.storeUIState.dragging;
- const storeHeaderButtons = application.reactive.storeUIState.headerButtons;
- component_subscribe($$self, storeHeaderButtons, (value) => $$invalidate(21, $storeHeaderButtons = value));
- const storeHeaderIcon = application.reactive.storeAppOptions.headerIcon;
- component_subscribe($$self, storeHeaderIcon, (value) => $$invalidate(6, $storeHeaderIcon = value));
- const storeHeaderNoTitleMinimized = application.reactive.storeAppOptions.headerNoTitleMinimized;
- component_subscribe($$self, storeHeaderNoTitleMinimized, (value) => $$invalidate(23, $storeHeaderNoTitleMinimized = value));
- const storeMinimizable = application.reactive.storeAppOptions.minimizable;
- component_subscribe($$self, storeMinimizable, (value) => $$invalidate(5, $storeMinimizable = value));
- const storeMinimized = application.reactive.storeUIState.minimized;
- component_subscribe($$self, storeMinimized, (value) => $$invalidate(22, $storeMinimized = value));
- const s_DRAG_TARGET_CLASSLIST = Object.freeze(["tjs-app-icon", "tjs-window-header-spacer", "window-header", "window-title"]);
- let dragOptions;
- let displayHeaderTitle;
- let buttonsLeft;
- let buttonsRight;
- function minimizable(node, booleanStore) {
- const callback = (event) => {
- if (event.target.classList.contains("window-title") || event.target.classList.contains("window-header") || event.target.classList.contains("keep-minimized")) {
- application._onToggleMinimize(event);
- }
- };
- function activateListeners() {
- node.addEventListener("dblclick", callback);
- }
- function removeListeners() {
- node.removeEventListener("dblclick", callback);
- }
- if (booleanStore) {
- activateListeners();
- }
- return {
- update: (booleanStore2) => {
- if (booleanStore2) {
- activateListeners();
- } else {
- removeListeners();
- }
- },
- destroy: () => removeListeners()
- };
- }
- function onPointerdown(event) {
- const rootEl = $elementRoot;
- if ($focusAuto && rootEl instanceof HTMLElement && rootEl?.isConnected) {
- if ($focusKeep) {
- const focusOutside = document.activeElement instanceof HTMLElement && !rootEl.contains(document.activeElement);
- if (focusOutside) {
- rootEl.focus();
- } else {
- event.preventDefault();
- }
- } else {
- rootEl.focus();
- }
- }
- }
- $$self.$$set = ($$props2) => {
- if ("draggable" in $$props2)
- $$invalidate(0, draggable$1 = $$props2.draggable);
- if ("draggableOptions" in $$props2)
- $$invalidate(20, draggableOptions = $$props2.draggableOptions);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty[0] & /*draggable*/
- 1) {
- $$invalidate(0, draggable$1 = typeof draggable$1 === "function" ? draggable$1 : draggable);
- }
- if ($$self.$$.dirty[0] & /*draggableOptions, $storeDraggable*/
- 17825792) {
- $$invalidate(3, dragOptions = Object.assign(
- {},
- {
- ease: true,
- easeOptions: { duration: 0.08, ease: cubicOut }
- },
- isObject(draggableOptions) ? draggableOptions : {},
- {
- position: application.position,
- active: $storeDraggable,
- storeDragging,
- hasTargetClassList: s_DRAG_TARGET_CLASSLIST
- }
- ));
- }
- if ($$self.$$.dirty[0] & /*$storeHeaderNoTitleMinimized, $storeMinimized*/
- 12582912) {
- $$invalidate(4, displayHeaderTitle = $storeHeaderNoTitleMinimized && $storeMinimized ? "none" : null);
- }
- if ($$self.$$.dirty[0] & /*$storeHeaderButtons, buttonsLeft, buttonsRight*/
- 2097158) {
- {
- $$invalidate(1, buttonsLeft = []);
- $$invalidate(2, buttonsRight = []);
- for (const button of $storeHeaderButtons) {
- const buttonsList = typeof button?.alignLeft === "boolean" && button?.alignLeft ? buttonsLeft : buttonsRight;
- buttonsList.push(isSvelteComponent(button) ? { class: button, props: {} } : {
- class: TJSHeaderButton,
- props: { button }
- });
- }
- }
- }
- };
- return [
- draggable$1,
- buttonsLeft,
- buttonsRight,
- dragOptions,
- displayHeaderTitle,
- $storeMinimizable,
- $storeHeaderIcon,
- $storeTitle,
- focusAuto,
- focusKeep,
- elementRoot,
- storeTitle,
- storeDraggable,
- storeHeaderButtons,
- storeHeaderIcon,
- storeHeaderNoTitleMinimized,
- storeMinimizable,
- storeMinimized,
- minimizable,
- onPointerdown,
- draggableOptions,
- $storeHeaderButtons,
- $storeMinimized,
- $storeHeaderNoTitleMinimized,
- $storeDraggable
- ];
- }
- class TJSApplicationHeader extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$o, create_fragment$o, safe_not_equal, { draggable: 0, draggableOptions: 20 }, null, [-1, -1]);
- }
- }
- const TJSFocusWrap_svelte_svelte_type_style_lang = "";
- function create_fragment$n(ctx) {
- let div;
- let mounted;
- let dispose;
- return {
- c() {
- div = element("div");
- attr(div, "class", "tjs-focus-wrap svelte-ese-kjcljd");
- attr(div, "tabindex", "0");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- ctx[4](div);
- if (!mounted) {
- dispose = listen(
- div,
- "focus",
- /*onFocus*/
- ctx[1]
- );
- mounted = true;
- }
- },
- p: noop,
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- ctx[4](null);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$n($$self, $$props, $$invalidate) {
- let { elementRoot = void 0 } = $$props;
- let { enabled = true } = $$props;
- let ignoreElements, wrapEl;
- function onFocus() {
- if (!enabled) {
- return;
- }
- if (elementRoot instanceof HTMLElement) {
- const firstFocusEl = A11yHelper.getFirstFocusableElement(elementRoot, ignoreElements);
- if (firstFocusEl instanceof HTMLElement && firstFocusEl !== wrapEl) {
- firstFocusEl.focus();
- } else {
- elementRoot.focus();
- }
- }
- }
- function div_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- wrapEl = $$value;
- $$invalidate(0, wrapEl);
- });
- }
- $$self.$$set = ($$props2) => {
- if ("elementRoot" in $$props2)
- $$invalidate(2, elementRoot = $$props2.elementRoot);
- if ("enabled" in $$props2)
- $$invalidate(3, enabled = $$props2.enabled);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*wrapEl*/
- 1) {
- if (wrapEl) {
- ignoreElements = /* @__PURE__ */ new Set([wrapEl]);
- }
- }
- };
- return [wrapEl, onFocus, elementRoot, enabled, div_binding];
- }
- class TJSFocusWrap extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$n, create_fragment$n, safe_not_equal, { elementRoot: 2, enabled: 3 });
- }
- }
- function create_fragment$m(ctx) {
- let div;
- let resizable_action;
- let mounted;
- let dispose;
- return {
- c() {
- div = element("div");
- div.innerHTML = `<i class="fas fa-arrows-alt-h"></i>`;
- attr(div, "class", "window-resizable-handle");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- ctx[10](div);
- if (!mounted) {
- dispose = action_destroyer(resizable_action = /*resizable*/
- ctx[6].call(null, div, {
- active: (
- /*$storeResizable*/
- ctx[1]
- ),
- storeResizing: (
- /*storeResizing*/
- ctx[5]
- )
- }));
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (resizable_action && is_function(resizable_action.update) && dirty & /*$storeResizable*/
- 2)
- resizable_action.update.call(null, {
- active: (
- /*$storeResizable*/
- ctx2[1]
- ),
- storeResizing: (
- /*storeResizing*/
- ctx2[5]
- )
- });
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- ctx[10](null);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$m($$self, $$props, $$invalidate) {
- let $storeElementRoot;
- let $storeMinimized;
- let $storeResizable;
- let { isResizable = false } = $$props;
- const application = getContext("#external").application;
- const storeElementRoot = getContext("storeElementRoot");
- component_subscribe($$self, storeElementRoot, (value) => $$invalidate(8, $storeElementRoot = value));
- const storeResizable = application.reactive.storeAppOptions.resizable;
- component_subscribe($$self, storeResizable, (value) => $$invalidate(1, $storeResizable = value));
- const storeMinimized = application.reactive.storeUIState.minimized;
- component_subscribe($$self, storeMinimized, (value) => $$invalidate(9, $storeMinimized = value));
- const storeResizing = application.reactive.storeUIState.resizing;
- let elementResize;
- function resizable(node, { active: active2 = true, storeResizing: storeResizing2 = void 0 } = {}) {
- let position = null;
- let initialPosition = {};
- let resizing = false;
- const handlers = {
- resizeDown: ["pointerdown", (e) => onResizePointerDown(e), false],
- resizeMove: ["pointermove", (e) => onResizePointerMove(e), false],
- resizeUp: ["pointerup", (e) => onResizePointerUp(e), false]
- };
- function activateListeners() {
- node.addEventListener(...handlers.resizeDown);
- $$invalidate(7, isResizable = true);
- node.style.display = "block";
- }
- function removeListeners() {
- if (typeof storeResizing2?.set === "function") {
- storeResizing2.set(false);
- }
- node.removeEventListener(...handlers.resizeDown);
- node.removeEventListener(...handlers.resizeMove);
- node.removeEventListener(...handlers.resizeUp);
- node.style.display = "none";
- $$invalidate(7, isResizable = false);
- }
- if (active2) {
- activateListeners();
- } else {
- node.style.display = "none";
- }
- function onResizePointerDown(event) {
- event.preventDefault();
- resizing = false;
- position = application.position.get();
- if (position.height === "auto") {
- position.height = $storeElementRoot.clientHeight;
- }
- if (position.width === "auto") {
- position.width = $storeElementRoot.clientWidth;
- }
- initialPosition = { x: event.clientX, y: event.clientY };
- node.addEventListener(...handlers.resizeMove);
- node.addEventListener(...handlers.resizeUp);
- node.setPointerCapture(event.pointerId);
- }
- function onResizePointerMove(event) {
- event.preventDefault();
- if (!resizing && typeof storeResizing2?.set === "function") {
- resizing = true;
- storeResizing2.set(true);
- }
- application.position.set({
- width: position.width + (event.clientX - initialPosition.x),
- height: position.height + (event.clientY - initialPosition.y)
- });
- }
- function onResizePointerUp(event) {
- resizing = false;
- if (typeof storeResizing2?.set === "function") {
- storeResizing2.set(false);
- }
- event.preventDefault();
- node.removeEventListener(...handlers.resizeMove);
- node.removeEventListener(...handlers.resizeUp);
- application._onResize(event);
- }
- return {
- update: ({ active: active3 }) => {
- if (active3) {
- activateListeners();
- } else {
- removeListeners();
- }
- },
- destroy: () => removeListeners()
- };
- }
- function div_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- elementResize = $$value;
- $$invalidate(0, elementResize), $$invalidate(7, isResizable), $$invalidate(9, $storeMinimized), $$invalidate(8, $storeElementRoot);
- });
- }
- $$self.$$set = ($$props2) => {
- if ("isResizable" in $$props2)
- $$invalidate(7, isResizable = $$props2.isResizable);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*elementResize, isResizable, $storeMinimized, $storeElementRoot*/
- 897) {
- if (elementResize) {
- $$invalidate(0, elementResize.style.display = isResizable && !$storeMinimized ? "block" : "none", elementResize);
- const elementRoot = $storeElementRoot;
- if (elementRoot) {
- elementRoot.classList[isResizable ? "add" : "remove"]("resizable");
- }
- }
- }
- };
- return [
- elementResize,
- $storeResizable,
- storeElementRoot,
- storeResizable,
- storeMinimized,
- storeResizing,
- resizable,
- isResizable,
- $storeElementRoot,
- $storeMinimized,
- div_binding
- ];
- }
- class ResizableHandle extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$m, create_fragment$m, safe_not_equal, { isResizable: 7 });
- }
- }
- const ApplicationShell_svelte_svelte_type_style_lang = "";
- function create_else_block$2(ctx) {
- let div;
- let tjsapplicationheader;
- let t0;
- let section;
- let applyStyles_action;
- let t1;
- let resizablehandle;
- let t2;
- let tjsfocuswrap;
- let div_id_value;
- let div_class_value;
- let div_data_appid_value;
- let applyStyles_action_1;
- let current;
- let mounted;
- let dispose;
- tjsapplicationheader = new TJSApplicationHeader({
- props: {
- draggable: (
- /*draggable*/
- ctx[6]
- ),
- draggableOptions: (
- /*draggableOptions*/
- ctx[7]
- )
- }
- });
- const default_slot_template = (
- /*#slots*/
- ctx[36].default
- );
- const default_slot = create_slot(
- default_slot_template,
- ctx,
- /*$$scope*/
- ctx[35],
- null
- );
- resizablehandle = new ResizableHandle({});
- tjsfocuswrap = new TJSFocusWrap({
- props: {
- elementRoot: (
- /*elementRoot*/
- ctx[1]
- ),
- enabled: (
- /*focusWrapEnabled*/
- ctx[11]
- )
- }
- });
- return {
- c() {
- div = element("div");
- create_component(tjsapplicationheader.$$.fragment);
- t0 = space();
- section = element("section");
- if (default_slot)
- default_slot.c();
- t1 = space();
- create_component(resizablehandle.$$.fragment);
- t2 = space();
- create_component(tjsfocuswrap.$$.fragment);
- attr(section, "class", "window-content svelte-ese-oz81f7");
- attr(section, "tabindex", "-1");
- attr(div, "id", div_id_value = /*application*/
- ctx[10].id);
- attr(div, "class", div_class_value = "app window-app " + /*application*/
- ctx[10].options.classes.join(" ") + " svelte-ese-oz81f7");
- attr(div, "data-appid", div_data_appid_value = /*application*/
- ctx[10].appId);
- attr(div, "tabindex", "-1");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- mount_component(tjsapplicationheader, div, null);
- append(div, t0);
- append(div, section);
- if (default_slot) {
- default_slot.m(section, null);
- }
- ctx[39](section);
- append(div, t1);
- mount_component(resizablehandle, div, null);
- append(div, t2);
- mount_component(tjsfocuswrap, div, null);
- ctx[40](div);
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- section,
- "pointerdown",
- /*onPointerdownContent*/
- ctx[21]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- section,
- /*stylesContent*/
- ctx[9]
- )),
- action_destroyer(
- /*contentResizeObserver*/
- ctx[13].call(
- null,
- section,
- /*resizeObservedContent*/
- ctx[22]
- )
- ),
- listen(div, "close:popup", stop_propagation(prevent_default(
- /*onClosePopup*/
- ctx[18]
- ))),
- listen(
- div,
- "keydown",
- /*onKeydown*/
- ctx[19],
- true
- ),
- listen(
- div,
- "pointerdown",
- /*onPointerdownApp*/
- ctx[20]
- ),
- action_destroyer(applyStyles_action_1 = applyStyles.call(
- null,
- div,
- /*stylesApp*/
- ctx[8]
- )),
- action_destroyer(
- /*appResizeObserver*/
- ctx[12].call(
- null,
- div,
- /*resizeObservedApp*/
- ctx[23]
- )
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- const tjsapplicationheader_changes = {};
- if (dirty[0] & /*draggable*/
- 64)
- tjsapplicationheader_changes.draggable = /*draggable*/
- ctx2[6];
- if (dirty[0] & /*draggableOptions*/
- 128)
- tjsapplicationheader_changes.draggableOptions = /*draggableOptions*/
- ctx2[7];
- tjsapplicationheader.$set(tjsapplicationheader_changes);
- if (default_slot) {
- if (default_slot.p && (!current || dirty[1] & /*$$scope*/
- 16)) {
- update_slot_base(
- default_slot,
- default_slot_template,
- ctx2,
- /*$$scope*/
- ctx2[35],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx2[35]
- ) : get_slot_changes(
- default_slot_template,
- /*$$scope*/
- ctx2[35],
- dirty,
- null
- ),
- null
- );
- }
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty[0] & /*stylesContent*/
- 512)
- applyStyles_action.update.call(
- null,
- /*stylesContent*/
- ctx2[9]
- );
- const tjsfocuswrap_changes = {};
- if (dirty[0] & /*elementRoot*/
- 2)
- tjsfocuswrap_changes.elementRoot = /*elementRoot*/
- ctx2[1];
- if (dirty[0] & /*focusWrapEnabled*/
- 2048)
- tjsfocuswrap_changes.enabled = /*focusWrapEnabled*/
- ctx2[11];
- tjsfocuswrap.$set(tjsfocuswrap_changes);
- if (!current || dirty[0] & /*application*/
- 1024 && div_id_value !== (div_id_value = /*application*/
- ctx2[10].id)) {
- attr(div, "id", div_id_value);
- }
- if (!current || dirty[0] & /*application*/
- 1024 && div_class_value !== (div_class_value = "app window-app " + /*application*/
- ctx2[10].options.classes.join(" ") + " svelte-ese-oz81f7")) {
- attr(div, "class", div_class_value);
- }
- if (!current || dirty[0] & /*application*/
- 1024 && div_data_appid_value !== (div_data_appid_value = /*application*/
- ctx2[10].appId)) {
- attr(div, "data-appid", div_data_appid_value);
- }
- if (applyStyles_action_1 && is_function(applyStyles_action_1.update) && dirty[0] & /*stylesApp*/
- 256)
- applyStyles_action_1.update.call(
- null,
- /*stylesApp*/
- ctx2[8]
- );
- },
- i(local) {
- if (current)
- return;
- transition_in(tjsapplicationheader.$$.fragment, local);
- transition_in(default_slot, local);
- transition_in(resizablehandle.$$.fragment, local);
- transition_in(tjsfocuswrap.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(tjsapplicationheader.$$.fragment, local);
- transition_out(default_slot, local);
- transition_out(resizablehandle.$$.fragment, local);
- transition_out(tjsfocuswrap.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(tjsapplicationheader);
- if (default_slot)
- default_slot.d(detaching);
- ctx[39](null);
- destroy_component(resizablehandle);
- destroy_component(tjsfocuswrap);
- ctx[40](null);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_if_block$8(ctx) {
- let div;
- let tjsapplicationheader;
- let t0;
- let section;
- let applyStyles_action;
- let t1;
- let resizablehandle;
- let t2;
- let tjsfocuswrap;
- let div_id_value;
- let div_class_value;
- let div_data_appid_value;
- let applyStyles_action_1;
- let div_intro;
- let div_outro;
- let current;
- let mounted;
- let dispose;
- tjsapplicationheader = new TJSApplicationHeader({
- props: {
- draggable: (
- /*draggable*/
- ctx[6]
- ),
- draggableOptions: (
- /*draggableOptions*/
- ctx[7]
- )
- }
- });
- const default_slot_template = (
- /*#slots*/
- ctx[36].default
- );
- const default_slot = create_slot(
- default_slot_template,
- ctx,
- /*$$scope*/
- ctx[35],
- null
- );
- resizablehandle = new ResizableHandle({});
- tjsfocuswrap = new TJSFocusWrap({
- props: { elementRoot: (
- /*elementRoot*/
- ctx[1]
- ) }
- });
- return {
- c() {
- div = element("div");
- create_component(tjsapplicationheader.$$.fragment);
- t0 = space();
- section = element("section");
- if (default_slot)
- default_slot.c();
- t1 = space();
- create_component(resizablehandle.$$.fragment);
- t2 = space();
- create_component(tjsfocuswrap.$$.fragment);
- attr(section, "class", "window-content svelte-ese-oz81f7");
- attr(section, "tabindex", "-1");
- attr(div, "id", div_id_value = /*application*/
- ctx[10].id);
- attr(div, "class", div_class_value = "app window-app " + /*application*/
- ctx[10].options.classes.join(" ") + " svelte-ese-oz81f7");
- attr(div, "data-appid", div_data_appid_value = /*application*/
- ctx[10].appId);
- attr(div, "tabindex", "-1");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- mount_component(tjsapplicationheader, div, null);
- append(div, t0);
- append(div, section);
- if (default_slot) {
- default_slot.m(section, null);
- }
- ctx[37](section);
- append(div, t1);
- mount_component(resizablehandle, div, null);
- append(div, t2);
- mount_component(tjsfocuswrap, div, null);
- ctx[38](div);
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- section,
- "pointerdown",
- /*onPointerdownContent*/
- ctx[21]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- section,
- /*stylesContent*/
- ctx[9]
- )),
- action_destroyer(
- /*contentResizeObserver*/
- ctx[13].call(
- null,
- section,
- /*resizeObservedContent*/
- ctx[22]
- )
- ),
- listen(div, "close:popup", stop_propagation(prevent_default(
- /*onClosePopup*/
- ctx[18]
- ))),
- listen(
- div,
- "keydown",
- /*onKeydown*/
- ctx[19],
- true
- ),
- listen(
- div,
- "pointerdown",
- /*onPointerdownApp*/
- ctx[20]
- ),
- action_destroyer(applyStyles_action_1 = applyStyles.call(
- null,
- div,
- /*stylesApp*/
- ctx[8]
- )),
- action_destroyer(
- /*appResizeObserver*/
- ctx[12].call(
- null,
- div,
- /*resizeObservedApp*/
- ctx[23]
- )
- )
- ];
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const tjsapplicationheader_changes = {};
- if (dirty[0] & /*draggable*/
- 64)
- tjsapplicationheader_changes.draggable = /*draggable*/
- ctx[6];
- if (dirty[0] & /*draggableOptions*/
- 128)
- tjsapplicationheader_changes.draggableOptions = /*draggableOptions*/
- ctx[7];
- tjsapplicationheader.$set(tjsapplicationheader_changes);
- if (default_slot) {
- if (default_slot.p && (!current || dirty[1] & /*$$scope*/
- 16)) {
- update_slot_base(
- default_slot,
- default_slot_template,
- ctx,
- /*$$scope*/
- ctx[35],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx[35]
- ) : get_slot_changes(
- default_slot_template,
- /*$$scope*/
- ctx[35],
- dirty,
- null
- ),
- null
- );
- }
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty[0] & /*stylesContent*/
- 512)
- applyStyles_action.update.call(
- null,
- /*stylesContent*/
- ctx[9]
- );
- const tjsfocuswrap_changes = {};
- if (dirty[0] & /*elementRoot*/
- 2)
- tjsfocuswrap_changes.elementRoot = /*elementRoot*/
- ctx[1];
- tjsfocuswrap.$set(tjsfocuswrap_changes);
- if (!current || dirty[0] & /*application*/
- 1024 && div_id_value !== (div_id_value = /*application*/
- ctx[10].id)) {
- attr(div, "id", div_id_value);
- }
- if (!current || dirty[0] & /*application*/
- 1024 && div_class_value !== (div_class_value = "app window-app " + /*application*/
- ctx[10].options.classes.join(" ") + " svelte-ese-oz81f7")) {
- attr(div, "class", div_class_value);
- }
- if (!current || dirty[0] & /*application*/
- 1024 && div_data_appid_value !== (div_data_appid_value = /*application*/
- ctx[10].appId)) {
- attr(div, "data-appid", div_data_appid_value);
- }
- if (applyStyles_action_1 && is_function(applyStyles_action_1.update) && dirty[0] & /*stylesApp*/
- 256)
- applyStyles_action_1.update.call(
- null,
- /*stylesApp*/
- ctx[8]
- );
- },
- i(local) {
- if (current)
- return;
- transition_in(tjsapplicationheader.$$.fragment, local);
- transition_in(default_slot, local);
- transition_in(resizablehandle.$$.fragment, local);
- transition_in(tjsfocuswrap.$$.fragment, local);
- add_render_callback(() => {
- if (div_outro)
- div_outro.end(1);
- div_intro = create_in_transition(
- div,
- /*inTransition*/
- ctx[2],
- /*inTransitionOptions*/
- ctx[4]
- );
- div_intro.start();
- });
- current = true;
- },
- o(local) {
- transition_out(tjsapplicationheader.$$.fragment, local);
- transition_out(default_slot, local);
- transition_out(resizablehandle.$$.fragment, local);
- transition_out(tjsfocuswrap.$$.fragment, local);
- if (div_intro)
- div_intro.invalidate();
- div_outro = create_out_transition(
- div,
- /*outTransition*/
- ctx[3],
- /*outTransitionOptions*/
- ctx[5]
- );
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(tjsapplicationheader);
- if (default_slot)
- default_slot.d(detaching);
- ctx[37](null);
- destroy_component(resizablehandle);
- destroy_component(tjsfocuswrap);
- ctx[38](null);
- if (detaching && div_outro)
- div_outro.end();
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_fragment$l(ctx) {
- let current_block_type_index;
- let if_block;
- let if_block_anchor;
- let current;
- const if_block_creators = [create_if_block$8, create_else_block$2];
- const if_blocks = [];
- function select_block_type(ctx2, dirty) {
- if (
- /*inTransition*/
- ctx2[2] || /*outTransition*/
- ctx2[3]
- )
- return 0;
- return 1;
- }
- current_block_type_index = select_block_type(ctx);
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
- return {
- c() {
- if_block.c();
- if_block_anchor = empty();
- },
- m(target, anchor) {
- if_blocks[current_block_type_index].m(target, anchor);
- insert(target, if_block_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- let previous_block_index = current_block_type_index;
- current_block_type_index = select_block_type(ctx2);
- if (current_block_type_index === previous_block_index) {
- if_blocks[current_block_type_index].p(ctx2, dirty);
- } else {
- group_outros();
- transition_out(if_blocks[previous_block_index], 1, 1, () => {
- if_blocks[previous_block_index] = null;
- });
- check_outros();
- if_block = if_blocks[current_block_type_index];
- if (!if_block) {
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
- if_block.c();
- } else {
- if_block.p(ctx2, dirty);
- }
- transition_in(if_block, 1);
- if_block.m(if_block_anchor.parentNode, if_block_anchor);
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block);
- current = true;
- },
- o(local) {
- transition_out(if_block);
- current = false;
- },
- d(detaching) {
- if_blocks[current_block_type_index].d(detaching);
- if (detaching)
- detach(if_block_anchor);
- }
- };
- }
- function instance$l($$self, $$props, $$invalidate) {
- let $focusKeep;
- let $focusAuto;
- let $minimized;
- let $focusTrap;
- let { $$slots: slots = {}, $$scope } = $$props;
- let { elementContent = void 0 } = $$props;
- let { elementRoot = void 0 } = $$props;
- let { draggable: draggable2 = void 0 } = $$props;
- let { draggableOptions = void 0 } = $$props;
- let { stylesApp = void 0 } = $$props;
- let { stylesContent = void 0 } = $$props;
- let { appOffsetHeight = false } = $$props;
- let { appOffsetWidth = false } = $$props;
- const appResizeObserver = !!appOffsetHeight || !!appOffsetWidth ? resizeObserver : () => null;
- let { contentOffsetHeight = false } = $$props;
- let { contentOffsetWidth = false } = $$props;
- const contentResizeObserver = !!contentOffsetHeight || !!contentOffsetWidth ? resizeObserver : () => null;
- const internal = new AppShellContextInternal();
- const s_IGNORE_CLASSES = { ignoreClasses: ["tjs-focus-wrap"] };
- setContext("#internal", internal);
- const { application } = getContext("#external");
- const { focusAuto, focusKeep, focusTrap } = application.reactive.storeAppOptions;
- component_subscribe($$self, focusAuto, (value) => $$invalidate(32, $focusAuto = value));
- component_subscribe($$self, focusKeep, (value) => $$invalidate(41, $focusKeep = value));
- component_subscribe($$self, focusTrap, (value) => $$invalidate(34, $focusTrap = value));
- const { minimized } = application.reactive.storeUIState;
- component_subscribe($$self, minimized, (value) => $$invalidate(33, $minimized = value));
- let focusWrapEnabled;
- let { transition = void 0 } = $$props;
- let { inTransition = void 0 } = $$props;
- let { outTransition = void 0 } = $$props;
- let { transitionOptions = void 0 } = $$props;
- let { inTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS } = $$props;
- let { outTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS } = $$props;
- let oldTransition = void 0;
- let oldTransitionOptions = void 0;
- onMount(() => elementRoot.focus());
- function onClosePopup(event) {
- if (!$focusAuto) {
- return;
- }
- const targetEl = event?.detail?.target;
- if (!(targetEl instanceof HTMLElement)) {
- return;
- }
- if (A11yHelper.isFocusable(targetEl)) {
- return;
- }
- const elementRootContains = elementRoot.contains(targetEl);
- if (targetEl === elementRoot) {
- elementRoot.focus();
- } else if (targetEl === elementContent) {
- elementContent.focus();
- } else if (elementRootContains) {
- if (elementContent.contains(targetEl)) {
- elementContent.focus();
- } else {
- elementRoot.focus();
- }
- }
- }
- function onKeydown(event) {
- if (focusWrapEnabled && event.shiftKey && event.code === "Tab") {
- const allFocusable = A11yHelper.getFocusableElements(elementRoot, s_IGNORE_CLASSES);
- const firstFocusEl = allFocusable.length > 0 ? allFocusable[0] : void 0;
- const lastFocusEl = allFocusable.length > 0 ? allFocusable[allFocusable.length - 1] : void 0;
- if (elementRoot === document.activeElement || firstFocusEl === document.activeElement) {
- if (lastFocusEl instanceof HTMLElement && firstFocusEl !== lastFocusEl) {
- lastFocusEl.focus();
- }
- event.preventDefault();
- event.stopPropagation();
- }
- }
- if (typeof application?.options?.popOut === "boolean" && application.options.popOut && application !== globalThis.ui?.activeWindow) {
- application.bringToTop.call(application);
- }
- }
- function onPointerdownApp() {
- if (typeof application?.options?.popOut === "boolean" && application.options.popOut && application !== globalThis.ui?.activeWindow) {
- application.bringToTop.call(application);
- }
- }
- function onPointerdownContent(event) {
- const focusable = A11yHelper.isFocusable(event.target);
- if (!focusable && $focusAuto) {
- if ($focusKeep) {
- const focusOutside = document.activeElement instanceof HTMLElement && !elementRoot.contains(document.activeElement);
- if (focusOutside) {
- elementContent.focus();
- } else {
- event.preventDefault();
- }
- } else {
- elementContent.focus();
- }
- }
- }
- function resizeObservedContent(offsetWidth, offsetHeight) {
- $$invalidate(27, contentOffsetWidth = offsetWidth);
- $$invalidate(26, contentOffsetHeight = offsetHeight);
- }
- function resizeObservedApp(offsetWidth, offsetHeight, contentWidth, contentHeight) {
- application.position.stores.resizeObserved.update((object) => {
- object.contentWidth = contentWidth;
- object.contentHeight = contentHeight;
- object.offsetWidth = offsetWidth;
- object.offsetHeight = offsetHeight;
- return object;
- });
- $$invalidate(24, appOffsetHeight = offsetHeight);
- $$invalidate(25, appOffsetWidth = offsetWidth);
- }
- function section_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- elementContent = $$value;
- $$invalidate(0, elementContent);
- });
- }
- function div_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- elementRoot = $$value;
- $$invalidate(1, elementRoot);
- });
- }
- function section_binding_1($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- elementContent = $$value;
- $$invalidate(0, elementContent);
- });
- }
- function div_binding_1($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- elementRoot = $$value;
- $$invalidate(1, elementRoot);
- });
- }
- $$self.$$set = ($$props2) => {
- if ("elementContent" in $$props2)
- $$invalidate(0, elementContent = $$props2.elementContent);
- if ("elementRoot" in $$props2)
- $$invalidate(1, elementRoot = $$props2.elementRoot);
- if ("draggable" in $$props2)
- $$invalidate(6, draggable2 = $$props2.draggable);
- if ("draggableOptions" in $$props2)
- $$invalidate(7, draggableOptions = $$props2.draggableOptions);
- if ("stylesApp" in $$props2)
- $$invalidate(8, stylesApp = $$props2.stylesApp);
- if ("stylesContent" in $$props2)
- $$invalidate(9, stylesContent = $$props2.stylesContent);
- if ("appOffsetHeight" in $$props2)
- $$invalidate(24, appOffsetHeight = $$props2.appOffsetHeight);
- if ("appOffsetWidth" in $$props2)
- $$invalidate(25, appOffsetWidth = $$props2.appOffsetWidth);
- if ("contentOffsetHeight" in $$props2)
- $$invalidate(26, contentOffsetHeight = $$props2.contentOffsetHeight);
- if ("contentOffsetWidth" in $$props2)
- $$invalidate(27, contentOffsetWidth = $$props2.contentOffsetWidth);
- if ("transition" in $$props2)
- $$invalidate(28, transition = $$props2.transition);
- if ("inTransition" in $$props2)
- $$invalidate(2, inTransition = $$props2.inTransition);
- if ("outTransition" in $$props2)
- $$invalidate(3, outTransition = $$props2.outTransition);
- if ("transitionOptions" in $$props2)
- $$invalidate(29, transitionOptions = $$props2.transitionOptions);
- if ("inTransitionOptions" in $$props2)
- $$invalidate(4, inTransitionOptions = $$props2.inTransitionOptions);
- if ("outTransitionOptions" in $$props2)
- $$invalidate(5, outTransitionOptions = $$props2.outTransitionOptions);
- if ("$$scope" in $$props2)
- $$invalidate(35, $$scope = $$props2.$$scope);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty[0] & /*elementContent*/
- 1) {
- if (elementContent !== void 0 && elementContent !== null) {
- getContext("#internal").stores.elementContent.set(elementContent);
- }
- }
- if ($$self.$$.dirty[0] & /*elementRoot*/
- 2) {
- if (elementRoot !== void 0 && elementRoot !== null) {
- getContext("#internal").stores.elementRoot.set(elementRoot);
- }
- }
- if ($$self.$$.dirty[1] & /*$focusAuto, $focusTrap, $minimized*/
- 14) {
- $$invalidate(11, focusWrapEnabled = $focusAuto && $focusTrap && !$minimized);
- }
- if ($$self.$$.dirty[0] & /*oldTransition, transition*/
- 1342177280) {
- if (oldTransition !== transition) {
- const newTransition = typeof transition === "function" ? transition : void 0;
- $$invalidate(2, inTransition = newTransition);
- $$invalidate(3, outTransition = newTransition);
- $$invalidate(30, oldTransition = newTransition);
- }
- }
- if ($$self.$$.dirty[0] & /*transitionOptions*/
- 536870912 | $$self.$$.dirty[1] & /*oldTransitionOptions*/
- 1) {
- if (oldTransitionOptions !== transitionOptions) {
- const newOptions = transitionOptions !== s_DEFAULT_TRANSITION_OPTIONS && isObject(transitionOptions) ? transitionOptions : s_DEFAULT_TRANSITION_OPTIONS;
- $$invalidate(4, inTransitionOptions = newOptions);
- $$invalidate(5, outTransitionOptions = newOptions);
- $$invalidate(31, oldTransitionOptions = newOptions);
- }
- }
- if ($$self.$$.dirty[0] & /*inTransition*/
- 4) {
- if (typeof inTransition !== "function") {
- $$invalidate(2, inTransition = void 0);
- }
- }
- if ($$self.$$.dirty[0] & /*outTransition, application*/
- 1032) {
- {
- if (typeof outTransition !== "function") {
- $$invalidate(3, outTransition = void 0);
- }
- if (application && typeof application?.options?.defaultCloseAnimation === "boolean") {
- $$invalidate(10, application.options.defaultCloseAnimation = outTransition === void 0, application);
- }
- }
- }
- if ($$self.$$.dirty[0] & /*inTransitionOptions*/
- 16) {
- if (typeof inTransitionOptions !== "object") {
- $$invalidate(4, inTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS);
- }
- }
- if ($$self.$$.dirty[0] & /*outTransitionOptions*/
- 32) {
- if (typeof outTransitionOptions !== "object") {
- $$invalidate(5, outTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS);
- }
- }
- };
- return [
- elementContent,
- elementRoot,
- inTransition,
- outTransition,
- inTransitionOptions,
- outTransitionOptions,
- draggable2,
- draggableOptions,
- stylesApp,
- stylesContent,
- application,
- focusWrapEnabled,
- appResizeObserver,
- contentResizeObserver,
- focusAuto,
- focusKeep,
- focusTrap,
- minimized,
- onClosePopup,
- onKeydown,
- onPointerdownApp,
- onPointerdownContent,
- resizeObservedContent,
- resizeObservedApp,
- appOffsetHeight,
- appOffsetWidth,
- contentOffsetHeight,
- contentOffsetWidth,
- transition,
- transitionOptions,
- oldTransition,
- oldTransitionOptions,
- $focusAuto,
- $minimized,
- $focusTrap,
- $$scope,
- slots,
- section_binding,
- div_binding,
- section_binding_1,
- div_binding_1
- ];
- }
- class ApplicationShell extends SvelteComponent {
- constructor(options) {
- super();
- init(
- this,
- options,
- instance$l,
- create_fragment$l,
- safe_not_equal,
- {
- elementContent: 0,
- elementRoot: 1,
- draggable: 6,
- draggableOptions: 7,
- stylesApp: 8,
- stylesContent: 9,
- appOffsetHeight: 24,
- appOffsetWidth: 25,
- contentOffsetHeight: 26,
- contentOffsetWidth: 27,
- transition: 28,
- inTransition: 2,
- outTransition: 3,
- transitionOptions: 29,
- inTransitionOptions: 4,
- outTransitionOptions: 5
- },
- null,
- [-1, -1]
- );
- }
- get elementContent() {
- return this.$$.ctx[0];
- }
- set elementContent(elementContent) {
- this.$$set({ elementContent });
- flush();
- }
- get elementRoot() {
- return this.$$.ctx[1];
- }
- set elementRoot(elementRoot) {
- this.$$set({ elementRoot });
- flush();
- }
- get draggable() {
- return this.$$.ctx[6];
- }
- set draggable(draggable2) {
- this.$$set({ draggable: draggable2 });
- flush();
- }
- get draggableOptions() {
- return this.$$.ctx[7];
- }
- set draggableOptions(draggableOptions) {
- this.$$set({ draggableOptions });
- flush();
- }
- get stylesApp() {
- return this.$$.ctx[8];
- }
- set stylesApp(stylesApp) {
- this.$$set({ stylesApp });
- flush();
- }
- get stylesContent() {
- return this.$$.ctx[9];
- }
- set stylesContent(stylesContent) {
- this.$$set({ stylesContent });
- flush();
- }
- get appOffsetHeight() {
- return this.$$.ctx[24];
- }
- set appOffsetHeight(appOffsetHeight) {
- this.$$set({ appOffsetHeight });
- flush();
- }
- get appOffsetWidth() {
- return this.$$.ctx[25];
- }
- set appOffsetWidth(appOffsetWidth) {
- this.$$set({ appOffsetWidth });
- flush();
- }
- get contentOffsetHeight() {
- return this.$$.ctx[26];
- }
- set contentOffsetHeight(contentOffsetHeight) {
- this.$$set({ contentOffsetHeight });
- flush();
- }
- get contentOffsetWidth() {
- return this.$$.ctx[27];
- }
- set contentOffsetWidth(contentOffsetWidth) {
- this.$$set({ contentOffsetWidth });
- flush();
- }
- get transition() {
- return this.$$.ctx[28];
- }
- set transition(transition) {
- this.$$set({ transition });
- flush();
- }
- get inTransition() {
- return this.$$.ctx[2];
- }
- set inTransition(inTransition) {
- this.$$set({ inTransition });
- flush();
- }
- get outTransition() {
- return this.$$.ctx[3];
- }
- set outTransition(outTransition) {
- this.$$set({ outTransition });
- flush();
- }
- get transitionOptions() {
- return this.$$.ctx[29];
- }
- set transitionOptions(transitionOptions) {
- this.$$set({ transitionOptions });
- flush();
- }
- get inTransitionOptions() {
- return this.$$.ctx[4];
- }
- set inTransitionOptions(inTransitionOptions) {
- this.$$set({ inTransitionOptions });
- flush();
- }
- get outTransitionOptions() {
- return this.$$.ctx[5];
- }
- set outTransitionOptions(outTransitionOptions) {
- this.$$set({ outTransitionOptions });
- flush();
- }
- }
- const EmptyApplicationShell_svelte_svelte_type_style_lang = "";
- const TJSApplicationShell_svelte_svelte_type_style_lang = "";
- const DialogContent_svelte_svelte_type_style_lang = "";
- cssVariables.setProperties({
- // Anchor text shadow / header buttons
- "--tjs-default-text-shadow-focus-hover": "0 0 8px var(--color-shadow-primary)",
- // TJSApplicationShell app background.
- "--tjs-app-background": `url("${globalThis.foundry.utils.getRoute("/ui/denim075.png")}")`
- }, false);
- Hooks.on("PopOut:loading", (app) => {
- if (app instanceof SvelteApplication) {
- app.position.enabled = false;
- }
- });
- Hooks.on("PopOut:popin", (app) => {
- if (app instanceof SvelteApplication) {
- app.position.enabled = true;
- }
- });
- Hooks.on("PopOut:close", (app) => {
- if (app instanceof SvelteApplication) {
- app.position.enabled = true;
- }
- });
- class loading_bar {
- constructor() {
- this.total = 0;
- this.current = 0;
- this.lastPct = 0;
- }
- init(context, total) {
- this.context = context;
- this.total = total;
- this.current = 0;
- this.lastPct = 0;
- SceneNavigation.displayProgressBar({ label: this.context, pct: 1 });
- }
- incrementProgress() {
- this.current += 1;
- const pct = Math.round(this.current / this.total * 100);
- if (pct !== this.lastPct) {
- debug(`${pct}% loaded...`);
- SceneNavigation.displayProgressBar({ label: this.context, pct });
- }
- this.lastPct = pct;
- }
- }
- const LoadingBar = new loading_bar();
- const SequencerFileCache = {
- _videos: {},
- _preloadedFiles: /* @__PURE__ */ new Set(),
- _totalCacheSize: 0,
- _validTypes: ["video/webm", "video/x-webm", "application/octet-stream"],
- async loadVideo(inSrc) {
- if (!this._videos[inSrc]) {
- const blob = await fetch(inSrc, {
- mode: "cors",
- credentials: "same-origin"
- }).then((r) => r.blob()).catch((err) => {
- console.error(err);
- });
- if (this._validTypes.indexOf(blob?.type) === -1)
- return false;
- while (this._totalCacheSize + blob.size > 524288e3) {
- const entries = Object.entries(this._videos);
- entries.sort((a, b) => {
- return b[1].lastUsed - a[1].lastUsed;
- });
- const [oldSrc] = entries[0];
- this._preloadedFiles.delete(oldSrc);
- this._totalCacheSize -= this._videos[oldSrc].blob.size;
- delete this._videos[oldSrc];
- }
- this._totalCacheSize += blob.size;
- this._preloadedFiles.add(inSrc);
- this._videos[inSrc] = {
- blob,
- lastUsed: +new Date()
- };
- }
- this._videos[inSrc].lastUsed = +new Date();
- return this._videos[inSrc].blob;
- },
- srcExists(inSrc) {
- if (this._preloadedFiles.has(inSrc)) {
- return true;
- }
- return srcExists(inSrc);
- },
- async loadFile(inSrc, preload = false) {
- if (inSrc.toLowerCase().endsWith(".webm")) {
- let blob = await this.loadVideo(inSrc);
- if (!blob)
- return false;
- this._preloadedFiles.add(inSrc);
- if (preload)
- return true;
- return get_video_texture(blob);
- } else if (AudioHelper.hasAudioExtension(inSrc)) {
- try {
- const audio2 = await AudioHelper.preloadSound(inSrc);
- if (audio2) {
- this._preloadedFiles.add(inSrc);
- }
- return audio2;
- } catch (err) {
- console.error(`Failed to load audio: ${inSrc}`);
- return false;
- }
- }
- const texture = await loadTexture(inSrc);
- if (texture) {
- this._preloadedFiles.add(inSrc);
- }
- return texture;
- }
- };
- async function get_video_texture(inBlob) {
- return new Promise(async (resolve) => {
- const video = document.createElement("video");
- video.preload = "auto";
- video.crossOrigin = "anonymous";
- video.controls = true;
- video.autoplay = false;
- video.autoload = true;
- video.muted = true;
- video.src = URL.createObjectURL(inBlob);
- let canplay = true;
- video.oncanplay = async () => {
- if (!canplay)
- return;
- canplay = false;
- video.height = video.videoHeight;
- video.width = video.videoWidth;
- const baseTexture = PIXI.BaseTexture.from(video, {
- resourceOptions: { autoPlay: false }
- });
- if (game.settings.get(CONSTANTS.MODULE_NAME, "enable-fix-pixi")) {
- baseTexture.alphaMode = PIXI.ALPHA_MODES.PREMULTIPLIED_ALPHA;
- }
- const texture = new PIXI.Texture(baseTexture);
- resolve(texture);
- };
- video.onerror = () => {
- URL.revokeObjectURL(video.src);
- reject();
- };
- });
- }
- const flipBookTextureCache = {};
- class SequencerFileBase {
- static make(inData, inDBPath, inMetadata) {
- const originalFile = inData?.file ?? inData;
- const file = foundry.utils.duplicate(originalFile);
- const isRangeFind = typeof file !== "string" && !Array.isArray(originalFile) ? Object.keys(originalFile).filter((key) => key.endsWith("ft")).length > 0 : false;
- return isRangeFind ? new SequencerFileRangeFind(inData, inDBPath, inMetadata) : new SequencerFile(inData, inDBPath, inMetadata);
- }
- }
- class SequencerFile extends SequencerFileBase {
- rangeFind = false;
- constructor(inData, inDBPath, inMetadata) {
- super();
- inData = foundry.utils.duplicate(inData);
- inMetadata = foundry.utils.duplicate(inMetadata);
- this.originalData = inData;
- this.originalMetadata = inMetadata;
- for (let [key, value] of Object.entries(inMetadata)) {
- this[key] = value;
- }
- this.dbPath = inDBPath;
- this.moduleName = inDBPath.split(".")[0];
- this.originalFile = inData?.file ?? inData;
- this.file = foundry.utils.duplicate(this.originalFile);
- this.fileIndex = null;
- this.fileTextureMap = Object.fromEntries(
- this.getAllFiles().map((file) => {
- return [file, false];
- })
- );
- this.twister = false;
- }
- clone() {
- return SequencerFile.make(
- this.originalData,
- this.dbPath,
- this.originalMetadata
- );
- }
- async validate() {
- let isValid = true;
- const directories = {};
- const allFiles = this.getAllFiles();
- for (const file of allFiles) {
- let directory = file.split("/");
- directory.pop();
- directory = directory.join("/");
- if (directories[directory] === void 0) {
- directories[directory] = await getFiles(directory);
- }
- }
- for (const file of allFiles) {
- let directory = file.split("/");
- directory.pop();
- directory = directory.join("/");
- if (directories[directory].indexOf(file) === -1) {
- console.warn(
- `"${this.dbPath}" has an incorrect file path, could not find file. Points to:
- ${file}`
- );
- isValid = false;
- }
- }
- return isValid;
- }
- getAllFiles() {
- return [this.file].deepFlatten();
- }
- getFile() {
- if (Array.isArray(this.file)) {
- this.fileIndex = is_real_number(this.fileIndex) ? this.fileIndex : random_array_element(this.file, {
- twister: this.twister,
- index: true
- });
- return this.file[this.fileIndex];
- }
- return this.file;
- }
- getTimestamps() {
- if (Array.isArray(this.originalMetadata?.timestamps)) {
- return this.originalMetadata?.timestamps?.[this.fileIndex] ?? this.originalMetadata?.timestamps[0];
- }
- return this.originalMetadata?.timestamps;
- }
- getPreviewFile(entry) {
- let parts = entry.split(".");
- let files2 = this.getAllFiles();
- if (Array.isArray(files2)) {
- if (is_real_number(parts[parts.length - 1])) {
- files2 = files2[parts[parts.length - 1]];
- } else {
- const index = Math.floor(interpolate(0, files2.length - 1, 0.5));
- files2 = files2?.[index - 1] ?? files2[index];
- }
- }
- return files2;
- }
- destroy() {
- if (this.originalMetadata?.flipbook)
- return;
- for (let texture of Object.values(this.fileTextureMap)) {
- if (!texture)
- continue;
- try {
- texture?.baseTexture?.resource?.source?.removeAttribute("src");
- } catch (err) {
- }
- try {
- texture?.baseTexture?.resource?.source?.pause();
- } catch (err) {
- }
- try {
- texture?.baseTexture?.resource?.source?.remove();
- } catch (err) {
- }
- try {
- texture?.baseTexture?.resource?.source?.load();
- } catch (err) {
- }
- texture.destroy();
- }
- }
- async _getTexture(file) {
- if (this.fileTextureMap[file])
- return this.fileTextureMap[file];
- this.fileTextureMap[file] = await SequencerFileCache.loadFile(file);
- return this.fileTextureMap[file];
- }
- _adjustScaleForPadding(distance, width2) {
- return distance / (width2 - (this.template ? this.template[1] + this.template[2] : 0));
- }
- _adjustAnchorForPadding(width2) {
- return this.template ? this.template[1] / width2 : void 0;
- }
- async _getFlipBookSheet(filePath) {
- if (!this.originalMetadata?.flipbook)
- return false;
- if (flipBookTextureCache[filePath]) {
- return flipBookTextureCache[filePath];
- }
- flipBookTextureCache[filePath] = this.file.map((file) => {
- return PIXI.Texture.from(file);
- });
- return flipBookTextureCache[filePath];
- }
- async getTexture(distance) {
- const filePath = this.getFile();
- const texture = await this._getTexture(this.getFile());
- const sheet = await this._getFlipBookSheet(filePath);
- return {
- filePath,
- texture,
- sheet,
- spriteScale: this._adjustScaleForPadding(distance, texture.width),
- spriteAnchor: this._adjustAnchorForPadding(texture.width)
- };
- }
- }
- class SequencerFileRangeFind extends SequencerFile {
- rangeFind = true;
- constructor(...args) {
- super(...args);
- this._fileDistanceMap = false;
- }
- static get ftToDistanceMap() {
- return {
- "90ft": canvas.grid.size * 15,
- "60ft": canvas.grid.size * 9,
- "30ft": canvas.grid.size * 5,
- "15ft": canvas.grid.size * 2,
- "05ft": 0
- };
- }
- get _gridSizeDiff() {
- return canvas.grid.size / this.template[0];
- }
- getAllFiles() {
- return Object.values(this.file).deepFlatten();
- }
- getFile(inFt) {
- if (inFt && this.file[inFt]) {
- if (Array.isArray(this.file[inFt])) {
- const fileIndex = is_real_number(this.fileIndex) ? Math.min(this.file[inFt].length - 1, this.fileIndex) : random_array_element(this.file[inFt], {
- twister: this.twister,
- index: true
- });
- return this.file[inFt][fileIndex];
- }
- return this.file[inFt];
- }
- return this.file;
- }
- getPreviewFile(entry) {
- let parts = entry.split(".");
- const ft = parts.find(
- (part) => Object.keys(SequencerFileRangeFind.ftToDistanceMap).indexOf(part) > -1
- );
- if (!ft) {
- return super.getPreviewFile(entry);
- }
- const fileIndex = parts.slice(parts.indexOf(ft) + 1)?.[0];
- if (is_real_number(Number(fileIndex))) {
- this.fileIndex = Number(fileIndex);
- }
- return this.getFile(ft);
- }
- async getTexture(distance = 400) {
- const { filePath, texture } = await this._getTextureForDistance(distance);
- return {
- filePath,
- texture,
- spriteScale: this._adjustScaleForPadding(distance, texture.width),
- spriteAnchor: this._adjustAnchorForPadding(texture.width)
- };
- }
- _getMatchingDistance(inEntry) {
- return SequencerFileRangeFind.ftToDistanceMap[inEntry] / this._gridSizeDiff;
- }
- _rangeFind(inDistance) {
- if (!this._fileDistanceMap) {
- let distances = Object.keys(this.file).filter(
- (entry) => Object.keys(SequencerFileRangeFind.ftToDistanceMap).indexOf(entry) > -1
- ).map((ft) => {
- return {
- file: this.getFile(ft),
- minDistance: this._getMatchingDistance(ft)
- };
- });
- let uniqueDistances = [
- ...new Set(distances.map((item) => item.minDistance))
- ];
- uniqueDistances.sort((a, b) => a - b);
- let max = Math.max(...uniqueDistances);
- let min = Math.min(...uniqueDistances);
- this._fileDistanceMap = distances.map((entry) => {
- entry.distances = {
- min: entry.minDistance === min ? 0 : entry.minDistance,
- max: entry.minDistance === max ? Infinity : uniqueDistances[uniqueDistances.indexOf(entry.minDistance) + 1]
- };
- return entry;
- });
- }
- const possibleFiles = this._fileDistanceMap.filter((entry) => {
- const relativeDistance = inDistance / this._gridSizeDiff;
- return relativeDistance >= entry.distances.min && relativeDistance < entry.distances.max;
- }).map((entry) => entry.file).flat();
- return possibleFiles.length > 1 ? random_array_element(possibleFiles, { twister: this.twister }) : possibleFiles[0];
- }
- async _getTextureForDistance(distance) {
- const filePath = this._rangeFind(distance);
- const texture = await this._getTexture(filePath);
- return { filePath, texture };
- }
- }
- class Database {
- #entriesStore = writable$1({});
- privateModules = [];
- flattenedEntries = [];
- inverseFlattenedEntries = /* @__PURE__ */ new Map();
- get entries() {
- return get_store_value(this.#entriesStore);
- }
- set entries(entries) {
- this.#entriesStore.set(entries);
- }
- get entriesStore() {
- return this.#entriesStore;
- }
- get publicModules() {
- return Object.keys(this.entries).filter(
- (module2) => !this.privateModules.includes(module2)
- );
- }
- get publicFlattenedEntries() {
- return this.flattenedEntries.filter((entry) => {
- return this.privateModules.indexOf(entry.split(".")[0]) === -1;
- });
- }
- get publicFlattenedSimpleEntries() {
- return make_array_unique(
- this.publicFlattenedEntries.map((entry) => {
- return entry.split(CONSTANTS.FEET_REGEX)[0];
- })
- );
- }
- /**
- * Retrieves an object of every public entry
- *
- * @return {object}
- */
- get filePathDatabasePaths() {
- const fileDatabaseObject = {};
- Object.entries(this.entries).map((entry) => entry[1]).deepFlatten().forEach((sequencerFile) => {
- if (sequencerFile?.rangeFind) {
- Object.entries(sequencerFile.file).forEach((entry) => {
- fileDatabaseObject[entry[1]] = sequencerFile.dbPath + "." + entry[0];
- });
- } else {
- fileDatabaseObject[sequencerFile.file] = sequencerFile.dbPath;
- }
- });
- return fileDatabaseObject;
- }
- /**
- * Registers a set of entries to the database on the given module name
- *
- * @param {string} inModuleName The namespace to assign to the inserted entries
- * @param {object} inEntries The entries to merge into the database
- * @param {boolean} isPrivate Whether to mark these entries as private and not show in Effect Player or Database Viewer
- * @return {boolean}
- */
- registerEntries(inModuleName, inEntries, isPrivate = false) {
- if (inModuleName.includes("."))
- return this._throwError(
- "registerEntries",
- "module name must not contain periods"
- );
- if (this.entries[inModuleName])
- custom_warning(
- "Sequencer",
- `registerEntries | module "${inModuleName}" has already been registered to the database! Do you have two similar modules active?`,
- true
- );
- this._flatten(inEntries, inModuleName);
- const processedEntries = this._processEntries(inModuleName, inEntries);
- if (isPrivate)
- this.privateModules.push(inModuleName);
- this.entries = foundry.utils.mergeObject(this.entries, {
- [inModuleName]: processedEntries
- });
- debug(
- `Sequencer | Database | Entries for "${inModuleName}" registered`
- );
- Hooks.callAll("registerSequencerDatabaseEntries", inModuleName);
- return true;
- }
- /**
- * Validates the entries under a certain module name, checking whether paths to assets are correct or not
- *
- * @param {string} inModuleName The namespace to assign to the inserted entries
- * @return {boolean}
- */
- async validateEntries(inModuleName) {
- let entries = this.getEntry(inModuleName);
- if (!Array.isArray(entries)) {
- entries = [entries];
- }
- ui.notifications.info(
- `Validating paths registered to "${inModuleName}"...`
- );
- let isValid = true;
- LoadingBar.init(
- `Validating paths registered to "${inModuleName}"...`,
- entries.length
- );
- for (let entry of entries) {
- const result = await entry.validate();
- LoadingBar.incrementProgress();
- isValid = !(!result || !isValid);
- }
- if (!isValid) {
- ui.notifications.error(
- `Validation of paths registered to "${inModuleName}" failed! Errors logged in console.`
- );
- } else {
- ui.notifications.info(
- `Validation of paths registered to "${inModuleName}" complete! No errors found!`
- );
- }
- }
- /**
- * Quickly checks if the entry exists in the database
- *
- * @param {string} inString The entry to find in the database
- * @return {boolean} If the entry exists in the database
- */
- entryExists(inString) {
- if (typeof inString !== "string")
- return this._throwError("entryExists", "inString must be of type string");
- inString = inString.trim();
- if (inString === "")
- return this._throwError("entryExists", "inString cannot be empty");
- inString = inString.replace(/\[[0-9]+]$/, "");
- return this.flattenedEntries.find((entry) => entry.startsWith(inString));
- }
- /**
- * Gets the entry in the database by a dot-notated string
- *
- * @param {string} inString The entry to find in the database
- * @param {boolean} softFail Whether it should soft fail (no error) when no entry was found
- * @return {array|SequencerFile|boolean} The found entry in the database, or false if not found (with warning)
- */
- getEntry(inString, { softFail = false } = {}) {
- if (typeof inString !== "string") {
- if (softFail)
- return false;
- return this._throwError("getEntry", "inString must be of type string");
- }
- inString = inString.trim();
- if (inString === "") {
- if (softFail)
- return false;
- return this._throwError("getEntry", "inString cannot be empty");
- }
- inString = inString.replace(/\[[0-9]+]$/, "");
- if (!this.entryExists(inString)) {
- if (softFail)
- return false;
- return this._throwError(
- "getEntry",
- `Could not find ${inString} in database`
- );
- }
- let ft = false;
- let index = false;
- if (CONSTANTS.FEET_REGEX.test(inString)) {
- ft = inString.match(CONSTANTS.FEET_REGEX)[0];
- const split = inString.split(ft).filter((str) => str !== "");
- if (split.length > 1) {
- index = split[1].split(".")[0];
- }
- inString = split[0];
- }
- const module2 = inString.split(".")[0];
- const exactEntries = this.entries[module2].filter((entry) => {
- return entry.dbPath === inString;
- });
- let filteredEntries = (exactEntries.length ? exactEntries : this.entries[module2].filter((entry) => {
- return entry.dbPath.startsWith(inString);
- })).map((entry) => {
- let foundFile = entry;
- if (ft)
- foundFile = entry.file?.[ft] ?? foundFile;
- if (index)
- foundFile = foundFile?.[index] ?? foundFile;
- return foundFile;
- });
- if (!filteredEntries.length)
- return this._throwError(
- "getEntry",
- `Could not find ${inString} in database`
- );
- const foundEntry = filteredEntries.length === 1 ? filteredEntries[0] : filteredEntries;
- if (index && filteredEntries.length === 1) {
- foundEntry.fileIndex = Number(index);
- }
- return foundEntry;
- }
- /**
- * Gets all files under a database path
- *
- * @param {string} inDBPath The module to get all files from
- * @return {array|boolean} The found entries in the database under the module's name, or false if not found (with warning)
- */
- getAllFileEntries(inDBPath) {
- if (typeof inDBPath !== "string")
- return this._throwError(
- "getAllFileEntries",
- "inDBPath must be of type string"
- );
- inDBPath = inDBPath.trim();
- if (inDBPath === "")
- return this._throwError("getAllFileEntries", "inDBPath cannot be empty");
- if (!this.entryExists(inDBPath))
- return this._throwError(
- "getAllFileEntries",
- `Could not find ${inDBPath} in database`
- );
- const entries = this._recurseGetFilePaths(inDBPath);
- return make_array_unique(entries.flat());
- }
- /**
- * Get all valid entries under a certain path
- *
- * @param {string} inPath The database path to get entries under
- * @return {array|boolean} An array containing the next layer of valid paths
- */
- getPathsUnder(inPath, {
- ranges = false,
- arrays = false,
- match = false,
- fullyQualified = false
- } = {}) {
- if (typeof inPath !== "string")
- return this._throwError("getPathsUnder", "inPath must be of type string");
- inPath = inPath.trim();
- if (inPath === "")
- return this._throwError("getPathsUnder", "inPath cannot be empty");
- inPath = inPath.replace(/\[[0-9]+]$/, "");
- if (!this.entryExists(inPath))
- return this._throwError(
- "getPathsUnder",
- `Could not find ${inPath} in database`
- );
- const entries = this.flattenedEntries.filter((e) => {
- return (e.startsWith(inPath + ".") || e === inPath) && (!match || match && e.match(match));
- });
- if (entries.length === 0)
- return [];
- return make_array_unique(
- entries.map((e) => !arrays ? e.split(CONSTANTS.ARRAY_REGEX)[0] : e).map((e) => !ranges ? e.split(CONSTANTS.FEET_REGEX)[0] : e).map((e) => !fullyQualified ? e.split(inPath)[1] : e).map((e) => !fullyQualified ? e ? e.split(".")[1] : "" : e).filter(Boolean)
- );
- }
- /**
- * Get all valid entries under a certain path
- *
- * @param {string} inPath The database path to search for
- * @param {boolean} publicOnly Whether to only search for public modules
- * @return {array|boolean} An array containing potential database paths
- */
- searchFor(inPath, publicOnly = true) {
- const modules = publicOnly ? this.publicModules : Object.keys(this.entries);
- const originalEntries = publicOnly ? this.publicFlattenedEntries : this.flattenedEntries;
- if ((!inPath || inPath === "") && !modules.includes(inPath))
- return modules;
- if (typeof inPath !== "string") {
- return this._throwError("searchFor", "inString must be of type string");
- }
- inPath = inPath.trim();
- if (inPath === "")
- return this._throwError("searchFor", "inString cannot be empty");
- inPath = inPath.replace(/\[[0-9]+]$/, "");
- inPath = inPath.trim();
- let entries = originalEntries.filter(
- (e) => e.startsWith(inPath) && e !== inPath
- );
- if (inPath.endsWith("."))
- inPath = inPath.substring(0, inPath.length - 1);
- let length = inPath.split(".").length + 1;
- let foundEntries = entries.map((e) => {
- let path = e.split(CONSTANTS.FEET_REGEX)[0];
- return path.split(".").slice(0, length).join(".");
- });
- if (foundEntries.length === 0) {
- const regexString = str_to_search_regex_str(inPath).replace(/\s+/g, "|");
- const searchParts = regexString.split("|").length;
- const regexSearch = new RegExp(regexString, "gu");
- foundEntries = originalEntries.filter((e) => {
- return e.match(regexSearch)?.length >= searchParts;
- }).map((e) => {
- return e.split(CONSTANTS.FEET_REGEX)[0];
- });
- }
- return make_array_unique(foundEntries);
- }
- /**
- * Throws an error without THROWING one. Duh.
- *
- * @param inFunctionName
- * @param inError
- * @returns {boolean}
- * @private
- */
- _throwError(inFunctionName, inError) {
- let error = `Sequencer | Database | ${inFunctionName} - ${inError}`;
- ui.notifications.error(error);
- return false;
- }
- /**
- * Gets all file paths from the entirety of
- *
- * @param inDBPath
- * @returns {Array}
- * @private
- */
- _recurseGetFilePaths(inDBPath) {
- const module2 = inDBPath.split(".")[0];
- return this.entries[module2].filter((entry) => entry.dbPath.startsWith(inDBPath)).map((entry) => {
- return entry.getAllFiles();
- }).flat();
- }
- /**
- * Flattens a given object to just their db path and file path
- *
- * @param entries
- * @param inModule
- * @private
- */
- _flatten(entries, inModule) {
- let flattened = flatten_object(
- foundry.utils.duplicate({ [inModule]: entries })
- );
- this.flattenedEntries = make_array_unique(
- this.flattenedEntries.concat(
- Object.keys(flattened).map((file) => file.split(".file")[0])
- )
- );
- this.inverseFlattenedEntries = Object.keys(flattened).reduce(
- (acc, entry) => {
- return acc.set(flattened[entry], entry.split(".file")[0]);
- },
- this.inverseFlattenedEntries
- );
- }
- /**
- * Processes and recurse into a large object containing file paths at any given depth
- *
- * @param moduleName
- * @param entries
- * @returns {object}
- * @private
- */
- _processEntries(moduleName, entries) {
- const allPaths = new Set(
- this.flattenedEntries.filter((e) => e.split(".")[0] === moduleName).map((e) => e.split(CONSTANTS.FEET_REGEX)[0])
- );
- const allTemplates = foundry.utils.mergeObject(entries?._templates ?? {}, {
- default: [100, 0, 0]
- });
- if (entries?._templates) {
- delete entries?._templates;
- }
- const moduleEntries = [];
- const mediaFileExtensions = Object.keys(CONST.FILE_CATEGORIES.IMAGE).concat(Object.keys(CONST.FILE_CATEGORIES.VIDEO)).concat(Object.keys(CONST.FILE_CATEGORIES.AUDIO));
- for (let wholeDBPath of allPaths) {
- let metadata = this._getCleanData(entries);
- let dbPath = wholeDBPath.split(".");
- dbPath.shift();
- let combinedPath = "";
- for (let part of dbPath) {
- combinedPath = combinedPath ? combinedPath + "." + part : part;
- const entry = getProperty(entries, combinedPath);
- if (Array.isArray(entry) || typeof entry === "string" || entry?.file) {
- metadata = this._getCleanData(entry, { existingData: metadata });
- break;
- }
- metadata = this._getCleanData(entry, { existingData: metadata });
- }
- if (!metadata.template)
- metadata.template = "default";
- if (typeof metadata.template === "string") {
- metadata.template = allTemplates?.[metadata.template] ?? allTemplates?.["default"];
- }
- let data = getProperty(entries, dbPath.join("."));
- if (!Array.isArray(data) && !(typeof data === "string")) {
- data = this._getCleanData(data, { metadata: false });
- }
- if (typeof data === "string") {
- const existingEntry = this.entryExists(data);
- const extension = data.split(".")[data.split(".").length - 1].toLowerCase();
- if (!existingEntry && extension && !mediaFileExtensions.includes(extension)) {
- console.warn(
- `Sequencer | Database | registerEntries - failed to register ${wholeDBPath} to ${data}!`
- );
- this.flattenedEntries.splice(
- this.flattenedEntries.indexOf(wholeDBPath),
- 1
- );
- continue;
- } else if (existingEntry) {
- const sequencerFile = this.getEntry(data);
- const clone = sequencerFile.clone();
- clone.dbPath = wholeDBPath;
- clone.metadata = foundry.utils.mergeObject(
- clone.metadata ?? {},
- metadata ?? {}
- );
- moduleEntries.push(clone);
- continue;
- }
- }
- moduleEntries.push(SequencerFileBase.make(data, wholeDBPath, metadata));
- }
- return moduleEntries;
- }
- _getCleanData(data, { existingData = {}, metadata = true } = {}) {
- data = Object.entries(data).filter((entry) => {
- return metadata === entry[0].startsWith("_");
- });
- if (metadata) {
- data = data.map((entry) => [entry[0].slice(1), entry[1]]);
- }
- return foundry.utils.mergeObject(existingData, Object.fromEntries(data));
- }
- }
- const SequencerDatabase = new Database();
- const TreeViewEntry_svelte_svelte_type_style_lang = "";
- function create_if_block_2$1(ctx) {
- let a;
- let i;
- let mounted;
- let dispose;
- return {
- c() {
- a = element("a");
- i = element("i");
- attr(i, "class", "fas svelte-ese-uyryhb");
- toggle_class(
- i,
- "fa-angle-down",
- /*data*/
- ctx[0].open
- );
- toggle_class(i, "fa-angle-right", !/*data*/
- ctx[0].open);
- attr(a, "class", "svelte-ese-uyryhb");
- },
- m(target, anchor) {
- insert(target, a, anchor);
- append(a, i);
- if (!mounted) {
- dispose = listen(
- a,
- "click",
- /*click_handler*/
- ctx[6]
- );
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (dirty & /*data*/
- 1) {
- toggle_class(
- i,
- "fa-angle-down",
- /*data*/
- ctx2[0].open
- );
- }
- if (dirty & /*data*/
- 1) {
- toggle_class(i, "fa-angle-right", !/*data*/
- ctx2[0].open);
- }
- },
- d(detaching) {
- if (detaching)
- detach(a);
- mounted = false;
- dispose();
- }
- };
- }
- function create_if_block$7(ctx) {
- let t0;
- let a0;
- let i0;
- let t1;
- let a1;
- let mounted;
- let dispose;
- let if_block = !/*data*/
- ctx[0].hasChildren && create_if_block_1$4(ctx);
- return {
- c() {
- if (if_block)
- if_block.c();
- t0 = space();
- a0 = element("a");
- i0 = element("i");
- t1 = space();
- a1 = element("a");
- a1.innerHTML = `<i class="fas fa-play svelte-ese-uyryhb"></i>`;
- attr(i0, "class", "fas fa-database svelte-ese-uyryhb");
- toggle_class(
- i0,
- "flash-it",
- /*flashDBPath*/
- ctx[2]
- );
- attr(a0, "class", "database-entry-button svelte-ese-uyryhb");
- attr(a1, "class", "database-entry-button svelte-ese-uyryhb");
- },
- m(target, anchor) {
- if (if_block)
- if_block.m(target, anchor);
- insert(target, t0, anchor);
- insert(target, a0, anchor);
- append(a0, i0);
- insert(target, t1, anchor);
- insert(target, a1, anchor);
- if (!mounted) {
- dispose = [
- listen(
- a0,
- "click",
- /*click_handler_2*/
- ctx[8]
- ),
- listen(
- a1,
- "click",
- /*click_handler_3*/
- ctx[9]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (!/*data*/
- ctx2[0].hasChildren) {
- if (if_block) {
- if_block.p(ctx2, dirty);
- } else {
- if_block = create_if_block_1$4(ctx2);
- if_block.c();
- if_block.m(t0.parentNode, t0);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- if (dirty & /*flashDBPath*/
- 4) {
- toggle_class(
- i0,
- "flash-it",
- /*flashDBPath*/
- ctx2[2]
- );
- }
- },
- d(detaching) {
- if (if_block)
- if_block.d(detaching);
- if (detaching)
- detach(t0);
- if (detaching)
- detach(a0);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(a1);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_if_block_1$4(ctx) {
- let a;
- let i;
- let mounted;
- let dispose;
- return {
- c() {
- a = element("a");
- i = element("i");
- attr(i, "class", "fas fa-file svelte-ese-uyryhb");
- toggle_class(
- i,
- "flash-it",
- /*flashFilePath*/
- ctx[1]
- );
- attr(a, "class", "database-entry-button svelte-ese-uyryhb");
- },
- m(target, anchor) {
- insert(target, a, anchor);
- append(a, i);
- if (!mounted) {
- dispose = listen(
- a,
- "click",
- /*click_handler_1*/
- ctx[7]
- );
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (dirty & /*flashFilePath*/
- 2) {
- toggle_class(
- i,
- "flash-it",
- /*flashFilePath*/
- ctx2[1]
- );
- }
- },
- d(detaching) {
- if (detaching)
- detach(a);
- mounted = false;
- dispose();
- }
- };
- }
- function create_fragment$k(ctx) {
- let div3;
- let div2;
- let t0;
- let show_if = (
- /*data*/
- ctx[0].fullPath.includes(".")
- );
- let t1;
- let div1;
- let div0;
- let t2;
- let t3_value = (
- /*data*/
- ctx[0].path + ""
- );
- let t3;
- let div1_title_value;
- let if_block0 = (
- /*data*/
- ctx[0].hasChildren && create_if_block_2$1(ctx)
- );
- let if_block1 = show_if && create_if_block$7(ctx);
- return {
- c() {
- div3 = element("div");
- div2 = element("div");
- if (if_block0)
- if_block0.c();
- t0 = space();
- if (if_block1)
- if_block1.c();
- t1 = space();
- div1 = element("div");
- div0 = element("div");
- t2 = space();
- t3 = text$1(t3_value);
- attr(div0, "class", "database-entry-text-highlight svelte-ese-uyryhb");
- attr(div1, "class", "database-entry-text svelte-ese-uyryhb");
- attr(div1, "title", div1_title_value = /*data*/
- ctx[0].path);
- attr(div2, "class", "database-entry-text-container svelte-ese-uyryhb");
- attr(div3, "class", "database-entry svelte-ese-uyryhb");
- set_style(
- div3,
- "margin-left",
- /*data*/
- ctx[0].depth * 15 + "px"
- );
- },
- m(target, anchor) {
- insert(target, div3, anchor);
- append(div3, div2);
- if (if_block0)
- if_block0.m(div2, null);
- append(div2, t0);
- if (if_block1)
- if_block1.m(div2, null);
- append(div2, t1);
- append(div2, div1);
- append(div1, div0);
- div0.innerHTML = /*highlight*/
- ctx[3];
- append(div1, t2);
- append(div1, t3);
- },
- p(ctx2, [dirty]) {
- if (
- /*data*/
- ctx2[0].hasChildren
- ) {
- if (if_block0) {
- if_block0.p(ctx2, dirty);
- } else {
- if_block0 = create_if_block_2$1(ctx2);
- if_block0.c();
- if_block0.m(div2, t0);
- }
- } else if (if_block0) {
- if_block0.d(1);
- if_block0 = null;
- }
- if (dirty & /*data*/
- 1)
- show_if = /*data*/
- ctx2[0].fullPath.includes(".");
- if (show_if) {
- if (if_block1) {
- if_block1.p(ctx2, dirty);
- } else {
- if_block1 = create_if_block$7(ctx2);
- if_block1.c();
- if_block1.m(div2, t1);
- }
- } else if (if_block1) {
- if_block1.d(1);
- if_block1 = null;
- }
- if (dirty & /*highlight*/
- 8)
- div0.innerHTML = /*highlight*/
- ctx2[3];
- if (dirty & /*data*/
- 1 && t3_value !== (t3_value = /*data*/
- ctx2[0].path + ""))
- set_data(t3, t3_value);
- if (dirty & /*data*/
- 1 && div1_title_value !== (div1_title_value = /*data*/
- ctx2[0].path)) {
- attr(div1, "title", div1_title_value);
- }
- if (dirty & /*data*/
- 1) {
- set_style(
- div3,
- "margin-left",
- /*data*/
- ctx2[0].depth * 15 + "px"
- );
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div3);
- if (if_block0)
- if_block0.d();
- if (if_block1)
- if_block1.d();
- }
- };
- }
- function instance$k($$self, $$props, $$invalidate) {
- let highlight;
- let $searchRegex;
- let { data } = $$props;
- const searchRegex = databaseStore.searchRegex;
- component_subscribe($$self, searchRegex, (value) => $$invalidate(5, $searchRegex = value));
- let flashFilePath = false;
- let flashDBPath = false;
- const click_handler = (e) => {
- databaseStore.openTreePath(data.fullPath, !data.open, e.ctrlKey);
- };
- const click_handler_1 = (e) => {
- databaseStore.copyPath(data.fullPath, true, e.ctrlKey);
- $$invalidate(1, flashFilePath = true);
- setTimeout(
- () => {
- $$invalidate(1, flashFilePath = false);
- },
- 400
- );
- };
- const click_handler_2 = (e) => {
- databaseStore.copyPath(data.fullPath, false, e.ctrlKey);
- $$invalidate(2, flashDBPath = true);
- setTimeout(
- () => {
- $$invalidate(2, flashDBPath = false);
- },
- 400
- );
- };
- const click_handler_3 = () => {
- databaseStore.playFile(data.fullPath);
- };
- $$self.$$set = ($$props2) => {
- if ("data" in $$props2)
- $$invalidate(0, data = $$props2.data);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*data, $searchRegex*/
- 33) {
- $$invalidate(3, highlight = data.path.replace($searchRegex, "<mark>$&</mark>"));
- }
- };
- return [
- data,
- flashFilePath,
- flashDBPath,
- highlight,
- searchRegex,
- $searchRegex,
- click_handler,
- click_handler_1,
- click_handler_2,
- click_handler_3
- ];
- }
- class TreeViewEntry extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$k, create_fragment$k, safe_not_equal, { data: 0 });
- }
- }
- function create_fragment$j(ctx) {
- let div;
- return {
- c() {
- div = element("div");
- set_style(div, "margin-bottom", "0.3rem");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- },
- p: noop,
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- }
- };
- }
- function instance$j($$self, $$props, $$invalidate) {
- let { data } = $$props;
- $$self.$$set = ($$props2) => {
- if ("data" in $$props2)
- $$invalidate(0, data = $$props2.data);
- };
- return [data];
- }
- class TreeViewSeparator extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$j, create_fragment$j, safe_not_equal, { data: 0 });
- }
- }
- let lastFile = false;
- function getFileData(entryText) {
- let entry = SequencerDatabase.getEntry(entryText);
- if (Array.isArray(entry)) {
- if (entry.includes(lastFile) && entry.length > 1) {
- entry.splice(entry.indexOf(lastFile), 1);
- }
- entry = random_array_element(entry);
- lastFile = entry;
- }
- let previewFile = entry?.file ?? entry;
- if (entry instanceof SequencerFileBase) {
- previewFile = entry.clone().getPreviewFile(entryText);
- }
- let lowerCaseEntry = previewFile ? previewFile.toLowerCase() : "unknown.jpg";
- const isAudio = lowerCaseEntry.endsWith("ogg") || lowerCaseEntry.endsWith("mp3") || lowerCaseEntry.endsWith("wav");
- const isImage = !lowerCaseEntry.endsWith("webm") && !isAudio;
- const isVideo = !isAudio && !isImage;
- const icon = previewFile ? isVideo ? "fa-film" : isAudio ? "fa-volume-high" : "fa-image" : "fa-question-mark";
- const title = previewFile ? isVideo ? "Animated WebM" : isAudio ? "Audio" : "Image" : "Unknown";
- return {
- file: previewFile ?? "unknown.jpg",
- dbEntry: entry,
- icon,
- title,
- isAudio,
- isImage,
- isVideo
- };
- }
- function copyPath(dbPath, getFilepath, quotes = false) {
- const tempInput = document.createElement("input");
- tempInput.value = `${dbPath}`;
- let entry;
- if (getFilepath) {
- entry = Sequencer.Database.getEntry(dbPath);
- if (Array.isArray(entry)) {
- entry = random_array_element(entry);
- }
- if (entry instanceof SequencerFileBase) {
- const specificFt = dbPath.match(CONSTANTS.FEET_REGEX);
- if (specificFt) {
- const ft = specificFt[0].replaceAll(".", "");
- entry = entry.getFile(ft);
- } else {
- const files2 = entry.getAllFiles();
- if (Array.isArray(files2)) {
- const index = Math.floor(interpolate(0, files2.length - 1, 0.5));
- entry = files2[index];
- }
- }
- }
- tempInput.value = `${entry?.file ?? entry}`;
- }
- if (quotes) {
- tempInput.value = `"${tempInput.value}"`;
- }
- document.body.appendChild(tempInput);
- tempInput.select();
- document.execCommand("copy");
- document.body.removeChild(tempInput);
- document.execCommand("copy");
- }
- function playFile(entry) {
- const { file, isAudio, isImage, isVideo } = getFileData(entry);
- databaseStore.elements.audio.classList.toggle("hidden", !isAudio);
- databaseStore.elements.image.classList.toggle("hidden", !isImage);
- databaseStore.elements.player.classList.toggle("hidden", !isVideo);
- if (isImage) {
- databaseStore.elements.image.src = file;
- databaseStore.metadata.set({
- type: "Image",
- duration: "n/a"
- });
- return;
- }
- const element2 = isAudio ? databaseStore.elements.audio : databaseStore.elements.player;
- element2.onerror = () => {
- const error = `Sequencer Database Viewer | Could not play file: ${file}`;
- ui.notifications.error(error);
- console.error(error);
- };
- element2.oncanplay = () => {
- element2.play();
- };
- element2.onloadedmetadata = () => {
- databaseStore.metadata.set({
- type: isVideo ? "Video" : isAudio ? "Audio" : "Image",
- duration: isImage ? "n/a" : element2.duration * 1e3 + "ms"
- });
- };
- element2.src = file;
- }
- const treeStore = writable$1({});
- const visibleTreeStore = writable$1([]);
- let flattenedEntries = [];
- const entriesStore = SequencerDatabase.entriesStore;
- const packStore = writable$1(SequencerDatabase.publicModules);
- const selectedPackStore = writable$1("all");
- const searchStore = writable$1("");
- const cleanSearchStore = writable$1("");
- const searchRegexStore = writable$1(new RegExp("", "gu"));
- SequencerDatabase.entriesStore.subscribe(() => {
- packStore.set(SequencerDatabase.publicModules);
- });
- const databaseStore = {
- metadata: writable$1(false),
- allRanges: writable$1(false),
- subLists: writable$1(false),
- listView: writable$1(false),
- packStore,
- selectedPackStore,
- visibleTreeStore,
- search: searchStore,
- cleanSearchStore,
- searchRegex: searchRegexStore,
- elements: {},
- copyPath,
- playFile,
- openTreePath
- };
- entriesStore.subscribe(() => {
- filterFlattenedEntries();
- });
- databaseStore.allRanges.subscribe(() => {
- filterFlattenedEntries();
- });
- databaseStore.subLists.subscribe(() => {
- filterFlattenedEntries();
- });
- databaseStore.selectedPackStore.subscribe(() => {
- filterFlattenedEntries();
- });
- searchStore.subscribe((val) => {
- const cleanSearch = str_to_search_regex_str(val).replace(/\s+/g, "|");
- cleanSearchStore.set(cleanSearch);
- searchRegexStore.set(new RegExp(cleanSearch, "gu"));
- updateVisualTree();
- });
- function filterFlattenedEntries() {
- const selectedPack = get_store_value(selectedPackStore);
- const search = get_store_value(searchStore);
- const searchRegex = get_store_value(searchRegexStore);
- const subLists = get_store_value(databaseStore.subLists);
- const allRanges = get_store_value(databaseStore.allRanges);
- flattenedEntries = make_array_unique(
- SequencerDatabase.publicFlattenedEntries.filter((e) => {
- return (selectedPack === "all" || e.startsWith(selectedPack + ".")) && (!search || e.match(searchRegex));
- }).map((e) => !subLists ? e.split(CONSTANTS.ARRAY_REGEX)[0] : e).map((e) => !allRanges ? e.split(CONSTANTS.FEET_REGEX)[0] : e)
- );
- treeStore.set(
- flattenedEntries.reduce((acc, entry) => {
- let path = "";
- for (const part of entry.split(".")) {
- const fullPath = path ? path + "." + part : part;
- path = path ? path + ".children." + part : part;
- if (!getProperty(acc, path)) {
- setProperty(
- acc,
- path,
- foundry.utils.mergeObject(
- {
- path: part,
- fullPath,
- open: false,
- children: {}
- },
- getProperty(acc, path)
- )
- );
- }
- }
- return acc;
- }, {})
- );
- }
- function openTreePath(fullPath, open, openAll = false) {
- treeStore.update((tree) => {
- const fullTreePath = fullPath.split(".").join(".children.");
- const node = getProperty(tree, fullTreePath);
- setProperty(tree, fullTreePath + ".open", open);
- if ((!open || openAll) && !foundry.utils.isEmpty(node.children)) {
- recurseOpenTree(node.children, open);
- }
- return tree;
- });
- }
- function recurseOpenTree(children2, open) {
- for (const node of Object.values(children2)) {
- node.open = open;
- if (!foundry.utils.isEmpty(node.children)) {
- recurseOpenTree(node.children, open);
- }
- }
- }
- treeStore.subscribe(() => {
- updateVisualTree();
- });
- function updateVisualTree() {
- const tree = get_store_value(treeStore);
- const visibleTree = recurseTree(tree).deepFlatten().filter((e) => e.visible);
- visibleTreeStore.set(visibleTree);
- }
- function recurseTree(tree, path = "", depth = 0) {
- const search = get_store_value(searchStore);
- const searchRegex = get_store_value(searchRegexStore);
- const searchParts = get_store_value(cleanSearchStore).split("|");
- return Object.entries(tree).map(([key, data]) => {
- const fullPath = path ? path + "." + key : key;
- const children2 = recurseTree(
- data.children,
- fullPath,
- depth + 1
- ).deepFlatten();
- const matchParts = make_array_unique(fullPath.match(searchRegex) || []);
- const open = data.open || search && (matchParts.length >= searchParts.length || children2.filter((e) => e.visible).length);
- let visible = !search || matchParts.length >= searchParts.length;
- if (visible) {
- children2.forEach((e) => e.visible = true);
- } else {
- visible = children2.filter((e) => e.visible).length;
- }
- const entry = {
- class: TreeViewEntry,
- path: key,
- fullPath,
- open,
- visible,
- hasChildren: !foundry.utils.isEmpty(data.children),
- depth
- };
- const leaf = [entry];
- if ((data.open || entry.open) && entry.hasChildren) {
- leaf.push(...children2, {
- fullPath: randomID(),
- class: TreeViewSeparator
- });
- }
- return leaf;
- });
- }
- const DatabaseEntry_svelte_svelte_type_style_lang = "";
- function create_fragment$i(ctx) {
- let div2;
- let button0;
- let t0;
- let button1;
- let i1;
- let t1;
- let button2;
- let i2;
- let t2;
- let div1;
- let div0;
- let t3;
- let t4;
- let mounted;
- let dispose;
- return {
- c() {
- div2 = element("div");
- button0 = element("button");
- button0.innerHTML = `<i class="fas fa-play svelte-ese-flzvpb"></i>`;
- t0 = space();
- button1 = element("button");
- i1 = element("i");
- t1 = space();
- button2 = element("button");
- i2 = element("i");
- t2 = space();
- div1 = element("div");
- div0 = element("div");
- t3 = space();
- t4 = text$1(
- /*entry*/
- ctx[0]
- );
- attr(button0, "type", "button");
- attr(button0, "class", "btn_play svelte-ese-flzvpb");
- attr(i1, "class", "fas fa-file svelte-ese-flzvpb");
- toggle_class(
- i1,
- "flash-it",
- /*flashFilePath*/
- ctx[1]
- );
- attr(button1, "type", "button");
- attr(button1, "class", "btn_copy_filepath svelte-ese-flzvpb");
- attr(i2, "class", "fas fa-database svelte-ese-flzvpb");
- toggle_class(
- i2,
- "flash-it",
- /*flashDBPath*/
- ctx[2]
- );
- attr(button2, "type", "button");
- attr(button2, "class", "btn_copy_databasepath svelte-ese-flzvpb");
- attr(div0, "class", "database-entry-text-highlight svelte-ese-flzvpb");
- attr(div1, "class", "database-entry-text svelte-ese-flzvpb");
- attr(
- div1,
- "title",
- /*entry*/
- ctx[0]
- );
- attr(div2, "class", "database-entry svelte-ese-flzvpb");
- attr(
- div2,
- "data-id",
- /*entry*/
- ctx[0]
- );
- },
- m(target, anchor) {
- insert(target, div2, anchor);
- append(div2, button0);
- append(div2, t0);
- append(div2, button1);
- append(button1, i1);
- append(div2, t1);
- append(div2, button2);
- append(button2, i2);
- append(div2, t2);
- append(div2, div1);
- append(div1, div0);
- div0.innerHTML = /*highlight*/
- ctx[3];
- append(div1, t3);
- append(div1, t4);
- if (!mounted) {
- dispose = [
- listen(
- button0,
- "click",
- /*click_handler*/
- ctx[6]
- ),
- listen(
- button1,
- "click",
- /*click_handler_1*/
- ctx[7]
- ),
- listen(
- button2,
- "click",
- /*click_handler_2*/
- ctx[8]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*flashFilePath*/
- 2) {
- toggle_class(
- i1,
- "flash-it",
- /*flashFilePath*/
- ctx2[1]
- );
- }
- if (dirty & /*flashDBPath*/
- 4) {
- toggle_class(
- i2,
- "flash-it",
- /*flashDBPath*/
- ctx2[2]
- );
- }
- if (dirty & /*highlight*/
- 8)
- div0.innerHTML = /*highlight*/
- ctx2[3];
- if (dirty & /*entry*/
- 1)
- set_data(
- t4,
- /*entry*/
- ctx2[0]
- );
- if (dirty & /*entry*/
- 1) {
- attr(
- div1,
- "title",
- /*entry*/
- ctx2[0]
- );
- }
- if (dirty & /*entry*/
- 1) {
- attr(
- div2,
- "data-id",
- /*entry*/
- ctx2[0]
- );
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div2);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$i($$self, $$props, $$invalidate) {
- let highlight;
- let $searchRegex;
- createEventDispatcher();
- let { entry } = $$props;
- const searchRegex = databaseStore.searchRegex;
- component_subscribe($$self, searchRegex, (value) => $$invalidate(5, $searchRegex = value));
- let flashFilePath = false;
- let flashDBPath = false;
- const click_handler = () => {
- databaseStore.playFile(entry);
- };
- const click_handler_1 = (e) => {
- databaseStore.copyPath(entry, true, e.ctrlKey);
- $$invalidate(1, flashFilePath = true);
- setTimeout(
- () => {
- $$invalidate(1, flashFilePath = false);
- },
- 400
- );
- };
- const click_handler_2 = (e) => {
- databaseStore.copyPath(entry, false, e.ctrlKey);
- $$invalidate(2, flashDBPath = true);
- setTimeout(
- () => {
- $$invalidate(2, flashDBPath = false);
- },
- 400
- );
- };
- $$self.$$set = ($$props2) => {
- if ("entry" in $$props2)
- $$invalidate(0, entry = $$props2.entry);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*entry, $searchRegex*/
- 33) {
- $$invalidate(3, highlight = entry.replace($searchRegex, "<mark>$&</mark>"));
- }
- };
- return [
- entry,
- flashFilePath,
- flashDBPath,
- highlight,
- searchRegex,
- $searchRegex,
- click_handler,
- click_handler_1,
- click_handler_2
- ];
- }
- class DatabaseEntry extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$i, create_fragment$i, safe_not_equal, { entry: 0 });
- }
- }
- const DIRECTION_TYPE = {
- FRONT: "FRONT",
- // scroll up or left
- BEHIND: "BEHIND"
- // scroll down or right
- };
- const CALC_TYPE = {
- INIT: "INIT",
- FIXED: "FIXED",
- DYNAMIC: "DYNAMIC"
- };
- const LEADING_BUFFER = 2;
- class Virtual {
- param;
- callUpdate;
- firstRangeTotalSize = 0;
- firstRangeAverageSize = 0;
- lastCalcIndex = 0;
- fixedSizeValue = 0;
- calcType = CALC_TYPE.INIT;
- offset = 0;
- direction = "";
- range;
- constructor(param, callUpdate) {
- this.init(param, callUpdate);
- }
- init(param, callUpdate) {
- this.param = param;
- this.callUpdate = callUpdate;
- this.sizes = /* @__PURE__ */ new Map();
- this.firstRangeTotalSize = 0;
- this.firstRangeAverageSize = 0;
- this.lastCalcIndex = 0;
- this.fixedSizeValue = 0;
- this.calcType = CALC_TYPE.INIT;
- this.offset = 0;
- this.direction = "";
- this.range = /* @__PURE__ */ Object.create(null);
- if (param) {
- this.checkRange(0, param.keeps - 1);
- }
- }
- destroy() {
- this.init(null, null);
- }
- // return current render range
- getRange() {
- const range = /* @__PURE__ */ Object.create(null);
- range.start = this.range.start;
- range.end = this.range.end;
- range.padFront = this.range.padFront;
- range.padBehind = this.range.padBehind;
- return range;
- }
- isBehind() {
- return this.direction === DIRECTION_TYPE.BEHIND;
- }
- isFront() {
- return this.direction === DIRECTION_TYPE.FRONT;
- }
- // return start index offset
- getOffset(start) {
- return (start < 1 ? 0 : this.getIndexOffset(start)) + this.param.slotHeaderSize;
- }
- updateParam(key, value) {
- if (this.param && key in this.param) {
- if (key === "uniqueIds") {
- this.sizes.forEach((v, key2) => {
- if (!value.includes(key2)) {
- this.sizes.delete(key2);
- }
- });
- }
- this.param[key] = value;
- }
- }
- // save each size map by id
- saveSize(id, size) {
- this.sizes.set(id, size);
- if (this.calcType === CALC_TYPE.INIT) {
- this.fixedSizeValue = size;
- this.calcType = CALC_TYPE.FIXED;
- } else if (this.calcType === CALC_TYPE.FIXED && this.fixedSizeValue !== size) {
- this.calcType = CALC_TYPE.DYNAMIC;
- delete this.fixedSizeValue;
- }
- if (this.calcType !== CALC_TYPE.FIXED && typeof this.firstRangeTotalSize !== "undefined") {
- if (this.sizes.size < Math.min(this.param.keeps, this.param.uniqueIds.length)) {
- this.firstRangeTotalSize = [...this.sizes.values()].reduce((acc, val) => acc + val, 0);
- this.firstRangeAverageSize = Math.round(this.firstRangeTotalSize / this.sizes.size);
- } else {
- delete this.firstRangeTotalSize;
- }
- }
- }
- // in some special situation (e.g. length change) we need to update in a row
- // try going to render next range by a leading buffer according to current direction
- handleDataSourcesChange() {
- let start = this.range.start;
- if (this.isFront()) {
- start = start - LEADING_BUFFER;
- } else if (this.isBehind()) {
- start = start + LEADING_BUFFER;
- }
- start = Math.max(start, 0);
- this.updateRange(this.range.start, this.getEndByStart(start));
- }
- // when slot size change, we also need force update
- handleSlotSizeChange() {
- this.handleDataSourcesChange();
- }
- // calculating range on scroll
- handleScroll(offset2) {
- this.direction = offset2 < this.offset ? DIRECTION_TYPE.FRONT : DIRECTION_TYPE.BEHIND;
- this.offset = offset2;
- if (!this.param) {
- return;
- }
- if (this.direction === DIRECTION_TYPE.FRONT) {
- this.handleFront();
- } else if (this.direction === DIRECTION_TYPE.BEHIND) {
- this.handleBehind();
- }
- }
- // ----------- public method end -----------
- handleFront() {
- const overs = this.getScrollOvers();
- if (overs > this.range.start) {
- return;
- }
- const start = Math.max(overs - this.param.buffer, 0);
- this.checkRange(start, this.getEndByStart(start));
- }
- handleBehind() {
- const overs = this.getScrollOvers();
- if (overs < this.range.start + this.param.buffer) {
- return;
- }
- this.checkRange(overs, this.getEndByStart(overs));
- }
- // return the pass overs according to current scroll offset
- getScrollOvers() {
- const offset2 = this.offset - this.param.slotHeaderSize;
- if (offset2 <= 0) {
- return 0;
- }
- if (this.isFixedType()) {
- return Math.floor(offset2 / this.fixedSizeValue);
- }
- let low = 0;
- let middle = 0;
- let middleOffset = 0;
- let high = this.param.uniqueIds.length;
- while (low <= high) {
- middle = low + Math.floor((high - low) / 2);
- middleOffset = this.getIndexOffset(middle);
- if (middleOffset === offset2) {
- return middle;
- } else if (middleOffset < offset2) {
- low = middle + 1;
- } else if (middleOffset > offset2) {
- high = middle - 1;
- }
- }
- return low > 0 ? --low : 0;
- }
- // return a scroll offset from given index, can efficiency be improved more here?
- // although the call frequency is very high, its only a superposition of numbers
- getIndexOffset(givenIndex) {
- if (!givenIndex) {
- return 0;
- }
- let offset2 = 0;
- let indexSize = 0;
- for (let index = 0; index < givenIndex; index++) {
- indexSize = this.sizes.get(this.param.uniqueIds[index]);
- offset2 = offset2 + (typeof indexSize === "number" ? indexSize : this.getEstimateSize());
- }
- this.lastCalcIndex = Math.max(this.lastCalcIndex, givenIndex - 1);
- this.lastCalcIndex = Math.min(this.lastCalcIndex, this.getLastIndex());
- return offset2;
- }
- // is fixed size type
- isFixedType() {
- return this.calcType === CALC_TYPE.FIXED;
- }
- // return the real last index
- getLastIndex() {
- return this.param.uniqueIds.length - 1;
- }
- // in some conditions range is broke, we need correct it
- // and then decide whether need update to next range
- checkRange(start, end) {
- const keeps = this.param.keeps;
- const total = this.param.uniqueIds.length;
- if (total <= keeps) {
- start = 0;
- end = this.getLastIndex();
- } else if (end - start < keeps - 1) {
- start = end - keeps + 1;
- }
- if (this.range.start !== start) {
- this.updateRange(start, end);
- }
- }
- // setting to a new range and rerender
- updateRange(start, end) {
- this.range.start = start;
- this.range.end = end;
- this.range.padFront = this.getPadFront();
- this.range.padBehind = this.getPadBehind();
- this.callUpdate(this.getRange());
- }
- // return end base on start
- getEndByStart(start) {
- const theoryEnd = start + this.param.keeps - 1;
- const truelyEnd = Math.min(theoryEnd, this.getLastIndex());
- return truelyEnd;
- }
- // return total front offset
- getPadFront() {
- if (this.isFixedType()) {
- return this.fixedSizeValue * this.range.start;
- } else {
- return this.getIndexOffset(this.range.start);
- }
- }
- // return total behind offset
- getPadBehind() {
- const end = this.range.end;
- const lastIndex = this.getLastIndex();
- if (this.isFixedType()) {
- return (lastIndex - end) * this.fixedSizeValue;
- }
- if (this.lastCalcIndex === lastIndex) {
- return this.getIndexOffset(lastIndex) - this.getIndexOffset(end);
- } else {
- return (lastIndex - end) * this.getEstimateSize();
- }
- }
- // get the item estimate size
- getEstimateSize() {
- return this.isFixedType() ? this.fixedSizeValue : this.firstRangeAverageSize || this.param.estimateSize;
- }
- }
- function create_fragment$h(ctx) {
- let div;
- let current;
- const default_slot_template = (
- /*#slots*/
- ctx[5].default
- );
- const default_slot = create_slot(
- default_slot_template,
- ctx,
- /*$$scope*/
- ctx[4],
- null
- );
- return {
- c() {
- div = element("div");
- if (default_slot)
- default_slot.c();
- attr(div, "class", "virtual-scroll-item");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- if (default_slot) {
- default_slot.m(div, null);
- }
- ctx[6](div);
- current = true;
- },
- p(ctx2, [dirty]) {
- if (default_slot) {
- if (default_slot.p && (!current || dirty & /*$$scope*/
- 16)) {
- update_slot_base(
- default_slot,
- default_slot_template,
- ctx2,
- /*$$scope*/
- ctx2[4],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx2[4]
- ) : get_slot_changes(
- default_slot_template,
- /*$$scope*/
- ctx2[4],
- dirty,
- null
- ),
- null
- );
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(default_slot, local);
- current = true;
- },
- o(local) {
- transition_out(default_slot, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- if (default_slot)
- default_slot.d(detaching);
- ctx[6](null);
- }
- };
- }
- function instance$h($$self, $$props, $$invalidate) {
- let { $$slots: slots = {}, $$scope } = $$props;
- let { horizontal = false } = $$props;
- let { uniqueKey } = $$props;
- let { type = "item" } = $$props;
- let resizeObserver2;
- let itemDiv;
- let previousSize;
- const dispatch2 = createEventDispatcher();
- const shapeKey = horizontal ? "offsetWidth" : "offsetHeight";
- onMount(() => {
- if (typeof ResizeObserver !== "undefined") {
- resizeObserver2 = new ResizeObserver(dispatchSizeChange);
- resizeObserver2.observe(itemDiv);
- }
- });
- afterUpdate(dispatchSizeChange);
- onDestroy(() => {
- if (resizeObserver2) {
- resizeObserver2.disconnect();
- resizeObserver2 = null;
- }
- });
- function dispatchSizeChange() {
- const size = itemDiv ? itemDiv[shapeKey] : 0;
- if (size === previousSize)
- return;
- previousSize = size;
- dispatch2("resize", { id: uniqueKey, size, type });
- }
- function div_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- itemDiv = $$value;
- $$invalidate(0, itemDiv);
- });
- }
- $$self.$$set = ($$props2) => {
- if ("horizontal" in $$props2)
- $$invalidate(1, horizontal = $$props2.horizontal);
- if ("uniqueKey" in $$props2)
- $$invalidate(2, uniqueKey = $$props2.uniqueKey);
- if ("type" in $$props2)
- $$invalidate(3, type = $$props2.type);
- if ("$$scope" in $$props2)
- $$invalidate(4, $$scope = $$props2.$$scope);
- };
- return [itemDiv, horizontal, uniqueKey, type, $$scope, slots, div_binding];
- }
- class Item extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$h, create_fragment$h, safe_not_equal, { horizontal: 1, uniqueKey: 2, type: 3 });
- }
- }
- const get_footer_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
- 4 });
- const get_footer_slot_context = (ctx) => ({ data: (
- /*dataItem*/
- ctx[39]
- ) });
- function get_each_context$6(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[39] = list[i];
- return child_ctx;
- }
- const get_default_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
- 4 });
- const get_default_slot_context = (ctx) => ({ data: (
- /*dataItem*/
- ctx[39]
- ) });
- const get_header_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
- 4 });
- const get_header_slot_context = (ctx) => ({ data: (
- /*dataItem*/
- ctx[39]
- ) });
- function create_if_block_1$3(ctx) {
- let item;
- let current;
- item = new Item({
- props: {
- type: "slot",
- uniqueKey: "header",
- $$slots: { default: [create_default_slot_2$1] },
- $$scope: { ctx }
- }
- });
- item.$on(
- "resize",
- /*onItemResized*/
- ctx[6]
- );
- return {
- c() {
- create_component(item.$$.fragment);
- },
- m(target, anchor) {
- mount_component(item, target, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const item_changes = {};
- if (dirty[0] & /*$$scope, displayItems*/
- 536870916) {
- item_changes.$$scope = { dirty, ctx: ctx2 };
- }
- item.$set(item_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(item.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(item.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(item, detaching);
- }
- };
- }
- function create_default_slot_2$1(ctx) {
- let current;
- const header_slot_template = (
- /*#slots*/
- ctx[26].header
- );
- const header_slot = create_slot(
- header_slot_template,
- ctx,
- /*$$scope*/
- ctx[29],
- get_header_slot_context
- );
- return {
- c() {
- if (header_slot)
- header_slot.c();
- },
- m(target, anchor) {
- if (header_slot) {
- header_slot.m(target, anchor);
- }
- current = true;
- },
- p(ctx2, dirty) {
- if (header_slot) {
- if (header_slot.p && (!current || dirty[0] & /*$$scope, displayItems*/
- 536870916)) {
- update_slot_base(
- header_slot,
- header_slot_template,
- ctx2,
- /*$$scope*/
- ctx2[29],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx2[29]
- ) : get_slot_changes(
- header_slot_template,
- /*$$scope*/
- ctx2[29],
- dirty,
- get_header_slot_changes
- ),
- get_header_slot_context
- );
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(header_slot, local);
- current = true;
- },
- o(local) {
- transition_out(header_slot, local);
- current = false;
- },
- d(detaching) {
- if (header_slot)
- header_slot.d(detaching);
- }
- };
- }
- function create_default_slot_1$1(ctx) {
- let t;
- let current;
- const default_slot_template = (
- /*#slots*/
- ctx[26].default
- );
- const default_slot = create_slot(
- default_slot_template,
- ctx,
- /*$$scope*/
- ctx[29],
- get_default_slot_context
- );
- return {
- c() {
- if (default_slot)
- default_slot.c();
- t = space();
- },
- m(target, anchor) {
- if (default_slot) {
- default_slot.m(target, anchor);
- }
- insert(target, t, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- if (default_slot) {
- if (default_slot.p && (!current || dirty[0] & /*$$scope, displayItems*/
- 536870916)) {
- update_slot_base(
- default_slot,
- default_slot_template,
- ctx2,
- /*$$scope*/
- ctx2[29],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx2[29]
- ) : get_slot_changes(
- default_slot_template,
- /*$$scope*/
- ctx2[29],
- dirty,
- get_default_slot_changes
- ),
- get_default_slot_context
- );
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(default_slot, local);
- current = true;
- },
- o(local) {
- transition_out(default_slot, local);
- current = false;
- },
- d(detaching) {
- if (default_slot)
- default_slot.d(detaching);
- if (detaching)
- detach(t);
- }
- };
- }
- function create_each_block$6(key_2, ctx) {
- let first;
- let item;
- let current;
- item = new Item({
- props: {
- uniqueKey: (
- /*dataItem*/
- ctx[39][
- /*key*/
- ctx[0]
- ]
- ),
- horizontal: (
- /*isHorizontal*/
- ctx[1]
- ),
- type: "item",
- $$slots: { default: [create_default_slot_1$1] },
- $$scope: { ctx }
- }
- });
- item.$on(
- "resize",
- /*onItemResized*/
- ctx[6]
- );
- return {
- key: key_2,
- first: null,
- c() {
- first = empty();
- create_component(item.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(item, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const item_changes = {};
- if (dirty[0] & /*displayItems, key*/
- 5)
- item_changes.uniqueKey = /*dataItem*/
- ctx[39][
- /*key*/
- ctx[0]
- ];
- if (dirty[0] & /*isHorizontal*/
- 2)
- item_changes.horizontal = /*isHorizontal*/
- ctx[1];
- if (dirty[0] & /*$$scope, displayItems*/
- 536870916) {
- item_changes.$$scope = { dirty, ctx };
- }
- item.$set(item_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(item.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(item.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(first);
- destroy_component(item, detaching);
- }
- };
- }
- function create_if_block$6(ctx) {
- let item;
- let current;
- item = new Item({
- props: {
- type: "slot",
- uniqueKey: "footer",
- $$slots: { default: [create_default_slot$2] },
- $$scope: { ctx }
- }
- });
- item.$on(
- "resize",
- /*onItemResized*/
- ctx[6]
- );
- return {
- c() {
- create_component(item.$$.fragment);
- },
- m(target, anchor) {
- mount_component(item, target, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const item_changes = {};
- if (dirty[0] & /*$$scope, displayItems*/
- 536870916) {
- item_changes.$$scope = { dirty, ctx: ctx2 };
- }
- item.$set(item_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(item.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(item.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(item, detaching);
- }
- };
- }
- function create_default_slot$2(ctx) {
- let current;
- const footer_slot_template = (
- /*#slots*/
- ctx[26].footer
- );
- const footer_slot = create_slot(
- footer_slot_template,
- ctx,
- /*$$scope*/
- ctx[29],
- get_footer_slot_context
- );
- return {
- c() {
- if (footer_slot)
- footer_slot.c();
- },
- m(target, anchor) {
- if (footer_slot) {
- footer_slot.m(target, anchor);
- }
- current = true;
- },
- p(ctx2, dirty) {
- if (footer_slot) {
- if (footer_slot.p && (!current || dirty[0] & /*$$scope, displayItems*/
- 536870916)) {
- update_slot_base(
- footer_slot,
- footer_slot_template,
- ctx2,
- /*$$scope*/
- ctx2[29],
- !current ? get_all_dirty_from_scope(
- /*$$scope*/
- ctx2[29]
- ) : get_slot_changes(
- footer_slot_template,
- /*$$scope*/
- ctx2[29],
- dirty,
- get_footer_slot_changes
- ),
- get_footer_slot_context
- );
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(footer_slot, local);
- current = true;
- },
- o(local) {
- transition_out(footer_slot, local);
- current = false;
- },
- d(detaching) {
- if (footer_slot)
- footer_slot.d(detaching);
- }
- };
- }
- function create_fragment$g(ctx) {
- let div2;
- let t0;
- let div0;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let t1;
- let t2;
- let div1;
- let current;
- let mounted;
- let dispose;
- let if_block0 = (
- /*$$slots*/
- ctx[8].header && create_if_block_1$3(ctx)
- );
- let each_value = (
- /*displayItems*/
- ctx[2]
- );
- const get_key = (ctx2) => (
- /*dataItem*/
- ctx2[39][
- /*key*/
- ctx2[0]
- ]
- );
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context$6(ctx, each_value, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block$6(key, child_ctx));
- }
- let if_block1 = (
- /*$$slots*/
- ctx[8].footer && create_if_block$6(ctx)
- );
- return {
- c() {
- div2 = element("div");
- if (if_block0)
- if_block0.c();
- t0 = space();
- div0 = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- t1 = space();
- if (if_block1)
- if_block1.c();
- t2 = space();
- div1 = element("div");
- set_style(
- div0,
- "padding",
- /*paddingStyle*/
- ctx[3]
- );
- attr(div1, "class", "shepherd");
- set_style(
- div1,
- "width",
- /*isHorizontal*/
- ctx[1] ? "0px" : "100%"
- );
- set_style(
- div1,
- "height",
- /*isHorizontal*/
- ctx[1] ? "100%" : "0px"
- );
- set_style(div2, "overflow-y", "auto");
- set_style(div2, "height", "inherit");
- },
- m(target, anchor) {
- insert(target, div2, anchor);
- if (if_block0)
- if_block0.m(div2, null);
- append(div2, t0);
- append(div2, div0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div0, null);
- }
- append(div2, t1);
- if (if_block1)
- if_block1.m(div2, null);
- append(div2, t2);
- append(div2, div1);
- ctx[27](div1);
- ctx[28](div2);
- current = true;
- if (!mounted) {
- dispose = listen(
- div2,
- "scroll",
- /*onScroll*/
- ctx[7]
- );
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (
- /*$$slots*/
- ctx2[8].header
- ) {
- if (if_block0) {
- if_block0.p(ctx2, dirty);
- if (dirty[0] & /*$$slots*/
- 256) {
- transition_in(if_block0, 1);
- }
- } else {
- if_block0 = create_if_block_1$3(ctx2);
- if_block0.c();
- transition_in(if_block0, 1);
- if_block0.m(div2, t0);
- }
- } else if (if_block0) {
- group_outros();
- transition_out(if_block0, 1, 1, () => {
- if_block0 = null;
- });
- check_outros();
- }
- if (dirty[0] & /*displayItems, key, isHorizontal, onItemResized, $$scope*/
- 536870983) {
- each_value = /*displayItems*/
- ctx2[2];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div0, outro_and_destroy_block, create_each_block$6, null, get_each_context$6);
- check_outros();
- }
- if (!current || dirty[0] & /*paddingStyle*/
- 8) {
- set_style(
- div0,
- "padding",
- /*paddingStyle*/
- ctx2[3]
- );
- }
- if (
- /*$$slots*/
- ctx2[8].footer
- ) {
- if (if_block1) {
- if_block1.p(ctx2, dirty);
- if (dirty[0] & /*$$slots*/
- 256) {
- transition_in(if_block1, 1);
- }
- } else {
- if_block1 = create_if_block$6(ctx2);
- if_block1.c();
- transition_in(if_block1, 1);
- if_block1.m(div2, t2);
- }
- } else if (if_block1) {
- group_outros();
- transition_out(if_block1, 1, 1, () => {
- if_block1 = null;
- });
- check_outros();
- }
- if (!current || dirty[0] & /*isHorizontal*/
- 2) {
- set_style(
- div1,
- "width",
- /*isHorizontal*/
- ctx2[1] ? "0px" : "100%"
- );
- }
- if (!current || dirty[0] & /*isHorizontal*/
- 2) {
- set_style(
- div1,
- "height",
- /*isHorizontal*/
- ctx2[1] ? "100%" : "0px"
- );
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block0);
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- transition_in(if_block1);
- current = true;
- },
- o(local) {
- transition_out(if_block0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- transition_out(if_block1);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div2);
- if (if_block0)
- if_block0.d();
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- if (if_block1)
- if_block1.d();
- ctx[27](null);
- ctx[28](null);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$g($$self, $$props, $$invalidate) {
- let { $$slots: slots = {}, $$scope } = $$props;
- const $$slots = compute_slots(slots);
- let { key = "id" } = $$props;
- let { data } = $$props;
- let { keeps = 30 } = $$props;
- let { estimateSize = 50 } = $$props;
- let { isHorizontal = false } = $$props;
- let { start = 0 } = $$props;
- let { offset: offset2 = 0 } = $$props;
- let { pageMode = false } = $$props;
- let { topThreshold = 0 } = $$props;
- let { bottomThreshold = 0 } = $$props;
- let displayItems = [];
- let paddingStyle;
- let directionKey = isHorizontal ? "scrollLeft" : "scrollTop";
- let range = null;
- let virtual = new Virtual(
- {
- slotHeaderSize: 0,
- slotFooterSize: 0,
- keeps,
- estimateSize,
- buffer: Math.round(keeps / 3),
- // recommend for a third of keeps
- uniqueIds: getUniqueIdFromDataSources()
- },
- onRangeChanged
- );
- let root;
- let shepherd;
- const dispatch2 = createEventDispatcher();
- function getSize(id) {
- return virtual.sizes.get(id);
- }
- function getSizes() {
- return virtual.sizes.size;
- }
- function getOffset() {
- if (pageMode) {
- return document.documentElement[directionKey] || document.body[directionKey];
- } else {
- return root ? Math.ceil(root[directionKey]) : 0;
- }
- }
- function getClientSize() {
- const key2 = isHorizontal ? "clientWidth" : "clientHeight";
- if (pageMode) {
- return document.documentElement[key2] || document.body[key2];
- } else {
- return root ? Math.ceil(root[key2]) : 0;
- }
- }
- function getScrollSize() {
- const key2 = isHorizontal ? "scrollWidth" : "scrollHeight";
- if (pageMode) {
- return document.documentElement[key2] || document.body[key2];
- } else {
- return root ? Math.ceil(root[key2]) : 0;
- }
- }
- function updatePageModeFront() {
- if (root) {
- const rect = root.getBoundingClientRect();
- const { defaultView } = root.ownerDocument;
- const offsetFront = isHorizontal ? rect.left + defaultView.pageXOffset : rect.top + defaultView.pageYOffset;
- virtual.updateParam("slotHeaderSize", offsetFront);
- }
- }
- function scrollToOffset(offset3) {
- if (pageMode) {
- document.body[directionKey] = offset3;
- document.documentElement[directionKey] = offset3;
- } else if (root) {
- $$invalidate(4, root[directionKey] = offset3, root);
- }
- }
- function scrollToIndex(index) {
- if (index >= data.length - 1) {
- scrollToBottom();
- } else {
- const offset3 = virtual.getOffset(index);
- scrollToOffset(offset3);
- }
- }
- function scrollToBottom() {
- if (shepherd) {
- const offset3 = shepherd[isHorizontal ? "offsetLeft" : "offsetTop"];
- scrollToOffset(offset3);
- setTimeout(
- () => {
- if (getOffset() + getClientSize() + 1 < getScrollSize()) {
- scrollToBottom();
- }
- },
- 3
- );
- }
- }
- onMount(() => {
- if (start) {
- scrollToIndex(start);
- } else if (offset2) {
- scrollToOffset(offset2);
- }
- if (pageMode) {
- updatePageModeFront();
- document.addEventListener("scroll", onScroll, { passive: false });
- }
- });
- onDestroy(() => {
- virtual.destroy();
- if (pageMode) {
- document.removeEventListener("scroll", onScroll);
- }
- });
- function getUniqueIdFromDataSources() {
- return data.map((dataSource) => dataSource[key]);
- }
- function onItemResized(event) {
- const { id, size, type } = event.detail;
- if (type === "item")
- virtual.saveSize(id, size);
- else if (type === "slot") {
- if (id === "header")
- virtual.updateParam("slotHeaderSize", size);
- else if (id === "footer")
- virtual.updateParam("slotFooterSize", size);
- }
- }
- function onRangeChanged(range_) {
- range = range_;
- $$invalidate(3, paddingStyle = $$invalidate(3, paddingStyle = isHorizontal ? `0px ${range.padBehind}px 0px ${range.padFront}px` : `${range.padFront}px 0px ${range.padBehind}px`));
- $$invalidate(2, displayItems = data.slice(range.start, range.end + 1));
- }
- function onScroll(event) {
- const offset3 = getOffset();
- const clientSize = getClientSize();
- const scrollSize = getScrollSize();
- if (offset3 < 0 || offset3 + clientSize > scrollSize || !scrollSize) {
- return;
- }
- virtual.handleScroll(offset3);
- emitEvent(offset3, clientSize, scrollSize, event);
- }
- function emitEvent(offset3, clientSize, scrollSize, event) {
- dispatch2("scroll", { event, range: virtual.getRange() });
- if (virtual.isFront() && !!data.length && offset3 - topThreshold <= 0) {
- dispatch2("top");
- } else if (virtual.isBehind() && offset3 + clientSize + bottomThreshold >= scrollSize) {
- dispatch2("bottom");
- }
- }
- function handleKeepsChange(keeps2) {
- virtual.updateParam("keeps", keeps2);
- virtual.handleSlotSizeChange();
- }
- async function handleDataSourcesChange(data2) {
- virtual.updateParam("uniqueIds", getUniqueIdFromDataSources());
- virtual.handleDataSourcesChange();
- }
- function div1_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- shepherd = $$value;
- $$invalidate(5, shepherd);
- });
- }
- function div2_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- root = $$value;
- $$invalidate(4, root);
- });
- }
- $$self.$$set = ($$props2) => {
- if ("key" in $$props2)
- $$invalidate(0, key = $$props2.key);
- if ("data" in $$props2)
- $$invalidate(9, data = $$props2.data);
- if ("keeps" in $$props2)
- $$invalidate(10, keeps = $$props2.keeps);
- if ("estimateSize" in $$props2)
- $$invalidate(11, estimateSize = $$props2.estimateSize);
- if ("isHorizontal" in $$props2)
- $$invalidate(1, isHorizontal = $$props2.isHorizontal);
- if ("start" in $$props2)
- $$invalidate(12, start = $$props2.start);
- if ("offset" in $$props2)
- $$invalidate(13, offset2 = $$props2.offset);
- if ("pageMode" in $$props2)
- $$invalidate(14, pageMode = $$props2.pageMode);
- if ("topThreshold" in $$props2)
- $$invalidate(15, topThreshold = $$props2.topThreshold);
- if ("bottomThreshold" in $$props2)
- $$invalidate(16, bottomThreshold = $$props2.bottomThreshold);
- if ("$$scope" in $$props2)
- $$invalidate(29, $$scope = $$props2.$$scope);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty[0] & /*offset*/
- 8192) {
- scrollToOffset(offset2);
- }
- if ($$self.$$.dirty[0] & /*start*/
- 4096) {
- scrollToIndex(start);
- }
- if ($$self.$$.dirty[0] & /*keeps*/
- 1024) {
- handleKeepsChange(keeps);
- }
- if ($$self.$$.dirty[0] & /*data*/
- 512) {
- handleDataSourcesChange();
- }
- };
- return [
- key,
- isHorizontal,
- displayItems,
- paddingStyle,
- root,
- shepherd,
- onItemResized,
- onScroll,
- $$slots,
- data,
- keeps,
- estimateSize,
- start,
- offset2,
- pageMode,
- topThreshold,
- bottomThreshold,
- getSize,
- getSizes,
- getOffset,
- getClientSize,
- getScrollSize,
- updatePageModeFront,
- scrollToOffset,
- scrollToIndex,
- scrollToBottom,
- slots,
- div1_binding,
- div2_binding,
- $$scope
- ];
- }
- class VirtualScroll extends SvelteComponent {
- constructor(options) {
- super();
- init(
- this,
- options,
- instance$g,
- create_fragment$g,
- safe_not_equal,
- {
- key: 0,
- data: 9,
- keeps: 10,
- estimateSize: 11,
- isHorizontal: 1,
- start: 12,
- offset: 13,
- pageMode: 14,
- topThreshold: 15,
- bottomThreshold: 16,
- getSize: 17,
- getSizes: 18,
- getOffset: 19,
- getClientSize: 20,
- getScrollSize: 21,
- updatePageModeFront: 22,
- scrollToOffset: 23,
- scrollToIndex: 24,
- scrollToBottom: 25
- },
- null,
- [-1, -1]
- );
- }
- get getSize() {
- return this.$$.ctx[17];
- }
- get getSizes() {
- return this.$$.ctx[18];
- }
- get getOffset() {
- return this.$$.ctx[19];
- }
- get getClientSize() {
- return this.$$.ctx[20];
- }
- get getScrollSize() {
- return this.$$.ctx[21];
- }
- get updatePageModeFront() {
- return this.$$.ctx[22];
- }
- get scrollToOffset() {
- return this.$$.ctx[23];
- }
- get scrollToIndex() {
- return this.$$.ctx[24];
- }
- get scrollToBottom() {
- return this.$$.ctx[25];
- }
- }
- const databaseShell_svelte_svelte_type_style_lang = "";
- function get_each_context$5(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[41] = list[i];
- child_ctx[43] = i;
- return child_ctx;
- }
- function create_each_block$5(ctx) {
- let option;
- let t_value = (
- /*pack*/
- ctx[41] + ""
- );
- let t;
- let option_value_value;
- return {
- c() {
- option = element("option");
- t = text$1(t_value);
- option.__value = option_value_value = /*pack*/
- ctx[41];
- option.value = option.__value;
- },
- m(target, anchor) {
- insert(target, option, anchor);
- append(option, t);
- },
- p(ctx2, dirty) {
- if (dirty[0] & /*$packStore*/
- 128 && t_value !== (t_value = /*pack*/
- ctx2[41] + ""))
- set_data(t, t_value);
- if (dirty[0] & /*$packStore*/
- 128 && option_value_value !== (option_value_value = /*pack*/
- ctx2[41])) {
- option.__value = option_value_value;
- option.value = option.__value;
- }
- },
- d(detaching) {
- if (detaching)
- detach(option);
- }
- };
- }
- function create_else_block_1(ctx) {
- let div;
- let virtualscroll;
- let current;
- virtualscroll = new VirtualScroll({
- props: {
- data: (
- /*$visibleTreeStore*/
- ctx[9]
- ),
- key: "fullPath",
- $$slots: {
- default: [
- create_default_slot_2,
- ({ data }) => ({ 40: data }),
- ({ data }) => [0, data ? 512 : 0]
- ]
- },
- $$scope: { ctx }
- }
- });
- return {
- c() {
- div = element("div");
- create_component(virtualscroll.$$.fragment);
- attr(div, "class", "sequencer-database-entries-tree svelte-ese-gdt8h0");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- mount_component(virtualscroll, div, null);
- current = true;
- },
- p(ctx2, dirty) {
- const virtualscroll_changes = {};
- if (dirty[0] & /*$visibleTreeStore*/
- 512)
- virtualscroll_changes.data = /*$visibleTreeStore*/
- ctx2[9];
- if (dirty[1] & /*$$scope, data*/
- 8704) {
- virtualscroll_changes.$$scope = { dirty, ctx: ctx2 };
- }
- virtualscroll.$set(virtualscroll_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(virtualscroll.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(virtualscroll.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(virtualscroll);
- }
- };
- }
- function create_if_block_1$2(ctx) {
- let div;
- let virtualscroll;
- let current;
- virtualscroll = new VirtualScroll({
- props: {
- data: (
- /*filteredEntries*/
- ctx[6]
- ),
- key: "entry",
- $$slots: {
- default: [
- create_default_slot_1,
- ({ data }) => ({ 40: data }),
- ({ data }) => [0, data ? 512 : 0]
- ]
- },
- $$scope: { ctx }
- }
- });
- return {
- c() {
- div = element("div");
- create_component(virtualscroll.$$.fragment);
- attr(div, "class", "sequencer-database-entries svelte-ese-gdt8h0");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- mount_component(virtualscroll, div, null);
- current = true;
- },
- p(ctx2, dirty) {
- const virtualscroll_changes = {};
- if (dirty[0] & /*filteredEntries*/
- 64)
- virtualscroll_changes.data = /*filteredEntries*/
- ctx2[6];
- if (dirty[1] & /*$$scope, data*/
- 8704) {
- virtualscroll_changes.$$scope = { dirty, ctx: ctx2 };
- }
- virtualscroll.$set(virtualscroll_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(virtualscroll.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(virtualscroll.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(virtualscroll);
- }
- };
- }
- function create_default_slot_2(ctx) {
- let switch_instance;
- let switch_instance_anchor;
- let current;
- var switch_value = (
- /*data*/
- ctx[40].class
- );
- function switch_props(ctx2) {
- return { props: { data: (
- /*data*/
- ctx2[40]
- ) } };
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props(ctx));
- }
- return {
- c() {
- if (switch_instance)
- create_component(switch_instance.$$.fragment);
- switch_instance_anchor = empty();
- },
- m(target, anchor) {
- if (switch_instance)
- mount_component(switch_instance, target, anchor);
- insert(target, switch_instance_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const switch_instance_changes = {};
- if (dirty[1] & /*data*/
- 512)
- switch_instance_changes.data = /*data*/
- ctx2[40];
- if (switch_value !== (switch_value = /*data*/
- ctx2[40].class)) {
- if (switch_instance) {
- group_outros();
- const old_component = switch_instance;
- transition_out(old_component.$$.fragment, 1, 0, () => {
- destroy_component(old_component, 1);
- });
- check_outros();
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props(ctx2));
- create_component(switch_instance.$$.fragment);
- transition_in(switch_instance.$$.fragment, 1);
- mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
- } else {
- switch_instance = null;
- }
- } else if (switch_value) {
- switch_instance.$set(switch_instance_changes);
- }
- },
- i(local) {
- if (current)
- return;
- if (switch_instance)
- transition_in(switch_instance.$$.fragment, local);
- current = true;
- },
- o(local) {
- if (switch_instance)
- transition_out(switch_instance.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(switch_instance_anchor);
- if (switch_instance)
- destroy_component(switch_instance, detaching);
- }
- };
- }
- function create_default_slot_1(ctx) {
- let databaseentry;
- let current;
- databaseentry = new DatabaseEntry({ props: { entry: (
- /*data*/
- ctx[40].entry
- ) } });
- return {
- c() {
- create_component(databaseentry.$$.fragment);
- },
- m(target, anchor) {
- mount_component(databaseentry, target, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const databaseentry_changes = {};
- if (dirty[1] & /*data*/
- 512)
- databaseentry_changes.entry = /*data*/
- ctx2[40].entry;
- databaseentry.$set(databaseentry_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(databaseentry.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(databaseentry.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(databaseentry, detaching);
- }
- };
- }
- function create_else_block$1(ctx) {
- let t;
- return {
- c() {
- t = text$1("No file loaded...");
- },
- m(target, anchor) {
- insert(target, t, anchor);
- },
- p: noop,
- d(detaching) {
- if (detaching)
- detach(t);
- }
- };
- }
- function create_if_block$5(ctx) {
- let t0;
- let t1_value = (
- /*$metadata*/
- ctx[10].type + ""
- );
- let t1;
- let t2;
- let t3_value = (
- /*$metadata*/
- ctx[10].duration + ""
- );
- let t3;
- return {
- c() {
- t0 = text$1("Type: ");
- t1 = text$1(t1_value);
- t2 = text$1(" | Duration: ");
- t3 = text$1(t3_value);
- },
- m(target, anchor) {
- insert(target, t0, anchor);
- insert(target, t1, anchor);
- insert(target, t2, anchor);
- insert(target, t3, anchor);
- },
- p(ctx2, dirty) {
- if (dirty[0] & /*$metadata*/
- 1024 && t1_value !== (t1_value = /*$metadata*/
- ctx2[10].type + ""))
- set_data(t1, t1_value);
- if (dirty[0] & /*$metadata*/
- 1024 && t3_value !== (t3_value = /*$metadata*/
- ctx2[10].duration + ""))
- set_data(t3, t3_value);
- },
- d(detaching) {
- if (detaching)
- detach(t0);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(t2);
- if (detaching)
- detach(t3);
- }
- };
- }
- function create_default_slot$1(ctx) {
- let div4;
- let div0;
- let select;
- let option;
- let t1;
- let input0;
- let t2;
- let input1;
- let t3;
- let label0;
- let t5;
- let input2;
- let t6;
- let label1;
- let t8;
- let input3;
- let t9;
- let label2;
- let t11;
- let div3;
- let current_block_type_index;
- let if_block0;
- let t12;
- let div2;
- let video;
- let t13;
- let img;
- let t14;
- let audio2;
- let t15;
- let div1;
- let current;
- let mounted;
- let dispose;
- let each_value = (
- /*$packStore*/
- ctx[7]
- );
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$5(get_each_context$5(ctx, each_value, i));
- }
- const if_block_creators = [create_if_block_1$2, create_else_block_1];
- const if_blocks = [];
- function select_block_type(ctx2, dirty) {
- if (
- /*$listView*/
- ctx2[4]
- )
- return 0;
- return 1;
- }
- current_block_type_index = select_block_type(ctx);
- if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
- function select_block_type_1(ctx2, dirty) {
- if (
- /*$metadata*/
- ctx2[10]
- )
- return create_if_block$5;
- return create_else_block$1;
- }
- let current_block_type = select_block_type_1(ctx);
- let if_block1 = current_block_type(ctx);
- return {
- c() {
- div4 = element("div");
- div0 = element("div");
- select = element("select");
- option = element("option");
- option.textContent = `${localize("SEQUENCER.Database.AllPacks")}`;
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- t1 = space();
- input0 = element("input");
- t2 = space();
- input1 = element("input");
- t3 = space();
- label0 = element("label");
- label0.textContent = `${localize("SEQUENCER.Database.ShowAllRanges")}`;
- t5 = space();
- input2 = element("input");
- t6 = space();
- label1 = element("label");
- label1.textContent = `${localize("SEQUENCER.Database.ShowSubLists")}`;
- t8 = space();
- input3 = element("input");
- t9 = space();
- label2 = element("label");
- label2.textContent = `${localize("SEQUENCER.Database.ListView")}`;
- t11 = space();
- div3 = element("div");
- if_block0.c();
- t12 = space();
- div2 = element("div");
- video = element("video");
- t13 = space();
- img = element("img");
- t14 = space();
- audio2 = element("audio");
- audio2.innerHTML = `<source type="audio/ogg"/>`;
- t15 = space();
- div1 = element("div");
- if_block1.c();
- option.__value = "all";
- option.value = option.__value;
- attr(select, "name", "pack-select");
- attr(select, "class", "svelte-ese-gdt8h0");
- if (
- /*$selectedPackStore*/
- ctx[2] === void 0
- )
- add_render_callback(() => (
- /*select_change_handler*/
- ctx[26].call(select)
- ));
- attr(input0, "class", "ml-2 svelte-ese-gdt8h0");
- attr(input0, "placeholder", localize("SEQUENCER.Database.Search"));
- attr(input0, "type", "text");
- attr(input1, "class", "ml-2");
- attr(input1, "id", "database-all-ranges");
- attr(input1, "type", "checkbox");
- attr(label0, "class", "all-ranges-label svelte-ese-gdt8h0");
- attr(label0, "for", "database-all-ranges");
- attr(input2, "class", "ml-2");
- attr(input2, "id", "include-sub-lists");
- attr(input2, "type", "checkbox");
- attr(label1, "class", "all-ranges-label svelte-ese-gdt8h0");
- attr(label1, "for", "include-sub-lists");
- attr(input3, "class", "ml-2");
- attr(input3, "id", "treeview");
- attr(input3, "type", "checkbox");
- attr(label2, "class", "all-ranges-label svelte-ese-gdt8h0");
- attr(label2, "for", "treeview");
- attr(div0, "class", "sequencer-database-header svelte-ese-gdt8h0");
- video.autoplay = true;
- attr(video, "class", "database-player svelte-ese-gdt8h0");
- attr(video, "height", "335");
- video.loop = true;
- attr(video, "preload", "");
- attr(video, "width", "335");
- attr(img, "class", "database-image hidden svelte-ese-gdt8h0");
- attr(audio2, "class", "database-audio hidden svelte-ese-gdt8h0");
- attr(div1, "class", "sequencer-database-metadata-container svelte-ese-gdt8h0");
- attr(div2, "class", "sequencer-database-player-container svelte-ese-gdt8h0");
- attr(div3, "class", "sequencer-database-entries-container svelte-ese-gdt8h0");
- attr(div4, "class", "sequencer-database-content svelte-ese-gdt8h0");
- },
- m(target, anchor) {
- insert(target, div4, anchor);
- append(div4, div0);
- append(div0, select);
- append(select, option);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(select, null);
- }
- select_option(
- select,
- /*$selectedPackStore*/
- ctx[2]
- );
- append(div0, t1);
- append(div0, input0);
- set_input_value(
- input0,
- /*$search*/
- ctx[1]
- );
- append(div0, t2);
- append(div0, input1);
- input1.checked = /*$allRanges*/
- ctx[3];
- append(div0, t3);
- append(div0, label0);
- append(div0, t5);
- append(div0, input2);
- input2.checked = /*$subLists*/
- ctx[8];
- append(div0, t6);
- append(div0, label1);
- append(div0, t8);
- append(div0, input3);
- input3.checked = /*$listView*/
- ctx[4];
- append(div0, t9);
- append(div0, label2);
- append(div4, t11);
- append(div4, div3);
- if_blocks[current_block_type_index].m(div3, null);
- append(div3, t12);
- append(div3, div2);
- append(div2, video);
- ctx[31](video);
- append(div2, t13);
- append(div2, img);
- ctx[34](img);
- append(div2, t14);
- append(div2, audio2);
- ctx[35](audio2);
- append(div2, t15);
- append(div2, div1);
- if_block1.m(div1, null);
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- select,
- "change",
- /*select_change_handler*/
- ctx[26]
- ),
- listen(
- input0,
- "input",
- /*input0_input_handler*/
- ctx[27]
- ),
- listen(
- input1,
- "change",
- /*input1_change_handler*/
- ctx[28]
- ),
- listen(
- input2,
- "change",
- /*input2_change_handler*/
- ctx[29]
- ),
- listen(
- input3,
- "change",
- /*input3_change_handler*/
- ctx[30]
- ),
- listen(
- video,
- "mouseenter",
- /*mouseenter_handler*/
- ctx[32]
- ),
- listen(
- video,
- "mouseleave",
- /*mouseleave_handler*/
- ctx[33]
- ),
- listen(
- audio2,
- "mouseenter",
- /*mouseenter_handler_1*/
- ctx[36]
- ),
- listen(
- audio2,
- "mouseleave",
- /*mouseleave_handler_1*/
- ctx[37]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (dirty[0] & /*$packStore*/
- 128) {
- each_value = /*$packStore*/
- ctx2[7];
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$5(ctx2, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- } else {
- each_blocks[i] = create_each_block$5(child_ctx);
- each_blocks[i].c();
- each_blocks[i].m(select, null);
- }
- }
- for (; i < each_blocks.length; i += 1) {
- each_blocks[i].d(1);
- }
- each_blocks.length = each_value.length;
- }
- if (dirty[0] & /*$selectedPackStore, $packStore*/
- 132) {
- select_option(
- select,
- /*$selectedPackStore*/
- ctx2[2]
- );
- }
- if (dirty[0] & /*$search*/
- 2 && input0.value !== /*$search*/
- ctx2[1]) {
- set_input_value(
- input0,
- /*$search*/
- ctx2[1]
- );
- }
- if (dirty[0] & /*$allRanges*/
- 8) {
- input1.checked = /*$allRanges*/
- ctx2[3];
- }
- if (dirty[0] & /*$subLists*/
- 256) {
- input2.checked = /*$subLists*/
- ctx2[8];
- }
- if (dirty[0] & /*$listView*/
- 16) {
- input3.checked = /*$listView*/
- ctx2[4];
- }
- let previous_block_index = current_block_type_index;
- current_block_type_index = select_block_type(ctx2);
- if (current_block_type_index === previous_block_index) {
- if_blocks[current_block_type_index].p(ctx2, dirty);
- } else {
- group_outros();
- transition_out(if_blocks[previous_block_index], 1, 1, () => {
- if_blocks[previous_block_index] = null;
- });
- check_outros();
- if_block0 = if_blocks[current_block_type_index];
- if (!if_block0) {
- if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
- if_block0.c();
- } else {
- if_block0.p(ctx2, dirty);
- }
- transition_in(if_block0, 1);
- if_block0.m(div3, t12);
- }
- if (current_block_type === (current_block_type = select_block_type_1(ctx2)) && if_block1) {
- if_block1.p(ctx2, dirty);
- } else {
- if_block1.d(1);
- if_block1 = current_block_type(ctx2);
- if (if_block1) {
- if_block1.c();
- if_block1.m(div1, null);
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block0);
- current = true;
- },
- o(local) {
- transition_out(if_block0);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div4);
- destroy_each(each_blocks, detaching);
- if_blocks[current_block_type_index].d();
- ctx[31](null);
- ctx[34](null);
- ctx[35](null);
- if_block1.d();
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_fragment$f(ctx) {
- let applicationshell;
- let updating_elementRoot;
- let current;
- function applicationshell_elementRoot_binding(value) {
- ctx[38](value);
- }
- let applicationshell_props = {
- $$slots: { default: [create_default_slot$1] },
- $$scope: { ctx }
- };
- if (
- /*elementRoot*/
- ctx[0] !== void 0
- ) {
- applicationshell_props.elementRoot = /*elementRoot*/
- ctx[0];
- }
- applicationshell = new ApplicationShell({ props: applicationshell_props });
- binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding));
- return {
- c() {
- create_component(applicationshell.$$.fragment);
- },
- m(target, anchor) {
- mount_component(applicationshell, target, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const applicationshell_changes = {};
- if (dirty[0] & /*$metadata, databaseStore, filteredEntries, $listView, $visibleTreeStore, $subLists, $allRanges, $search, $selectedPackStore, $packStore*/
- 2046 | dirty[1] & /*$$scope*/
- 8192) {
- applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
- }
- if (!updating_elementRoot && dirty[0] & /*elementRoot*/
- 1) {
- updating_elementRoot = true;
- applicationshell_changes.elementRoot = /*elementRoot*/
- ctx2[0];
- add_flush_callback(() => updating_elementRoot = false);
- }
- applicationshell.$set(applicationshell_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(applicationshell.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(applicationshell.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(applicationshell, detaching);
- }
- };
- }
- function instance$f($$self, $$props, $$invalidate) {
- let $search;
- let $selectedPackStore;
- let $searchRegex;
- let $cleanSearchStore;
- let $allRanges;
- let $entriesStore;
- let $listView;
- let $packStore;
- let $subLists;
- let $visibleTreeStore;
- let $metadata;
- getContext("#external");
- let { elementRoot } = $$props;
- let entries = [];
- let filteredEntries = [];
- const selectedPackStore2 = databaseStore.selectedPackStore;
- component_subscribe($$self, selectedPackStore2, (value) => $$invalidate(2, $selectedPackStore = value));
- const packStore2 = databaseStore.packStore;
- component_subscribe($$self, packStore2, (value) => $$invalidate(7, $packStore = value));
- const metadata = databaseStore.metadata;
- component_subscribe($$self, metadata, (value) => $$invalidate(10, $metadata = value));
- const allRanges = databaseStore.allRanges;
- component_subscribe($$self, allRanges, (value) => $$invalidate(3, $allRanges = value));
- const subLists = databaseStore.subLists;
- component_subscribe($$self, subLists, (value) => $$invalidate(8, $subLists = value));
- const listView = databaseStore.listView;
- component_subscribe($$self, listView, (value) => $$invalidate(4, $listView = value));
- const visibleTreeStore2 = databaseStore.visibleTreeStore;
- component_subscribe($$self, visibleTreeStore2, (value) => $$invalidate(9, $visibleTreeStore = value));
- const search = databaseStore.search;
- component_subscribe($$self, search, (value) => $$invalidate(1, $search = value));
- const cleanSearchStore2 = databaseStore.cleanSearchStore;
- component_subscribe($$self, cleanSearchStore2, (value) => $$invalidate(24, $cleanSearchStore = value));
- const searchRegex = databaseStore.searchRegex;
- component_subscribe($$self, searchRegex, (value) => $$invalidate(23, $searchRegex = value));
- const entriesStore2 = SequencerDatabase.entriesStore;
- component_subscribe($$self, entriesStore2, (value) => $$invalidate(25, $entriesStore = value));
- listView.set(game.settings.get(CONSTANTS.MODULE_NAME, "db-list-view"));
- function select_change_handler() {
- $selectedPackStore = select_value(this);
- selectedPackStore2.set($selectedPackStore);
- }
- function input0_input_handler() {
- $search = this.value;
- search.set($search);
- }
- function input1_change_handler() {
- $allRanges = this.checked;
- allRanges.set($allRanges);
- }
- function input2_change_handler() {
- $subLists = this.checked;
- subLists.set($subLists);
- }
- function input3_change_handler() {
- $listView = this.checked;
- listView.set($listView);
- }
- function video_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- databaseStore.elements.player = $$value;
- $$invalidate(5, databaseStore);
- });
- }
- const mouseenter_handler = () => {
- $$invalidate(5, databaseStore.elements.player.controls = true, databaseStore);
- };
- const mouseleave_handler = () => {
- $$invalidate(5, databaseStore.elements.player.controls = false, databaseStore);
- };
- function img_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- databaseStore.elements.image = $$value;
- $$invalidate(5, databaseStore);
- });
- }
- function audio_binding($$value) {
- binding_callbacks[$$value ? "unshift" : "push"](() => {
- databaseStore.elements.audio = $$value;
- $$invalidate(5, databaseStore);
- });
- }
- const mouseenter_handler_1 = () => {
- $$invalidate(5, databaseStore.elements.audio.controls = true, databaseStore);
- };
- const mouseleave_handler_1 = () => {
- $$invalidate(5, databaseStore.elements.audio.controls = false, databaseStore);
- };
- function applicationshell_elementRoot_binding(value) {
- elementRoot = value;
- $$invalidate(0, elementRoot);
- }
- $$self.$$set = ($$props2) => {
- if ("elementRoot" in $$props2)
- $$invalidate(0, elementRoot = $$props2.elementRoot);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty[0] & /*$listView*/
- 16) {
- game.settings.set(CONSTANTS.MODULE_NAME, "db-list-view", $listView);
- }
- if ($$self.$$.dirty[0] & /*$entriesStore, $allRanges*/
- 33554440) {
- {
- const specificRanges = $allRanges ? Sequencer.Database.publicFlattenedEntries : Sequencer.Database.publicFlattenedSimpleEntries;
- $$invalidate(22, entries = specificRanges.map((entry) => {
- return { pack: entry.split(".")[0], entry };
- }));
- }
- }
- if ($$self.$$.dirty[0] & /*$cleanSearchStore, entries, $searchRegex, $selectedPackStore, $search*/
- 29360134) {
- {
- const searchParts = $cleanSearchStore.split("|");
- $$invalidate(6, filteredEntries = entries.filter((part) => {
- const matchParts = make_array_unique(part.entry.match($searchRegex) || []);
- return ($selectedPackStore === "all" || $selectedPackStore === part.pack) && ($search === "" || matchParts.length >= searchParts.length);
- }));
- }
- }
- };
- return [
- elementRoot,
- $search,
- $selectedPackStore,
- $allRanges,
- $listView,
- databaseStore,
- filteredEntries,
- $packStore,
- $subLists,
- $visibleTreeStore,
- $metadata,
- selectedPackStore2,
- packStore2,
- metadata,
- allRanges,
- subLists,
- listView,
- visibleTreeStore2,
- search,
- cleanSearchStore2,
- searchRegex,
- entriesStore2,
- entries,
- $searchRegex,
- $cleanSearchStore,
- $entriesStore,
- select_change_handler,
- input0_input_handler,
- input1_change_handler,
- input2_change_handler,
- input3_change_handler,
- video_binding,
- mouseenter_handler,
- mouseleave_handler,
- img_binding,
- audio_binding,
- mouseenter_handler_1,
- mouseleave_handler_1,
- applicationshell_elementRoot_binding
- ];
- }
- class Database_shell extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$f, create_fragment$f, safe_not_equal, { elementRoot: 0 }, null, [-1, -1]);
- }
- get elementRoot() {
- return this.$$.ctx[0];
- }
- set elementRoot(elementRoot) {
- this.$$set({ elementRoot });
- flush();
- }
- }
- class DatabaseViewerApp extends SvelteApplication {
- static get defaultOptions() {
- return foundry.utils.mergeObject(super.defaultOptions, {
- title: game.i18n.localize("SEQUENCER.Database.Title"),
- classes: ["dialog"],
- width: 900,
- height: 425,
- svelte: {
- class: Database_shell,
- target: document.body
- }
- });
- }
- static getActiveApp() {
- return Object.values(ui.windows).find((app) => {
- return app instanceof this && app._state > Application.RENDER_STATES.CLOSED;
- });
- }
- static async show(options = {}) {
- const existingApp = this.getActiveApp();
- if (existingApp)
- return existingApp.render(false, { focus: true });
- return new Promise((resolve) => {
- options.resolve = resolve;
- new this(options).render(true, { focus: true });
- });
- }
- }
- const HowTo_svelte_svelte_type_style_lang = "";
- function create_if_block$4(ctx) {
- let p;
- let raw0_value = localize("SEQUENCER.HowTo.PermissionsExplanation") + "";
- let t0;
- let button;
- let i;
- let t1;
- let html_tag;
- let raw1_value = localize("SEQUENCER.HowTo.OpenModuleSettings") + "";
- let mounted;
- let dispose;
- return {
- c() {
- p = element("p");
- t0 = space();
- button = element("button");
- i = element("i");
- t1 = space();
- html_tag = new HtmlTag(false);
- attr(i, "class", "fas fa-plug");
- html_tag.a = null;
- attr(button, "type", "button");
- attr(button, "class", "w-100 open-module-settings");
- },
- m(target, anchor) {
- insert(target, p, anchor);
- p.innerHTML = raw0_value;
- insert(target, t0, anchor);
- insert(target, button, anchor);
- append(button, i);
- append(button, t1);
- html_tag.m(raw1_value, button);
- if (!mounted) {
- dispose = listen(
- button,
- "click",
- /*openSettings*/
- ctx[0]
- );
- mounted = true;
- }
- },
- p: noop,
- d(detaching) {
- if (detaching)
- detach(p);
- if (detaching)
- detach(t0);
- if (detaching)
- detach(button);
- mounted = false;
- dispose();
- }
- };
- }
- function create_fragment$e(ctx) {
- let div;
- let p0;
- let raw0_value = localize("SEQUENCER.HowTo.Welcome") + "";
- let t0;
- let p1;
- let raw1_value = localize("SEQUENCER.HowTo.Explanation") + "";
- let t1;
- let t2;
- let p2;
- let raw2_value = localize("SEQUENCER.HowTo.PlayerExplanation") + "";
- let t3;
- let p3;
- let raw3_value = localize("SEQUENCER.HowTo.LayerExplanation") + "";
- let t4;
- let ol;
- let li0;
- let strong0;
- let raw4_value = localize("SEQUENCER.HowTo.Click") + "";
- let br0;
- let t5;
- let html_tag;
- let raw5_value = localize("SEQUENCER.HowTo.ClickLabel") + "";
- let t6;
- let li1;
- let strong1;
- let raw6_value = localize("SEQUENCER.HowTo.ClickDrag") + "";
- let br1;
- let t7;
- let html_tag_1;
- let raw7_value = localize("SEQUENCER.HowTo.ClickDragLabel") + "";
- let t8;
- let li2;
- let strong2;
- let raw8_value = localize("SEQUENCER.HowTo.Shift") + "";
- let br2;
- let t9;
- let html_tag_2;
- let raw9_value = localize("SEQUENCER.HowTo.ShiftLabel") + "";
- let t10;
- let li3;
- let strong3;
- let raw10_value = localize("SEQUENCER.HowTo.ShiftControl") + "";
- let br3;
- let t11;
- let html_tag_3;
- let raw11_value = localize("SEQUENCER.HowTo.ShiftControlLabel") + "";
- let t12;
- let li4;
- let strong4;
- let raw12_value = localize("SEQUENCER.HowTo.MoreToCome") + "";
- let if_block = game.user.isGM && create_if_block$4(ctx);
- return {
- c() {
- div = element("div");
- p0 = element("p");
- t0 = space();
- p1 = element("p");
- t1 = space();
- if (if_block)
- if_block.c();
- t2 = space();
- p2 = element("p");
- t3 = space();
- p3 = element("p");
- t4 = space();
- ol = element("ol");
- li0 = element("li");
- strong0 = element("strong");
- br0 = element("br");
- t5 = space();
- html_tag = new HtmlTag(false);
- t6 = space();
- li1 = element("li");
- strong1 = element("strong");
- br1 = element("br");
- t7 = space();
- html_tag_1 = new HtmlTag(false);
- t8 = space();
- li2 = element("li");
- strong2 = element("strong");
- br2 = element("br");
- t9 = space();
- html_tag_2 = new HtmlTag(false);
- t10 = space();
- li3 = element("li");
- strong3 = element("strong");
- br3 = element("br");
- t11 = space();
- html_tag_3 = new HtmlTag(false);
- t12 = space();
- li4 = element("li");
- strong4 = element("strong");
- html_tag.a = null;
- attr(li0, "class", "svelte-ese-1gfsmnk");
- html_tag_1.a = null;
- attr(li1, "class", "svelte-ese-1gfsmnk");
- html_tag_2.a = null;
- attr(li2, "class", "svelte-ese-1gfsmnk");
- html_tag_3.a = null;
- attr(li3, "class", "svelte-ese-1gfsmnk");
- attr(li4, "class", "svelte-ese-1gfsmnk");
- attr(div, "class", "howto-container svelte-ese-1gfsmnk");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, p0);
- p0.innerHTML = raw0_value;
- append(div, t0);
- append(div, p1);
- p1.innerHTML = raw1_value;
- append(div, t1);
- if (if_block)
- if_block.m(div, null);
- append(div, t2);
- append(div, p2);
- p2.innerHTML = raw2_value;
- append(div, t3);
- append(div, p3);
- p3.innerHTML = raw3_value;
- append(div, t4);
- append(div, ol);
- append(ol, li0);
- append(li0, strong0);
- strong0.innerHTML = raw4_value;
- append(li0, br0);
- append(li0, t5);
- html_tag.m(raw5_value, li0);
- append(ol, t6);
- append(ol, li1);
- append(li1, strong1);
- strong1.innerHTML = raw6_value;
- append(li1, br1);
- append(li1, t7);
- html_tag_1.m(raw7_value, li1);
- append(ol, t8);
- append(ol, li2);
- append(li2, strong2);
- strong2.innerHTML = raw8_value;
- append(li2, br2);
- append(li2, t9);
- html_tag_2.m(raw9_value, li2);
- append(ol, t10);
- append(ol, li3);
- append(li3, strong3);
- strong3.innerHTML = raw10_value;
- append(li3, br3);
- append(li3, t11);
- html_tag_3.m(raw11_value, li3);
- append(ol, t12);
- append(ol, li4);
- append(li4, strong4);
- strong4.innerHTML = raw12_value;
- },
- p(ctx2, [dirty]) {
- if (game.user.isGM)
- if_block.p(ctx2, dirty);
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- if (if_block)
- if_block.d();
- }
- };
- }
- function instance$e($$self) {
- async function openSettings() {
- const settings = new SettingsConfig();
- await settings.render(true);
- await wait$1(75);
- const focusElement = settings.element.find('select[name="sequencer.permissions-effect-create"]');
- settings.element.find("div.scrollable").scrollTop(focusElement.offset().top);
- await wait$1(250);
- focusElement.css("box-shadow", "rgba(200, 64, 67, 0.75) inset 0 0 10px");
- await wait$1(5e3);
- focusElement.css("box-shadow", "none");
- }
- return [openSettings];
- }
- class HowTo extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$e, create_fragment$e, safe_not_equal, {});
- }
- }
- const Tabs_svelte_svelte_type_style_lang = "";
- function get_each_context$4(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[6] = list[i];
- child_ctx[8] = i;
- return child_ctx;
- }
- function create_if_block_1$1(ctx) {
- let div;
- return {
- c() {
- div = element("div");
- set_style(div, "border-right", "1px solid rgba(0,0,0,0.5)");
- set_style(div, "margin", "0 10px");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- },
- d(detaching) {
- if (detaching)
- detach(div);
- }
- };
- }
- function create_if_block$3(ctx) {
- let i;
- let i_class_value;
- return {
- c() {
- i = element("i");
- attr(i, "class", i_class_value = "icon " + /*tab*/
- ctx[6].icon + " svelte-ese-123fyp");
- },
- m(target, anchor) {
- insert(target, i, anchor);
- },
- p(ctx2, dirty) {
- if (dirty & /*tabs*/
- 2 && i_class_value !== (i_class_value = "icon " + /*tab*/
- ctx2[6].icon + " svelte-ese-123fyp")) {
- attr(i, "class", i_class_value);
- }
- },
- d(detaching) {
- if (detaching)
- detach(i);
- }
- };
- }
- function create_each_block$4(key_1, ctx) {
- let first;
- let t0;
- let div;
- let t1;
- let t2_value = localize(
- /*tab*/
- ctx[6].label
- ) + "";
- let t2;
- let t3;
- let mounted;
- let dispose;
- let if_block0 = (
- /*separateElements*/
- ctx[3] && /*index*/
- ctx[8] > 0 && create_if_block_1$1()
- );
- let if_block1 = (
- /*tab*/
- ctx[6].icon && create_if_block$3(ctx)
- );
- function click_handler() {
- return (
- /*click_handler*/
- ctx[5](
- /*tab*/
- ctx[6]
- )
- );
- }
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- if (if_block0)
- if_block0.c();
- t0 = space();
- div = element("div");
- if (if_block1)
- if_block1.c();
- t1 = space();
- t2 = text$1(t2_value);
- t3 = space();
- attr(div, "class", "item item-piles-flexrow item-piles-clickable-link svelte-ese-123fyp");
- attr(div, "data-tab", "rest");
- toggle_class(
- div,
- "underscore",
- /*underscore*/
- ctx[2]
- );
- toggle_class(
- div,
- "active",
- /*activeTab*/
- ctx[0] === /*tab*/
- ctx[6].value
- );
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- if (if_block0)
- if_block0.m(target, anchor);
- insert(target, t0, anchor);
- insert(target, div, anchor);
- if (if_block1)
- if_block1.m(div, null);
- append(div, t1);
- append(div, t2);
- append(div, t3);
- if (!mounted) {
- dispose = listen(div, "click", click_handler);
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- if (
- /*separateElements*/
- ctx[3] && /*index*/
- ctx[8] > 0
- ) {
- if (if_block0)
- ;
- else {
- if_block0 = create_if_block_1$1();
- if_block0.c();
- if_block0.m(t0.parentNode, t0);
- }
- } else if (if_block0) {
- if_block0.d(1);
- if_block0 = null;
- }
- if (
- /*tab*/
- ctx[6].icon
- ) {
- if (if_block1) {
- if_block1.p(ctx, dirty);
- } else {
- if_block1 = create_if_block$3(ctx);
- if_block1.c();
- if_block1.m(div, t1);
- }
- } else if (if_block1) {
- if_block1.d(1);
- if_block1 = null;
- }
- if (dirty & /*tabs*/
- 2 && t2_value !== (t2_value = localize(
- /*tab*/
- ctx[6].label
- ) + ""))
- set_data(t2, t2_value);
- if (dirty & /*underscore*/
- 4) {
- toggle_class(
- div,
- "underscore",
- /*underscore*/
- ctx[2]
- );
- }
- if (dirty & /*activeTab, tabs*/
- 3) {
- toggle_class(
- div,
- "active",
- /*activeTab*/
- ctx[0] === /*tab*/
- ctx[6].value
- );
- }
- },
- d(detaching) {
- if (detaching)
- detach(first);
- if (if_block0)
- if_block0.d(detaching);
- if (detaching)
- detach(t0);
- if (detaching)
- detach(div);
- if (if_block1)
- if_block1.d();
- mounted = false;
- dispose();
- }
- };
- }
- function create_fragment$d(ctx) {
- let nav;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let nav_style_value;
- let each_value = (
- /*tabs*/
- ctx[1].filter(func)
- );
- const get_key = (ctx2) => (
- /*tab*/
- ctx2[6].value
- );
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context$4(ctx, each_value, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block$4(key, child_ctx));
- }
- return {
- c() {
- nav = element("nav");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(nav, "class", "tabs svelte-ese-123fyp");
- attr(nav, "data-group", "primary");
- attr(nav, "style", nav_style_value = /*$$props*/
- ctx[4].style);
- },
- m(target, anchor) {
- insert(target, nav, anchor);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(nav, null);
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*underscore, activeTab, tabs, localize, separateElements*/
- 15) {
- each_value = /*tabs*/
- ctx2[1].filter(func);
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, nav, destroy_block, create_each_block$4, null, get_each_context$4);
- }
- if (dirty & /*$$props*/
- 16 && nav_style_value !== (nav_style_value = /*$$props*/
- ctx2[4].style)) {
- attr(nav, "style", nav_style_value);
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(nav);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- }
- };
- }
- const func = (tab) => !tab.hidden;
- function instance$d($$self, $$props, $$invalidate) {
- let { activeTab } = $$props;
- let { tabs } = $$props;
- let { underscore = false } = $$props;
- let { separateElements = false } = $$props;
- const click_handler = (tab) => {
- $$invalidate(0, activeTab = tab.value);
- };
- $$self.$$set = ($$new_props) => {
- $$invalidate(4, $$props = assign(assign({}, $$props), exclude_internal_props($$new_props)));
- if ("activeTab" in $$new_props)
- $$invalidate(0, activeTab = $$new_props.activeTab);
- if ("tabs" in $$new_props)
- $$invalidate(1, tabs = $$new_props.tabs);
- if ("underscore" in $$new_props)
- $$invalidate(2, underscore = $$new_props.underscore);
- if ("separateElements" in $$new_props)
- $$invalidate(3, separateElements = $$new_props.separateElements);
- };
- $$props = exclude_internal_props($$props);
- return [activeTab, tabs, underscore, separateElements, $$props, click_handler];
- }
- class Tabs extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$d, create_fragment$d, safe_not_equal, {
- activeTab: 0,
- tabs: 1,
- underscore: 2,
- separateElements: 3
- });
- }
- }
- const SequenceManager = {
- VisibleEffects: writable$1({}),
- RunningSounds: writable$1({}),
- RunningSequences: writable$1({})
- };
- SequenceManager.VisibleEffects.get = (id) => {
- return get_store_value(SequenceManager.VisibleEffects)[id];
- };
- SequenceManager.VisibleEffects.add = (id, data) => {
- SequenceManager.VisibleEffects.update((effects) => {
- effects[id] = data;
- return effects;
- });
- };
- SequenceManager.VisibleEffects.delete = (id) => {
- SequenceManager.VisibleEffects.update((effects) => {
- delete effects[id];
- return effects;
- });
- };
- SequenceManager.VisibleEffects.values = () => {
- return Object.values(get_store_value(SequenceManager.VisibleEffects));
- };
- SequenceManager.RunningSounds.get = (id) => {
- return get_store_value(SequenceManager.RunningSounds)[id];
- };
- SequenceManager.RunningSounds.add = (id, data) => {
- SequenceManager.RunningSounds.update((effects) => {
- effects[id] = data;
- return effects;
- });
- };
- SequenceManager.RunningSounds.delete = (id) => {
- SequenceManager.RunningSounds.update((effects) => {
- delete effects[id];
- return effects;
- });
- };
- SequenceManager.RunningSounds.values = () => {
- return Object.values(get_store_value(SequenceManager.RunningSounds));
- };
- SequenceManager.RunningSounds.keys = () => {
- return Object.keys(get_store_value(SequenceManager.RunningSounds));
- };
- SequenceManager.RunningSequences.get = (id) => {
- return get_store_value(SequenceManager.RunningSequences)[id];
- };
- SequenceManager.RunningSequences.add = (id, sequence) => {
- SequenceManager.RunningSequences.update((sequences) => {
- sequences[id] = sequence;
- return sequences;
- });
- };
- SequenceManager.RunningSequences.delete = (id) => {
- SequenceManager.RunningSequences.update((sequences) => {
- delete sequences[id];
- return sequences;
- });
- };
- SequenceManager.RunningSequences.clearFinishedSequences = () => {
- SequenceManager.RunningSequences.update((sequences) => {
- for (const sequence of Object.values(sequences)) {
- if (get_store_value(sequence.status) === CONSTANTS.STATUS.COMPLETE || get_store_value(sequence.status) === CONSTANTS.STATUS.ABORTED) {
- delete sequences[sequence.id];
- }
- }
- return sequences;
- });
- };
- SequenceManager.RunningSequences.stopAll = () => {
- SequenceManager.RunningSequences.update((sequences) => {
- for (const sequence of Object.values(sequences)) {
- sequence._abort();
- }
- return sequences;
- });
- };
- SequenceManager.RunningSequences.values = () => {
- return Object.values(get_store_value(SequenceManager.RunningSequences));
- };
- class ColorMatrixFilter extends globalThis.PIXI.filters.ColorMatrixFilter {
- /**
- * Properties & default values:
- * - hue [false]
- * - brightness [1]
- * - contrast [1]
- * - saturate [1]
- */
- constructor(inData) {
- super();
- this.isValid = true;
- this.values = {};
- for (let [key, value] of Object.entries(inData)) {
- this.setValue(key, value);
- if (!this.isValid)
- break;
- }
- }
- setValue(key, value) {
- try {
- this.values[key] = value;
- this[key](value, true);
- } catch (err) {
- ui.notifications.warn(
- `Sequencer | ${this.constructor.name} | Could not set property ${key}`
- );
- }
- }
- }
- class BlurFilter extends globalThis.PIXI.filters.BlurFilter {
- /**
- * Properties & default values:
- * - strength [8]
- * - blur [2]
- * - blurX [2]
- * - blurY [2]
- * - quality [4]
- * - resolution [PIXI.settings.FILTER_RESOLUTION]
- * - kernelSize [5]
- */
- constructor(inData = {}) {
- inData = foundry.utils.mergeObject(
- {
- strength: 1,
- quality: 4,
- resolution: PIXI.settings.FILTER_RESOLUTION,
- kernelSize: 5
- },
- inData
- );
- super(...Object.values(inData));
- this.isValid = true;
- for (let [key, value] of Object.entries(inData)) {
- try {
- this[key] = value;
- } catch (err) {
- ui.notifications.warn(
- `Sequencer | ${this.constructor.name} | Could not set property ${key}`
- );
- this.isValid = false;
- }
- }
- }
- }
- class NoiseFilter extends globalThis.PIXI.filters.NoiseFilter {
- /**
- * Properties & default values:
- * - noise [0.5]
- * - seed [Math.random()]
- */
- constructor(inData = {}) {
- super();
- inData = foundry.utils.mergeObject(
- {
- noise: 0.5,
- seed: Math.random()
- },
- inData
- );
- this.isValid = true;
- for (let [key, value] of Object.entries(inData)) {
- try {
- this[key] = value;
- } catch (err) {
- ui.notifications.warn(
- `Sequencer | ${this.constructor.name} | Could not set property ${key}`
- );
- this.isValid = false;
- }
- }
- }
- }
- class GlowFilter extends globalThis.PIXI.filters.GlowFilter {
- /**
- * Properties & default values:
- * - distance [10]
- * - outerStrength [4]
- * - innerStrength [0]
- * - color [0xffffff]
- * - quality [0.1]
- * - knockout [false]
- */
- constructor(inData = {}) {
- inData = foundry.utils.mergeObject(
- {
- distance: 10,
- outerStrength: 4,
- innerStrength: 0,
- color: 16777215,
- quality: 0.1,
- knockout: false
- },
- inData
- );
- super(inData);
- this.isValid = true;
- }
- }
- let shader = `
- uniform sampler2D uSampler;
- varying vec2 vTextureCoord;
- float alpha;
-
- void main() {
- vec4 pixel = texture2D(uSampler, vTextureCoord);
- alpha = smoothstep(0.6,1.0,pixel.a);
- gl_FragColor = vec4(alpha, alpha, alpha, pixel.a);
- }
- `;
- class ClipFilter extends PIXI.Filter {
- constructor() {
- super(null, shader);
- }
- }
- const filters = {
- ColorMatrix: ColorMatrixFilter,
- Blur: BlurFilter,
- Noise: NoiseFilter,
- Glow: GlowFilter,
- Clip: ClipFilter
- };
- const SequencerAnimationEngine = {
- _animations: [],
- _debug: void 0,
- _deltas: [],
- ticker: false,
- dt: 0,
- isRunning: false,
- addAnimation(origin, attributes = [], timeDifference = 0) {
- if (!Array.isArray(attributes))
- attributes = [attributes];
- return new Promise((resolve) => {
- this._animations.push({
- origin,
- attributes: attributes.map((attribute) => {
- attribute.targetId = get_object_identifier(attribute.target) + "-" + attribute.propertyName;
- attribute.started = false;
- attribute.initialized = false;
- attribute.finishing = false;
- attribute.complete = false;
- attribute.progress = 0;
- attribute.value = 0;
- attribute.duration = attribute.duration ?? 0;
- attribute.durationDone = timeDifference ?? 0;
- if (attribute?.looping) {
- attribute.loopDuration = attribute.loopDuration ?? attribute.duration ?? 0;
- attribute.loopDurationDone = timeDifference % attribute.loopDuration;
- attribute.loops = attribute.loops ?? 0;
- attribute.loopsDone = Math.floor(
- attribute.durationDone / attribute.duration
- );
- attribute.index = attribute.loopsDone % attribute.values.length;
- attribute.nextIndex = (attribute.loopsDone + 1) % attribute.values.length;
- if (!attribute.pingPong && attribute.nextIndex === 0) {
- attribute.index = 0;
- attribute.nextIndex = 1;
- }
- }
- return attribute;
- }),
- complete: false,
- totalDt: timeDifference,
- resolve
- });
- if (!this.ticker || !this.ticker.started) {
- this.start();
- }
- debug(`Added animations to Animation Engine`);
- });
- },
- endAnimations(target) {
- this._animations = this._animations.filter(
- (animation2) => animation2.origin !== target
- );
- },
- start() {
- debug(`Animation Engine Started`);
- if (!this.ticker) {
- this.ticker = new PIXI.Ticker();
- this.ticker.add(this.nextFrame.bind(this));
- }
- this.ticker.start();
- },
- nextFrame() {
- if (this._animations.length === 0) {
- debug(`Animation Engine Paused`);
- this.ticker.stop();
- this._startingValues = {};
- return;
- }
- this._animations.forEach((animation2) => this._animate(animation2));
- this._animations = this._animations.filter(
- (animation2) => !animation2.complete
- );
- this._applyDeltas();
- for (const targetId of Object.keys(this._startingValues)) {
- if (!this._animations.some(
- (_a) => _a.attributes.some((_b) => _b.targetId === targetId)
- )) {
- delete this._startingValues[targetId];
- }
- }
- },
- _startingValues: {},
- _applyDeltas() {
- const deltas = [];
- for (const animation2 of this._animations) {
- for (const attribute of animation2.attributes) {
- if (!attribute.started || attribute.complete)
- continue;
- if (attribute.finishing) {
- attribute.complete = true;
- }
- let delta = deltas.find(
- (delta2) => attribute.targetId === delta2.targetId && attribute.setPropertyName === delta2.setPropertyName
- );
- if (!delta) {
- delta = {
- targetId: attribute.targetId,
- target: attribute.target,
- getPropertyName: attribute.getPropertyName ?? attribute.propertyName,
- setPropertyName: attribute.propertyName,
- value: 0
- };
- if (attribute.target instanceof PIXI.filters.ColorMatrixFilter) {
- delta.value = attribute.previousValue;
- }
- deltas.push(delta);
- }
- delta.value += attribute.delta;
- }
- }
- for (let delta of deltas) {
- const finalValue = deep_get(delta.target, delta.getPropertyName) + delta.value;
- try {
- deep_set(delta.target, delta.setPropertyName, finalValue);
- } catch (err) {
- }
- }
- },
- _animate(animation2) {
- animation2.totalDt += this.ticker.elapsedMS;
- animation2.attributes.filter((attribute) => !attribute.complete).forEach(
- (attribute) => this._animateAttribute(animation2.totalDt, attribute)
- );
- animation2.complete = animation2.attributes.filter((attribute) => !attribute.complete).length === 0;
- if (animation2.complete) {
- animation2.resolve();
- }
- },
- _animateAttribute(totalDt, attribute) {
- if (totalDt < attribute.delay)
- return;
- if (!attribute.started) {
- const funkyProperty = attribute.propertyName.includes("scale") || attribute.propertyName.includes("alpha");
- if (this._startingValues[attribute.targetId] === void 0 || attribute.absolute) {
- const getProperty2 = funkyProperty || attribute.from === void 0;
- this._startingValues[attribute.targetId] = getProperty2 ? deep_get(
- attribute.target,
- attribute.getPropertyName ?? attribute.propertyName
- ) : attribute.from;
- if (!attribute.propertyName.includes("scale")) {
- deep_set(
- attribute.target,
- attribute.propertyName,
- this._startingValues[attribute.targetId]
- );
- }
- }
- attribute.previousValue = this._startingValues[attribute.targetId];
- if (attribute?.looping) {
- attribute.values = attribute.values.map((value) => {
- return value + attribute.previousValue - (funkyProperty ? 1 : 0);
- });
- } else if (attribute.from === void 0) {
- attribute.from = attribute.previousValue;
- }
- }
- attribute.started = true;
- if (attribute?.looping && attribute?.indefinite) {
- this._handleIndefiniteLoop(attribute);
- } else if (attribute?.looping) {
- this._handleLoops(attribute);
- } else {
- this._handleDefault(attribute);
- }
- attribute.delta = attribute.value - attribute.previousValue;
- attribute.previousValue = attribute.value;
- },
- _handleBaseLoop(attribute) {
- if (!attribute.initialized) {
- if (attribute.values.length === 1) {
- attribute.values.unshift(
- deep_get(attribute.target, attribute.propertyName)
- );
- }
- attribute.initialized = true;
- }
- attribute.loopDurationDone += this.ticker.deltaMS;
- attribute.progress = attribute.loopDurationDone / attribute.loopDuration;
- attribute.value = interpolate(
- attribute.values[attribute.index],
- attribute.values[attribute.nextIndex],
- attribute.progress,
- attribute.ease
- );
- if (attribute.progress >= 1) {
- attribute.loopDurationDone -= attribute.loopDuration;
- attribute.index = (attribute.index + 1) % attribute.values.length;
- attribute.nextIndex = (attribute.nextIndex + 1) % attribute.values.length;
- if (!attribute.pingPong && attribute.nextIndex === 0) {
- attribute.index = 0;
- attribute.nextIndex = 1;
- }
- attribute.loopsDone++;
- attribute.value = interpolate(
- attribute.values[attribute.index],
- attribute.values[attribute.nextIndex],
- attribute.progress % 1,
- attribute.ease
- );
- }
- },
- _handleIndefiniteLoop(attribute) {
- return this._handleBaseLoop(attribute);
- },
- _handleLoops(attribute) {
- this._handleBaseLoop(attribute);
- attribute.durationDone += this.ticker.deltaMS;
- attribute.overallProgress = attribute.durationDone / attribute.duration;
- if (attribute.progress >= 1 && attribute.loopsDone === attribute.loops * 2) {
- attribute.finishing = true;
- attribute.value = attribute.values[attribute.index];
- }
- if (attribute.overallProgress >= 1) {
- attribute.finishing = true;
- }
- },
- _handleDefault(attribute) {
- attribute.durationDone += this.ticker.deltaMS;
- attribute.progress = attribute.durationDone / attribute.duration;
- attribute.value = interpolate(
- attribute.from,
- attribute.to,
- attribute.progress,
- attribute.ease
- );
- if (attribute.progress >= 1) {
- attribute.value = attribute.to;
- attribute.finishing = true;
- }
- }
- };
- class SequencerAudioHelper {
- /**
- * Play an audio file.
- *
- * @param {{src: string, loop?: boolean, volume?: number, _fadeIn?: {duration: number}, _fadeOut?: {duration: number}, duration?: number}} data The data that describes the audio to play.
- * @param {boolean} [push=false] A flag indicating whether or not to make other clients play the audio, too.
- * @returns {Number} A promise that resolves when the audio file has finished playing.
- */
- static async play(data, push = true) {
- if (push)
- sequencerSocket.executeForOthers(SOCKET_HANDLERS.PLAY_SOUND, data);
- return this._play(data);
- }
- /**
- * @param {{src: string, loop?: boolean, volume: number, _fadeIn?: {duration: number}, _fadeOut?: {duration: number}, duration?: number}} data
- * @returns {Number}
- * @private
- */
- static async _play(data) {
- if (!game.settings.get("sequencer", "soundsEnabled") || game.user.viewedScene !== data.sceneId || data?.users?.length && !data?.users?.includes(game.userId)) {
- return new Promise((resolve) => setTimeout(resolve, data.duration));
- }
- Hooks.callAll("createSequencerSound", data);
- debug(`Playing sound:`, data);
- data.volume = (data.volume ?? 0.8) * game.settings.get("core", "globalInterfaceVolume");
- const sound = await game.audio.play(data.src, {
- volume: data.fadeIn ? 0 : data.volume,
- loop: data.loop,
- offset: data.startTime
- });
- SequenceManager.RunningSounds.add(data.id, sound);
- if (data.fadeIn) {
- SequencerAnimationEngine.addAnimation(data.id, {
- target: sound,
- propertyName: "volume",
- from: 0,
- to: data.volume,
- duration: Math.min(data.fadeIn.duration, data.duration),
- ease: data.fadeIn.ease,
- delay: Math.min(data.fadeIn.delay, data.duration)
- });
- }
- if (data.fadeOut) {
- SequencerAnimationEngine.addAnimation(data.id, {
- target: sound,
- propertyName: "volume",
- from: data.volume,
- to: 0,
- duration: Math.min(data.fadeOut.duration, data.duration),
- ease: data.fadeOut.ease,
- delay: Math.max(
- data.duration - data.fadeOut.duration + data.fadeOut.delay,
- 0
- )
- });
- }
- if (data.duration) {
- setTimeout(() => {
- sound.stop();
- }, data.duration);
- }
- new Promise((resolve) => {
- sound.on("stop", resolve);
- sound.on("end", resolve);
- }).then(() => {
- SequenceManager.RunningSounds.delete(data.id);
- Hooks.callAll("endedSequencerSound", data);
- });
- return data.duration;
- }
- static stop(ids, push = true) {
- if (push && game.user.isGM)
- sequencerSocket.executeForOthers(SOCKET_HANDLERS.STOP_SOUNDS, ids);
- return this._stop(ids);
- }
- static _stop(ids) {
- for (const id of ids) {
- const sound = SequenceManager.RunningSounds.get(id);
- if (sound) {
- sound.stop();
- }
- }
- }
- }
- let lockedView = false;
- class SequencerFoundryReplicator {
- static registerHooks() {
- Hooks.on("canvasPan", () => {
- if (!lockedView)
- return;
- canvas.stage.pivot.set(lockedView.x, lockedView.y);
- canvas.stage.scale.set(lockedView.scale, lockedView.scale);
- canvas.updateBlur(lockedView.scale);
- canvas.controls._onCanvasPan();
- canvas.hud.align();
- });
- }
- static _validateObject(inObject, sceneId) {
- if (is_UUID(inObject) || !is_object_canvas_data(inObject)) {
- inObject = get_object_from_scene(inObject, sceneId);
- }
- return inObject?._object ?? inObject;
- }
- static _getPositionFromData(data) {
- const source = this._validateObject(data.source, data.sceneId);
- const position = source instanceof PlaceableObject ? get_object_position(source) : source?.worldPosition || source?.center || source;
- const multiplier = data.randomOffset;
- const twister = new MersenneTwister(data.seed);
- if (source && multiplier) {
- let randomOffset = get_random_offset(
- source,
- multiplier,
- twister
- );
- position.x -= randomOffset.x;
- position.y -= randomOffset.y;
- }
- let extraOffset = data.offset;
- if (extraOffset) {
- let newOffset = {
- x: extraOffset.x,
- y: extraOffset.y
- };
- if (extraOffset.gridUnits) {
- newOffset.x *= canvas.grid.size;
- newOffset.y *= canvas.grid.size;
- }
- if (extraOffset.local) {
- newOffset = rotateAroundPoint(
- 0,
- 0,
- newOffset.x,
- newOffset.y,
- source?.rotation ?? 0
- );
- }
- position.x -= newOffset.x;
- position.y -= newOffset.y;
- }
- return position;
- }
- static playScrollingText(data, push = true) {
- if (push) {
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.CREATE_SCROLLING_TEXT,
- data
- );
- }
- return this._playScrollingText(data);
- }
- static _playScrollingText(data) {
- if (game.user.viewedScene !== data.sceneId)
- return;
- if (data.users.length && !data.users.includes(game.userId))
- return;
- canvas.interface.createScrollingText(
- this._getPositionFromData(data),
- data.content,
- data.options
- );
- return data.options?.duration ?? 2e3;
- }
- static panCanvas(data, push = true) {
- if (push) {
- sequencerSocket.executeForOthers(SOCKET_HANDLERS.PAN_CANVAS, data);
- }
- return this._panCanvas(data);
- }
- static _panCanvas(data) {
- if (game.user.viewedScene !== data.sceneId)
- return;
- if (data.users.length && !data.users.includes(game.userId))
- return;
- if (data.source) {
- const position = this._getPositionFromData(data);
- canvas.animatePan({
- x: position.x,
- y: position.y,
- scale: data.scale,
- duration: data.duration,
- speed: data.speed
- });
- if (data.speed) {
- let ray = new Ray(canvas.stage.pivot, {
- x: position.x,
- y: position.y
- });
- data.duration = Math.round(ray.distance * 1e3 / data.speed);
- }
- if (data.lockView > 0) {
- setTimeout(() => {
- lockedView = {
- x: position.x,
- y: position.y,
- scale: data.scale
- };
- }, data.duration);
- setTimeout(() => {
- lockedView = false;
- }, data.lockView + data.duration);
- }
- } else {
- data.duration = 0;
- }
- if (data.shake) {
- setTimeout(() => {
- this._shake(data.shake);
- }, data.duration);
- }
- return data.duration + Math.max(data.lockView ?? 0, data.shake?.duration ?? 0);
- }
- static _shake(shakeData) {
- let x = random_float_between(-1, 1);
- let y = random_float_between(-1, 1);
- let rot = shakeData.rotation ? random_float_between(-1, 1) : 0;
- let positions = [{ x, y, rot }];
- for (let index = 0; index < Math.floor(shakeData.duration / shakeData.frequency); index++) {
- x = flip_negate(x, Math.random());
- y = flip_negate(y, Math.random());
- rot = shakeData.rotation ? flip_negate(rot, Math.random()) : 0;
- positions.push({ x, y, rot });
- }
- let currentDuration = 0;
- positions = positions.map((pos) => {
- let fadeStrength = 1;
- if (shakeData.fadeInDuration && currentDuration <= shakeData.fadeInDuration) {
- fadeStrength = Math.max(
- 0,
- Math.min(1, currentDuration / shakeData.fadeInDuration)
- );
- }
- if (shakeData.fadeOutDuration && currentDuration >= shakeData.duration - shakeData.fadeOutDuration) {
- fadeStrength = Math.max(
- 0,
- Math.min(
- 1,
- (shakeData.duration - currentDuration) / shakeData.fadeOutDuration
- )
- );
- }
- pos.x *= shakeData.strength * fadeStrength;
- pos.y *= shakeData.strength * fadeStrength;
- if (shakeData.rotation) {
- pos.rot *= shakeData.strength / 7.5 * fadeStrength;
- } else {
- pos.rot = 0;
- }
- currentDuration += shakeData.frequency;
- return {
- transform: `translate(${pos.x}px, ${pos.y}px) rotate(${pos.rot}deg)`
- };
- });
- document.getElementById("board").animate(positions, {
- duration: shakeData.duration
- });
- }
- }
- const SOCKET_HANDLERS = {
- PLAY_EFFECT: "playEffect",
- END_EFFECTS: "endEffects",
- UPDATE_EFFECT: "updateEffects",
- ADD_EFFECT_ANIMATIONS: "addEffectAnimations",
- PLAY_SOUND: "playSound",
- STOP_SOUNDS: "stopSounds",
- PRELOAD: "preload",
- PRELOAD_RESPONSE: "preloadResponse",
- PRELOAD_DONE: "preloadDone",
- UPDATE_DOCUMENT: "updateDocument",
- ADD_FLAGS: "addFlags",
- REMOVE_FLAGS: "removeFlags",
- UPDATE_POSITION: "updatePosition",
- CREATE_SCROLLING_TEXT: "createScrollingText",
- PAN_CANVAS: "panCanvas",
- RUN_SEQUENCE_LOCALLY: "runSequenceLocally"
- };
- let sequencerSocket;
- function registerSocket() {
- if (sequencerSocket)
- return;
- sequencerSocket = socketlib.registerModule(CONSTANTS.MODULE_NAME);
- sequencerSocket.register(
- SOCKET_HANDLERS.PLAY_EFFECT,
- (...args) => Sequencer.EffectManager._playEffect(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.END_EFFECTS,
- (...args) => Sequencer.EffectManager._endManyEffects(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.UPDATE_EFFECT,
- (...args) => Sequencer.EffectManager._updateEffect(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
- (...args) => Sequencer.EffectManager._addEffectAnimations(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.PLAY_SOUND,
- (...args) => SequencerAudioHelper._play(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.STOP_SOUNDS,
- (...args) => SequencerAudioHelper._stop(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.PRELOAD,
- (...args) => Sequencer.Preloader.respond(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.PRELOAD_RESPONSE,
- (...args) => Sequencer.Preloader.handleResponse(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.UPDATE_DOCUMENT,
- (...args) => updateDocument(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.ADD_FLAGS,
- (...args) => flagManager._addFlags(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.REMOVE_FLAGS,
- (...args) => flagManager._removeFlags(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.UPDATE_POSITION,
- (...args) => Sequencer.EffectManager._updatePosition(...args)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.CREATE_SCROLLING_TEXT,
- (data) => SequencerFoundryReplicator._playScrollingText(data)
- );
- sequencerSocket.register(
- SOCKET_HANDLERS.PAN_CANVAS,
- (data) => SequencerFoundryReplicator._panCanvas(data)
- );
- sequencerSocket.register(SOCKET_HANDLERS.RUN_SEQUENCE_LOCALLY, (data) => {
- debug("Playing remote Sequence");
- new Sequence().fromJSON(data).play();
- });
- }
- async function updateDocument(documentUuid, updates, animate) {
- const document2 = await fromUuid(documentUuid);
- return document2.update(updates, animate);
- }
- const flagManager = {
- flagAddBuffer: /* @__PURE__ */ new Map(),
- flagRemoveBuffer: /* @__PURE__ */ new Map(),
- _latestFlagVersion: false,
- get latestFlagVersion() {
- if (!this._latestFlagVersion) {
- const versions = Object.keys(this.migrations);
- versions.sort((a, b) => {
- return isNewerVersion(a, b) ? -1 : 1;
- });
- this._latestFlagVersion = versions[0];
- }
- return this._latestFlagVersion;
- },
- /**
- * Sanitizes the effect data, accounting for changes to the structure in previous versions
- *
- * @param inDocument
- * @returns {array}
- */
- getFlags(inDocument) {
- let effects = getProperty(inDocument, CONSTANTS.EFFECTS_FLAG);
- if (!effects?.length)
- return [];
- effects = foundry.utils.deepClone(effects);
- const changes = [];
- for (let [effectId, effectData] of effects) {
- let effectVersion = effectData?.flagVersion ?? "1.0.0";
- if (effectData.flagVersion === this.latestFlagVersion)
- continue;
- for (let [version, migration] of Object.entries(this.migrations)) {
- if (!isNewerVersion(version, effectVersion))
- continue;
- effectData = migration(inDocument, effectData);
- }
- debug(
- `Migrated effect with ID ${effectId} from version ${effectVersion} to version ${this.latestFlagVersion}`
- );
- effectData.flagVersion = this.latestFlagVersion;
- changes.push(effectData);
- }
- if (changes.length) {
- flagManager.addFlags(inDocument.uuid, changes);
- }
- return effects;
- },
- migrations: {
- "2.0.0": (inDocument, effectData) => {
- effectData._id = effectData.id;
- effectData.creationTimestamp = effectData.timestamp;
- if (effectData.template) {
- effectData.template = {
- gridSize: effectData.template[0],
- startPoint: effectData.template[1],
- endPoint: effectData.template[2]
- };
- }
- if (effectData.attachTo) {
- effectData.attachTo = {
- active: true,
- align: "center",
- rotation: true,
- bindVisibility: true,
- bindAlpha: true
- };
- effectData.source = inDocument.uuid;
- const objectSize = get_object_dimensions(inDocument, true);
- effectData.offset = {
- x: effectData.position.x - objectSize.width,
- y: effectData.position.y - objectSize.height
- };
- } else if (effectData.position) {
- effectData.source = effectData.position;
- }
- if (effectData.reachTowards) {
- effectData.stretchTo = {
- attachTo: false,
- onlyX: false
- };
- }
- if (effectData.filters) {
- effectData.filters = Object.entries(effectData.filters).map((entry) => {
- return {
- className: entry[0],
- ...entry[1]
- };
- });
- }
- effectData.moveSpeed = effectData.speed;
- effectData.target = null;
- effectData.forcedIndex = null;
- effectData.flipX = false;
- effectData.flipY = false;
- effectData.nameOffsetMap = {};
- effectData.sequenceId = 0;
- delete effectData.id;
- delete effectData.timestamp;
- delete effectData.position;
- delete effectData.reachTowards;
- delete effectData.speed;
- delete effectData.audioVolume;
- delete effectData.gridSizeDifference;
- delete effectData.template;
- if (effectData.animatedProperties) {
- delete effectData.animatedProperties.fadeInAudio;
- delete effectData.animatedProperties.fadeOutAudio;
- }
- effectData = foundry.utils.mergeObject(
- effectData,
- effectData.animatedProperties
- );
- delete effectData.animatedProperties;
- return effectData;
- },
- "2.0.6": (inDocument, effectData) => {
- effectData.private = null;
- return effectData;
- },
- "2.0.8": (inDocument, effectData) => {
- if (effectData.stretchTo) {
- effectData.stretchTo.tiling = false;
- }
- return effectData;
- },
- "2.0.9": (inDocument, effectData) => {
- effectData.tilingTexture = false;
- if (effectData.stretchTo?.tiling !== void 0) {
- if (effectData.stretchTo.tiling) {
- effectData.tilingTexture = {
- scale: { x: 1, y: 1 },
- position: { x: 0, y: 0 }
- };
- }
- delete effectData.stretchTo.tiling;
- }
- return effectData;
- },
- "2.1.0": (inDocument, effectData) => {
- if (effectData.randomOffset) {
- effectData.randomOffset = {
- source: !effectData.target ? effectData.randomOffset : false,
- target: !!effectData.target ? effectData.randomOffset : false
- };
- }
- if (effectData.nameOffsetMap) {
- Object.values(effectData.nameOffsetMap).forEach((offsetMap) => {
- if (offsetMap.randomOffset) {
- offsetMap.randomOffset = {
- source: !offsetMap.target ? offsetMap.randomOffset : false,
- target: !!offsetMap.target ? offsetMap.randomOffset : false
- };
- }
- });
- }
- return effectData;
- }
- },
- /**
- * Adds effects to a given document
- *
- * @param inObjectUUID
- * @param inEffects
- */
- addFlags: (inObjectUUID, inEffects) => {
- if (!Array.isArray(inEffects))
- inEffects = [inEffects];
- sequencerSocket.executeAsGM(
- SOCKET_HANDLERS.ADD_FLAGS,
- inObjectUUID,
- inEffects
- );
- },
- /**
- * Removes effects from a given document
- *
- * @param inObjectUUID
- * @param inEffects
- * @param removeAll
- */
- removeFlags: (inObjectUUID, inEffects, removeAll = false) => {
- sequencerSocket.executeAsGM(
- SOCKET_HANDLERS.REMOVE_FLAGS,
- inObjectUUID,
- inEffects,
- removeAll
- );
- },
- _addFlags: (inObjectUUID, inEffects) => {
- if (!Array.isArray(inEffects))
- inEffects = [inEffects];
- let flagsToSet = flagManager.flagAddBuffer.get(inObjectUUID) ?? {
- effects: []
- };
- flagsToSet.effects.push(...inEffects);
- flagManager.flagAddBuffer.set(inObjectUUID, flagsToSet);
- flagManager.updateFlags();
- },
- _removeFlags: (inObjectUUID, inEffects, removeAll = false) => {
- if (inEffects && !Array.isArray(inEffects))
- inEffects = [inEffects];
- let flagsToSet = flagManager.flagRemoveBuffer.get(inObjectUUID) ?? {
- effects: [],
- removeAll
- };
- if (inEffects)
- flagsToSet.effects.push(...inEffects);
- flagManager.flagRemoveBuffer.set(inObjectUUID, flagsToSet);
- flagManager.updateFlags();
- },
- updateFlags: debounce(async () => {
- let flagsToAdd = Array.from(flagManager.flagAddBuffer);
- let flagsToRemove = Array.from(flagManager.flagRemoveBuffer);
- flagManager.flagAddBuffer.clear();
- flagManager.flagRemoveBuffer.clear();
- flagsToAdd.forEach((entry) => entry[1].original = true);
- flagsToRemove.forEach((entry) => entry[1].original = true);
- const objects = /* @__PURE__ */ new Set([
- ...flagsToAdd.map((effect) => effect[0]).filter(Boolean),
- ...flagsToRemove.map((effect) => effect[0]).filter(Boolean)
- ]);
- flagsToAdd = new Map(flagsToAdd);
- flagsToRemove = new Map(flagsToRemove);
- const actorUpdates = {};
- const sceneObjectsToUpdate = {};
- for (let objectUUID of objects) {
- let object = fromUuidSync(objectUUID);
- if (!object) {
- debug(
- `Failed to set flags on non-existent object with UUID: ${objectUUID}`
- );
- continue;
- }
- let toAdd = flagsToAdd.get(objectUUID) ?? { effects: [] };
- let toRemove = flagsToRemove.get(objectUUID) ?? {
- effects: [],
- removeAll: false
- };
- const existingFlags = new Map(
- getProperty(object, CONSTANTS.EFFECTS_FLAG) ?? []
- );
- if (toRemove?.removeAll) {
- toRemove.effects = Array.from(existingFlags).map((entry) => entry[0]);
- }
- for (let effect of toAdd.effects) {
- if (typeof effect === "string") {
- effect = existingFlags.get(effect);
- if (!effect)
- continue;
- }
- existingFlags.set(effect._id, effect);
- }
- for (let effect of toRemove.effects) {
- if (typeof effect === "string") {
- effect = existingFlags.get(effect);
- if (!effect)
- continue;
- }
- existingFlags.delete(effect._id);
- }
- let flagsToSet = Array.from(existingFlags);
- const options = {};
- const isLinkedToken = object instanceof TokenDocument && object.actorLink;
- const isLinkedActor = object instanceof Actor && object.prototypeToken.actorLink;
- if ((isLinkedToken || isLinkedActor) && (toAdd.original || toRemove.original)) {
- const actor = isLinkedActor ? object : object.actor;
- actorUpdates[actor.id] = flagsToSet.filter(
- (effect) => effect[1]?.persistOptions?.persistTokenPrototype
- );
- flagsToSet = flagsToSet.filter(
- (effect) => !effect[1]?.persistOptions?.persistTokenPrototype
- );
- if (isLinkedToken && game.modules.get("multilevel-tokens")?.active && getProperty(object, "flags.multilevel-tokens.stoken")) {
- options["mlt_bypass"] = true;
- }
- }
- if (object?.documentName === "Scene") {
- const sceneId = object.id;
- sceneObjectsToUpdate[sceneId] = sceneObjectsToUpdate[sceneId] ?? {
- updates: {},
- documents: {}
- };
- sceneObjectsToUpdate[sceneId].updates[CONSTANTS.EFFECTS_FLAG] = flagsToSet;
- } else if (!(object instanceof Actor)) {
- const sceneId = object.parent.id;
- const docName = object.documentName;
- sceneObjectsToUpdate[sceneId] = sceneObjectsToUpdate[sceneId] ?? {
- updates: {},
- documents: {}
- };
- sceneObjectsToUpdate[sceneId].documents[docName] = sceneObjectsToUpdate[sceneId].documents[docName] ?? {
- options: {},
- updates: []
- };
- sceneObjectsToUpdate[sceneId].documents[docName].options = options;
- sceneObjectsToUpdate[sceneId].documents[docName].updates.push({
- _id: object.id,
- [CONSTANTS.EFFECTS_FLAG]: flagsToSet
- });
- }
- }
- for (const [sceneId, sceneData] of Object.entries(sceneObjectsToUpdate)) {
- const scene = game.scenes.get(sceneId);
- if (!foundry.utils.isEmpty(sceneData.updates)) {
- await scene.update(sceneData.updates);
- }
- for (const [documentType, documentData] of Object.entries(
- sceneData.documents
- )) {
- await scene.updateEmbeddedDocuments(
- documentType,
- documentData.updates,
- documentData.options
- );
- debug(
- `Flags set for documents of type "${documentType}" in scene with ID "${sceneId}"`
- );
- }
- }
- await Actor.updateDocuments(
- Object.entries(actorUpdates).map(([actorId, effects]) => ({
- _id: actorId,
- [CONSTANTS.EFFECTS_FLAG]: effects
- }))
- );
- }, 250)
- };
- const PositionContainer = /* @__PURE__ */ new Map();
- const TemporaryPositionsContainer = /* @__PURE__ */ new Map();
- class SequencerEffectManager {
- /**
- * Returns all of the currently running effects on the canvas
- *
- * @returns {Array}
- */
- static get effects() {
- return Array.from(SequenceManager.VisibleEffects.values());
- }
- static _updatePosition(uuid, position) {
- TemporaryPositionsContainer.set(uuid, position);
- }
- static getPositionForUUID(uuid) {
- return TemporaryPositionsContainer.get(uuid);
- }
- /**
- * Opens the Sequencer Effects UI with the effects tab open
- */
- static show() {
- return EffectsUIApp.show({ tab: "manager" });
- }
- /**
- * Play an effect on the canvas.
- *
- * @param {object} data The data that describes the audio to play
- * @param {boolean} [push=true] A flag indicating whether or not to make other clients play the effect
- * @returns {CanvasEffect} A CanvasEffect object
- */
- static async play(data, push = true) {
- if (!user_can_do("permissions-effect-create")) {
- custom_warning(
- "Sequencer",
- "EffectManager | play | Players do not have permissions to play effects. This can be configured in Sequencer's module settings."
- );
- return;
- }
- if (push)
- sequencerSocket.executeForOthers(SOCKET_HANDLERS.PLAY_EFFECT, data);
- if (data?.persistOptions?.persistTokenPrototype) {
- this._playPrototypeTokenEffects(data, push);
- }
- return this._playEffect(data);
- }
- /**
- * Get effects that are playing on the canvas based on a set of filters
- *
- * @param {object} inFilter An object containing filters that determine which effects to return
- * - object: An ID or a PlaceableObject
- * - name: The name of the effect
- * - sceneId: the ID of the scene to search within
- * @returns {Array} An array containing effects that match the given filter
- */
- static getEffects(inFilter = {}) {
- const filters2 = this._validateFilters(inFilter);
- if (!inFilter)
- throw custom_error(
- "Sequencer",
- "EffectManager | getEffects | Incorrect or incomplete parameters provided"
- );
- return this._filterEffects(filters2);
- }
- /**
- * Updates effects based on a set of filters
- *
- * @param {object} inFilter An object containing filters that determine which effects to return
- * - object: An ID or a PlaceableObject
- * - name: The name of the effect
- * - sceneId: the ID of the scene to search within
- * - effects: a single CanvasEffect or its ID, or an array of such
- * @param {object} inUpdates
- * @returns {promise}
- */
- static updateEffects(inFilter, inUpdates) {
- inFilter = this._validateFilters(inFilter);
- if (!inFilter)
- throw custom_error(
- "Sequencer",
- "EffectManager | updateEffects | Incorrect or incomplete parameters provided"
- );
- CanvasEffect.validateUpdate(inUpdates);
- const effectsToUpdate = this._filterEffects(inFilter).filter(
- (effect) => effect.userCanUpdate
- );
- return Promise.allSettled(
- effectsToUpdate.map((effect) => effect.update(inUpdates))
- );
- }
- /**
- * End effects that are playing on the canvas based on a set of filters
- *
- * @param {object} inFilter An object containing filters that determine which effects to end
- * - object: An ID or a PlaceableObject
- * - name: The name of the effect
- * - sceneId: the ID of the scene to search within
- * - effects: a single CanvasEffect or its ID, or an array of such
- * @param {boolean} [push=true] A flag indicating whether or not to make other clients end the effects
- * @returns {promise} A promise that resolves when the effects have ended
- */
- static async endEffects(inFilter = {}, push = true) {
- inFilter = this._validateFilters(inFilter);
- if (!inFilter)
- throw custom_error(
- "Sequencer",
- "EffectManager | endEffects | Incorrect or incomplete parameters provided"
- );
- const effectsToEnd = this._getEffectsByFilter(inFilter);
- if (!effectsToEnd.length)
- return;
- if (push)
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.END_EFFECTS,
- effectsToEnd
- );
- return this._endManyEffects(effectsToEnd);
- }
- /**
- * End all effects that are playing on the canvas
- *
- * @param {string} [inSceneId] A parameter which determines which scene to end all effects on, defaults to current viewed scene
- * @param {boolean} [push=true] A flag indicating whether or not to make other clients end all effects
- * @returns {promise} A promise that resolves when all of the effects have _ended
- */
- static async endAllEffects(inSceneId = game.user.viewedScene, push = true) {
- const inFilter = this._validateFilters({ sceneId: inSceneId });
- if (!inFilter)
- throw custom_error(
- "Sequencer",
- "EffectManager | endAllEffects | Incorrect or incomplete parameters provided"
- );
- const effectsToEnd = this._getEffectsByFilter(inFilter);
- if (!effectsToEnd.length)
- return;
- if (push)
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.END_EFFECTS,
- effectsToEnd
- );
- return this._endManyEffects(effectsToEnd);
- }
- static _getEffectsByFilter(inFilter) {
- return make_array_unique(
- this._filterEffects(inFilter).filter((effect) => effect.userCanDelete).map((effect) => {
- return effect.data?.persistOptions?.persistTokenPrototype ? effect.data?.persistOptions?.id ?? effect.id : effect.id;
- })
- );
- }
- /**
- * If an effect has been named its position will be cached, which can be retrieved with this method
- *
- * @param {string} inName
- * @returns {object|boolean}
- * @private
- */
- static getEffectPositionByName(inName) {
- if (!(typeof inName === "string"))
- throw custom_error(
- "Sequencer",
- "EffectManager | getEffectPositionByName | inName must be of type string"
- );
- return PositionContainer.get(inName) ?? false;
- }
- /**
- * Filters the existing effects based on the given filter
- *
- * @param inFilter
- * @returns {array}
- * @private
- */
- static _filterEffects(inFilter) {
- if (inFilter.name) {
- inFilter.name = new RegExp(
- str_to_search_regex_str(safe_str(inFilter.name)),
- "gu"
- );
- }
- let effects = this.effects;
- if (inFilter.sceneId && inFilter.sceneId !== canvas.scene.id) {
- effects = get_all_documents_from_scene(inFilter.sceneId).map((doc) => {
- return getProperty(doc, CONSTANTS.EFFECTS_FLAG);
- }).filter((flags) => !!flags).map((flags) => {
- return flags.map((flag) => CanvasEffect.make(flag[1]));
- }).deepFlatten();
- }
- return effects.filter((effect) => {
- return (!inFilter.effects || inFilter.effects.includes(effect.id)) && (!inFilter.name || effect.data.name && effect.data.name.match(inFilter.name)?.length) && (!inFilter.source || inFilter.source === effect.data.source) && (!inFilter.target || inFilter.target === effect.data.target) && (!inFilter.origin || inFilter.origin === effect.data.origin);
- });
- }
- /**
- * Validates an object actually exists, and gets its UUID
- *
- * @param object
- * @param sceneId
- * @returns {string}
- * @private
- */
- static _validateObject(object, sceneId) {
- if (!(object instanceof foundry.abstract.Document || object instanceof PlaceableObject || typeof object === "string")) {
- throw custom_error(
- "Sequencer",
- "EffectManager | object must be instance of PlaceableObject or of type string"
- );
- } else if (object instanceof PlaceableObject || object instanceof foundry.abstract.Document) {
- object = get_object_identifier(object?.document ?? object);
- } else if (typeof object === "string") {
- const actualObject = get_object_from_scene(object, sceneId);
- if (!actualObject) {
- throw custom_error(
- "Sequencer",
- `EffectManager | could not find object with ID: ${object}`
- );
- }
- const uuid = get_object_identifier(actualObject);
- if (!uuid) {
- throw custom_error(
- "Sequencer",
- `EffectManager | could could not establish identifier of object with ID: ${object}`
- );
- }
- object = uuid;
- }
- return object;
- }
- /**
- * Validates the filter given to any of the above public methods
- *
- * @param inFilter
- * @returns {boolean}
- * @private
- */
- static _validateFilters(inFilter) {
- if (inFilter?.sceneId) {
- if (typeof inFilter.sceneId !== "string")
- throw custom_error(
- "Sequencer",
- "EffectManager | inFilter.sceneId must be of type string"
- );
- if (!game.scenes.get(inFilter.sceneId))
- throw custom_error(
- "Sequencer",
- "EffectManager | inFilter.sceneId must be a valid scene id (could not find scene)"
- );
- } else {
- inFilter.sceneId = game.user.viewedScene;
- }
- if (inFilter?.object) {
- inFilter.source = this._validateObject(inFilter.object, inFilter.sceneId);
- delete inFilter.object;
- }
- if (inFilter?.source) {
- inFilter.source = this._validateObject(inFilter.source, inFilter.sceneId);
- }
- if (inFilter?.target) {
- inFilter.target = this._validateObject(inFilter.target, inFilter.sceneId);
- }
- if (inFilter?.name && typeof inFilter?.name !== "string")
- throw custom_error(
- "Sequencer",
- "EffectManager | inFilter.name must be of type string"
- );
- if (inFilter?.origin && typeof inFilter?.origin !== "string")
- throw custom_error(
- "Sequencer",
- "EffectManager | inFilter.origin must be of type string"
- );
- if (inFilter?.effects) {
- if (!Array.isArray(inFilter.effects))
- inFilter.effects = [inFilter.effects];
- inFilter.effects = inFilter.effects.map((effect) => {
- if (!(typeof effect === "string" || effect instanceof CanvasEffect))
- throw custom_error(
- "Sequencer",
- "EffectManager | collections in inFilter.effects must be of type string or CanvasEffect"
- );
- if (effect instanceof CanvasEffect)
- return effect.id;
- return effect;
- });
- }
- if (!inFilter.name && !inFilter.origin && !inFilter.target && !inFilter.sceneId && !inFilter.effects && !inFilter.origin)
- return false;
- return foundry.utils.mergeObject(
- {
- effects: false,
- name: false,
- source: false,
- target: false,
- sceneId: false,
- origin: false
- },
- inFilter
- );
- }
- /**
- * Actually plays the effect on the canvas
- *
- * @param data
- * @param setFlags
- * @returns {Promise<{duration: Promise<number>, promise: Promise<void>}>}
- * @private
- */
- static async _playEffect(data, setFlags = true) {
- const effect = CanvasEffect.make(data);
- if (data.persist && setFlags && effect.context && effect.owner && !data.temporary && !data.remote) {
- flagManager.addFlags(effect.context.uuid, effect.data);
- }
- if (!effect.shouldPlay)
- return;
- const playData = effect.play();
- SequenceManager.VisibleEffects.add(effect.id, effect);
- if (effect.data.name) {
- effect._ticker.add(() => {
- if (effect.isDestroyed)
- return;
- PositionContainer.set(effect.data.name, {
- start: effect.sourcePosition,
- end: effect.targetPosition
- });
- });
- }
- if (data.temporary && effect.owner) {
- let lastSourcePosition = {};
- let lastTargetPosition = {};
- effect._ticker.add(() => {
- if (effect.source && !effect.isSourceDestroyed) {
- const sourceData = effect.getSourceData();
- if (JSON.stringify(sourceData) !== lastSourcePosition) {
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.UPDATE_POSITION,
- data.source,
- sourceData
- );
- lastSourcePosition = JSON.stringify(sourceData);
- }
- }
- if (effect.target && !effect.isTargetDestroyed) {
- const targetData = effect.getTargetData();
- if (JSON.stringify(targetData) !== lastTargetPosition) {
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.UPDATE_POSITION,
- data.target,
- targetData
- );
- lastTargetPosition = JSON.stringify(targetData);
- }
- }
- });
- }
- if (!data.persist) {
- playData.promise.then(() => this._removeEffect(effect));
- }
- return playData;
- }
- /**
- * Updates a single effect with the given data
- *
- * @param inEffectId
- * @param inUpdates
- * @returns {promise|boolean}
- * @private
- */
- static _updateEffect(inEffectId, inUpdates) {
- const effect = SequenceManager.VisibleEffects.get(inEffectId);
- if (!effect)
- return false;
- return effect._update(inUpdates);
- }
- /**
- * Updates a single effect with new animations
- *
- * @param inEffectId
- * @param inAnimations
- * @param inLoopingAnimations
- * @returns {promise|boolean}
- * @private
- */
- static _addEffectAnimations(inEffectId, inAnimations, inLoopingAnimations) {
- const effect = SequenceManager.VisibleEffects.get(inEffectId);
- if (!effect)
- return false;
- return effect._addAnimations(inAnimations, inLoopingAnimations);
- }
- /**
- * Sets up persisting effects when the scene is first loaded
- *
- * @returns {promise}
- */
- static async initializePersistentEffects() {
- await this.tearDownPersists();
- const allObjects = get_all_documents_from_scene();
- allObjects.push(canvas.scene);
- const docEffectsMap = allObjects.reduce((acc, doc) => {
- let effects = flagManager.getFlags(doc);
- effects.forEach((e) => {
- if (is_UUID(e[1].source) && e[1].source !== doc.uuid) {
- e[1].delete = true;
- }
- });
- if (doc instanceof TokenDocument && doc?.actorLink) {
- const actorEffects = flagManager.getFlags(doc?.actor);
- actorEffects.forEach((e) => {
- e[1]._id = randomID();
- e[1].source = doc.uuid;
- e[1].sceneId = doc.parent.id;
- });
- effects = effects.concat(actorEffects);
- }
- if (effects.length) {
- acc[doc.uuid] = effects;
- }
- return acc;
- }, {});
- const promises = Object.entries(docEffectsMap).map(([uuid, effects]) => {
- return this._playEffectMap(effects, fromUuidSync(uuid));
- }).flat();
- return Promise.all(promises).then(() => {
- Hooks.callAll("sequencerEffectManagerReady");
- });
- }
- /**
- * Tears down persisting effects when the scene is unloaded
- */
- static tearDownPersists() {
- return Promise.allSettled(
- this.effects.map((effect) => {
- SequenceManager.VisibleEffects.delete(effect.id);
- return effect.destroy();
- })
- );
- }
- static setup() {
- Hooks.on("preCreateToken", this._patchCreationData.bind(this));
- Hooks.on("preCreateDrawing", this._patchCreationData.bind(this));
- Hooks.on("preCreateTile", this._patchCreationData.bind(this));
- Hooks.on("preCreateMeasuredTemplate", this._patchCreationData.bind(this));
- Hooks.on("createToken", this._documentCreated.bind(this));
- Hooks.on("createDrawing", this._documentCreated.bind(this));
- Hooks.on("createTile", this._documentCreated.bind(this));
- Hooks.on("createMeasuredTemplate", this._documentCreated.bind(this));
- }
- /**
- * Patches an object's creation data before it's created so that the effect plays on it correctly
- *
- * @param inDocument
- * @param data
- * @param options
- * @returns {*}
- */
- static async _patchCreationData(inDocument, data, options) {
- const effects = flagManager.getFlags(inDocument);
- if (!effects?.length)
- return;
- const updates = {};
- let documentUuid;
- if (!inDocument._id) {
- const documentId = randomID();
- documentUuid = inDocument.uuid + documentId;
- updates["_id"] = documentId;
- options.keepId = true;
- } else {
- documentUuid = inDocument.uuid;
- }
- updates[CONSTANTS.EFFECTS_FLAG] = this._patchEffectDataForDocument(
- documentUuid,
- effects
- );
- return inDocument.updateSource(updates);
- }
- static _patchEffectDataForDocument(inDocumentUuid, effects) {
- return effects.map((effect) => {
- effect[0] = randomID();
- const effectData = effect[1];
- effectData._id = effect[0];
- if (is_UUID(effectData.source)) {
- if (effectData.masks.includes(effectData.source)) {
- const index = effectData.masks.indexOf(effectData.source);
- effectData.masks[index] = inDocumentUuid;
- }
- effectData.source = inDocumentUuid;
- }
- effectData.sceneId = inDocumentUuid.split(".")[1];
- return effect;
- });
- }
- /**
- * Plays the effects of a given document on creation
- *
- * @param inDocument
- * @returns {*}
- */
- static async _documentCreated(inDocument) {
- let effects = flagManager.getFlags(inDocument);
- if (inDocument instanceof TokenDocument && inDocument?.actorLink) {
- let actorEffects = flagManager.getFlags(inDocument.actor);
- if (actorEffects.length) {
- actorEffects = this._patchEffectDataForDocument(
- inDocument.uuid,
- actorEffects
- );
- }
- effects = effects.concat(actorEffects);
- }
- if (!effects?.length)
- return;
- return this._playEffectMap(effects, inDocument);
- }
- /**
- * Plays multiple effects at the same time
- *
- * @param inEffects
- * @param inDocument
- * @returns {Promise<{duration: Promise<number>, promise: Promise<void>}[]>}
- * @private
- */
- static _playEffectMap(inEffects, inDocument) {
- if (inEffects instanceof Map)
- inEffects = Array.from(inEffects);
- return Promise.all(
- inEffects.map((effect) => {
- if (!CanvasEffect.checkValid(effect[1])) {
- if (!game.user.isGM)
- return;
- custom_warning(
- `Sequencer`,
- `Removed effect from ${inDocument.uuid} as it no longer had a valid source or target`
- );
- return flagManager.removeFlags(inDocument.uuid, effect);
- }
- return this._playEffect(effect[1], false).then((result) => {
- if (!result) {
- debug("Error playing effect");
- }
- }).catch((err) => {
- debug("Error playing effect:", err);
- });
- })
- );
- }
- /**
- * Ends one or many effects at the same time, returning a promise that resolves once every effect has fully ended
- *
- * @param inEffectIds
- * @returns {Promise}
- * @private
- */
- static async _endManyEffects(inEffectIds = false) {
- const actorEffectsToEnd = this.effects.filter((effect) => {
- return effect.context?.actorLink && inEffectIds.includes(effect.data?.persistOptions?.id);
- });
- const effectsByActorUuid = Object.values(
- group_by(actorEffectsToEnd, "context.actor.uuid")
- );
- const regularEffectsToEnd = this.effects.filter((effect) => {
- return inEffectIds.includes(effect.id) || !effect.context?.actorLink && inEffectIds.includes(effect.data?.persistOptions?.id);
- });
- const effectsByContextUuid = Object.values(
- group_by(regularEffectsToEnd, "context.uuid")
- );
- effectsByContextUuid.forEach((effects) => {
- effects = effects.filter(
- (effect) => effect.data.persist && !effect.data.temporary
- );
- if (!effects.length)
- return;
- const effectData = effects.map((effect) => effect.data);
- flagManager.removeFlags(
- effects[0].context.uuid,
- effectData,
- !inEffectIds
- );
- });
- effectsByActorUuid.forEach((effects) => {
- effects = effects.filter(
- (effect) => effect.data.persist && !effect.data.temporary
- );
- if (!effects.length)
- return;
- const effectContext = effects[0].context;
- const effectData = effects.map((effect) => effect.data);
- if (!(effectContext instanceof TokenDocument && effectContext.actorLink && effectContext.actor.prototypeToken.actorLink)) {
- return;
- }
- const persistentEffectData = effectData.filter(
- (data) => data?.persistOptions?.persistTokenPrototype
- );
- if (!persistentEffectData.length)
- return;
- const actorEffects = flagManager.getFlags(effectContext.actor);
- const applicableActorEffects = actorEffects.filter((effect) => {
- return effect[1]?.persistOptions?.persistTokenPrototype && persistentEffectData.some(
- (persistentEffect) => persistentEffect.persistOptions.id === effect[1]?.persistOptions?.id
- );
- }).map((e) => e[0]);
- flagManager.removeFlags(
- effectContext.actor.uuid,
- applicableActorEffects,
- !inEffectIds
- );
- });
- const effectsToEnd = effectsByContextUuid.concat(effectsByActorUuid).deepFlatten();
- return Promise.allSettled(
- effectsToEnd.map((effect) => this._removeEffect(effect))
- );
- }
- static _effectContextFilter(inUUID, effectData) {
- return effectData?.source === inUUID || effectData?.target === inUUID || (effectData?.tiedDocuments ?? []).indexOf(inUUID) > -1;
- }
- /**
- * Handles the deletion of objects that effects are attached to
- *
- * @param inUUID
- * @returns {Promise}
- */
- static objectDeleted(inUUID) {
- const documentsToCheck = game.scenes.filter((scene) => scene.id !== game.user.viewedScene).map((scene) => [scene, ...get_all_documents_from_scene(scene.id)]).deepFlatten();
- const documentEffectsToEnd = documentsToCheck.map((obj) => {
- const objEffects = flagManager.getFlags(obj);
- const effectsToEnd = objEffects.filter(
- ([effectId, effectData]) => this._effectContextFilter(inUUID, effectData)
- );
- return {
- document: obj,
- effects: effectsToEnd.map((effect) => effect[0])
- };
- }).filter((obj) => obj.effects.length);
- const visibleEffectsToEnd = this.effects.filter((effect) => this._effectContextFilter(inUUID, effect.data)).map((e) => e.id);
- return Promise.allSettled([
- this._endManyEffects(visibleEffectsToEnd),
- ...documentEffectsToEnd.map((obj) => {
- return flagManager.removeFlags(obj.document.uuid, obj.effects);
- })
- ]);
- }
- /**
- * Removes the effect from the manager and ends it, returning a promise that resolves once the effect has fully _ended
- *
- * @param effect
- * @returns {Promise}
- * @private
- */
- static _removeEffect(effect) {
- SequenceManager.VisibleEffects.delete(effect.id);
- TemporaryPositionsContainer.delete(effect.data.source);
- TemporaryPositionsContainer.delete(effect.data.target);
- return effect.endEffect();
- }
- static async _playPrototypeTokenEffects(data, push) {
- if (!is_UUID(data.source))
- return;
- const object = fromUuidSync(data.source);
- if (!(object instanceof TokenDocument))
- return;
- const tokenEffectsToPlay = game.scenes.map(
- (scene) => scene.tokens.filter((token) => {
- return token.actorLink && token.actor === object.actor && token !== object;
- })
- ).deepFlatten();
- for (const tokenDocument of tokenEffectsToPlay) {
- const duplicatedData = foundry.utils.deepClone(data);
- duplicatedData._id = randomID();
- duplicatedData.sceneId = tokenDocument.uuid.split(".")[1];
- duplicatedData.masks = duplicatedData.masks.map((uuid) => uuid.replace(duplicatedData.source, tokenDocument.uuid)).filter((uuid) => uuid.includes(duplicatedData.sceneId));
- duplicatedData.source = tokenDocument.uuid;
- if (CanvasEffect.checkValid(duplicatedData)) {
- if (push)
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.PLAY_EFFECT,
- duplicatedData
- );
- if (duplicatedData.sceneId === game.user.viewedScene) {
- await this._playEffect(duplicatedData, false);
- }
- }
- }
- }
- }
- class BaseEffectsLayer extends InteractionLayer {
- static get layerOptions() {
- return foundry.utils.mergeObject(super.layerOptions, {
- elevation: 1e8,
- name: "sequencerEffects"
- });
- }
- }
- class SequencerInterfaceLayer extends InteractionLayer {
- constructor(...args) {
- super(...args);
- }
- static get layerOptions() {
- return foundry.utils.mergeObject(super.layerOptions, {
- elevation: 1e8,
- name: "sequencerInterfaceEffects"
- });
- }
- deactivate() {
- super.deactivate();
- if (!this.active)
- return;
- this._clearChildren();
- this.active = false;
- InteractionManager.tearDown();
- }
- _setup() {
- if (!this.UIContainer || this.UIContainer._destroyed) {
- this.UIContainer = new PIXI.Container();
- this.UIContainer.sortableChildren = true;
- this.UIContainer.parentName = "sequencerUIContainer";
- this.UIContainer.zIndex = 1e13;
- this.addChild(this.UIContainer);
- this.linePoint = this.UIContainer.addChild(new PIXI.Graphics());
- this.line = this.UIContainer.addChild(new PIXI.Graphics());
- this.lineHead = this.UIContainer.addChild(new PIXI.Graphics());
- this.suggestionPoint = this.UIContainer.addChild(new PIXI.Graphics());
- this.effectHoverBoxes = this.UIContainer.addChild(new PIXI.Graphics());
- this.effectSelectionBorder = this.UIContainer.addChild(
- new PIXI.Graphics()
- );
- this.effectSourcePosition = this.UIContainer.addChild(
- new PIXI.Graphics()
- );
- this.effectTargetPosition = this.UIContainer.addChild(
- new PIXI.Graphics()
- );
- this.suggestionPoint.filters = [new PIXI.filters.AlphaFilter(0.75)];
- this.effectSourcePosition.filters = [new PIXI.filters.AlphaFilter(0.75)];
- this.effectTargetPosition.filters = [new PIXI.filters.AlphaFilter(0.75)];
- this.effectSelectionBorder.zIndex = 1;
- this.effectSourcePosition.interactive = true;
- this.effectSourcePosition.on("mousedown", () => {
- SelectionManager.sourcePointSelected();
- });
- this.effectTargetPosition.interactive = true;
- this.effectTargetPosition.on("mousedown", () => {
- SelectionManager.targetPointSelected();
- });
- }
- }
- async _draw(...args) {
- }
- render(...args) {
- super.render(...args);
- this._setup();
- this._clearChildren();
- this._drawHoveredEffectElements();
- if (!this.active)
- return;
- this._drawLine();
- this._drawPoints();
- this._drawSelectedEffectElements();
- this._drawSuggestionPoint();
- }
- _clearChildren() {
- if (!this.UIContainer)
- return;
- this.UIContainer.children.forEach((child) => {
- child.clear();
- });
- }
- _drawLine() {
- if (!EffectPlayer.startPos || !EffectPlayer.endPos || game?.activeTool !== "play-effect")
- return;
- this.line.lineStyle(3, CONSTANTS.COLOR.PRIMARY, 1);
- this.line.moveTo(EffectPlayer.startPos.x, EffectPlayer.startPos.y);
- this.line.lineTo(EffectPlayer.endPos.x, EffectPlayer.endPos.y);
- }
- _drawPoints() {
- if (game?.activeTool !== "play-effect")
- return;
- const startPos = EffectPlayer.startPos || EffectPlayer.cursorPos;
- this.linePoint.beginFill(CONSTANTS.COLOR.PRIMARY);
- this.linePoint.drawCircle(startPos.x, startPos.y, 5);
- if (EffectPlayer.sourceAttachFound) {
- this._drawCrossAtLocation(this.linePoint, startPos);
- }
- if (!EffectPlayer.endPos)
- return;
- const angle = new Ray(startPos, EffectPlayer.endPos).angle;
- this.lineHead.beginFill(CONSTANTS.COLOR.PRIMARY);
- this.lineHead.moveTo(0, -5);
- this.lineHead.lineTo(-15, 30);
- this.lineHead.lineTo(15, 30);
- this.lineHead.endFill();
- this.lineHead.rotation = angle + Math.PI / 2;
- this.lineHead.position.set(EffectPlayer.endPos.x, EffectPlayer.endPos.y);
- if (EffectPlayer.targetAttachFound) {
- this.linePoint.beginFill(CONSTANTS.COLOR.SECONDARY);
- this._drawCrossAtLocation(this.linePoint, EffectPlayer.endPos);
- }
- }
- _drawHoveredEffectElements() {
- const effects = new Set(SelectionManager.hoveredEffects);
- if (SelectionManager.hoveredEffectUI)
- effects.add(SelectionManager.hoveredEffectUI);
- for (const effect of effects) {
- if (!effect || effect === SelectionManager.selectedEffect || effect.data.screenSpace || effect._isEnding)
- continue;
- this._drawBoxAroundEffect(this.effectHoverBoxes, effect);
- }
- }
- _drawSelectedEffectElements() {
- if (!SelectionManager.selectedEffect)
- return;
- this._drawBoxAroundEffect(
- this.effectSelectionBorder,
- SelectionManager.selectedEffect,
- true
- );
- this._drawEffectStartEndPoints(SelectionManager.selectedEffect);
- }
- _drawBoxAroundEffect(graphic, effect, selected = false) {
- if (!effect || effect._destroyed || !effect.spriteContainer || !effect.ready)
- return;
- graphic.lineStyle(3, selected ? CONSTANTS.COLOR.PRIMARY : 16777215, 0.9);
- let boundingBox = effect.sprite.getLocalBounds();
- let dimensions = {
- x: effect.position.x + boundingBox.x * effect.sprite.scale.x,
- y: effect.position.y + boundingBox.y * effect.sprite.scale.y,
- width: boundingBox.width * effect.sprite.scale.x,
- height: boundingBox.height * effect.sprite.scale.y
- };
- if (effect.data.shapes.length) {
- for (const shape of Object.values(effect.shapes)) {
- boundingBox = shape.getLocalBounds();
- dimensions = {
- x: Math.min(
- dimensions.x,
- effect.position.x + boundingBox.x * shape.scale.x
- ),
- y: Math.min(
- dimensions.y,
- effect.position.y + boundingBox.y * shape.scale.y
- ),
- width: Math.max(dimensions.width, boundingBox.width * shape.scale.x),
- height: Math.max(
- dimensions.height,
- boundingBox.height * shape.scale.y
- )
- };
- }
- }
- const rotation2 = Math.normalizeRadians(
- effect.rotationContainer.rotation + effect.spriteContainer.rotation + effect.sprite.rotation
- );
- this._drawRectangle(graphic, effect.position, rotation2, dimensions);
- }
- _drawRectangle(graphic, position, rotation2, dimensions) {
- graphic.moveTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x,
- y: dimensions.y
- },
- -rotation2
- )
- );
- graphic.lineTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x + dimensions.width,
- y: dimensions.y
- },
- -rotation2
- )
- );
- graphic.lineTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x + dimensions.width,
- y: dimensions.y + dimensions.height
- },
- -rotation2
- )
- );
- graphic.lineTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x,
- y: dimensions.y + dimensions.height
- },
- -rotation2
- )
- );
- graphic.lineTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x,
- y: dimensions.y
- },
- -rotation2
- )
- );
- graphic.lineTo(
- ...rotate_coordinate(
- position,
- {
- x: dimensions.x + dimensions.width,
- y: dimensions.y
- },
- -rotation2
- )
- );
- }
- /**
- * Draws the start/end point circles
- * @private
- */
- _drawEffectStartEndPoints(effect) {
- if (!effect || effect._destroyed || !effect.spriteContainer)
- return;
- if (!effect.data.stretchTo || !effect.sourcePosition || !effect.targetPosition)
- return;
- this.effectSourcePosition.beginFill(CONSTANTS.COLOR.PRIMARY);
- this.effectSourcePosition.drawCircle(
- effect.sourcePosition.x,
- effect.sourcePosition.y,
- canvas.grid.size * 0.25
- );
- if (typeof effect.data.source === "string") {
- this._drawCrossAtLocation(
- this.effectSourcePosition,
- effect.sourcePosition
- );
- }
- this.effectTargetPosition.beginFill(CONSTANTS.COLOR.SECONDARY);
- this.effectTargetPosition.drawCircle(
- effect.targetPosition.x,
- effect.targetPosition.y,
- canvas.grid.size * 0.25
- );
- this.effectTargetPosition.alpha = 0.75;
- if (typeof effect.data.target === "string") {
- this._drawCrossAtLocation(
- this.effectTargetPosition,
- effect.targetPosition
- );
- }
- }
- _drawSuggestionPoint() {
- if (!SelectionManager.suggestedProperties || !SelectionManager.selectedEffect)
- return;
- const effect = SelectionManager.selectedEffect;
- const suggestion = SelectionManager.suggestedProperties;
- this.suggestionPoint.position.set(0, 0);
- this.suggestionPoint.rotation = 0;
- if (effect.data.stretchTo) {
- this.suggestionPoint.beginFill(suggestion.color);
- this.suggestionPoint.drawCircle(
- suggestion.position.x,
- suggestion.position.y,
- canvas.grid.size * 0.25
- );
- if (suggestion.showCursor) {
- this._drawCrossAtLocation(this.suggestionPoint, suggestion.position);
- }
- return;
- }
- const boundingBox = effect.spriteContainer.getLocalBounds();
- const dimensions = {
- x: boundingBox.x * effect.scale.x,
- y: boundingBox.y * effect.scale.y,
- width: boundingBox.width * effect.scale.x,
- height: boundingBox.height * effect.scale.y
- };
- this.suggestionPoint.lineStyle(3, CONSTANTS.COLOR.PRIMARY, 0.9);
- this.suggestionPoint.position.set(
- suggestion.position.x,
- suggestion.position.y
- );
- this._drawRectangle(
- this.suggestionPoint,
- suggestion.position,
- effect.rotation,
- dimensions,
- true
- );
- if (suggestion.showCursor) {
- this.suggestionPoint.beginFill(CONSTANTS.COLOR.SECONDARY);
- this._drawCrossAtLocation(this.suggestionPoint);
- }
- if (suggestion.showPoint) {
- this.suggestionPoint.drawCircle(0, 0, canvas.grid.size * 0.2);
- }
- }
- _drawCrossAtLocation(inElement, inPosition = { x: 0, y: 0 }) {
- inElement.drawRect(
- inPosition.x + canvas.grid.size * -0.05,
- inPosition.y + canvas.grid.size * -0.5,
- canvas.grid.size * 0.1,
- canvas.grid.size
- );
- inElement.drawRect(
- inPosition.x + canvas.grid.size * -0.5,
- inPosition.y + canvas.grid.size * -0.05,
- canvas.grid.size,
- canvas.grid.size * 0.1
- );
- }
- }
- class UIEffectsLayer extends InteractionLayer {
- static get layerOptions() {
- return foundry.utils.mergeObject(super.layerOptions, {
- zIndex: 999999999999999,
- name: "sequencerEffectsAboveEverything"
- });
- }
- updateTransform() {
- if (this.sortableChildren && this.sortDirty) {
- this.sortChildren();
- }
- this._boundsID++;
- this.transform.updateTransform(PIXI.Transform.IDENTITY);
- this.worldAlpha = this.alpha;
- for (let child of this.children) {
- if (child.visible) {
- child.updateTransform();
- }
- }
- }
- }
- let layer = false;
- class SequencerAboveUILayer {
- constructor(name, zIndex = 0.1) {
- this.canvas = document.createElement("canvas");
- this.canvas.id = name;
- this.canvas.style.cssText = `
- position:absolute;
- touch-action: none;
- pointer-events: none;
- width:100%;
- height:100%;
- z-index:${zIndex};
- padding: 0;
- margin: 0;
- `;
- document.body.appendChild(this.canvas);
- this.app = new PIXI.Application({
- width: window.innerWidth,
- height: window.innerHeight,
- view: this.canvas,
- antialias: true,
- backgroundAlpha: 0,
- sharedTicker: true
- });
- this.app.resizeTo = window;
- this.app.stage.renderable = false;
- }
- static setup() {
- if (!game.settings.get("sequencer", "enable-above-ui-screenspace"))
- return;
- layer = new this("sequencerUILayerAbove", 1e4);
- }
- static getLayer() {
- return layer ? layer.app.stage : canvas.uiEffectsLayer;
- }
- static addChild(...args) {
- const result = this.getLayer().addChild(...args);
- layer.app.stage.renderable = layer.app.stage.children.length > 0;
- return result;
- }
- static sortChildren() {
- return this.getLayer().sortChildren();
- }
- static removeContainerByEffect(inEffect) {
- const child = this.getLayer().children.find((child2) => child2 === inEffect);
- if (!child)
- return;
- this.getLayer().removeChild(child);
- layer.app.stage.renderable = layer.app.stage.children.length > 0;
- }
- updateTransform() {
- if (this.app.stage.sortableChildren && this.app.stage.sortDirty) {
- this.app.stage.sortChildren();
- }
- this.app.stage._boundsID++;
- this.app.stage.transform.updateTransform(PIXI.Transform.IDENTITY);
- this.app.stage.worldAlpha = this.app.stage.alpha;
- for (let child of this.app.stage.children) {
- if (child.visible) {
- child.updateTransform();
- }
- }
- }
- }
- class VisionSamplerShader extends BaseSamplerShader {
- /** @override */
- static classPluginName = null;
- /** @inheritdoc */
- static vertexShader = `
- precision ${PIXI.settings.PRECISION_VERTEX} float;
- attribute vec2 aVertexPosition;
- attribute vec2 aTextureCoord;
- uniform mat3 projectionMatrix;
- uniform vec2 screenDimensions;
- varying vec2 vUvsMask;
- varying vec2 vUvs;
- void main() {
- vUvs = aTextureCoord;
- vUvsMask = aVertexPosition / screenDimensions;
- gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- }
- `;
- /** @inheritdoc */
- static fragmentShader = `
- precision ${PIXI.settings.PRECISION_FRAGMENT} float;
- varying vec2 vUvs;
- varying vec2 vUvsMask;
- uniform vec4 tintAlpha;
- uniform sampler2D sampler;
- uniform sampler2D maskSampler;
- uniform bool enableVisionMasking;
- void main() {
- float mask = enableVisionMasking ? texture2D(maskSampler, vUvsMask).r : 1.0;
- gl_FragColor = texture2D(sampler, vUvs) * tintAlpha * mask;
- }
- `;
- /** @inheritdoc */
- static defaultUniforms = {
- tintAlpha: [1, 1, 1, 1],
- sampler: 0,
- maskSampler: 0,
- screenDimensions: [1, 1],
- enableVisionMasking: false
- };
- /** @override */
- _preRender(mesh) {
- super._preRender(mesh);
- this.uniforms.maskSampler = canvas.masks.vision.renderTexture;
- this.uniforms.screenDimensions = canvas.screenDimensions;
- this.uniforms.enableVisionMasking = canvas.effects.visibility.visible;
- }
- }
- class MaskFilter extends AbstractBaseFilter {
- /** @override */
- static fragmentShader = ` varying vec2 vTextureCoord;
-
- uniform sampler2D uSampler;
- uniform sampler2D uMaskSampler;
-
- void main(void) {
- gl_FragColor = texture2D(uSampler, vTextureCoord)
- * texture2D(uMaskSampler, vTextureCoord).a;
- }`;
- /** @override */
- static defaultUniforms = { uMaskSampler: null };
- /** @type {DisplayObject[]|null} */
- masks = [];
- /** @override */
- apply(filterManager, input, output, clearMode, currentState) {
- const maskFilterTexture = filterManager.getFilterTexture();
- const originalFilterTexture = this.#push(
- filterManager,
- currentState,
- maskFilterTexture
- );
- const renderer = filterManager.renderer;
- for (const mask of this.masks) {
- if (mask?.obj?.destroyed)
- continue;
- const renderable = mask.renderable;
- mask.renderable = true;
- mask.render(renderer);
- mask.renderable = renderable;
- }
- renderer.batch.flush();
- this.#pop(filterManager, currentState, originalFilterTexture);
- this.uniforms.uMaskSampler = maskFilterTexture;
- filterManager.applyFilter(this, input, output, clearMode);
- filterManager.returnFilterTexture(maskFilterTexture);
- }
- #push(filterManager, currentState, maskFilterTexture) {
- const originalFilterTexture = currentState.renderTexture;
- currentState.renderTexture = maskFilterTexture;
- filterManager.defaultFilterStack.push(currentState);
- filterManager.bindAndClear(maskFilterTexture);
- return originalFilterTexture;
- }
- #pop(filterManager, currentState, originalFilterTexture) {
- currentState.renderTexture = originalFilterTexture;
- filterManager.defaultFilterStack.pop();
- if (filterManager.activeState === currentState) {
- return;
- }
- filterManager.activeState = currentState;
- const globalUniforms = filterManager.globalUniforms.uniforms;
- globalUniforms.outputFrame = currentState.sourceFrame;
- globalUniforms.resolution = currentState.resolution;
- const inputSize = globalUniforms.inputSize;
- const inputPixel = globalUniforms.inputPixel;
- const inputClamp = globalUniforms.inputClamp;
- inputSize[0] = currentState.destinationFrame.width;
- inputSize[1] = currentState.destinationFrame.height;
- inputSize[2] = 1 / inputSize[0];
- inputSize[3] = 1 / inputSize[1];
- inputPixel[0] = Math.round(inputSize[0] * currentState.resolution);
- inputPixel[1] = Math.round(inputSize[1] * currentState.resolution);
- inputPixel[2] = 1 / inputPixel[0];
- inputPixel[3] = 1 / inputPixel[1];
- inputClamp[0] = 0.5 * inputPixel[2];
- inputClamp[1] = 0.5 * inputPixel[3];
- inputClamp[2] = currentState.sourceFrame.width * inputSize[2] - 0.5 * inputPixel[2];
- inputClamp[3] = currentState.sourceFrame.height * inputSize[3] - 0.5 * inputPixel[3];
- if (currentState.legacy) {
- const filterArea = globalUniforms.filterArea;
- filterArea[0] = currentState.destinationFrame.width;
- filterArea[1] = currentState.destinationFrame.height;
- filterArea[2] = currentState.sourceFrame.x;
- filterArea[3] = currentState.sourceFrame.y;
- globalUniforms.filterClamp = globalUniforms.inputClamp;
- }
- filterManager.globalUniforms.update();
- }
- }
- const hooksManager = {
- _hooks: /* @__PURE__ */ new Map(),
- _hooksRegistered: /* @__PURE__ */ new Set(),
- addHook(effectUuid, hookName, callable, callNow = false) {
- if (!this._hooksRegistered.has(hookName)) {
- debug("registering hook for: " + hookName);
- this._hooksRegistered.add(hookName);
- Hooks.on(hookName, (...args) => {
- this._hookCalled(hookName, ...args);
- });
- }
- const key = hookName + "-" + effectUuid;
- if (!this._hooks.has(key)) {
- this._hooks.set(key, []);
- }
- this._hooks.get(key).push(callable);
- if (callNow) {
- setTimeout(() => {
- callable();
- }, 20);
- }
- },
- _hookCalled(hookName, ...args) {
- Array.from(this._hooks).filter((entry) => entry[0].startsWith(hookName + "-")).map((hooks) => hooks[1]).deepFlatten().forEach((callback) => callback(...args));
- },
- removeHooks(effectUuid) {
- Array.from(this._hooks).filter((entry) => entry[0].endsWith("-" + effectUuid)).forEach((entry) => this._hooks.delete(entry[0]));
- }
- };
- class CanvasEffect extends PIXI.Container {
- #elevation = 0;
- #sort = 0;
- constructor(inData) {
- super();
- this.sortableChildren = true;
- this.actualCreationTime = +new Date();
- this.data = inData;
- this._resolve = null;
- this._durationResolve = null;
- this.ready = false;
- this._ended = false;
- this._isEnding = false;
- this._cachedSourceData = {};
- this._cachedTargetData = {};
- this.uuid = false;
- }
- static get protectedValues() {
- return [
- "_id",
- "sequenceId",
- "creationTimestamp",
- "creatorUserId",
- "moduleName",
- "index",
- "repetition",
- "moves",
- "fadeIn",
- "fadeOut",
- "scaleIn",
- "scaleOut",
- "rotateIn",
- "rotateOut",
- "fadeInAudio",
- "fadeOutAudio",
- "animations",
- "nameOffsetMap",
- "persist"
- ];
- }
- /** @type {number} */
- get elevation() {
- return this.#elevation;
- }
- set elevation(value) {
- this.#elevation = value;
- }
- /** @type {number} */
- get sort() {
- return this.#sort;
- }
- set sort(value) {
- this.#sort = value;
- }
- get context() {
- return this.data.attachTo?.active && this.sourceDocument ? this.sourceDocument : game.scenes.get(this.data.sceneId);
- }
- get isIsometricActive() {
- const sceneIsIsometric = getProperty(
- game.scenes.get(this.data.sceneId),
- CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED
- );
- return CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE && sceneIsIsometric;
- }
- /**
- * The ID of the effect
- *
- * @returns {string}
- */
- get id() {
- return this.data._id;
- }
- /**
- * Whether this effect is destroyed or is in the process of being destroyed
- */
- get isDestroyed() {
- return this.source && this.isSourceDestroyed || this.target && this.isTargetDestroyed;
- }
- /**
- * Whether the source of this effect is temporary
- *
- * @returns {boolean}
- */
- get isSourceTemporary() {
- return this.data.attachTo?.active && this.sourceDocument && !is_UUID(this.sourceDocument?.uuid);
- }
- /**
- * Whether the source of this effect has been destroyed
- *
- * @returns {boolean}
- */
- get isSourceDestroyed() {
- return this.source && (this.source?.destroyed || !this.sourceDocument?.object);
- }
- /**
- * Whether the target of this effect is temporary
- *
- * @returns {boolean}
- */
- get isTargetTemporary() {
- return (this.data.stretchTo?.attachTo || this.data.rotateTowards?.attachTo) && this.targetDocument && !is_UUID(this.targetDocument.uuid);
- }
- /**
- * Whether the target of this effect has been destroyed
- *
- * @returns {boolean}
- */
- get isTargetDestroyed() {
- return this.target && (this.target?.destroyed || !this.targetDocument?.object);
- }
- /**
- * The source object (or source location) of the effect
- *
- * @returns {boolean|object}
- */
- get source() {
- if (!this._source && this.data.source) {
- this._source = this._getObjectByID(this.data.source);
- this._source = this._source?._object ?? this._source;
- }
- return this._source;
- }
- /**
- * Retrieves the source document
- *
- * @returns {Document|PlaceableObject}
- */
- get sourceDocument() {
- return this.source?.document ?? this.source;
- }
- /**
- * Retrieves the PIXI object for the source object
- *
- * @returns {*|PIXI.Sprite|TileHUD<Application.Options>}
- */
- get sourceMesh() {
- return this.source?.mesh ?? this.source?.template;
- }
- /**
- * The source position with the relevant offsets calculated
- *
- * @returns {{x: number, y: number}}
- */
- get sourcePosition() {
- let position = this.getSourceData().position;
- let offset2 = this._getOffset(this.data.source, true);
- return {
- x: position.x - offset2.x,
- y: position.y - offset2.y
- };
- }
- /**
- * The target object (or target location) of the effect
- *
- * @returns {boolean|object}
- */
- get target() {
- if (!this._target && this.data.target) {
- this._target = this._getObjectByID(this.data.target);
- this._target = this._target?._object ?? this._target;
- }
- return this._target;
- }
- /**
- * Retrieves the document of the target
- *
- * @returns {Document|PlaceableObject}
- */
- get targetDocument() {
- return this.target?.document ?? this.target;
- }
- /**
- * Retrieves the PIXI object for the target object
- *
- * @returns {*|PIXI.Sprite|TileHUD<Application.Options>}
- */
- get targetMesh() {
- return this.target?.mesh ?? this.target?.template;
- }
- /**
- * The target position with the relevant offsets calculated
- *
- * @returns {{x: number, y: number}}
- */
- get targetPosition() {
- const position = this.getTargetData().position;
- const offset2 = this._getOffset(this.data.target);
- return {
- x: position.x - offset2.x,
- y: position.y - offset2.y
- };
- }
- /**
- * Returns this effect's world position
- *
- * @returns {{x: number, y: number}}
- */
- get worldPosition() {
- const t = canvas.stage.worldTransform;
- return {
- x: (this.sprite.worldTransform.tx - t.tx) / canvas.stage.scale.x,
- y: (this.sprite.worldTransform.ty - t.ty) / canvas.stage.scale.y
- };
- }
- /**
- * Whether the current user is the owner of this effect
- *
- * @returns {boolean}
- */
- get owner() {
- return this.data.creatorUserId === game.user.id;
- }
- /**
- * Whether the current user can update this effect
- *
- * @returns {boolean}
- */
- get userCanUpdate() {
- return game.user.isGM || this.owner || this.data.attachTo?.active && this.sourceDocument.canUserModify(game.user, "update");
- }
- /**
- * Whether the current user can delete this effect
- *
- * @returns {boolean}
- */
- get userCanDelete() {
- return this.userCanUpdate || user_can_do("permissions-effect-delete");
- }
- /**
- * Whether this effect is on the current scene
- *
- * @returns {boolean}
- */
- get onCurrentScene() {
- return this.data.sceneId === game.user.viewedScene;
- }
- /**
- * Whether this effect should be shown as faded or not - effects created by users for other users should be shown
- * for all
- *
- * @returns {boolean}
- */
- get shouldShowFadedVersion() {
- return this.data.users && this.data.users.length && !(this.data.users.length === 1 && this.data.users.includes(this.data.creatorUserId)) && !this.data.users.includes(game.userId);
- }
- /**
- * Getter for the current playing video of the effect
- *
- * @returns {null|*}
- */
- get video() {
- return this._video;
- }
- /**
- * Setter for the current playing video of the effect
- */
- set video(inVideo) {
- if (!inVideo)
- return;
- inVideo.playbackRate = this.data.playbackRate ? this.data.playbackRate : 1;
- inVideo.muted = !this.data.volume;
- inVideo.volume = (this.data.volume ?? 0) * game.settings.get("core", "globalInterfaceVolume");
- if (!this._video) {
- this._video = inVideo;
- return;
- }
- const isLooping = this._video?.loop;
- const currentTime = this._video.currentTime;
- this._video = inVideo;
- this._video.currentTime = this.playNaturally ? 0 : Math.min(currentTime, this._video.duration);
- this._video.loop = isLooping;
- this.updateTexture();
- }
- async playMedia() {
- if (this.animatedSprite) {
- await this.sprite.play();
- } else if (this.video) {
- try {
- await this.video.play().then(() => {
- this.updateTexture();
- });
- } catch (err) {
- }
- }
- this._setupTimestampHook(this.mediaCurrentTime * 1e3);
- }
- updateTexture() {
- if (this._texture.valid) {
- this._texture.update();
- }
- }
- async pauseMedia() {
- if (this.animatedSprite) {
- return this.sprite.stop();
- } else if (this.video) {
- return this.video.pause();
- }
- }
- get mediaLooping() {
- if (this.animatedSprite) {
- return this.sprite.loop;
- }
- return this.video?.loop ?? false;
- }
- set mediaLooping(looping) {
- if (this.animatedSprite) {
- this.sprite.loop = looping;
- return;
- }
- if (this.video) {
- this.video.loop = looping;
- }
- }
- get mediaIsPlaying() {
- if (this.animatedSprite) {
- return this.sprite.playing;
- }
- return this.video;
- }
- get mediaCurrentTime() {
- if (this.animatedSprite) {
- return this.sprite.currentFrame / this.sprite.totalFrames * (this.sprite.totalFrames / 24);
- }
- return this.video?.currentTime ?? null;
- }
- get mediaPlaybackRate() {
- if (this.animatedSprite) {
- return this.sprite.animationSpeed;
- } else if (this.video) {
- return this.video.playbackRate;
- }
- }
- set mediaPlaybackRate(inPlaybackRate) {
- if (this.animatedSprite) {
- this.sprite.animationSpeed = 0.4 * inPlaybackRate;
- } else if (this.video) {
- this.video.playbackRate = inPlaybackRate;
- }
- }
- set mediaCurrentTime(newTime) {
- if (this.animatedSprite) {
- const newFrame = Math.floor(newTime * this.sprite.totalFrames);
- const clampedFrame = Math.max(
- 0,
- Math.min(newFrame, this.sprite.totalFrames)
- );
- if (this.mediaIsPlaying) {
- this.sprite.gotoAndPlay(clampedFrame);
- } else {
- this.sprite.gotoAndStop(clampedFrame);
- }
- } else if (this.video) {
- this.video.currentTime = newTime;
- }
- }
- get mediaDuration() {
- if (this.animatedSprite) {
- return this.sprite.totalFrames / this.sprite.animationSpeed / PIXI.Ticker.shared.FPS;
- } else if (this.video) {
- return this.video?.duration / this.mediaPlaybackRate;
- }
- return 1;
- }
- get hasAnimatedMedia() {
- return !!(this.video || this.animatedSprite);
- }
- /**
- * The template of the effect, determining the effect's internal grid size, and start/end padding
- *
- * @returns {object}
- */
- get template() {
- return foundry.utils.mergeObject(
- {
- gridSize: 100,
- startPoint: 0,
- endPoint: 0
- },
- this._template ?? {}
- );
- }
- /**
- * The grid size difference between the internal effect's grid vs the grid on the canvas. If the effect is in screen space, we ignore this.
- *
- * @returns {number}
- */
- get gridSizeDifference() {
- return canvas.grid.size / this.template.gridSize;
- }
- /**
- * Whether the effect should be flipped on any given axis
- *
- * @returns {number}
- */
- get flipX() {
- return this.data.flipX ? -1 : 1;
- }
- get flipY() {
- return this.data.flipY ? -1 : 1;
- }
- /**
- * Whether this effect should play at all, depending on a multitude of factors
- *
- * @returns {boolean}
- */
- get shouldPlay() {
- return (game.user.viewedScene === this.data.sceneId || this.data.creatorUserId === game.userId) && (game.user.isGM || !this.data.users || this.data.users.length === 0 || this.data.users.includes(game.userId));
- }
- get shouldPlayVisible() {
- let playVisible = this.shouldPlay && game.settings.get("sequencer", "effectsEnabled") && game.user.viewedScene === this.data.sceneId;
- if (isNewerVersion(game.version, "10.289") && game.settings.get("core", "photosensitiveMode")) {
- playVisible = false;
- throttled_custom_warning(
- this.data.moduleName,
- "Photosensitive Mode is turned on, so Sequencer's visual effects aren't being rendered"
- );
- }
- return playVisible;
- }
- /**
- * Whether this effect should play naturally, or be constrained to a subsection of the video
- *
- * @returns {boolean}
- */
- get playNaturally() {
- return (!this.data.time || this._startTime === 0 && this._endTime === this.mediaDuration) && this._animationTimes.loopStart === void 0 && this._animationTimes.loopEnd === void 0;
- }
- static make(inData) {
- return !inData.persist ? new CanvasEffect(inData) : new PersistentCanvasEffect(inData);
- }
- static checkValid(effectData) {
- if (effectData.delete) {
- return false;
- }
- let sourceExists = true;
- let targetExists = true;
- if (effectData.source && is_UUID(effectData.source)) {
- sourceExists = fromUuidSync(effectData.source);
- }
- if (effectData.target && is_UUID(effectData.target)) {
- targetExists = fromUuidSync(effectData.target);
- }
- for (let tiedDocumentUuid of effectData?.tiedDocuments ?? []) {
- if (tiedDocumentUuid && is_UUID(tiedDocumentUuid)) {
- let tiedDocumentExists = fromUuidSync(tiedDocumentUuid);
- if (!tiedDocumentExists)
- return false;
- }
- }
- if (effectData.source && is_UUID(effectData.source) && effectData.target && is_UUID(effectData.target)) {
- const sourceScene = effectData.source.split(".")[1];
- const targetScene = effectData.target.split(".")[1];
- if (sourceScene !== targetScene || sourceScene !== effectData.sceneId)
- return false;
- }
- return sourceExists && targetExists;
- }
- /**
- * Validates that the update contains the appropriate data
- *
- * @param inUpdates
- */
- static validateUpdate(inUpdates) {
- const updateKeys = Object.keys(inUpdates);
- const protectedValues = updateKeys.filter(
- (key) => CanvasEffect.protectedValues.includes(key)
- );
- if (protectedValues.length) {
- throw custom_error(
- "Sequencer",
- `CanvasEffect | update | You cannot update the following keys of an effect's data: ${protectedValues.join(
- "\n - "
- )}`
- );
- }
- if (updateKeys.includes("source")) {
- if (!(is_UUID(inUpdates.source) || is_object_canvas_data(inUpdates.source))) {
- throw custom_error(
- "Sequencer",
- `CanvasEffect | update | source must be of type document UUID or object with X and Y coordinates`
- );
- }
- }
- if (updateKeys.includes("target")) {
- if (!(is_UUID(inUpdates.target) || is_object_canvas_data(inUpdates.target))) {
- throw custom_error(
- "Sequencer",
- `CanvasEffect | update | target must be of type document UUID or object with X and Y coordinates`
- );
- }
- }
- }
- getHook(type, uuid) {
- if (!is_UUID(uuid))
- return false;
- const parts = uuid.split(".");
- return type + parts[parts.length - 2];
- }
- /**
- * Gets the source hook name
- *
- * @param {string} type
- * @returns {string|boolean}
- */
- getSourceHook(type = "") {
- return this.getHook(type, this.data.source);
- }
- /**
- * The source object's current position, or its current position
- *
- * @returns {boolean|object}
- */
- getSourceData() {
- if (this.data.temporary && !this.owner) {
- return SequencerEffectManager.getPositionForUUID(this.data.source);
- }
- const position = this.source instanceof PlaceableObject && !this.isSourceTemporary ? get_object_position(this.source) : this.source?.worldPosition || this.source?.center || this.source;
- const { width: width2, height } = get_object_dimensions(this.source);
- if (this.isIsometricActive && this.source instanceof PlaceableObject) {
- position.x += (this.sourceDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
- position.y -= (this.sourceDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
- if (this.data.isometric?.overlay || this.target instanceof PlaceableObject) {
- position.x += (this.source?.height ?? height) / 2;
- position.y -= (this.source?.height ?? height) / 2;
- }
- }
- if (position !== void 0) {
- this._cachedSourceData.position = position;
- }
- if (width2 !== void 0 && height !== void 0) {
- this._cachedSourceData.width = width2;
- this._cachedSourceData.height = height;
- }
- let rotation2 = 0;
- if (this.source instanceof MeasuredTemplate && this.sourceDocument?.t !== "rect") {
- rotation2 = Math.normalizeRadians(
- Math.toRadians(this.sourceDocument?.direction)
- );
- } else if (!(this.source instanceof MeasuredTemplate)) {
- rotation2 = this.sourceDocument?.rotation ? Math.normalizeRadians(Math.toRadians(this.sourceDocument?.rotation)) : 0;
- }
- if (rotation2 !== void 0) {
- this._cachedSourceData.rotation = rotation2;
- }
- const alpha = this.sourceDocument instanceof TokenDocument || this.sourceDocument instanceof TileDocument ? this.sourceDocument?.alpha ?? 1 : 1;
- if (alpha !== void 0) {
- this._cachedSourceData.alpha = alpha;
- }
- return {
- ...this._cachedSourceData
- };
- }
- /**
- * Gets the target hook name
- *
- * @param {string} type
- * @returns {string|boolean}
- */
- getTargetHook(type = "") {
- return this.getHook(type, this.data.target);
- }
- /**
- * The target object's current position, or its current position
- *
- * @returns {boolean|object}
- */
- getTargetData() {
- if (this.data.temporary && !this.owner) {
- return SequencerEffectManager.getPositionForUUID(this.data.target) ?? this.getSourceData();
- }
- const position = this.target instanceof PlaceableObject && !this.isTargetTemporary ? get_object_position(this.target, { measure: true }) : this.target?.worldPosition || this.target?.center || this.target;
- const { width: width2, height } = get_object_dimensions(this.target);
- if (this.isIsometricActive && this.target instanceof PlaceableObject) {
- const targetHeight = this.target?.height ?? height;
- position.x += (this.targetDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size + targetHeight;
- position.y -= (this.targetDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size + targetHeight;
- }
- if (width2 !== void 0 && height !== void 0) {
- this._cachedTargetData.width = width2;
- this._cachedTargetData.height = height;
- }
- if (position !== void 0) {
- this._cachedTargetData.position = position;
- }
- let rotation2 = 0;
- if (this.target instanceof MeasuredTemplate && this.targetDocument?.t !== "rect") {
- rotation2 = Math.normalizeRadians(
- Math.toRadians(this.targetDocument?.direction)
- );
- } else if (!(this.target instanceof MeasuredTemplate)) {
- rotation2 = this.targetDocument?.rotation ? Math.normalizeRadians(Math.toRadians(this.targetDocument?.rotation)) : 0;
- }
- if (rotation2 !== void 0) {
- this._cachedTargetData.rotation = rotation2;
- }
- const alpha = this.targetDocument instanceof TokenDocument || this.targetDocument instanceof TileDocument ? this.targetDocument?.alpha ?? 1 : 1;
- if (alpha !== void 0) {
- this._cachedTargetData.alpha = alpha;
- }
- return {
- ...this._cachedTargetData
- };
- }
- /**
- * Calculates the offset for a given offset property and name mapping
- *
- * @param {string} offsetMapName
- * @param {boolean} source
- * @returns {{x: number, y: number}|*}
- * @private
- */
- _getOffset(offsetMapName, source = false) {
- const key = source ? "source" : "target";
- const offset2 = {
- x: 0,
- y: 0
- };
- let twister = this._twister;
- let nameOffsetMap = this._nameOffsetMap?.[this.data.name];
- if (nameOffsetMap) {
- twister = nameOffsetMap.twister;
- }
- if (this.data.missed && (!source || !this.data.target)) {
- let missedOffset = this._offsetCache[key]?.missedOffset || calculate_missed_position(this.source, this.target, twister);
- this._offsetCache[key].missedOffset = missedOffset;
- offset2.x -= missedOffset.x;
- offset2.y -= missedOffset.y;
- }
- const obj = source ? this.source : this.target;
- const multiplier = source ? this.data.randomOffset?.source : this.data.randomOffset?.target;
- if (obj && multiplier) {
- let randomOffset = this._offsetCache[key]?.randomOffset || get_random_offset(obj, multiplier, twister);
- this._offsetCache[key].randomOffset = randomOffset;
- offset2.x -= randomOffset.x;
- offset2.y -= randomOffset.y;
- }
- let extraOffset = this.data?.offset?.[key];
- if (extraOffset) {
- let newOffset = {
- x: extraOffset.x,
- y: extraOffset.y
- };
- if (extraOffset.gridUnits) {
- newOffset.x *= canvas.grid.size;
- newOffset.y *= canvas.grid.size;
- }
- if (extraOffset.local) {
- if (!this._cachedSourceData?.position || !this._cachedTargetData?.position) {
- this.getSourceData();
- this.getTargetData();
- }
- const startPos = this._cachedSourceData.position;
- const endPos = this._cachedTargetData.position;
- const angle = this.target ? new Ray(startPos, endPos).angle : Ray.fromAngle(
- startPos.x,
- startPos.y,
- this._cachedSourceData.rotation,
- 1
- ).angle;
- newOffset = rotateAroundPoint(
- 0,
- 0,
- newOffset.x,
- newOffset.y,
- -angle
- );
- }
- offset2.x -= newOffset.x;
- offset2.y -= newOffset.y;
- }
- let offsetMap = this._nameOffsetMap?.[offsetMapName];
- if (!this._offsetCache[key]["nameCache"][offsetMapName]) {
- this._offsetCache[key]["nameCache"][offsetMapName] = {};
- }
- if (offsetMap) {
- if (offsetMap.missed) {
- const missedOffset = this._offsetCache[key]["nameCache"][offsetMapName]?.missedOffset || calculate_missed_position(
- offsetMap.sourceObj,
- offsetMap.targetObj,
- offsetMap.twister
- );
- this._offsetCache[key]["nameCache"][offsetMapName].missedOffset = missedOffset;
- offset2.x -= missedOffset.x;
- offset2.y -= missedOffset.y;
- }
- const obj2 = offsetMap.targetObj || offsetMap.sourceObj;
- const multiplier2 = offsetMap.randomOffset?.source || offsetMap.randomOffset?.target;
- if (obj2 && multiplier2) {
- let randomOffset = this._offsetCache[key]["nameCache"][offsetMapName]?.randomOffset || get_random_offset(obj2, multiplier2, offsetMap.twister);
- this._offsetCache[key]["nameCache"][offsetMapName].randomOffset = randomOffset;
- offset2.x -= randomOffset.x;
- offset2.y -= randomOffset.y;
- }
- if (offsetMap.offset) {
- offset2.x += offsetMap.offset.x;
- offset2.y += offsetMap.offset.y;
- }
- }
- return offset2;
- }
- /**
- * Initializes the name offset map by establishing targets
- *
- * @param inOffsetMap
- * @returns {{setup}|*}
- * @private
- */
- _setupOffsetMap(inOffsetMap) {
- if (!inOffsetMap.setup) {
- inOffsetMap.setup = true;
- inOffsetMap.sourceObj = inOffsetMap.source ? this._validateObject(inOffsetMap.source) : false;
- inOffsetMap.targetObj = inOffsetMap.target ? this._validateObject(inOffsetMap.target) : false;
- const repetition = this.data.repetition % inOffsetMap.repetitions;
- const seed = get_hash(`${inOffsetMap.seed}-${repetition}`);
- inOffsetMap.twister = new MersenneTwister(seed);
- }
- return inOffsetMap;
- }
- /**
- * Plays the effect, returning two promises; one that resolves once the duration has been established, and another
- * when the effect has finished playing
- *
- * @returns {Object}
- */
- play() {
- const durationPromise = new Promise((resolve, reject2) => {
- this._durationResolve = resolve;
- });
- const finishPromise = new Promise(async (resolve, reject2) => {
- this._resolve = resolve;
- Hooks.callAll("createSequencerEffect", this);
- debug(`Playing effect:`, this.data);
- this._initialize();
- });
- return {
- duration: durationPromise,
- promise: finishPromise
- };
- }
- /**
- * Ends the effect
- */
- endEffect() {
- if (this._ended)
- return;
- Hooks.callAll("endedSequencerEffect", this);
- this.destroy();
- }
- destroy(...args) {
- this._destroyDependencies();
- return super.destroy(...args);
- }
- /**
- * Updates this effect with the given parameters
- * @param inUpdates
- * @returns {Promise}
- */
- async update(inUpdates) {
- if (!this.userCanUpdate)
- throw custom_error(
- "Sequencer",
- "CanvasEffect | Update | You do not have permission to update this effect"
- );
- CanvasEffect.validateUpdate(inUpdates);
- const newData = foundry.utils.deepClone(this.data);
- const updateKeys = Object.keys(inUpdates);
- updateKeys.forEach((key) => {
- setProperty(newData, key, inUpdates[key]);
- });
- if (Object.keys(foundry.utils.diffObject(newData, this.data)).length === 0) {
- debug(
- `Skipped updating effect with ID ${this.id} - no changes needed`
- );
- return;
- }
- if (this.data.persist) {
- const originalSourceUUID = is_UUID(this.data.source) && this.data.attachTo ? this.data.source : "Scene." + this.data.sceneId;
- const newSourceUUID = is_UUID(newData.source) && newData.attachTo ? newData.source : "Scene." + newData.sceneId;
- if (originalSourceUUID !== newSourceUUID) {
- flagManager.removeFlags(originalSourceUUID, newData);
- }
- flagManager.addFlags(newSourceUUID, newData);
- }
- debug(`Updated effect with ID ${this.id}`);
- return sequencerSocket.executeForEveryone(
- SOCKET_HANDLERS.UPDATE_EFFECT,
- this.id,
- newData
- );
- }
- async addAnimatedProperties({ animations = [], loopingAnimation = [] } = {}) {
- const animationsToAdd = [];
- if (!Array.isArray(animations)) {
- throw custom_error(
- this.data.moduleName,
- `animations must be an array of arrays`
- );
- }
- for (const animationData of animations) {
- if (!Array.isArray(animationData)) {
- throw custom_error(
- this.data.moduleName,
- `each entry in animations must be an array, each with target, property name, and animation options`
- );
- }
- const result = validateAnimation(...animationData);
- if (typeof result === "string") {
- throw custom_error(this.data.moduleName, result);
- }
- result.creationTimestamp = +new Date();
- animationsToAdd.push(result);
- }
- if (!Array.isArray(loopingAnimation)) {
- throw custom_error(
- this.data.moduleName,
- `loopingAnimation must be an array of arrays`
- );
- }
- for (const animationData of loopingAnimation) {
- if (!Array.isArray(animationData)) {
- throw custom_error(
- this.data.moduleName,
- `each entry in loopingAnimation must be an array, each with target, property name, and animation options`
- );
- }
- const result = validateLoopingAnimation(...animationData);
- if (typeof result === "string") {
- throw custom_error(this.data.moduleName, result);
- }
- result.creationTimestamp = +new Date();
- animationsToAdd.push(result);
- }
- if (this.data.persist) {
- const originalSourceUUID = is_UUID(this.data.source) && this.data.attachTo ? this.data.source : "Scene." + this.data.sceneId;
- const newData = foundry.utils.deepClone(this.data);
- newData.animations = (newData.animations ?? []).concat(
- foundry.utils.deepClone(animationsToAdd)
- );
- flagManager.addFlags(originalSourceUUID, newData);
- }
- return sequencerSocket.executeForEveryone(
- SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
- this.id,
- animationsToAdd
- );
- }
- async _addAnimations(inAnimations) {
- this._playAnimations(inAnimations);
- this.data.animations = (this.data.animations ?? []).concat(inAnimations);
- }
- /**
- * Updates the effect
- *
- * @param inUpdates
- * @returns {Promise}
- * @private
- */
- _update(inUpdates) {
- this.data = inUpdates;
- Hooks.callAll("updateSequencerEffect", this);
- this._destroyDependencies();
- return this._reinitialize();
- }
- /**
- * Determines whether a position is within the bounds of this effect
- *
- * @param inPosition
- * @returns {boolean}
- */
- isPositionWithinBounds(inPosition) {
- if (!this.spriteContainer)
- return false;
- return is_position_within_bounds(
- inPosition,
- this.spriteContainer,
- this.parent
- );
- }
- /**
- * Initializes the effect and places it on the canvas
- *
- * @param {boolean} play
- * @returns {Promise}
- * @private
- */
- async _initialize(play = true) {
- this.ready = false;
- this._initializeVariables();
- await this._contextLostCallback();
- await this._loadTexture();
- this._addToContainer();
- this._createSprite();
- this._calculateDuration();
- this._createShapes();
- await this._setupMasks();
- await this._transformSprite();
- this._playCustomAnimations();
- this._playPresetAnimations();
- this._setEndTimeout();
- this._timeoutVisibility();
- if (play)
- await this.playMedia();
- this.ready = true;
- }
- /**
- * Reinitializes the effect after it has been updated
- *
- * @param play
- * @returns {Promise}
- * @private
- */
- async _reinitialize(play = true) {
- this.renderable = false;
- if (!this.shouldPlay) {
- return Sequencer.EffectManager._removeEffect(this);
- }
- this.actualCreationTime = +new Date();
- return this._initialize(play);
- }
- /**
- * Initializes variables core to the function of the effect
- * This is run as a part of the construction of the effect
- *
- * @private
- */
- _initializeVariables() {
- this.rotationContainer = this.addChild(new PIXI.Container());
- this.rotationContainer.id = this.id + "-rotationContainer";
- this.isometricContainer = this.rotationContainer.addChild(
- new PIXI.Container()
- );
- this.isometricContainer.id = this.id + "-isometricContainer";
- this.spriteContainer = this.isometricContainer.addChild(
- new PIXI.Container()
- );
- this.spriteContainer.id = this.id + "-spriteContainer";
- this._template = this.data.template;
- this._ended = null;
- this._maskContainer = null;
- this._maskSprite = null;
- this._file = null;
- this._loopOffset = 0;
- this.effectFilters = {};
- this._animationDuration = 0;
- this._animationTimes = {};
- this._twister = new MersenneTwister(this.data.creationTimestamp);
- this._video = null;
- this._distanceCache = null;
- this._isRangeFind = false;
- this._customAngle = 0;
- this._currentFilePath = this.data.file;
- this._relatedSprites = {};
- this._hooks = [];
- if (this._resetTimeout) {
- clearTimeout(this._resetTimeout);
- }
- this._resetTimeout = null;
- this._source = false;
- this._target = false;
- this._offsetCache = {
- source: { nameCache: {} },
- target: { nameCache: {} }
- };
- this._nameOffsetMap = Object.fromEntries(
- Object.entries(
- foundry.utils.deepClone(this.data.nameOffsetMap ?? {})
- ).map((entry) => {
- return [entry[0], this._setupOffsetMap(entry[1])];
- })
- );
- this.uuid = !is_UUID(this.context.uuid) ? this.id : this.context.uuid + ".data.flags.sequencer.effects." + this.id;
- const maxPerformance = game.settings.get("core", "performanceMode") === 3;
- const maxFPS = game.settings.get("core", "maxFPS");
- this._ticker = new PIXI.Ticker();
- this._ticker.maxFPS = maxPerformance && maxFPS === 60 ? 60 : maxFPS;
- this._ticker.start();
- }
- /**
- * Destroys all dependencies to this element, such as tickers, animations, textures, and child elements
- *
- * @private
- */
- _destroyDependencies() {
- if (this._ended)
- return;
- this._ended = true;
- this.mask = null;
- hooksManager.removeHooks(this.uuid);
- try {
- this._ticker.stop();
- this._ticker.destroy();
- } catch (err) {
- }
- this._ticker = null;
- Object.values(this._relatedSprites).forEach(
- (sprite) => sprite.destroy({ children: true })
- );
- SequencerAnimationEngine.endAnimations(this.id);
- if (this._maskContainer)
- this._maskContainer.destroy({ children: true });
- if (this._maskSprite) {
- try {
- this._maskSprite.texture.destroy(true);
- this._maskSprite.destroy();
- } catch (err) {
- }
- }
- if (this._file instanceof SequencerFileBase) {
- this._file.destroy();
- }
- if (this.video) {
- try {
- this.video.removeAttribute("src");
- this.video.pause();
- this.video.load();
- } catch (err) {
- }
- }
- try {
- if (this.data.screenSpace) {
- SequencerAboveUILayer.removeContainerByEffect(this);
- }
- } catch (err) {
- }
- this.removeChildren().forEach((child) => child.destroy({ children: true }));
- }
- /**
- * Plays preset animations
- *
- * @private
- */
- _playPresetAnimations() {
- this._moveTowards();
- this._fadeIn();
- this._fadeInAudio();
- this._scaleIn();
- this._rotateIn();
- this._fadeOut();
- this._fadeOutAudio();
- this._scaleOut();
- this._rotateOut();
- }
- /**
- * Gets an object based on an identifier, checking if it exists within the named offset map, whether it's a
- * coordinate object, or if it's an UUID that needs to be fetched from the scene
- *
- * @param inIdentifier
- * @returns {*}
- * @private
- */
- _getObjectByID(inIdentifier) {
- let source = inIdentifier;
- let offsetMap = this._nameOffsetMap?.[inIdentifier];
- if (offsetMap) {
- source = offsetMap?.targetObj || offsetMap?.sourceObj || source;
- } else {
- source = this._validateObject(source);
- }
- return source;
- }
- /**
- * Validates the given parameter, whether it's a UUID or a coordinate object, and returns the proper one
- *
- * @param inObject
- * @returns {*}
- * @private
- */
- _validateObject(inObject) {
- if (is_UUID(inObject) || !is_object_canvas_data(inObject)) {
- inObject = get_object_from_scene(inObject, this.data.sceneId);
- inObject = inObject?._object ?? inObject;
- }
- return inObject;
- }
- /**
- * Adds this effect to the appropriate container on the right layer
- *
- * @private
- */
- _addToContainer() {
- let layer2;
- if (this.data.screenSpaceAboveUI) {
- layer2 = SequencerAboveUILayer;
- } else if (this.data.screenSpace) {
- layer2 = canvas.sequencerEffectsUILayer;
- } else if (this.data.aboveInterface) {
- layer2 = canvas.controls;
- } else if (this.data.aboveLighting) {
- layer2 = canvas.interface;
- } else {
- layer2 = canvas.primary;
- }
- layer2.addChild(this);
- layer2.sortChildren();
- }
- /**
- * Loads the texture for this effect, handling cases where it's a simple path or a database path
- *
- * @private
- */
- async _loadTexture() {
- if (this.data.file === "") {
- return;
- }
- if (this.data.customRange) {
- this._file = SequencerFileBase.make(
- this.data.file,
- Object.values(this.template),
- "temporary.range.file"
- );
- } else {
- if (!Sequencer.Database.entryExists(this.data.file)) {
- let texture = await SequencerFileCache.loadFile(this.data.file);
- this.video = this.data.file.toLowerCase().endsWith(".webm") ? texture?.baseTexture?.resource?.source ?? false : false;
- this._texture = texture;
- this._file = texture;
- this._currentFilePath = this.data.file;
- return;
- }
- this._file = Sequencer.Database.getEntry(this.data.file).clone();
- }
- this._file.fileIndex = this.data.forcedIndex;
- this._file.twister = this._twister;
- this._isRangeFind = this._file?.rangeFind;
- this.spriteSheet = false;
- if (this.data.stretchTo) {
- let ray = new Ray(this.sourcePosition, this.targetPosition);
- this._rotateTowards(ray);
- ray = new Ray(this.sourcePosition, this.targetPosition);
- let { filePath, texture, sheet } = await this._getTextureForDistance(
- ray.distance
- );
- this._currentFilePath = filePath;
- this._texture = texture;
- this.spriteSheet = sheet;
- } else if (!this._isRangeFind || this._isRangeFind && !this.data.stretchTo) {
- const { filePath, texture, sheet } = await this._file.getTexture();
- this._currentFilePath = filePath;
- this._texture = texture;
- this.spriteSheet = sheet;
- }
- if (this._isRangeFind && (this.data.stretchTo?.attachTo?.active || this.data.attachTo?.active)) {
- let spriteType = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
- this._relatedSprites[this._currentFilePath] = new spriteType(
- this._texture,
- this.data.xray ? null : VisionSamplerShader
- );
- new Promise(async (resolve) => {
- for (let filePath of this._file.getAllFiles()) {
- if (filePath === this._currentFilePath)
- continue;
- let texture = await this._file._getTexture(filePath);
- let spriteType2 = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
- let sprite = new spriteType2(
- texture,
- this.data.xray ? null : VisionSamplerShader
- );
- sprite.renderable = false;
- this._relatedSprites[filePath] = sprite;
- }
- resolve();
- });
- }
- this._template = this._file.template ?? this._template;
- this.video = this._currentFilePath.toLowerCase().endsWith(".webm") ? this._texture?.baseTexture?.resource?.source : false;
- }
- /**
- * Calculates the duration of this effect, based on animation durations, the video source duration, end/start times, etc
- *
- * @private
- */
- _calculateDuration() {
- let playbackRate = this.data.playbackRate ? this.data.playbackRate : 1;
- this.mediaPlaybackRate = playbackRate;
- this._animationDuration = this.data.duration || this.mediaDuration * 1e3;
- if (this.data.moveSpeed && this.data.moves) {
- let distance = distance_between(
- this.sourcePosition,
- this.targetPosition
- );
- let durationFromSpeed = distance / this.data.moveSpeed * 1e3;
- this._animationDuration = Math.max(durationFromSpeed, this.data.duration);
- } else if (!this.data.duration && !this.hasAnimatedMedia) {
- let fadeDuration = (this.data.fadeIn?.duration ?? 0) + (this.data.fadeOut?.duration ?? 0);
- let scaleDuration = (this.data.scaleIn?.duration ?? 0) + (this.data.scaleOut?.duration ?? 0);
- let rotateDuration = (this.data.rotateIn?.duration ?? 0) + (this.data.rotateOut?.duration ?? 0);
- let moveDuration = 0;
- if (this.data.moves) {
- let distance = distance_between(
- this.sourcePosition,
- this.targetPosition
- );
- moveDuration = (this.data.moveSpeed ? distance / this.data.moveSpeed * 1e3 : 1e3) + this.data.moves.delay;
- }
- let animationDurations = this.data.animations ? Math.max(
- ...this.data.animations.map((animation2) => {
- if (animation2.looping) {
- if (animation2.loops === 0)
- return 0;
- return (animation2?.duration ?? 0) * (animation2?.loops ?? 0) + (animation2?.delay ?? 0);
- } else {
- return (animation2?.duration ?? 0) + (animation2?.delay ?? 0);
- }
- })
- ) : 0;
- this._animationDuration = Math.max(
- fadeDuration,
- scaleDuration,
- rotateDuration,
- moveDuration,
- animationDurations
- );
- this._animationDuration = this._animationDuration || 1e3;
- }
- this._startTime = 0;
- if (this.data.time?.start && this.mediaCurrentTime !== null) {
- let currentTime = !this.data.time.start.isPerc ? this.data.time.start.value ?? 0 : this._animationDuration * this.data.time.start.value;
- this.mediaCurrentTime = currentTime / 1e3;
- this._startTime = this.mediaCurrentTime;
- }
- if (this.data.time?.end) {
- this._animationDuration = !this.data.time.end.isPerc ? this.data.time.isRange ? this.data.time.end.value - this.data.time.start.value : this._animationDuration - this.data.time.end.value : this._animationDuration * this.data.time.end.value;
- }
- this._endTime = this._animationDuration / 1e3;
- if (this._file?.markers && this._startTime === 0 && this._endTime === this.mediaDuration) {
- this._animationTimes.loopStart = this._file.markers.loop.start / playbackRate / 1e3;
- this._animationTimes.loopEnd = this._file.markers.loop.end / playbackRate / 1e3;
- this._animationTimes.forcedEnd = this._file.markers.forcedEnd / playbackRate / 1e3;
- }
- this._durationResolve(this._animationDuration);
- this.mediaLooping = this._animationDuration / 1e3 > this.mediaDuration && !this.data.noLoop;
- }
- /**
- * If this effect is animatable, hold off on rendering it for a bit so that the animations have time to initialize to
- * prevent it from spawning and then jumping to the right place
- *
- * @private
- */
- _timeoutVisibility() {
- setTimeout(
- () => {
- this._setupHooks();
- },
- this.data.animations ? 50 : 0
- );
- }
- /**
- * If this effect is attached to an object, check whether the object has been destroyed, if so, end the effect
- *
- * @private
- */
- _contextLostCallback() {
- if (this.isSourceTemporary) {
- this._ticker.add(() => {
- if (this.isSourceDestroyed) {
- this._ticker.stop();
- this._source = this.sourcePosition;
- SequencerEffectManager.endEffects({ effects: this });
- }
- });
- }
- if (this.isTargetTemporary) {
- this._ticker.add(() => {
- if (this.isTargetDestroyed) {
- this._ticker.stop();
- this._target = this.targetPosition;
- SequencerEffectManager.endEffects({ effects: this });
- }
- });
- }
- }
- /**
- * Creates the sprite, and the relevant containers that manage the position and offsets of the overall visual look of the sprite
- *
- * @private
- */
- _createSprite() {
- this.renderable = false;
- const args = [this.spriteSheet ? this.spriteSheet : null];
- if (!this.data.xray && !this.spriteSheet && !this.data.screenSpace && !this.data.screenSpaceAboveUI) {
- args.push(VisionSamplerShader);
- }
- const spriteType = this.spriteSheet ? PIXI.AnimatedSprite : SpriteMesh;
- const sprite = new spriteType(...args);
- this.sprite = this.spriteContainer.addChild(sprite);
- this.sprite.id = this.id + "-sprite";
- Object.values(this._relatedSprites).forEach((sprite2) => {
- this.sprite.addChild(sprite2);
- });
- this.animatedSprite = false;
- if (this.spriteSheet) {
- this.animatedSprite = true;
- this.sprite.animationSpeed = 0.4;
- this.sprite.loop = false;
- }
- let textSprite;
- if (this.data.text) {
- const text2 = this.data.text.text;
- const fontSettings = foundry.utils.deepClone(this.data.text);
- fontSettings.fontSize = (fontSettings?.fontSize ?? 26) * (150 / canvas.grid.size);
- textSprite = new PIXI.Text(text2, fontSettings);
- textSprite.resolution = 5;
- textSprite.zIndex = 1;
- textSprite.anchor.set(
- this.data.text?.anchor?.x ?? 0.5,
- this.data.text?.anchor?.y ?? 0.5
- );
- }
- this.sprite.filters = [];
- if (this.data.filters) {
- for (let index = 0; index < this.data.filters.length; index++) {
- const filterData = this.data.filters[index];
- const filter2 = new filters[filterData.className](filterData.data);
- filter2.id = this.id + "-" + filterData.className + "-" + index.toString();
- this.sprite.filters.push(filter2);
- const filterKeyName = filterData.name || filterData.className;
- this.effectFilters[filterKeyName] = filter2;
- }
- }
- this.alphaFilter = new PIXI.filters.AlphaFilter(this.data.opacity);
- this.alphaFilter.id = this.id + "-alphaFilter";
- this.sprite.filters.push(this.alphaFilter);
- let spriteOffsetX = this.data.spriteOffset?.x ?? 0;
- let spriteOffsetY = this.data.spriteOffset?.y ?? 0;
- if (this.data.spriteOffset?.gridUnits) {
- spriteOffsetX *= canvas.grid.size;
- spriteOffsetY *= canvas.grid.size;
- }
- this.sprite.position.set(spriteOffsetX, spriteOffsetY);
- this.sprite.anchor.set(
- this.data.spriteAnchor?.x ?? 0.5,
- this.data.spriteAnchor?.y ?? 0.5
- );
- let spriteRotation = this.data.spriteRotation ?? 0;
- if (this.data.randomSpriteRotation) {
- spriteRotation += random_float_between(-360, 360, this._twister);
- }
- this.sprite.rotation = Math.normalizeRadians(
- Math.toRadians(spriteRotation)
- );
- this._customAngle = this.data.angle ?? 0;
- if (this.data.randomRotation) {
- this._customAngle += random_float_between(-360, 360, this._twister);
- }
- this.spriteContainer.rotation = -Math.normalizeRadians(
- Math.toRadians(this._customAngle)
- );
- if (CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE) {
- this.isometricContainer.rotation = Math.PI / 4;
- }
- if (this.data.tint) {
- this.sprite.tint = this.data.tint;
- }
- if (textSprite) {
- if (this.data.tint) {
- textSprite.tint = this.data.tint;
- }
- this.sprite.addChild(textSprite);
- }
- this.filters = [
- new PIXI.filters.ColorMatrixFilter({
- saturation: this.shouldShowFadedVersion ? -1 : 1
- }),
- new PIXI.filters.AlphaFilter(
- this.shouldShowFadedVersion ? game.settings.get(CONSTANTS.MODULE_NAME, "user-effect-opacity") / 100 : 1
- )
- ];
- this.updateElevation();
- }
- _createShapes() {
- const nonMaskShapes = (this.data?.shapes ?? []).filter(
- (shape) => !shape.isMask
- );
- this.shapes = {};
- for (const shape of nonMaskShapes) {
- const graphic = createShape(shape);
- graphic.filters = this.sprite.filters;
- this.spriteContainer.addChild(graphic);
- this.shapes[shape?.name ?? "shape-" + randomID()] = graphic;
- }
- }
- updateElevation() {
- const targetElevation = Math.max(
- get_object_elevation(this.source ?? {}),
- get_object_elevation(this.target ?? {})
- ) + 1;
- let effectElevation = this.data.elevation?.elevation ?? 0;
- if (!this.data.elevation?.absolute) {
- effectElevation += targetElevation;
- }
- const isIsometric = getProperty(
- game.scenes.get(this.data.sceneId),
- CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED
- );
- if (CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE && isIsometric) {
- const sourceSort = this.source ? this.sourceMesh.sort + (this.data.isometric?.overlay ? 1 : -1) : 0;
- const targetSort = this.target ? this.targetMesh.sort + (this.data.isometric?.overlay ? 1 : -1) : 0;
- this.sort = Math.max(sourceSort, targetSort);
- } else {
- this.sort = !is_real_number(this.data.zIndex) ? this.data.index + (this?.parent?.children?.length ?? 0) : 1e5 + this.data.zIndex;
- }
- this.elevation = effectElevation;
- this.zIndex = this.sort;
- this.sort += 100;
- if (this.parent) {
- this.parent.sortChildren();
- }
- }
- updateTransform() {
- super.updateTransform();
- if (this.data.screenSpace || this.data.screenSpaceAboveUI) {
- const [screenWidth, screenHeight] = canvas.screenDimensions;
- this.position.set(
- (this.data.screenSpacePosition?.x ?? 0) + screenWidth * (this.data.screenSpaceAnchor?.x ?? this.data.anchor?.x ?? 0.5),
- (this.data.screenSpacePosition?.y ?? 0) + screenHeight * (this.data.screenSpaceAnchor?.y ?? this.data.anchor?.y ?? 0.5)
- );
- if (this.data.screenSpaceScale) {
- const scaleData = this.data.screenSpaceScale ?? { x: 1, y: 1 };
- let scaleX = scaleData.x;
- let scaleY = scaleData.y;
- if (scaleData.fitX) {
- scaleX = scaleX * (screenWidth / this.sprite.width);
- }
- if (scaleData.fitY) {
- scaleY = scaleY * (screenHeight / this.sprite.height);
- }
- scaleX = scaleData.ratioX ? scaleY : scaleX;
- scaleY = scaleData.ratioY ? scaleX : scaleY;
- this.scale.set(scaleX, scaleY);
- }
- }
- }
- async _setupMasks() {
- const maskShapes = this.data.shapes.filter((shape) => shape.isMask);
- if (!this.data?.masks?.length && !maskShapes.length)
- return;
- const maskFilter = MaskFilter.create();
- for (const uuid of this.data.masks) {
- const documentObj = fromUuidSync(uuid);
- if (!documentObj || documentObj.parent.id !== this.data.sceneId)
- continue;
- const obj = documentObj.object;
- let shape = obj?.mesh;
- let shapeToAdd = shape;
- if (obj instanceof MeasuredTemplate || obj instanceof Drawing) {
- shape = obj?.shape?.geometry?.graphicsData?.[0]?.shape ?? obj?.shape;
- if (game.modules.get("walledtemplates")?.active && obj.walledtemplates?.walledTemplate) {
- let wt = obj.walledtemplates.walledTemplate;
- wt.options.padding = 3 * canvas.dimensions.distancePixels;
- shape = wt.computeShape();
- wt.options.padding = 0;
- }
- shapeToAdd = new PIXI.LegacyGraphics().beginFill().drawShape(shape).endFill();
- if (obj instanceof MeasuredTemplate) {
- shapeToAdd.position.set(documentObj.x, documentObj.y);
- } else {
- const {
- x,
- y,
- shape: { width: width2, height },
- rotation: rotation2
- } = documentObj;
- shapeToAdd.pivot.set(width2 / 2, height / 2);
- shapeToAdd.position.set(x + width2 / 2, y + height / 2);
- shapeToAdd.angle = rotation2;
- }
- shapeToAdd.cullable = true;
- shapeToAdd.custom = true;
- shapeToAdd.renderable = false;
- shapeToAdd.uuid = uuid;
- canvas.stage.addChild(shapeToAdd);
- }
- shapeToAdd.obj = obj;
- const updateMethod = (doc) => {
- if (doc !== documentObj)
- return;
- const mask = maskFilter.masks.find((shape2) => shape2.uuid === uuid);
- if (!mask)
- return;
- if (!mask.custom)
- return;
- mask.clear();
- if (obj instanceof MeasuredTemplate) {
- mask.position.set(documentObj.x, documentObj.y);
- let maskObj = documentObj.object;
- if (game.modules.get("walledtemplates")?.active && maskObj.walledtemplates?.walledTemplate) {
- let wt = maskObj.walledtemplates.walledTemplate;
- wt.options.padding = 3 * canvas.dimensions.distancePixels;
- shape = wt.computeShape();
- wt.options.padding = 0;
- }
- } else {
- const {
- x,
- y,
- shape: { width: width2, height },
- rotation: rotation2
- } = documentObj;
- mask.pivot.set(width2 / 2, height / 2);
- mask.position.set(x + width2 / 2, y + height / 2);
- mask.angle = rotation2;
- }
- mask.beginFill().drawShape(shape).endFill();
- };
- if (game.modules.get("walledtemplates")?.active) {
- hooksManager.addHook(this.uuid, "createWall", () => {
- setTimeout(() => {
- updateMethod(documentObj);
- }, 100);
- });
- hooksManager.addHook(this.uuid, "updateWall", () => {
- setTimeout(() => {
- updateMethod(documentObj);
- }, 100);
- });
- hooksManager.addHook(this.uuid, "deleteWall", () => {
- setTimeout(() => {
- updateMethod(documentObj);
- }, 100);
- });
- }
- hooksManager.addHook(this.uuid, this.getHook("update", uuid), (doc) => {
- setTimeout(() => {
- updateMethod(doc);
- }, 100);
- });
- maskFilter.masks.push(shapeToAdd);
- }
- for (const shapeData of maskShapes) {
- const shape = createShape(shapeData);
- shape.cullable = true;
- shape.custom = true;
- shape.renderable = false;
- this.spriteContainer.addChild(shape);
- this.shapes[shapeData?.name ?? "shape-" + randomID()] = shape;
- maskFilter.masks.push(shape);
- }
- this.sprite.filters.push(maskFilter);
- }
- /**
- * Sets up the hooks relating to this effect's source and target
- *
- * @private
- */
- _setupHooks() {
- const attachedToSource = this.data.attachTo?.active && is_UUID(this.data.source);
- const attachedToTarget = (this.data.stretchTo?.attachTo || this.data.rotateTowards?.attachTo) && is_UUID(this.data.target);
- const baseRenderable = this.shouldPlayVisible;
- let renderable = baseRenderable;
- let alpha = null;
- if (attachedToSource) {
- hooksManager.addHook(this.uuid, this.getSourceHook("delete"), (doc) => {
- const uuid = doc.uuid;
- if (doc !== this.sourceDocument)
- return;
- this._source = this._cachedSourceData.position;
- SequencerEffectManager.objectDeleted(uuid);
- });
- if (this.data.attachTo?.bindVisibility) {
- hooksManager.addHook(
- this.uuid,
- "sightRefresh",
- () => {
- const sourceVisible = this.source && (this.sourceMesh?.visible ?? true);
- const sourceHidden = this.sourceDocument && (this.sourceDocument?.hidden ?? false);
- const targetVisible = this.target && (!attachedToTarget || (this.targetMesh?.visible ?? true));
- this.renderable = baseRenderable && (sourceVisible || targetVisible) && this._checkWallCollisions();
- this.alpha = sourceVisible && sourceHidden ? 0.5 : 1;
- renderable = baseRenderable && this.renderable;
- },
- true
- );
- }
- if (this.data.attachTo?.bindAlpha || this.data.attachTo?.bindElevation) {
- hooksManager.addHook(this.uuid, this.getSourceHook("update"), (doc) => {
- if (doc !== this.sourceDocument)
- return;
- if (this.data.attachTo?.bindAlpha) {
- this.spriteContainer.alpha = this.getSourceData().alpha;
- }
- if (this.data.attachTo?.bindElevation) {
- this.updateElevation();
- }
- });
- }
- if (this.data.attachTo?.bindAlpha) {
- alpha = this.getSourceData().alpha;
- }
- }
- if (attachedToTarget) {
- hooksManager.addHook(this.uuid, this.getTargetHook("delete"), (doc) => {
- if (doc !== this.target)
- return;
- this._target = this._cachedTargetData.position;
- const uuid = doc.uuid;
- SequencerEffectManager.objectDeleted(uuid);
- });
- hooksManager.addHook(this.uuid, this.getTargetHook("update"), (doc) => {
- if (doc !== this.target)
- return;
- this.updateElevation();
- });
- }
- for (let uuid of this.data?.tiedDocuments ?? []) {
- const tiedDocument = fromUuidSync(uuid);
- if (tiedDocument) {
- hooksManager.addHook(
- this.uuid,
- this.getHook("delete", tiedDocument.uuid),
- (doc) => {
- if (tiedDocument !== doc)
- return;
- SequencerEffectManager.objectDeleted(doc.uuid);
- }
- );
- }
- }
- setTimeout(() => {
- this.renderable = renderable;
- this.spriteContainer.alpha = alpha ?? 1;
- }, 25);
- }
- /**
- * Calculates the padding and scale to stretch an effect across the given distance
- *
- * If the file is a SequencerFileBase instance, it will also pick the appropriate file for the right distance
- *
- * @param distance
- * @returns {Object}
- * @private
- */
- async _getTextureForDistance(distance) {
- if (!this._distanceCache || this._distanceCache?.distance !== distance) {
- let scaleX = 1;
- let scaleY = 1;
- let texture;
- let filePath;
- let spriteAnchor = this.data.anchor?.x ?? 1;
- if (this._file instanceof SequencerFileBase) {
- const scaledDistance = distance / (this.data.scale.x ?? 1);
- const result = await this._file.getTexture(scaledDistance);
- filePath = result.filePath;
- texture = result.texture;
- spriteAnchor = result.spriteAnchor ?? this.data.anchor?.x ?? 0;
- scaleX = result.spriteScale;
- if (this.data.stretchTo?.onlyX) {
- const widthWithPadding = texture.width - (this.template.startPoint + this.template.endPoint);
- scaleY = widthWithPadding / texture.width;
- } else {
- scaleY = result.spriteScale;
- }
- } else if (this._file instanceof PIXI.Texture) {
- filePath = this.data.file;
- texture = this._file;
- spriteAnchor = this.template.startPoint / texture.width;
- const widthWithPadding = texture.width - (this.template.startPoint + this.template.endPoint);
- let spriteScale = distance / widthWithPadding;
- scaleX = spriteScale;
- if (this.data.stretchTo?.onlyX) {
- scaleY = widthWithPadding / texture.width;
- } else {
- scaleY = spriteScale;
- }
- }
- this._distanceCache = {
- filePath,
- texture,
- spriteAnchor,
- scaleX,
- scaleY,
- distance
- };
- }
- return this._distanceCache;
- }
- /**
- * Applies the distance scaling to the sprite based on the previous method
- *
- * @returns {Promise<void>}
- * @private
- */
- async _applyDistanceScaling() {
- const ray = new Ray(this.sourcePosition, this.targetPosition);
- this._rotateTowards(ray);
- let { filePath, texture, spriteAnchor, scaleX, scaleY, distance } = await this._getTextureForDistance(ray.distance);
- if (this._currentFilePath !== filePath || this._relatedSprites[filePath] === void 0) {
- this._texture = texture;
- this.video = filePath.toLowerCase().endsWith(".webm") ? texture?.baseTexture?.resource?.source ?? false : false;
- Object.values(this._relatedSprites).forEach((subsprite) => {
- subsprite.renderable = false;
- });
- this._currentFilePath = filePath;
- if (this._relatedSprites[filePath]) {
- this._relatedSprites[filePath].renderable = true;
- } else {
- let sprite;
- let spriteType = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
- if (this.data.xray) {
- sprite = new spriteType(texture);
- } else {
- sprite = new spriteType(texture, VisionSamplerShader);
- }
- this._relatedSprites[filePath] = sprite;
- if (this.data.tint) {
- sprite.tint = this.data.tint;
- }
- this.sprite.addChild(sprite);
- }
- }
- this.playMedia();
- if (this._relatedSprites[filePath]) {
- if (this.data.attachTo?.active) {
- this._applyAttachmentOffset();
- }
- const sprite = this._relatedSprites[filePath];
- if (!sprite.parent) {
- this.sprite.addChild(sprite);
- }
- if (this.data.tilingTexture) {
- const scaleX2 = (this.data.scale.x ?? 1) * this.gridSizeDifference;
- const scaleY2 = (this.data.scale.y ?? 1) * this.gridSizeDifference;
- sprite.width = distance / scaleX2;
- sprite.height = texture.height;
- sprite.scale.set(scaleX2 * this.flipX, scaleY2 * this.flipY);
- sprite.tileScale.x = this.data.tilingTexture.scale.x;
- sprite.tileScale.y = this.data.tilingTexture.scale.y;
- sprite.tilePosition = this.data.tilingTexture.position;
- } else {
- sprite.scale.set(
- scaleX * (this.data.scale.x ?? 1) * this.flipX,
- scaleY * (this.data.scale.y ?? 1) * this.flipY
- );
- }
- sprite.anchor.set(
- this.flipX === 1 ? spriteAnchor : 1 - spriteAnchor,
- this.data.anchor?.y ?? 0.5
- );
- }
- }
- _checkWallCollisions() {
- if (!this.data.stretchTo?.attachTo || !this.data.stretchTo?.requiresLineOfSight)
- return true;
- const ray = new Ray(this.sourcePosition, this.targetPosition);
- const blockingObjects = canvas.walls.checkCollision(ray, { type: "sight" });
- if (!blockingObjects.length && !this.data.stretchTo?.hideLineOfSight) {
- this._ticker.stop();
- SequencerEffectManager.endEffects({ effects: this });
- }
- return !blockingObjects.length;
- }
- /**
- * Rotates the effect towards the target
- *
- * @param ray
- * @private
- */
- _rotateTowards(ray) {
- if (!ray) {
- const sourcePosition = this.flipX === 1 ? this.sourcePosition : this.targetPosition;
- const targetPosition = this.flipX === 1 ? this.targetPosition : this.sourcePosition;
- ray = new Ray(sourcePosition, targetPosition);
- }
- this.rotationContainer.rotation = Math.normalizeRadians(
- ray.angle + Math.toRadians(this.data.rotateTowards?.rotationOffset ?? 0)
- );
- this._tweakRotationForIsometric();
- }
- _tweakRotationForIsometric() {
- if (!CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE)
- return;
- if (this.data.stretchTo) {
- let skew = Math.normalizeRadians(
- this.rotationContainer.rotation - Math.PI / 4
- );
- if (Math.abs(skew) >= Math.PI / 2 - 0.5 && Math.abs(skew) <= Math.PI / 2 + 0.5) {
- skew -= Math.PI / 2;
- }
- this.isometricContainer.skew.set(Math.normalizeRadians(skew), 0);
- this.isometricContainer.rotation = 0;
- } else if (this.data?.isometric?.overlay) {
- this.rotationContainer.rotation = 0;
- let skew = Math.PI / 4 + this.rotationContainer.rotation;
- this.isometricContainer.skew.set(
- Math.normalizeRadians(skew - Math.PI / 4),
- 0
- );
- this.isometricContainer.scale.set(
- 1,
- window.scale ?? CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION
- );
- } else {
- this.isometricContainer.rotation = 0;
- }
- }
- /**
- * Transforms the sprite, rotating it, stretching it, scaling it, sizing it according its data
- *
- * @private
- */
- async _transformSprite() {
- if (this.data.stretchTo) {
- if (this.data.stretchTo?.attachTo) {
- this._transformStretchToAttachedSprite();
- }
- await this._applyDistanceScaling();
- } else {
- if (!this.sprite?.texture?.valid && this._texture?.valid) {
- this.sprite.texture = this._texture;
- }
- }
- if (this.video && (this._startTime || this._loopOffset > 0) && this.video?.currentTime !== void 0) {
- await wait$1(20);
- this.updateTexture();
- }
- if (!this.data.stretchTo) {
- this._transformNoStretchSprite();
- }
- if (this.data.attachTo?.active && !this.data.stretchTo?.attachTo) {
- await this._transformAttachedNoStretchSprite();
- } else {
- if (!this.data.screenSpace) {
- this.position.set(this.sourcePosition.x, this.sourcePosition.y);
- }
- }
- if (this.data.rotateTowards) {
- this._rotateTowards();
- if (this.data.rotateTowards?.attachTo) {
- this._transformRotateTowardsAttachedSprite();
- }
- }
- this._tweakRotationForIsometric();
- if (!this.data.anchor && this.data.rotateTowards) {
- const textureWidth = (this._texture?.width ?? this.sprite.width) / 2;
- const startPointRatio = this.template.startPoint / textureWidth;
- this.spriteContainer.pivot.set(
- this.sprite.width * (-0.5 + startPointRatio),
- 0
- );
- } else {
- this.spriteContainer.pivot.set(
- interpolate(
- this.sprite.width * -0.5,
- this.sprite.width * 0.5,
- this.data.anchor?.x ?? 0.5
- ),
- interpolate(
- this.sprite.height * -0.5,
- this.sprite.height * 0.5,
- this.data.anchor?.y ?? 0.5
- )
- );
- }
- }
- _transformStretchToAttachedSprite() {
- this._ticker.add(async () => {
- try {
- await this._applyDistanceScaling();
- } catch (err) {
- }
- });
- }
- _transformNoStretchSprite() {
- if (this.data.tilingTexture) {
- this.sprite.tileScale = {
- x: this.data.tilingTexture.scale.x * this.gridSizeDifference,
- y: this.data.tilingTexture.scale.y * this.gridSizeDifference
- };
- this.sprite.tilePosition = this.data.tilingTexture.position;
- }
- const baseScaleX = (this.data.scale?.x ?? 1) * (this.data.spriteScale?.x ?? 1) * this.flipX;
- const baseScaleY = (this.data.scale?.y ?? 1) * (this.data.spriteScale?.y ?? 1) * this.flipY;
- const heightWidthRatio = this.sprite.height / this.sprite.width;
- const widthHeightRatio = this.sprite.width / this.sprite.height;
- const ratioToUse = heightWidthRatio > widthHeightRatio;
- if (this.data.scaleToObject) {
- let { width: width2, height } = this.target ? this.getTargetData() : this.getSourceData();
- const target = this.targetDocument || this.sourceDocument;
- if (target instanceof TokenDocument) {
- width2 *= this.data.scaleToObject?.considerTokenScale ? target.texture.scaleX : 1;
- height *= this.data.scaleToObject?.considerTokenScale ? target.texture.scaleY : 1;
- }
- if (this.data.scaleToObject?.uniform) {
- let newWidth = Math.max(width2, height);
- height = Math.max(width2, height);
- width2 = newWidth;
- } else {
- width2 = width2 * (ratioToUse ? widthHeightRatio : 1);
- height = height * (!ratioToUse ? heightWidthRatio : 1);
- }
- this.sprite.width = width2 * (this.data.scaleToObject?.scale ?? 1) * baseScaleX;
- this.sprite.height = height * (this.data.scaleToObject?.scale ?? 1) * baseScaleY;
- } else if (this.data.size) {
- let { height, width: width2 } = this.data.size;
- if (this.data.size.width === "auto" || this.data.size.height === "auto") {
- height = this.sprite.height;
- width2 = this.sprite.width;
- if (this.data.size.width === "auto") {
- height = this.data.size.height;
- if (this.data.size.gridUnits) {
- height *= canvas.grid.size;
- }
- width2 = height * widthHeightRatio;
- } else if (this.data.size.height === "auto") {
- width2 = this.data.size.width;
- if (this.data.size.gridUnits) {
- width2 *= canvas.grid.size;
- }
- height = width2 * heightWidthRatio;
- }
- } else if (this.data.size.gridUnits) {
- height *= canvas.grid.size;
- width2 *= canvas.grid.size;
- }
- this.sprite.width = width2 * baseScaleX;
- this.sprite.height = height * baseScaleY;
- } else {
- this.sprite.scale.set(
- baseScaleX * this.gridSizeDifference,
- baseScaleY * this.gridSizeDifference
- );
- }
- }
- async _transformAttachedNoStretchSprite() {
- const applyRotation = this.data.attachTo?.followRotation && !(this.sourceDocument instanceof TokenDocument && this.sourceDocument.lockRotation) && (this.sourceDocument?.rotation !== void 0 || this.sourceDocument?.direction !== void 0) && !this.data.rotateTowards && !this.data.stretchTo;
- this._ticker.add(() => {
- if (this.isDestroyed)
- return;
- if (applyRotation) {
- this.rotationContainer.rotation = this.getSourceData().rotation;
- }
- this._tweakRotationForIsometric();
- try {
- this._applyAttachmentOffset();
- } catch (err) {
- debug_error(err);
- }
- });
- }
- _applyAttachmentOffset() {
- let offset2 = { x: 0, y: 0 };
- if (this.data.attachTo?.align && this.data.attachTo?.align !== "center") {
- offset2 = align({
- context: this.source,
- spriteWidth: this.sprite.width,
- spriteHeight: this.sprite.height,
- align: this.data.attachTo?.align,
- edge: this.data.attachTo?.edge
- });
- }
- this.position.set(
- this.sourcePosition.x - offset2.x,
- this.sourcePosition.y - offset2.y
- );
- }
- _transformRotateTowardsAttachedSprite() {
- this._ticker.add(async () => {
- if (this.isDestroyed)
- return;
- try {
- this._rotateTowards();
- } catch (err) {
- debug_error(err);
- }
- });
- }
- /**
- * Provided an animation targeting the rotation of the sprite's primary container, this method will counter-rotate
- * the sprite in an equal fashion so that the sprite's rotation remains static relative to this animation
- *
- * @param animation
- * @returns {*[]}
- * @private
- */
- _counterAnimateRotation(animation2) {
- if (animation2.target === this.spriteContainer && this.data.zeroSpriteRotation) {
- delete animation2.target;
- let counterAnimation = foundry.utils.deepClone(animation2);
- animation2.target = this.spriteContainer;
- counterAnimation.target = this.sprite;
- if (counterAnimation.values) {
- counterAnimation.values = counterAnimation.values.map(
- (value) => value * -1
- );
- } else {
- counterAnimation.from *= -1;
- counterAnimation.to *= -1;
- }
- if (!Array.isArray(animation2)) {
- animation2 = [animation2, counterAnimation];
- } else {
- animation2.push(counterAnimation);
- }
- }
- return animation2;
- }
- /**
- * Plays the custom animations of this effect
- *
- * @returns {number}
- * @private
- */
- _playCustomAnimations() {
- if (!this.data.animations)
- return 0;
- this._playAnimations(
- foundry.utils.deepClone(this.data.animations) ?? [],
- this.actualCreationTime - this.data.creationTimestamp
- );
- }
- _playAnimations(animations, timeDifference = 0) {
- let animationsToSend = [];
- const oneShotAnimations = animations.filter(
- (animation2) => !animation2.looping && !animation2.fromEnd
- );
- for (let animation2 of oneShotAnimations) {
- animation2.target = foundry.utils.getProperty(this, animation2.target);
- if (!animation2.target)
- continue;
- if (animation2.propertyName.indexOf("rotation") > -1) {
- animation2.from = animation2.from * (Math.PI / 180);
- animation2.to = animation2.to * (Math.PI / 180);
- }
- if (["position.x", "position.y", "height", "width"].includes(
- animation2.propertyName
- ) && animation2.gridUnits) {
- animation2.from *= canvas.grid.size;
- animation2.to *= canvas.grid.size;
- }
- if (["hue"].includes(animation2.propertyName)) {
- animation2.getPropertyName = "values." + animation2.propertyName;
- }
- animationsToSend = animationsToSend.concat(
- this._counterAnimateRotation(animation2)
- );
- }
- const loopingAnimations = animations.filter(
- (animation2) => animation2.looping
- );
- for (let animation2 of loopingAnimations) {
- animation2.target = foundry.utils.getProperty(this, animation2.target);
- if (!animation2.target)
- continue;
- if (animation2.propertyName.indexOf("rotation") > -1) {
- animation2.values = animation2.values.map((angle) => {
- return angle * (Math.PI / 180);
- });
- }
- if (["position.x", "position.y", "height", "width"].includes(
- animation2.propertyName
- ) && animation2.gridUnits) {
- animation2.values = animation2.values.map((value) => {
- return value * canvas.grid.size;
- });
- }
- if (["hue"].includes(animation2.propertyName)) {
- animation2.getPropertyName = "values." + animation2.propertyName;
- }
- animationsToSend = animationsToSend.concat(
- this._counterAnimateRotation(animation2)
- );
- }
- if (!(this instanceof PersistentCanvasEffect)) {
- animationsToSend = animationsToSend.concat(
- this._getFromEndCustomAnimations()
- );
- }
- setTimeout(() => {
- SequencerAnimationEngine.addAnimation(
- this.id,
- animationsToSend,
- timeDifference
- );
- }, 20);
- }
- _getFromEndCustomAnimations(immediate = false) {
- let fromEndAnimations = [];
- const animations = foundry.utils.deepClone(this.data.animations) ?? [];
- const oneShotEndingAnimations = animations.filter(
- (animation2) => !animation2.looping && animation2.fromEnd
- );
- for (let animation2 of oneShotEndingAnimations) {
- animation2.target = foundry.utils.getProperty(this, animation2.target);
- if (!animation2.target)
- continue;
- animation2.delay = is_real_number(immediate) ? Math.max(immediate - animation2.duration + animation2.delay, 0) : Math.max(
- this._animationDuration - animation2.duration + animation2.delay,
- 0
- );
- if (animation2.propertyName.indexOf("rotation") > -1) {
- animation2.from = animation2.from * (Math.PI / 180);
- animation2.to = animation2.to * (Math.PI / 180);
- }
- if (["position.x", "position.y", "height", "width"].includes(
- animation2.propertyName
- ) && animation2.gridUnits) {
- animation2.from *= canvas.grid.size;
- animation2.to *= canvas.grid.size;
- }
- fromEndAnimations = fromEndAnimations.concat(
- this._counterAnimateRotation(animation2)
- );
- }
- return fromEndAnimations;
- }
- /**
- * Fades in the effect at the start of the effect
- *
- * @returns {number|*}
- * @private
- */
- _fadeIn() {
- if (!this.data.fadeIn || !this.sprite)
- return 0;
- let fadeIn = this.data.fadeIn;
- if (this.actualCreationTime - (this.data.creationTimestamp + fadeIn.duration + fadeIn.delay) > 0) {
- return;
- }
- this.alphaFilter.alpha = 0;
- SequencerAnimationEngine.addAnimation(this.id, {
- target: this.alphaFilter,
- propertyName: "alpha",
- to: this.data.opacity,
- duration: fadeIn.duration,
- ease: fadeIn.ease,
- delay: fadeIn.delay,
- absolute: true
- });
- return fadeIn.duration + fadeIn.delay;
- }
- /**
- * Fades in the effect's audio at the start of the effect
- *
- * @returns {number|*}
- * @private
- */
- _fadeInAudio() {
- if (!this.data.fadeInAudio || !this.sprite || !this.video)
- return 0;
- let fadeInAudio = this.data.fadeInAudio;
- if (this.actualCreationTime - (this.data.creationTimestamp + fadeInAudio.duration + fadeInAudio.delay) > 0)
- return;
- this.video.volume = 0;
- SequencerAnimationEngine.addAnimation(this.id, {
- target: this,
- propertyName: "video.volume",
- to: (this.data.volume ?? 0) * game.settings.get("core", "globalInterfaceVolume"),
- duration: fadeInAudio.duration,
- ease: fadeInAudio.ease,
- delay: fadeInAudio.delay,
- absolute: true
- });
- return fadeInAudio.duration + fadeInAudio.delay;
- }
- /**
- * Fades out the effect at the end of the effect's duration
- *
- * @returns {number|*}
- * @private
- */
- _fadeOut(immediate = false) {
- if (!this.data.fadeOut || !this.sprite)
- return 0;
- let fadeOut = this.data.fadeOut;
- fadeOut.delay = is_real_number(immediate) ? Math.max(immediate - fadeOut.duration + fadeOut.delay, 0) : Math.max(this._animationDuration - fadeOut.duration + fadeOut.delay, 0);
- SequencerAnimationEngine.addAnimation(this.id, {
- target: this.alphaFilter,
- propertyName: "alpha",
- to: 0,
- duration: fadeOut.duration,
- ease: fadeOut.ease,
- delay: fadeOut.delay,
- absolute: true
- });
- return fadeOut.duration + fadeOut.delay;
- }
- /**
- * Fades out the effect at the end of the effect's duration
- *
- * @returns {number|*}
- * @private
- */
- _fadeOutAudio(immediate = false) {
- if (!this.data.fadeOutAudio || !this.sprite || !this.video)
- return 0;
- let fadeOutAudio = this.data.fadeOutAudio;
- fadeOutAudio.delay = is_real_number(immediate) ? Math.max(immediate - fadeOutAudio.duration + fadeOutAudio.delay, 0) : Math.max(
- this._animationDuration - fadeOutAudio.duration + fadeOutAudio.delay,
- 0
- );
- SequencerAnimationEngine.addAnimation(this.id, {
- target: this,
- propertyName: "video.volume",
- to: 0,
- duration: fadeOutAudio.duration,
- ease: fadeOutAudio.ease,
- delay: fadeOutAudio.delay,
- absolute: true
- });
- return fadeOutAudio.duration + fadeOutAudio.delay;
- }
- /**
- * Determines the scale to animate from or to
- * @param property
- * @returns {{x: number, y: number}}
- * @private
- */
- _determineScale(property) {
- let scale2 = {
- x: this.sprite.scale.x,
- y: this.sprite.scale.y
- };
- if (is_real_number(property.value)) {
- scale2.x *= property.value * this.gridSizeDifference * this.flipX;
- scale2.y *= property.value * this.gridSizeDifference * this.flipY;
- } else {
- scale2.x *= property.value.x * this.gridSizeDifference * this.flipX;
- scale2.y *= property.value.y * this.gridSizeDifference * this.flipY;
- }
- return scale2;
- }
- /**
- * Scales the effect in at the start of the effect
- *
- * @returns {number|*}
- * @private
- */
- _scaleIn() {
- if (!this.data.scaleIn || !this.sprite)
- return 0;
- let scaleIn = this.data.scaleIn;
- let fromScale = this._determineScale(scaleIn);
- if (this.actualCreationTime - (this.data.creationTimestamp + scaleIn.duration + scaleIn.delay) > 0)
- return;
- let toScale = {
- x: this.sprite.scale.x,
- y: this.sprite.scale.y
- };
- this.sprite.scale.set(fromScale.x, fromScale.y);
- SequencerAnimationEngine.addAnimation(this.id, [
- {
- target: this.sprite,
- propertyName: "scale.x",
- from: fromScale.x,
- to: toScale.x,
- duration: scaleIn.duration,
- ease: scaleIn.ease,
- delay: scaleIn.delay,
- absolute: true
- },
- {
- target: this.sprite,
- propertyName: "scale.y",
- from: fromScale.y,
- to: toScale.y,
- duration: scaleIn.duration,
- ease: scaleIn.ease,
- delay: scaleIn.delay,
- absolute: true
- }
- ]);
- return scaleIn.duration + scaleIn.delay;
- }
- /**
- * Scales the effect out at the end of the effect's duration
- *
- * @returns {number|*}
- * @private
- */
- _scaleOut(immediate = false) {
- if (!this.data.scaleOut || !this.sprite)
- return 0;
- let scaleOut = this.data.scaleOut;
- let scale2 = this._determineScale(scaleOut);
- scaleOut.delay = is_real_number(immediate) ? Math.max(immediate - scaleOut.duration + scaleOut.delay, 0) : Math.max(
- this._animationDuration - scaleOut.duration + scaleOut.delay,
- 0
- );
- SequencerAnimationEngine.addAnimation(this.id, [
- {
- target: this.sprite,
- propertyName: "scale.x",
- to: scale2.x,
- duration: scaleOut.duration,
- ease: scaleOut.ease,
- delay: scaleOut.delay,
- absolute: true
- },
- {
- target: this.sprite,
- propertyName: "scale.y",
- to: scale2.y,
- duration: scaleOut.duration,
- ease: scaleOut.ease,
- delay: scaleOut.delay,
- absolute: true
- }
- ]);
- return scaleOut.duration + scaleOut.delay;
- }
- /**
- * Rotates the effect in at the start of the effect
- *
- * @returns {number|*}
- * @private
- */
- _rotateIn() {
- if (!this.data.rotateIn || !this.sprite)
- return 0;
- let rotateIn = this.data.rotateIn;
- if (this.actualCreationTime - (this.data.creationTimestamp + rotateIn.duration + rotateIn.delay) > 0)
- return;
- let original_radians = this.spriteContainer.rotation;
- this.spriteContainer.rotation = rotateIn.value * (Math.PI / 180);
- SequencerAnimationEngine.addAnimation(
- this.id,
- this._counterAnimateRotation({
- target: this.spriteContainer,
- propertyName: "rotation",
- to: original_radians,
- duration: rotateIn.duration,
- ease: rotateIn.ease,
- delay: rotateIn.delay,
- absolute: true
- })
- );
- return rotateIn.duration + rotateIn.delay;
- }
- /**
- * Rotates the effect out at the end of the effect's duration
- *
- * @returns {number|*}
- * @private
- */
- _rotateOut(immediate = false) {
- if (!this.data.rotateOut || !this.sprite)
- return 0;
- let rotateOut = this.data.rotateOut;
- rotateOut.delay = is_real_number(immediate) ? Math.max(immediate - rotateOut.duration + rotateOut.delay, 0) : Math.max(
- this._animationDuration - rotateOut.duration + rotateOut.delay,
- 0
- );
- SequencerAnimationEngine.addAnimation(
- this.id,
- this._counterAnimateRotation({
- target: this.spriteContainer,
- propertyName: "rotation",
- to: rotateOut.value * (Math.PI / 180),
- duration: rotateOut.duration,
- ease: rotateOut.ease,
- delay: rotateOut.delay,
- absolute: true
- })
- );
- return rotateOut.duration + rotateOut.delay;
- }
- /**
- * Causes the effect to move towards the given location
- *
- * @returns {number|*}
- * @private
- */
- _moveTowards() {
- if (!this.data.moves || !this.sprite)
- return 0;
- let moves2 = this.data.moves;
- let movementDuration = this._animationDuration;
- if (this.data.moveSpeed) {
- const distance = distance_between(
- this.sourcePosition,
- this.targetPosition
- );
- movementDuration = distance / this.data.moveSpeed * 1e3;
- }
- if (this.data.moves.rotate)
- this._rotateTowards();
- const duration = movementDuration - moves2.delay;
- if (this.actualCreationTime - (this.data.creationTimestamp + duration + moves2.delay) > 0)
- return;
- SequencerAnimationEngine.addAnimation(this.id, [
- {
- target: this,
- propertyName: "position.x",
- to: this.targetPosition.x,
- duration,
- ease: moves2.ease,
- delay: moves2.delay
- },
- {
- target: this,
- propertyName: "position.y",
- to: this.targetPosition.y,
- duration,
- ease: moves2.ease,
- delay: moves2.delay
- }
- ]);
- return duration + moves2.delay;
- }
- /**
- * If this effect is temporary, this sets the timeout for when the effect should resolve and get removed;
- *
- * @private
- */
- _setEndTimeout() {
- setTimeout(() => {
- this._resolve(this.data);
- this.endEffect();
- }, this._animationDuration);
- }
- _setupTimestampHook(offset2) {
- if (!this._file?.originalMetadata?.timestamps || this._ended)
- return;
- const timestamps = this._file.getTimestamps();
- const timestampArray = Array.isArray(timestamps) ? timestamps : [timestamps];
- for (const timestamp of timestampArray) {
- if (!is_real_number(timestamp))
- continue;
- let realTimestamp = timestamp - offset2 / this.mediaPlaybackRate;
- if (realTimestamp < 0) {
- realTimestamp += this._endTime;
- }
- setTimeout(() => {
- if (this._ended)
- return;
- Hooks.callAll("sequencerEffectTimestamp", this, this._file);
- if (this.mediaLooping) {
- const offsets = (this._endTime - this.mediaCurrentTime) * -1e3;
- this._setupTimestampHook(offsets);
- }
- }, realTimestamp);
- }
- }
- }
- class PersistentCanvasEffect extends CanvasEffect {
- /**
- * @OVERRIDE
- * @returns {Promise<void>}
- * @private
- */
- async _initialize() {
- await super._initialize(false);
- await this._startEffect();
- }
- /**
- * @OVERRIDE
- * @returns {Promise<void>}
- * @private
- */
- async _reinitialize() {
- await super._reinitialize(false);
- }
- /** @OVERRIDE */
- _playPresetAnimations() {
- this._moveTowards();
- this._fadeIn();
- this._scaleIn();
- this._rotateIn();
- }
- /**
- * Starts the loop of this effect, calculating the difference between the effect's creation time, and the actual
- * creation time on the client
- *
- * @returns {Promise<void>}
- * @private
- */
- async _startEffect() {
- if (!this.hasAnimatedMedia)
- return;
- let creationTimeDifference = this.actualCreationTime - this.data.creationTimestamp;
- if (!this.data.noLoop) {
- return this._startLoop(creationTimeDifference);
- }
- if (creationTimeDifference < this._animationDuration) {
- this.mediaCurrentTime = creationTimeDifference / 1e3;
- if (this._endTime !== this.mediaDuration) {
- setTimeout(() => {
- this.mediaCurrentTime = this._endTime;
- this.updateTexture();
- }, this._endTime * 1e3 - creationTimeDifference);
- }
- await this.playMedia();
- return;
- }
- await this.pauseMedia();
- this.mediaCurrentTime = this._endTime;
- if (this.sprite.texture && this.video) {
- const oldRenderable = this.renderable;
- this.renderable = false;
- setTimeout(() => {
- this.renderable = oldRenderable;
- this.updateTexture();
- }, 350);
- }
- }
- /**
- * Kicks off the loop, or just sets the video to loop
- *
- * @param creationTimeDifference
- * @returns {Promise<void>}
- * @private
- */
- async _startLoop(creationTimeDifference) {
- this.mediaLooping = this.playNaturally;
- if (!this._animationTimes.loopStart) {
- this._loopOffset = creationTimeDifference % this._animationDuration / 1e3;
- } else if (creationTimeDifference / 1e3 > this._animationTimes.loopStart) {
- const loopDuration = this._animationTimes.loopEnd - this._animationTimes.loopStart;
- this._loopOffset = creationTimeDifference % (loopDuration * 1e3) / 1e3;
- }
- return this._resetLoop();
- }
- /**
- * Continuously reset the video to the right time so that the start and end time can be preserved
- *
- * @returns {Promise<void>}
- * @private
- */
- async _resetLoop(firstLoop = true) {
- if (this._ended)
- return;
- let loopWaitTime = 0;
- if (this._animationTimes.loopStart) {
- if (this._isEnding)
- return;
- this.mediaCurrentTime = (firstLoop ? 0 : this._animationTimes.loopStart) + (this._loopOffset > 0 ? this._loopOffset : 0);
- loopWaitTime = (this._animationTimes.loopEnd - this.mediaCurrentTime) * 1e3;
- } else {
- this.mediaCurrentTime = this._startTime + this._loopOffset;
- loopWaitTime = this._animationDuration - this._loopOffset * 1e3;
- }
- await this.playMedia();
- if (this.mediaLooping) {
- return;
- }
- this._resetTimeout = setTimeout(() => {
- if (this._ended)
- return;
- this._loopOffset = 0;
- this._resetLoop(false);
- }, loopWaitTime);
- }
- /** @OVERRIDE */
- _timeoutVisibility() {
- let creationTimeDifference = this.actualCreationTime - this.data.creationTimestamp;
- let timeout = creationTimeDifference === 0 && !this.data.animations ? 0 : 50;
- setTimeout(() => {
- this._setupHooks();
- }, timeout);
- }
- /** @OVERRIDE */
- _setEndTimeout() {
- let creationTimeDifference = this.actualCreationTime - this.data.creationTimestamp;
- if (!this.data.noLoop || creationTimeDifference >= this._animationDuration || !(this.hasAnimatedMedia || this.data.text))
- return;
- setTimeout(() => {
- this.pauseMedia();
- }, this._animationDuration);
- }
- /** @OVERRIDE */
- async endEffect() {
- if (this._isEnding)
- return;
- this._isEnding = true;
- let fullWaitDuration = 0;
- let extraEndDuration = this.data.extraEndDuration ?? 0;
- if (this._animationTimes?.forcedEnd) {
- this.mediaCurrentTime = this._animationTimes.forcedEnd;
- fullWaitDuration = (this.mediaDuration - (this._animationTimes?.forcedEnd ?? 0)) * 1e3;
- } else if (this._animationTimes?.loopEnd) {
- fullWaitDuration = (this.mediaDuration - this.mediaCurrentTime) * 1e3;
- this.mediaLooping = false;
- extraEndDuration = Math.max(extraEndDuration, fullWaitDuration);
- }
- const fromEndCustomAnimations = this._getFromEndCustomAnimations(extraEndDuration);
- const durations = [
- this._fadeOut(extraEndDuration),
- this._fadeOutAudio(extraEndDuration),
- this._scaleOut(extraEndDuration),
- this._rotateOut(extraEndDuration),
- this.data.extraEndDuration,
- fullWaitDuration,
- ...fromEndCustomAnimations.map(
- (animation2) => animation2.duration + animation2.delay
- )
- ].filter(Boolean);
- SequencerAnimationEngine.addAnimation(this.id, fromEndCustomAnimations);
- const waitDuration = Math.max(...durations, 0);
- this._resolve(waitDuration);
- return new Promise(
- (resolve) => setTimeout(() => {
- super.endEffect();
- resolve(this.data);
- }, waitDuration)
- );
- }
- }
- function createShape(shape) {
- const graphic = new PIXI.LegacyGraphics();
- graphic.beginFill(
- shape?.fillColor ?? 16777215,
- shape?.fillAlpha ?? shape?.isMask ? 1 : 0
- );
- graphic.lineStyle(
- shape.lineSize ?? (shape?.isMask ? 1 : 0),
- shape?.lineColor ?? 16777215
- );
- const offsetX = (shape.offset?.x ?? 0) * (shape.offset?.gridUnits ? canvas.grid.size : 1);
- const offsetY = (shape.offset?.y ?? 0) * (shape.offset?.gridUnits ? canvas.grid.size : 1);
- const sizeMultiplier = shape.gridUnits ? canvas.grid.size : 1;
- graphic.offset = {
- x: offsetX,
- y: offsetY
- };
- switch (shape.type) {
- case CONSTANTS.SHAPES.CIRC:
- graphic.drawCircle(
- graphic.offset.x,
- graphic.offset.y,
- shape.radius * sizeMultiplier
- );
- break;
- case CONSTANTS.SHAPES.RECT:
- graphic.drawRect(
- graphic.offset.x,
- graphic.offset.y,
- shape.width * sizeMultiplier,
- shape.height * sizeMultiplier
- );
- break;
- case CONSTANTS.SHAPES.ELIP:
- graphic.drawEllipse(
- graphic.offset.x,
- graphic.offset.y,
- shape.width * sizeMultiplier,
- shape.height * sizeMultiplier
- );
- break;
- case CONSTANTS.SHAPES.RREC:
- graphic.drawRoundedRect(
- graphic.offset.x,
- graphic.offset.y,
- shape.width * sizeMultiplier,
- shape.height * sizeMultiplier,
- shape.radius * sizeMultiplier
- );
- break;
- case CONSTANTS.SHAPES.POLY:
- graphic.drawPolygon(
- shape.points.map((point) => {
- return new PIXI.Point(
- point[0] * sizeMultiplier,
- point[1] * sizeMultiplier
- );
- })
- );
- break;
- }
- graphic.alpha = shape.alpha ?? 1;
- graphic.endFill();
- return graphic;
- }
- function calculate_missed_position(source, target, twister) {
- const sourcePosition = get_object_position(source);
- const sourceDimensions = get_object_dimensions(source, true);
- if (!target) {
- const angle2 = twister.random() * Math.PI * 2;
- let x2 = Math.cos(angle2) * sourceDimensions.width;
- let y2 = Math.sin(angle2) * sourceDimensions.height;
- return {
- x: random_float_between(x2 * 1.5, x2 * 2.5, twister),
- y: random_float_between(y2 * 1.5, y2 * 2.5, twister)
- };
- }
- const targetDimensions = get_object_dimensions(target, true);
- const targetPosition = get_object_position(target);
- const ray = new Ray(targetPosition, sourcePosition);
- let startRadians = ray.angle + Math.PI / 2;
- let endRadians = ray.angle - Math.PI / 2;
- const sizeCompensation = Math.max(
- 1,
- Math.abs(sourceDimensions.width - targetDimensions.height)
- );
- let distance = ray.distance / canvas.grid.size - sizeCompensation;
- if (distance <= 1) {
- const angle2 = twister.random() > 0.5 ? ray.angle + Math.PI / 4 : ray.angle - Math.PI / 4;
- const x2 = Math.cos(angle2) * targetDimensions.width;
- const y2 = Math.sin(angle2) * targetDimensions.height;
- return { x: x2, y: y2 };
- }
- distance = Math.max(Math.abs(distance - 15), 6);
- endRadians -= Math.PI / distance;
- startRadians += Math.PI / distance;
- const angle = interpolate(startRadians, endRadians, twister.random());
- const x = Math.cos(angle) * targetDimensions.width;
- const y = Math.sin(angle) * targetDimensions.height;
- return {
- x: random_float_between(x * 1.5, x * 2.5, twister),
- y: random_float_between(y * 1.5, y * 2.5, twister)
- };
- }
- function get_object_position(obj, { measure = false, exact = false } = {}) {
- if (obj instanceof CanvasEffect) {
- return obj.worldPosition;
- }
- obj = obj?._object ?? obj.object ?? obj;
- let pos = {};
- if (obj instanceof MeasuredTemplate) {
- if (measure) {
- if (obj.document.t === "cone" || obj.document.t === "ray") {
- pos.x = obj.ray.B.x;
- pos.y = obj.ray.B.y;
- }
- }
- if (obj.document.t === "rect") {
- pos.x = obj.x;
- pos.y = obj.y;
- if (!exact) {
- pos.x += Math.abs(obj.shape.width / 2) + obj.shape.x;
- pos.y += Math.abs(obj.shape.height / 2) + obj.shape.y;
- }
- }
- } else if (obj instanceof Tile) {
- pos = {
- x: obj.document.x,
- y: obj.document.y
- };
- if (!exact) {
- pos.x += Math.abs(obj.document.width / 2);
- pos.y += Math.abs(obj.document.height / 2);
- }
- } else if (obj instanceof Token) {
- const halfSize = get_object_dimensions(obj, true);
- pos = {
- x: obj.x + halfSize.width,
- y: obj.y + halfSize.height
- };
- if (exact) {
- pos.x -= halfSize.width;
- pos.y -= halfSize.height;
- }
- } else if (obj instanceof Drawing) {
- pos = {
- x: obj.document.x,
- y: obj.document.y
- };
- if (!exact) {
- const halfSize = get_object_dimensions(obj, true);
- pos.x += halfSize.width;
- pos.y += halfSize.height;
- }
- }
- pos = {
- x: pos.x ?? obj?.x ?? obj?.position?.x ?? obj?.position?._x ?? obj?.document?.x ?? obj?.document?.position?.x ?? null,
- y: pos.y ?? obj?.y ?? obj?.position?.y ?? obj?.position?._y ?? obj?.document?.y ?? obj?.document?.position?.y ?? null,
- elevation: obj?.elevation ?? obj?.document?.elevation ?? null
- };
- if (pos.x === null)
- delete pos["x"];
- if (pos.y === null)
- delete pos["y"];
- if (pos.elevation === null)
- delete pos["elevation"];
- return pos;
- }
- function get_random_offset(target, randomOffset, twister = false) {
- let { width: width2, height } = get_object_dimensions(target, true);
- width2 *= randomOffset;
- height *= randomOffset;
- return {
- x: random_float_between(width2 * -1, width2, twister),
- y: random_float_between(height * -1, height, twister)
- };
- }
- function get_object_dimensions(inObj, half = false) {
- inObj = inObj?.object ?? inObj?._object ?? inObj;
- let width2 = inObj?.hitArea?.width ?? inObj?.w ?? inObj?.shape?.width ?? (inObj?.shape?.radius ? inObj?.shape?.radius * 2 : void 0) ?? inObj?.width ?? canvas.grid.size;
- let height = inObj?.hitArea?.height ?? inObj?.h ?? inObj?.shape?.height ?? (inObj?.shape?.radius ? inObj?.shape?.radius * 2 : void 0) ?? inObj?.height ?? canvas.grid.size;
- return {
- width: width2 / (half ? 2 : 1),
- height: height / (half ? 2 : 1)
- };
- }
- const alignments = {
- "top-left": { x: 0.5, y: 0.5 },
- top: { x: 0, y: 0.5 },
- "top-right": { x: -0.5, y: 0.5 },
- left: { x: 0.5, y: 0 },
- center: { x: 0, y: 0 },
- right: { x: -0.5, y: 0 },
- "bottom-left": { x: 0.5, y: -0.5 },
- bottom: { x: 0, y: -0.5 },
- "bottom-right": { x: -0.5, y: -0.5 }
- };
- function align({
- context,
- spriteWidth,
- spriteHeight,
- align: align2,
- edge
- } = {}) {
- let { width: width2, height } = get_object_dimensions(context);
- const alignRatio = alignments[align2];
- const offset2 = {
- x: interpolate(width2 * -0.5, width2 * 0.5, alignRatio.x + 0.5),
- y: interpolate(height * -0.5, height * 0.5, alignRatio.y + 0.5)
- };
- return {
- x: offset2.x + (edge && edge !== "on" ? spriteWidth * alignRatio.x * (edge === "outer" ? 1 : -1) : 0),
- y: offset2.y + (edge && edge !== "on" ? spriteHeight * alignRatio.y * (edge === "outer" ? 1 : -1) : 0)
- };
- }
- function is_object_canvas_data(inObj) {
- if (typeof inObj !== "object")
- return false;
- const keys = Object.keys(inObj);
- keys.sort();
- return keys.includes("x") && keys.includes("y") || keys.includes("height") && keys.includes("width") && keys.includes("x") && keys.includes("y");
- }
- function get_object_canvas_data(inObject, measure = false) {
- inObject = inObject?.object ?? inObject;
- return {
- ...get_object_position(inObject, { measure }),
- ...get_object_dimensions(inObject?.mesh ?? inObject?.tile ?? inObject),
- elevation: get_object_elevation(inObject),
- uuid: inObject?.document?.uuid ?? inObject?.uuid,
- cachedLocation: true
- };
- }
- function get_object_elevation(inObject) {
- return inObject?.document?.elevation ?? inObject?.elevation ?? 0;
- }
- function get_mouse_position(snapToGrid = false, gridSnap = 2) {
- const pos = getCanvasMouse().getLocalPosition(canvas.app.stage);
- return !snapToGrid ? new PIXI.Point(pos.x, pos.y) : canvas.grid.getSnappedPosition(pos.x, pos.y, gridSnap);
- }
- function distance_between(p1, p2) {
- return new Ray(p1, p2).distance;
- }
- function is_position_within_bounds(inPosition, inElement, relativeTo) {
- const localPosition = inElement.toLocal(inPosition, relativeTo);
- return inElement.getLocalBounds().contains(localPosition.x, localPosition.y);
- }
- function rotate_coordinate(p1, p2, radians) {
- let cos = Math.cos(radians);
- let sin = Math.sin(radians);
- let nx = cos * (p2.x - p1.x) + sin * (p2.y - p1.y) + p1.x;
- let ny = cos * (p2.y - p1.y) - sin * (p2.x - p1.x) + p1.y;
- return [nx, ny];
- }
- function get_closest_token(inPosition, { minimumDistance = false } = {}) {
- let tokens = Array.from(canvas.scene.tokens);
- if (minimumDistance) {
- tokens = tokens.filter(
- (token) => distance_between(get_object_position(token), inPosition) <= minimumDistance
- );
- }
- tokens.sort((a, b) => {
- return distance_between(get_object_position(a), inPosition) - distance_between(get_object_position(b), inPosition);
- });
- return tokens?.[0] ?? false;
- }
- function rotateAroundPoint(cx, cy, x, y, radians) {
- const cos = Math.cos(radians);
- const sin = Math.sin(radians);
- const nx = cos * (x - cx) + sin * (y - cy) + cx;
- const ny = cos * (y - cy) - sin * (x - cx) + cy;
- return { x: nx, y: ny };
- }
- function validateAnimation(inTarget, inPropertyName, inOptions) {
- if (typeof inPropertyName !== "string") {
- return `inPropertyName must be of type string`;
- }
- if (typeof inTarget !== "string") {
- return `inTarget must be of type string`;
- }
- if (!is_real_number(inOptions.from)) {
- return `inOptions.from must be of type number`;
- }
- if (!is_real_number(inOptions.to)) {
- return `inOptions.to must be of type number`;
- }
- if (!is_real_number(inOptions.duration)) {
- return `inOptions.duration must be of type number`;
- }
- if (inOptions?.delay !== void 0 && !is_real_number(inOptions.delay)) {
- return `inOptions.delay must be of type number`;
- }
- if (inOptions?.ease !== void 0 && typeof inOptions.ease !== "string") {
- return `inOptions.ease must be of type string`;
- }
- if (inOptions?.fromEnd !== void 0 && typeof inOptions.fromEnd !== "boolean") {
- return `inOptions.fromEnd must be of type boolean`;
- }
- if (inOptions?.gridUnits !== void 0) {
- if (typeof inOptions.gridUnits !== "boolean") {
- return `inOptions.gridUnits must be of type boolean`;
- }
- if (inOptions.gridUnits && ![
- "position.x",
- "position.y",
- "scale.x",
- "scale.y",
- "height",
- "width"
- ].includes(inPropertyName)) {
- return `if inOptions.gridUnits is true, inPropertyName must be position.x, position.y, scale.x, scale.y, width, or height`;
- }
- }
- return {
- target: inTarget,
- propertyName: inPropertyName,
- from: inOptions?.from,
- to: inOptions?.to,
- duration: inOptions?.duration ?? 0,
- delay: inOptions?.delay ?? 0,
- ease: inOptions?.ease ?? "linear",
- looping: false,
- fromEnd: inOptions?.fromEnd ?? false,
- gridUnits: inOptions?.gridUnits ?? false
- };
- }
- function validateLoopingAnimation(inTarget, inPropertyName, inOptions) {
- if (typeof inPropertyName !== "string") {
- return `inPropertyName must be of type string`;
- }
- if (typeof inTarget !== "string") {
- return `inTarget must be of type string`;
- }
- if (!inOptions?.values) {
- if (!inOptions?.from === void 0 || !inOptions?.to === void 0) {
- return `if inOptions.values is not set, you must provide inOptions.from and inOptions.to`;
- }
- if (!is_real_number(inOptions.from)) {
- return `inOptions.from must be of type number`;
- }
- if (!is_real_number(inOptions.to)) {
- return `inOptions.to must be of type number`;
- }
- inOptions.values = [inOptions?.from, inOptions?.to];
- delete inOptions.from;
- delete inOptions.to;
- } else {
- if (!Array.isArray(inOptions.values)) {
- return `inOptions.values must be of type array`;
- }
- inOptions.values.forEach((value) => {
- if (!is_real_number(value)) {
- return `values in inOptions.keys must be of type number`;
- }
- });
- }
- if (!is_real_number(inOptions.duration)) {
- return `inOptions.duration must be of type number`;
- }
- if (inOptions?.delay !== void 0 && !is_real_number(inOptions.delay)) {
- return `inOptions.delay must be of type number`;
- }
- if (inOptions?.ease !== void 0 && typeof inOptions.ease !== "string") {
- return `inOptions.ease must be of type string`;
- }
- if (inOptions?.loops !== void 0 && !is_real_number(inOptions.loops)) {
- return `inOptions.loops must be of type number`;
- }
- if (inOptions?.pingPong !== void 0 && typeof inOptions.pingPong !== "boolean") {
- return `inOptions.pingPong must be of type boolean`;
- }
- if (inOptions?.gridUnits !== void 0) {
- if (typeof inOptions.gridUnits !== "boolean") {
- return `inOptions.gridUnits must be of type boolean`;
- }
- if (inOptions.gridUnits && ![
- "position.x",
- "position.y",
- "scale.x",
- "scale.y",
- "height",
- "width"
- ].includes(inPropertyName)) {
- return `if inOptions.gridUnits is true, inPropertyName must be position.x, position.y, scale.x, scale.y, width, or height`;
- }
- }
- return {
- target: inTarget,
- propertyName: inPropertyName,
- values: inOptions?.values,
- duration: inOptions?.duration ?? 0,
- delay: inOptions?.delay ?? 0,
- ease: inOptions?.ease ?? "linear",
- looping: true,
- loops: inOptions?.loops,
- indefinite: inOptions?.loops === void 0 || !is_real_number(inOptions?.loops),
- pingPong: inOptions?.pingPong ?? false,
- gridUnits: inOptions?.gridUnits ?? false
- };
- }
- const PlayerSettings = {
- file: {
- label: "SEQUENCER.Player.Option.File",
- store: writable$1(""),
- default: ""
- },
- scale: {
- label: "SEQUENCER.Player.Option.Scale",
- store: writable$1(1),
- default: 1
- },
- users: {
- label: "SEQUENCER.Player.Option.ForUsers",
- store: writable$1([]),
- default: []
- },
- belowTokens: {
- label: "SEQUENCER.Player.Option.BelowTokens",
- store: writable$1(false),
- default: false
- },
- snapToGrid: {
- label: "SEQUENCER.Player.Option.SnapToGrid",
- store: writable$1(false),
- default: false
- },
- rotation: {
- label: "SEQUENCER.Player.Option.Rotation",
- store: writable$1(0),
- default: 0
- },
- randomRotation: {
- label: "SEQUENCER.Player.Option.Randomize",
- store: writable$1(false),
- default: false
- },
- fadeIn: {
- label: "SEQUENCER.Player.Option.FadeIn",
- store: writable$1(0),
- default: 0
- },
- fadeOut: {
- label: "SEQUENCER.Player.Option.FadeOut",
- store: writable$1(0),
- default: 0
- },
- scaleIn: {
- label: "SEQUENCER.Player.Option.ScaleIn",
- store: writable$1(0),
- default: 0
- },
- scaleOut: {
- label: "SEQUENCER.Player.Option.ScaleOut",
- store: writable$1(0),
- default: 0
- },
- mirrorX: {
- label: "SEQUENCER.Player.Option.MirrorX",
- store: writable$1(false),
- default: false
- },
- mirrorY: {
- label: "SEQUENCER.Player.Option.MirrorY",
- store: writable$1(false),
- default: false
- },
- randomMirrorX: {
- label: "SEQUENCER.Player.Option.Randomize",
- store: writable$1(false),
- default: false
- },
- randomMirrorY: {
- label: "SEQUENCER.Player.Option.Randomize",
- store: writable$1(false),
- default: false
- },
- offsetX: {
- label: "SEQUENCER.Player.Option.OffsetX",
- store: writable$1(0),
- default: 0
- },
- offsetY: {
- label: "SEQUENCER.Player.Option.OffsetY",
- store: writable$1(0),
- default: 0
- },
- offsetGridUnits: {
- label: "SEQUENCER.Player.Option.GridUnits",
- store: writable$1(false),
- default: false
- },
- randomOffsetAmount: {
- label: "SEQUENCER.Player.Option.RandomOffset",
- store: writable$1(0),
- default: 0
- },
- randomOffset: {
- label: "SEQUENCER.Player.Option.Randomize",
- store: writable$1(false),
- default: false
- },
- preload: {
- label: "SEQUENCER.Player.Option.Preload",
- store: writable$1(false),
- default: false
- },
- moveTowards: {
- label: "SEQUENCER.Player.Option.DragBehavior",
- label_off: "SEQUENCER.Player.Option.DragStretch",
- label_on: "SEQUENCER.Player.Option.DragMove",
- store: writable$1(false),
- default: false
- },
- moveSpeed: {
- label: "SEQUENCER.Player.Option.MoveSpeed",
- store: writable$1(0),
- default: 0
- },
- attachTo: {
- label: "SEQUENCER.Player.Option.AttachTo",
- store: writable$1(false),
- default: false,
- callback: (e) => {
- EffectPlayer.sourceAttach = e.target.checked;
- }
- },
- stretchToAttach: {
- label: "SEQUENCER.Player.Option.StretchToAttach",
- store: writable$1(false),
- default: false,
- callback: (e) => {
- EffectPlayer.targetAttach = e.target.checked;
- }
- },
- persist: {
- label: "SEQUENCER.Player.Option.Persist",
- store: writable$1(false),
- default: false
- },
- repeat: {
- label: "SEQUENCER.Player.Option.Repeat",
- store: writable$1(false),
- default: false
- },
- repetitions: {
- label: "SEQUENCER.Player.Option.Repetitions",
- store: writable$1(1),
- default: 1
- },
- repeatDelayMin: {
- label: "SEQUENCER.Player.Option.DelayMin",
- store: writable$1(200),
- default: 200
- },
- repeatDelayMax: {
- label: "SEQUENCER.Player.Option.DelayMax",
- store: writable$1(400),
- default: 400
- }
- };
- PlayerSettings.export = () => {
- return Object.fromEntries(
- Object.entries(PlayerSettings).map((entry) => {
- return [entry[0], get_store_value(entry[1].store)];
- })
- );
- };
- PlayerSettings.import = (settings) => {
- Object.entries(PlayerSettings).forEach((entry) => {
- if (settings?.[entry[0]] !== void 0) {
- entry[1].store.set(settings?.[entry[0]]);
- } else if (entry[1]?.default !== void 0) {
- entry[1].store.set(entry[1].default);
- }
- });
- };
- PlayerSettings.getPresets = () => {
- return Object.keys(game.settings.get(CONSTANTS.MODULE_NAME, "effectPresets"));
- };
- PlayerSettings.loadPreset = (name) => {
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- return PlayerSettings.import(effectPresets[name]);
- };
- PlayerSettings.savePreset = async (name) => {
- const newName = await promptNewPresetName(name);
- if (!newName)
- return;
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- effectPresets[newName] = PlayerSettings.export();
- return game.settings.set(
- CONSTANTS.MODULE_NAME,
- "effectPresets",
- effectPresets
- );
- };
- PlayerSettings.copyPreset = async (name) => {
- const newName = await promptNewPresetName(name, true);
- if (!newName)
- return;
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- effectPresets[newName] = PlayerSettings.export();
- return game.settings.set(
- CONSTANTS.MODULE_NAME,
- "effectPresets",
- effectPresets
- );
- };
- PlayerSettings.deletePreset = (name) => {
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- delete effectPresets[name];
- return game.settings.set(
- CONSTANTS.MODULE_NAME,
- "effectPresets",
- effectPresets
- );
- };
- async function promptNewPresetName(inName, copy = false) {
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- let title = copy ? game.i18n.localize("SEQUENCER.Player.CopyPresetTitle") : game.i18n.localize("SEQUENCER.Player.CreateNewPresetTitle");
- let presetName = await new Promise((resolve) => {
- new Dialog({
- title,
- content: `<p><input type="text" placeholder="${game.i18n.localize(
- "SEQUENCER.Player.CreateNewPresetInputLabel"
- )}" id="newPresetName" style="width:100%;"></p>`,
- buttons: {
- okay: {
- icon: '<i class="fas fa-check"></i>',
- label: game.i18n.localize("SEQUENCER.OK"),
- callback: async (html) => {
- let name = html.find("#newPresetName").val();
- if (name === "" || !name) {
- name = false;
- }
- resolve(name);
- }
- },
- cancel: {
- icon: '<i class="fas fa-times"></i>',
- label: game.i18n.localize("SEQUENCER.Cancel"),
- callback: () => {
- resolve(false);
- }
- }
- },
- close: () => {
- },
- render: (html) => {
- html.find("#newPresetName").val(inName).focus();
- }
- }).render(true);
- });
- if (presetName) {
- if (presetName.toLowerCase() === "default") {
- Dialog.prompt({
- title: game.i18n.localize("SEQUENCER.Player.DefaultErrorTitle"),
- content: `<p>${game.i18n.localize(
- "SEQUENCER.Player.DefaultErrorContent"
- )}</p>`,
- label: game.i18n.localize("SEQUENCER.OK"),
- callback: () => {
- }
- });
- return false;
- }
- if (effectPresets[presetName]) {
- const overwrite = await Dialog.confirm({
- title: game.i18n.localize("SEQUENCER.Player.OverwritePresetTitle"),
- content: `<p>${game.i18n.format(
- "SEQUENCER.Player.OverwritePresetContent",
- { preset_name: presetName }
- )}</p>`
- });
- if (!overwrite) {
- presetName = await promptPresetName(presetName);
- }
- }
- }
- return presetName;
- }
- PlayerSettings.migrateOldPresets = () => {
- if (!game.user.isGM)
- return;
- const effectPresets = game.settings.get(
- CONSTANTS.MODULE_NAME,
- "effectPresets"
- );
- const presetsToUpdate = Object.values(effectPresets).filter((preset) => {
- return !preset?.version;
- });
- if (!presetsToUpdate.length)
- return;
- const newEffectPresets = Object.fromEntries(
- Object.entries(effectPresets).map(([name, preset]) => {
- if (preset?.version)
- return [name, preset];
- preset.version = game.modules.get(CONSTANTS.MODULE_NAME).version;
- if (preset.repetitions > 1) {
- preset.repeat = true;
- }
- if (preset.randomMirrorY) {
- preset.mirrorY = true;
- }
- if (preset.randomOffset) {
- preset.randomOffsetAmount = 1;
- preset.offsetGridUnits = true;
- }
- return [name, preset];
- })
- );
- return game.settings.set(
- CONSTANTS.MODULE_NAME,
- "effectPresets",
- newEffectPresets
- );
- };
- const InteractionManager = {
- startDragPosition: false,
- state: {
- LeftMouseDown: false,
- RightMouseDown: false,
- Dragging: false
- },
- get isLayerActive() {
- return canvas.sequencerInterfaceLayer.active;
- },
- initialize() {
- window.addEventListener("mousedown", (event) => {
- if (!canvas.ready)
- return;
- if (!this.isLayerActive)
- return;
- const hover = document.elementFromPoint(event.clientX, event.clientY);
- if (!hover || hover.id !== "board")
- return;
- const button = event.button;
- if (!(button === 0 || button === 2))
- return;
- if (button === 0) {
- this.state.LeftMouseDown = true;
- this._propagateEvent("mouseLeftDown");
- }
- if (button === 2) {
- this.state.RightMouseDown = true;
- this._propagateEvent("mouseRightDown");
- }
- });
- window.addEventListener("mouseup", (event) => {
- if (!canvas.ready)
- return;
- if (!this.isLayerActive)
- return;
- const hover = document.elementFromPoint(event.clientX, event.clientY);
- if (!hover || hover.id !== "board")
- return;
- if (document.activeElement.tagName !== "BODY")
- return;
- const button = event.button;
- if (!(button === 0 || button === 2))
- return;
- if (button === 0) {
- this.state.LeftMouseDown = false;
- this._propagateEvent("mouseLeftUp");
- this.state.Dragging = false;
- this.startDragPosition = false;
- }
- if (button === 2) {
- this.state.RightMouseDown = false;
- this._propagateEvent("mouseRightUp");
- this.state.Dragging = false;
- this.startDragPosition = false;
- }
- });
- window.addEventListener("mousemove", (event) => {
- if (!canvas.ready)
- return;
- const hover = document.elementFromPoint(event.clientX, event.clientY);
- if (!hover || hover.id !== "board")
- return;
- if (!this.isLayerActive)
- return;
- this._propagateEvent("mouseMove");
- if (this.state.LeftMouseDown && !this.startDragPosition) {
- this.startDragPosition = get_mouse_position();
- }
- if (this.state.LeftMouseDown && !this.state.Dragging) {
- const distance = distance_between(
- this.startDragPosition,
- get_mouse_position()
- );
- this.state.Dragging = distance > 20;
- }
- });
- EffectPlayer.initialize();
- SelectionManager.initialize();
- },
- tearDown() {
- EffectPlayer.tearDown();
- SelectionManager.tearDown();
- },
- _propagateEvent(eventName) {
- if (EffectPlayer.isActive && EffectPlayer[eventName]) {
- EffectPlayer[eventName]();
- }
- if (SelectionManager.isActive && SelectionManager[eventName]) {
- SelectionManager[eventName]();
- }
- }
- };
- const EffectPlayer = {
- sequenceBuffer: [],
- playMany: false,
- playManySequenced: false,
- cursorPos: false,
- startPos: false,
- endPos: false,
- get snapLocationToGrid() {
- return get_store_value(PlayerSettings.snapToGrid.store);
- },
- get sourceAttach() {
- return get_store_value(PlayerSettings.attachTo.store);
- },
- get targetAttach() {
- return get_store_value(PlayerSettings.stretchToAttach.store);
- },
- sourceAttachFound: false,
- targetAttachFound: false,
- get isActive() {
- return InteractionManager.isLayerActive && game?.activeTool === "play-effect";
- },
- /**
- * Opens the Sequencer Effects UI with the player tab open
- */
- show() {
- return EffectsUIApp.show({ tab: "player" });
- },
- initialize() {
- this.layer = canvas.sequencerInterfaceLayer;
- },
- tearDown() {
- this._reset();
- },
- /**
- * Mouse events
- */
- mouseLeftDown() {
- this._evaluateStartPosition();
- },
- mouseLeftUp() {
- if (!this.startPos)
- return;
- this._playEffect();
- this.startPos = false;
- this.endPos = false;
- this.sourceAttachFound = false;
- this.targetAttachFound = false;
- },
- mouseRightUp() {
- this._reset();
- },
- mouseMove() {
- this._evaluateCursorPosition();
- if (InteractionManager.state.Dragging) {
- this._evaluateEndPosition();
- }
- },
- /**
- * Hotkeys
- */
- playManyUp() {
- this._playEffects();
- this._reset();
- },
- /**
- * Private methods
- */
- _evaluatePosition(attach = false) {
- let position = get_mouse_position(this.snapLocationToGrid);
- const attachToObject = attach ? get_closest_token(position, {
- minimumDistance: canvas.grid.size
- }) : false;
- let attachFound = false;
- if (attachToObject) {
- attachFound = true;
- position = get_object_position(attachToObject);
- }
- return [position, attachFound];
- },
- _evaluateCursorPosition() {
- const attach = InteractionManager.state.Dragging ? this.targetAttach : this.sourceAttach;
- [this.cursorPos] = this._evaluatePosition(attach);
- },
- _evaluateStartPosition() {
- if (this.startPos)
- return;
- [this.startPos, this.sourceAttachFound] = this._evaluatePosition(
- this.sourceAttach
- );
- },
- _evaluateEndPosition() {
- [this.endPos, this.targetAttachFound] = this._evaluatePosition(
- this.targetAttach
- );
- },
- _reset() {
- if (!this.layer)
- return;
- this.startPos = false;
- this.endPos = false;
- this.sourceAttachFound = false;
- this.targetAttachFound = false;
- this.sequenceBuffer = [];
- this._evaluateCursorPosition();
- },
- async _playEffect() {
- const settings = foundry.utils.mergeObject(PlayerSettings.export(), {
- ...InteractionManager.state,
- startPos: this.startPos,
- endPos: this.endPos
- });
- if (!settings.users.length || settings.users?.[0] === "all")
- settings.users = [];
- if (settings.file === "")
- return;
- if (!(Sequencer.Database.entryExists(settings.file) || await SequencerFileCache.srcExists(settings.file))) {
- throw custom_error(
- "Sequencer",
- `Sequencer Player | Could not find file or database entry: ${settings.file}`
- );
- }
- if (settings.preload) {
- await Sequencer.Preloader.preloadForClients(settings.file);
- }
- const sequence = this.sequenceBuffer.length > 0 && this.playManySequenced ? this.sequenceBuffer[this.sequenceBuffer.length - 1] : new Sequence();
- const effect = sequence.effect().file(settings.file).forUsers(settings.users).mirrorX(settings.mirrorX && !settings.randomMirrorX).mirrorY(settings.mirrorY && !settings.randomMirrorY).randomizeMirrorX(settings.randomMirrorX).randomizeMirrorY(settings.randomMirrorY).persist(settings.persist).belowTokens(settings.belowTokens);
- if (settings.repeat) {
- effect.repeats(
- settings.repetitions,
- settings.repeatDelayMin,
- settings.repeatDelayMax
- );
- }
- if (settings.fadeIn > 0)
- effect.fadeIn(settings.fadeIn);
- if (settings.fadeOut > 0)
- effect.fadeOut(settings.fadeOut);
- const offsetData = settings.randomOffset ? {
- offset: { x: settings.offsetX, y: settings.offsetY },
- gridUnits: settings.offsetGridUnits
- } : {};
- const offsetSource = !settings.Dragging ? offsetData : {};
- const attachToObject = settings.attachTo ? get_closest_token(settings.startPos, {
- minimumDistance: canvas.grid.size
- }) : false;
- if (attachToObject) {
- effect.attachTo(attachToObject, {
- randomOffset: settings.randomOffset && !settings.Dragging ? settings.randomOffsetAmount : false,
- ...offsetSource
- });
- } else {
- effect.atLocation(settings.startPos, {
- randomOffset: settings.randomOffset && !settings.Dragging ? settings.randomOffsetAmount : false,
- ...offsetSource
- });
- }
- if (settings.persist && settings.name && settings.name !== "" && settings.name !== "default" && settings.name !== "new") {
- effect.name("Preset: " + settings.name);
- }
- if (settings.Dragging) {
- if (settings.moveTowards) {
- effect.moveTowards(settings.endPos, {
- randomOffset: settings.randomOffset ? settings.randomOffsetAmount : false,
- ...offsetData
- });
- if (settings.moveSpeed) {
- effect.moveSpeed(settings.moveSpeed);
- }
- } else {
- let target = settings.stretchToAttach ? get_closest_token(settings.endPos, {
- minimumDistance: canvas.grid.size
- }) : settings.endPos;
- effect.stretchTo(target, {
- attachTo: settings.stretchToAttach,
- randomOffset: settings.randomOffset ? settings.randomOffsetAmount : false,
- ...offsetData
- });
- }
- }
- if (!settings.Dragging || settings.Dragging && settings.moveTowards) {
- effect.scale(settings.scale);
- if (settings.scaleIn > 0)
- effect.scaleIn(0, settings.scaleIn, { ease: "easeInOutSine" });
- if (settings.scaleOut > 0)
- effect.scaleOut(0, settings.scaleOut, { ease: "easeInOutSine" });
- effect.randomRotation(settings.randomRotation);
- }
- if (this.playManySequenced) {
- effect.waitUntilFinished();
- }
- if (!this.playManySequenced || this.sequenceBuffer.length === 0) {
- this.sequenceBuffer.push(sequence);
- }
- if (!this.playMany && !this.playManySequenced)
- this._playEffects();
- },
- _playEffects() {
- this.sequenceBuffer.forEach((sequence) => sequence.play());
- this.sequenceBuffer = [];
- }
- };
- const SelectionManager = {
- selectedEffect: false,
- hoveredEffects: /* @__PURE__ */ new Set(),
- suggestedProperties: false,
- sourceOrTarget: false,
- dragOffset: false,
- hoveredEffectUI: false,
- get snapToGrid() {
- return get_store_value(PlayerSettings.snapToGrid.store);
- },
- set snapToGrid(bool) {
- PlayerSettings.snapToGrid.store.set(bool);
- },
- set attachToTarget(bool) {
- PlayerSettings.stretchToAttach.store.set(bool);
- },
- get attachToTarget() {
- return get_store_value(PlayerSettings.stretchToAttach.store);
- },
- get isActive() {
- return InteractionManager.isLayerActive && game?.activeTool === "select-effect";
- },
- get effects() {
- return SequencerEffectManager.effects.filter(
- (effect) => effect.userCanDelete
- );
- },
- initialize() {
- this.layer = canvas.sequencerInterfaceLayer;
- },
- tearDown() {
- this._reset();
- this.hoveredEffects = /* @__PURE__ */ new Set();
- },
- sourcePointSelected() {
- this.sourceOrTarget = "source";
- },
- targetPointSelected() {
- this.sourceOrTarget = "target";
- },
- /**
- * Mouse Events
- */
- mouseLeftDown() {
- if (!this.selectedEffect) {
- return this._selectEffects();
- }
- if (!this.hoveredEffects.size) {
- this._reset();
- }
- },
- mouseRightDown() {
- },
- mouseLeftUp() {
- if (!InteractionManager.state.Dragging) {
- return this._selectEffects();
- }
- if (!InteractionManager.state.Dragging || !this.selectedEffect || !this.suggestedProperties)
- return;
- this._updateEffect();
- },
- mouseRightUp() {
- InteractionManager.state.LeftMouseDown = false;
- this.suggestedProperties = false;
- this.sourceOrTarget = false;
- this.dragOffset = false;
- },
- mouseMove() {
- this._evaluateHoveredEffects();
- if (InteractionManager.state.LeftMouseDown && !InteractionManager.state.RightMouseDown) {
- this._evaluateEffectPositionUpdate();
- }
- },
- /**
- * Hotkeys
- */
- async delete() {
- if (!this.selectedEffect)
- return;
- await SequencerEffectManager.endEffects({ effects: this.selectedEffect });
- this.selectedEffect = false;
- },
- attachToTargetDown() {
- if (InteractionManager.state.LeftMouseDown && !InteractionManager.state.RightMouseDown) {
- this._evaluateEffectPositionUpdate();
- }
- },
- /**
- * Private methods
- */
- _selectEffects() {
- this._reset();
- if (!this.hoveredEffects.size)
- return;
- const firstElement = Array.from(this.hoveredEffects)[0];
- this.selectedEffect = !firstElement.selected ? firstElement : false;
- },
- _evaluateHoveredEffects() {
- const position = get_mouse_position();
- this.hoveredEffects = this.effects.filter(
- (effect) => effect.isPositionWithinBounds(position)
- );
- this.hoveredEffects.sort((a, b) => {
- return a.data.layer !== b.data.zIndex ? a.data.zIndex - b.data.zIndex : a.data.layer - b.data.zIndex;
- });
- this.hoveredEffects = new Set(this.hoveredEffects);
- },
- _evaluateEffectPositionUpdate() {
- if (!this.selectedEffect)
- return;
- if (this.selectedEffect.data.stretchTo && !this.sourceOrTarget) {
- return;
- }
- let showCursor = false;
- let showPoint = this.snapToGrid;
- let position = get_mouse_position(this.snapToGrid);
- if (!this.selectedEffect.data.stretchTo && !this.dragOffset) {
- this.dragOffset = {
- x: position.x - this.selectedEffect.position.x,
- y: position.y - this.selectedEffect.position.y
- };
- }
- if (this.attachToTarget) {
- const obj = get_closest_token(position, {
- minimumDistance: canvas.grid.size
- });
- if (obj) {
- position = get_object_position(obj);
- showCursor = true;
- showPoint = false;
- }
- }
- if (this.dragOffset && !showCursor && !this.snapToGrid) {
- position.x -= this.dragOffset.x;
- position.y -= this.dragOffset.y;
- }
- const color = (this.sourceOrTarget || "source") === "source" ? CONSTANTS.COLOR.PRIMARY : CONSTANTS.COLOR.SECONDARY;
- this.suggestedProperties = {
- position,
- showCursor,
- showPoint,
- color
- };
- },
- _updateEffect() {
- if (!this.selectedEffect)
- return;
- const updates = {
- attachTo: this.selectedEffect.data.attachTo,
- stretchTo: this.selectedEffect.data.stretchTo
- };
- const obj = this.attachToTarget ? get_closest_token(this.suggestedProperties.position, {
- minimumDistance: canvas.grid.size,
- type: TokenDocument
- }) : false;
- let objUuid = obj ? get_object_identifier(obj) : false;
- if (this.sourceOrTarget === "source") {
- if (!updates.attachTo) {
- updates.attachTo = {
- active: false,
- align: "center",
- rotation: true,
- bindVisibility: true,
- bindAlpha: true
- };
- }
- updates.attachTo = foundry.utils.mergeObject(updates.attachTo || {}, {
- active: this.attachToTarget && !!objUuid
- });
- if (this.attachToTarget && objUuid) {
- updates.source = objUuid;
- } else {
- updates["source"] = this.suggestedProperties.position;
- }
- } else if (this.sourceOrTarget === "target") {
- updates.stretchTo.attachTo = this.attachToTarget && !!objUuid;
- if (this.attachToTarget && objUuid) {
- updates.target = objUuid;
- } else {
- updates["target"] = this.suggestedProperties.position;
- }
- } else {
- updates["source"] = this.suggestedProperties.position;
- }
- this.selectedEffect.update(updates);
- this.suggestedProperties = false;
- this.sourceOrTarget = false;
- this.dragOffset = false;
- },
- _reset() {
- this.selectedEffect = false;
- this.suggestedProperties = false;
- this.sourceOrTarget = false;
- this.dragOffset = false;
- }
- };
- const EffectEntry_svelte_svelte_type_style_lang = "";
- function create_fragment$c(ctx) {
- let div1;
- let button;
- let t0;
- let div0;
- let t1_value = (
- /*getEffectName*/
- ctx[1](
- /*effect*/
- ctx[0]
- ) + ""
- );
- let t1;
- let mounted;
- let dispose;
- return {
- c() {
- div1 = element("div");
- button = element("button");
- button.innerHTML = `<i class="fas fa-times"></i>`;
- t0 = space();
- div0 = element("div");
- t1 = text$1(t1_value);
- attr(button, "class", "btn_end svelte-ese-1fyjvdk");
- attr(button, "type", "button");
- attr(div0, "class", "effect-text hover-text svelte-ese-1fyjvdk");
- attr(div1, "class", "effect hover-highlight svelte-ese-1fyjvdk");
- },
- m(target, anchor) {
- insert(target, div1, anchor);
- append(div1, button);
- append(div1, t0);
- append(div1, div0);
- append(div0, t1);
- if (!mounted) {
- dispose = [
- listen(
- button,
- "click",
- /*endEffect*/
- ctx[4]
- ),
- listen(
- div1,
- "mouseleave",
- /*mouseLeave*/
- ctx[3]
- ),
- listen(
- div1,
- "mouseover",
- /*mouseOver*/
- ctx[2]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*effect*/
- 1 && t1_value !== (t1_value = /*getEffectName*/
- ctx2[1](
- /*effect*/
- ctx2[0]
- ) + ""))
- set_data(t1, t1_value);
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div1);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$c($$self, $$props, $$invalidate) {
- let { effect } = $$props;
- function getEffectName(effect2) {
- let effectName = "Unknown effect";
- if (effect2.data.file) {
- effectName = effect2.data.file.split("\\").pop().split("/").pop();
- } else if (effect2.data.text) {
- effectName = "Text: " + effect2.data.text.text;
- } else {
- effectName = "Shape: " + effect2.data.shapes[0].type;
- }
- effectName = effect2.data.name ? `${effect2.data.name} (${effectName})` : effectName;
- if (effect2.data.creatorUserId !== game.userId) {
- let user_name = game.users.get(effect2.data.creatorUserId)?.name;
- let formattedUsername = user_name ? localize("SEQUENCER.ManagerPlayersEffect", { user_name }) : localize("SEQUENCER.ManagerUnknownEffect");
- effectName += ` (${formattedUsername})`;
- }
- return effectName;
- }
- function mouseOver() {
- SelectionManager.hoveredEffectUI = effect;
- }
- function mouseLeave() {
- SelectionManager.hoveredEffectUI = false;
- }
- function endEffect() {
- SequencerEffectManager.endEffects({ effects: [effect] });
- }
- $$self.$$set = ($$props2) => {
- if ("effect" in $$props2)
- $$invalidate(0, effect = $$props2.effect);
- };
- return [effect, getEffectName, mouseOver, mouseLeave, endEffect];
- }
- class EffectEntry extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$c, create_fragment$c, safe_not_equal, { effect: 0 });
- }
- }
- const SoundEntry_svelte_svelte_type_style_lang = "";
- function create_fragment$b(ctx) {
- let div1;
- let button;
- let t0;
- let div0;
- let t1_value = (
- /*sound*/
- ctx[0].src.split("/").slice(-1) + ""
- );
- let t1;
- let mounted;
- let dispose;
- return {
- c() {
- div1 = element("div");
- button = element("button");
- button.innerHTML = `<i class="fas fa-times"></i>`;
- t0 = space();
- div0 = element("div");
- t1 = text$1(t1_value);
- attr(button, "class", "btn_end svelte-ese-1fyjvdk");
- attr(button, "type", "button");
- attr(div0, "class", "effect-text hover-text svelte-ese-1fyjvdk");
- attr(div1, "class", "effect hover-highlight svelte-ese-1fyjvdk");
- },
- m(target, anchor) {
- insert(target, div1, anchor);
- append(div1, button);
- append(div1, t0);
- append(div1, div0);
- append(div0, t1);
- if (!mounted) {
- dispose = listen(
- button,
- "click",
- /*endSound*/
- ctx[1]
- );
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*sound*/
- 1 && t1_value !== (t1_value = /*sound*/
- ctx2[0].src.split("/").slice(-1) + ""))
- set_data(t1, t1_value);
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div1);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$b($$self, $$props, $$invalidate) {
- let { id } = $$props;
- let { sound } = $$props;
- function endSound() {
- SequencerAudioHelper.stop([id], true);
- }
- $$self.$$set = ($$props2) => {
- if ("id" in $$props2)
- $$invalidate(2, id = $$props2.id);
- if ("sound" in $$props2)
- $$invalidate(0, sound = $$props2.sound);
- };
- return [sound, endSound, id];
- }
- class SoundEntry extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$b, create_fragment$b, safe_not_equal, { id: 2, sound: 0 });
- }
- }
- const Manager_svelte_svelte_type_style_lang = "";
- function get_each_context$3(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[10] = list[i][0];
- child_ctx[11] = list[i][1];
- return child_ctx;
- }
- function get_each_context_1$1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[14] = list[i];
- return child_ctx;
- }
- function get_each_context_2$1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[14] = list[i];
- return child_ctx;
- }
- function create_if_block_5(ctx) {
- let div;
- let h2;
- return {
- c() {
- div = element("div");
- h2 = element("h2");
- h2.textContent = `${localize("SEQUENCER.Manager.NothingPlaying")}`;
- attr(div, "class", "no-effects");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, h2);
- },
- p: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- }
- };
- }
- function create_if_block_1(ctx) {
- let button;
- let t1;
- let div;
- let t2;
- let t3;
- let current;
- let mounted;
- let dispose;
- let if_block0 = (
- /*persistentEffects*/
- ctx[2].length && create_if_block_4(ctx)
- );
- let if_block1 = (
- /*temporaryEffects*/
- ctx[1].length && /*persistentEffects*/
- ctx[2].length && create_if_block_3()
- );
- let if_block2 = (
- /*temporaryEffects*/
- ctx[1].length && create_if_block_2(ctx)
- );
- return {
- c() {
- button = element("button");
- button.textContent = `${localize("SEQUENCER.Manager.EndAllEffects")}`;
- t1 = space();
- div = element("div");
- if (if_block0)
- if_block0.c();
- t2 = space();
- if (if_block1)
- if_block1.c();
- t3 = space();
- if (if_block2)
- if_block2.c();
- attr(button, "class", "w-100 end-all-effects mb-2 svelte-ese-nc5j73");
- attr(button, "type", "button");
- attr(div, "class", "effects svelte-ese-nc5j73");
- },
- m(target, anchor) {
- insert(target, button, anchor);
- insert(target, t1, anchor);
- insert(target, div, anchor);
- if (if_block0)
- if_block0.m(div, null);
- append(div, t2);
- if (if_block1)
- if_block1.m(div, null);
- append(div, t3);
- if (if_block2)
- if_block2.m(div, null);
- current = true;
- if (!mounted) {
- dispose = listen(
- button,
- "click",
- /*endAllEffects*/
- ctx[6]
- );
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (
- /*persistentEffects*/
- ctx2[2].length
- ) {
- if (if_block0) {
- if_block0.p(ctx2, dirty);
- if (dirty & /*persistentEffects*/
- 4) {
- transition_in(if_block0, 1);
- }
- } else {
- if_block0 = create_if_block_4(ctx2);
- if_block0.c();
- transition_in(if_block0, 1);
- if_block0.m(div, t2);
- }
- } else if (if_block0) {
- group_outros();
- transition_out(if_block0, 1, 1, () => {
- if_block0 = null;
- });
- check_outros();
- }
- if (
- /*temporaryEffects*/
- ctx2[1].length && /*persistentEffects*/
- ctx2[2].length
- ) {
- if (if_block1)
- ;
- else {
- if_block1 = create_if_block_3();
- if_block1.c();
- if_block1.m(div, t3);
- }
- } else if (if_block1) {
- if_block1.d(1);
- if_block1 = null;
- }
- if (
- /*temporaryEffects*/
- ctx2[1].length
- ) {
- if (if_block2) {
- if_block2.p(ctx2, dirty);
- if (dirty & /*temporaryEffects*/
- 2) {
- transition_in(if_block2, 1);
- }
- } else {
- if_block2 = create_if_block_2(ctx2);
- if_block2.c();
- transition_in(if_block2, 1);
- if_block2.m(div, null);
- }
- } else if (if_block2) {
- group_outros();
- transition_out(if_block2, 1, 1, () => {
- if_block2 = null;
- });
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block0);
- transition_in(if_block2);
- current = true;
- },
- o(local) {
- transition_out(if_block0);
- transition_out(if_block2);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(button);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(div);
- if (if_block0)
- if_block0.d();
- if (if_block1)
- if_block1.d();
- if (if_block2)
- if_block2.d();
- mounted = false;
- dispose();
- }
- };
- }
- function create_if_block_4(ctx) {
- let h2;
- let t1;
- let div;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let current;
- let each_value_2 = (
- /*persistentEffects*/
- ctx[2]
- );
- const get_key = (ctx2) => (
- /*effect*/
- ctx2[14].id
- );
- for (let i = 0; i < each_value_2.length; i += 1) {
- let child_ctx = get_each_context_2$1(ctx, each_value_2, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block_2$1(key, child_ctx));
- }
- return {
- c() {
- h2 = element("h2");
- h2.textContent = `${localize("SEQUENCER.Manager.PersistentEffects")}`;
- t1 = space();
- div = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- },
- m(target, anchor) {
- insert(target, h2, anchor);
- insert(target, t1, anchor);
- insert(target, div, anchor);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div, null);
- }
- current = true;
- },
- p(ctx2, dirty) {
- if (dirty & /*persistentEffects*/
- 4) {
- each_value_2 = /*persistentEffects*/
- ctx2[2];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value_2, each_1_lookup, div, outro_and_destroy_block, create_each_block_2$1, null, get_each_context_2$1);
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- for (let i = 0; i < each_value_2.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(h2);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(div);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- }
- };
- }
- function create_each_block_2$1(key_1, ctx) {
- let first;
- let effectentry;
- let current;
- effectentry = new EffectEntry({ props: { effect: (
- /*effect*/
- ctx[14]
- ) } });
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- create_component(effectentry.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(effectentry, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const effectentry_changes = {};
- if (dirty & /*persistentEffects*/
- 4)
- effectentry_changes.effect = /*effect*/
- ctx[14];
- effectentry.$set(effectentry_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(effectentry.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(effectentry.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(first);
- destroy_component(effectentry, detaching);
- }
- };
- }
- function create_if_block_3(ctx) {
- let hr;
- return {
- c() {
- hr = element("hr");
- },
- m(target, anchor) {
- insert(target, hr, anchor);
- },
- d(detaching) {
- if (detaching)
- detach(hr);
- }
- };
- }
- function create_if_block_2(ctx) {
- let h2;
- let t1;
- let div;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let current;
- let each_value_1 = (
- /*temporaryEffects*/
- ctx[1]
- );
- const get_key = (ctx2) => (
- /*effect*/
- ctx2[14].id
- );
- for (let i = 0; i < each_value_1.length; i += 1) {
- let child_ctx = get_each_context_1$1(ctx, each_value_1, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block_1$1(key, child_ctx));
- }
- return {
- c() {
- h2 = element("h2");
- h2.textContent = `${localize("SEQUENCER.Manager.TemporaryEffects")}`;
- t1 = space();
- div = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- },
- m(target, anchor) {
- insert(target, h2, anchor);
- insert(target, t1, anchor);
- insert(target, div, anchor);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div, null);
- }
- current = true;
- },
- p(ctx2, dirty) {
- if (dirty & /*temporaryEffects*/
- 2) {
- each_value_1 = /*temporaryEffects*/
- ctx2[1];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value_1, each_1_lookup, div, outro_and_destroy_block, create_each_block_1$1, null, get_each_context_1$1);
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- for (let i = 0; i < each_value_1.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(h2);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(div);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- }
- };
- }
- function create_each_block_1$1(key_1, ctx) {
- let first;
- let effectentry;
- let current;
- effectentry = new EffectEntry({ props: { effect: (
- /*effect*/
- ctx[14]
- ) } });
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- create_component(effectentry.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(effectentry, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const effectentry_changes = {};
- if (dirty & /*temporaryEffects*/
- 2)
- effectentry_changes.effect = /*effect*/
- ctx[14];
- effectentry.$set(effectentry_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(effectentry.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(effectentry.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(first);
- destroy_component(effectentry, detaching);
- }
- };
- }
- function create_if_block$2(ctx) {
- let button;
- let t1;
- let div1;
- let h2;
- let t3;
- let div0;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let current;
- let mounted;
- let dispose;
- let each_value = (
- /*sounds*/
- ctx[3]
- );
- const get_key = (ctx2) => (
- /*id*/
- ctx2[10]
- );
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context$3(ctx, each_value, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block$3(key, child_ctx));
- }
- return {
- c() {
- button = element("button");
- button.textContent = `${localize("SEQUENCER.Manager.EndAllSounds")}`;
- t1 = space();
- div1 = element("div");
- h2 = element("h2");
- h2.textContent = `${localize("SEQUENCER.Manager.Sounds")}`;
- t3 = space();
- div0 = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(button, "class", "w-100 end-all-effects mb-2 svelte-ese-nc5j73");
- attr(button, "type", "button");
- },
- m(target, anchor) {
- insert(target, button, anchor);
- insert(target, t1, anchor);
- insert(target, div1, anchor);
- append(div1, h2);
- append(div1, t3);
- append(div1, div0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div0, null);
- }
- current = true;
- if (!mounted) {
- dispose = listen(
- button,
- "click",
- /*endAllSounds*/
- ctx[7]
- );
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (dirty & /*sounds*/
- 8) {
- each_value = /*sounds*/
- ctx2[3];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div0, outro_and_destroy_block, create_each_block$3, null, get_each_context$3);
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(button);
- if (detaching)
- detach(t1);
- if (detaching)
- detach(div1);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- mounted = false;
- dispose();
- }
- };
- }
- function create_each_block$3(key_1, ctx) {
- let first;
- let soundentry;
- let current;
- soundentry = new SoundEntry({
- props: {
- id: (
- /*id*/
- ctx[10]
- ),
- sound: (
- /*sound*/
- ctx[11]
- )
- }
- });
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- create_component(soundentry.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(soundentry, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const soundentry_changes = {};
- if (dirty & /*sounds*/
- 8)
- soundentry_changes.id = /*id*/
- ctx[10];
- if (dirty & /*sounds*/
- 8)
- soundentry_changes.sound = /*sound*/
- ctx[11];
- soundentry.$set(soundentry_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(soundentry.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(soundentry.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(first);
- destroy_component(soundentry, detaching);
- }
- };
- }
- function create_fragment$a(ctx) {
- let div;
- let t0;
- let t1;
- let current;
- let if_block0 = !/*effects*/
- ctx[0].length && !/*sounds*/
- ctx[3].length && create_if_block_5();
- let if_block1 = (
- /*effects*/
- ctx[0].length && create_if_block_1(ctx)
- );
- let if_block2 = (
- /*sounds*/
- ctx[3].length && create_if_block$2(ctx)
- );
- return {
- c() {
- div = element("div");
- if (if_block0)
- if_block0.c();
- t0 = space();
- if (if_block1)
- if_block1.c();
- t1 = space();
- if (if_block2)
- if_block2.c();
- attr(div, "class", "effects-container svelte-ese-nc5j73");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- if (if_block0)
- if_block0.m(div, null);
- append(div, t0);
- if (if_block1)
- if_block1.m(div, null);
- append(div, t1);
- if (if_block2)
- if_block2.m(div, null);
- current = true;
- },
- p(ctx2, [dirty]) {
- if (!/*effects*/
- ctx2[0].length && !/*sounds*/
- ctx2[3].length) {
- if (if_block0) {
- if_block0.p(ctx2, dirty);
- } else {
- if_block0 = create_if_block_5();
- if_block0.c();
- if_block0.m(div, t0);
- }
- } else if (if_block0) {
- if_block0.d(1);
- if_block0 = null;
- }
- if (
- /*effects*/
- ctx2[0].length
- ) {
- if (if_block1) {
- if_block1.p(ctx2, dirty);
- if (dirty & /*effects*/
- 1) {
- transition_in(if_block1, 1);
- }
- } else {
- if_block1 = create_if_block_1(ctx2);
- if_block1.c();
- transition_in(if_block1, 1);
- if_block1.m(div, t1);
- }
- } else if (if_block1) {
- group_outros();
- transition_out(if_block1, 1, 1, () => {
- if_block1 = null;
- });
- check_outros();
- }
- if (
- /*sounds*/
- ctx2[3].length
- ) {
- if (if_block2) {
- if_block2.p(ctx2, dirty);
- if (dirty & /*sounds*/
- 8) {
- transition_in(if_block2, 1);
- }
- } else {
- if_block2 = create_if_block$2(ctx2);
- if_block2.c();
- transition_in(if_block2, 1);
- if_block2.m(div, null);
- }
- } else if (if_block2) {
- group_outros();
- transition_out(if_block2, 1, 1, () => {
- if_block2 = null;
- });
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block1);
- transition_in(if_block2);
- current = true;
- },
- o(local) {
- transition_out(if_block1);
- transition_out(if_block2);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- if (if_block0)
- if_block0.d();
- if (if_block1)
- if_block1.d();
- if (if_block2)
- if_block2.d();
- }
- };
- }
- function instance$a($$self, $$props, $$invalidate) {
- let effects;
- let sounds;
- let persistentEffects;
- let temporaryEffects;
- let $RunningSounds;
- let $VisibleEffects;
- const VisibleEffects = SequenceManager.VisibleEffects;
- component_subscribe($$self, VisibleEffects, (value) => $$invalidate(9, $VisibleEffects = value));
- const RunningSounds = SequenceManager.RunningSounds;
- component_subscribe($$self, RunningSounds, (value) => $$invalidate(8, $RunningSounds = value));
- function endAllEffects() {
- Sequencer.EffectManager.endEffects({
- effects: effects.filter((effect) => effect.userCanDelete && !effect.data.private)
- });
- }
- function endAllSounds() {
- SequencerAudioHelper.stop(RunningSounds.keys());
- }
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*$VisibleEffects*/
- 512) {
- $$invalidate(0, effects = Object.values($VisibleEffects));
- }
- if ($$self.$$.dirty & /*$RunningSounds*/
- 256) {
- $$invalidate(3, sounds = Object.entries($RunningSounds));
- }
- if ($$self.$$.dirty & /*effects*/
- 1) {
- $$invalidate(2, persistentEffects = effects.filter((effect) => effect.data.persist));
- }
- if ($$self.$$.dirty & /*effects*/
- 1) {
- $$invalidate(1, temporaryEffects = effects.filter((effect) => !effect.data.persist));
- }
- };
- return [
- effects,
- temporaryEffects,
- persistentEffects,
- sounds,
- VisibleEffects,
- RunningSounds,
- endAllEffects,
- endAllSounds,
- $RunningSounds,
- $VisibleEffects
- ];
- }
- class Manager extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$a, create_fragment$a, safe_not_equal, {});
- }
- }
- const SliderInput_svelte_svelte_type_style_lang = "";
- function create_fragment$9(ctx) {
- let div;
- let label;
- let t0_value = localize(
- /*setting*/
- ctx[0].label
- ) + "";
- let t0;
- let t1;
- let input0;
- let t2;
- let input1;
- let applyStyles_action;
- let mounted;
- let dispose;
- return {
- c() {
- div = element("div");
- label = element("label");
- t0 = text$1(t0_value);
- t1 = space();
- input0 = element("input");
- t2 = space();
- input1 = element("input");
- attr(label, "class", "svelte-ese-x3192w");
- input0.disabled = /*$isLocked*/
- ctx[6];
- attr(
- input0,
- "max",
- /*max*/
- ctx[2]
- );
- attr(
- input0,
- "min",
- /*min*/
- ctx[1]
- );
- attr(
- input0,
- "step",
- /*step*/
- ctx[4]
- );
- attr(input0, "type", "range");
- attr(input0, "class", "svelte-ese-x3192w");
- input1.disabled = /*$isLocked*/
- ctx[6];
- attr(
- input1,
- "max",
- /*maxInput*/
- ctx[3]
- );
- attr(
- input1,
- "min",
- /*min*/
- ctx[1]
- );
- input1.required = true;
- attr(
- input1,
- "step",
- /*step*/
- ctx[4]
- );
- attr(input1, "type", "number");
- attr(input1, "class", "svelte-ese-x3192w");
- set_style(div, "display", "flex");
- set_style(div, "align-items", "center");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, label);
- append(label, t0);
- append(div, t1);
- append(div, input0);
- set_input_value(
- input0,
- /*$store*/
- ctx[7]
- );
- append(div, t2);
- append(div, input1);
- set_input_value(
- input1,
- /*$store*/
- ctx[7]
- );
- if (!mounted) {
- dispose = [
- listen(
- input0,
- "change",
- /*input0_change_input_handler*/
- ctx[11]
- ),
- listen(
- input0,
- "input",
- /*input0_change_input_handler*/
- ctx[11]
- ),
- listen(
- input1,
- "input",
- /*input1_input_handler*/
- ctx[12]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- div,
- /*styles*/
- ctx[5]
- ))
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*setting*/
- 1 && t0_value !== (t0_value = localize(
- /*setting*/
- ctx2[0].label
- ) + ""))
- set_data(t0, t0_value);
- if (dirty & /*$isLocked*/
- 64) {
- input0.disabled = /*$isLocked*/
- ctx2[6];
- }
- if (dirty & /*max*/
- 4) {
- attr(
- input0,
- "max",
- /*max*/
- ctx2[2]
- );
- }
- if (dirty & /*min*/
- 2) {
- attr(
- input0,
- "min",
- /*min*/
- ctx2[1]
- );
- }
- if (dirty & /*step*/
- 16) {
- attr(
- input0,
- "step",
- /*step*/
- ctx2[4]
- );
- }
- if (dirty & /*$store*/
- 128) {
- set_input_value(
- input0,
- /*$store*/
- ctx2[7]
- );
- }
- if (dirty & /*$isLocked*/
- 64) {
- input1.disabled = /*$isLocked*/
- ctx2[6];
- }
- if (dirty & /*maxInput*/
- 8) {
- attr(
- input1,
- "max",
- /*maxInput*/
- ctx2[3]
- );
- }
- if (dirty & /*min*/
- 2) {
- attr(
- input1,
- "min",
- /*min*/
- ctx2[1]
- );
- }
- if (dirty & /*step*/
- 16) {
- attr(
- input1,
- "step",
- /*step*/
- ctx2[4]
- );
- }
- if (dirty & /*$store*/
- 128 && to_number(input1.value) !== /*$store*/
- ctx2[7]) {
- set_input_value(
- input1,
- /*$store*/
- ctx2[7]
- );
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
- 32)
- applyStyles_action.update.call(
- null,
- /*styles*/
- ctx2[5]
- );
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$9($$self, $$props, $$invalidate) {
- let $isLocked;
- let $store;
- let { setting } = $$props;
- let { lock = false } = $$props;
- let { min = 0.1 } = $$props;
- let { max = 2 } = $$props;
- let { maxInput = Infinity } = $$props;
- let { step = 0.01 } = $$props;
- let { styles = {} } = $$props;
- const store = setting.store;
- component_subscribe($$self, store, (value) => $$invalidate(7, $store = value));
- const isLocked = lock ? lock.store : writable$1(false);
- component_subscribe($$self, isLocked, (value) => $$invalidate(6, $isLocked = value));
- function input0_change_input_handler() {
- $store = to_number(this.value);
- store.set($store);
- }
- function input1_input_handler() {
- $store = to_number(this.value);
- store.set($store);
- }
- $$self.$$set = ($$props2) => {
- if ("setting" in $$props2)
- $$invalidate(0, setting = $$props2.setting);
- if ("lock" in $$props2)
- $$invalidate(10, lock = $$props2.lock);
- if ("min" in $$props2)
- $$invalidate(1, min = $$props2.min);
- if ("max" in $$props2)
- $$invalidate(2, max = $$props2.max);
- if ("maxInput" in $$props2)
- $$invalidate(3, maxInput = $$props2.maxInput);
- if ("step" in $$props2)
- $$invalidate(4, step = $$props2.step);
- if ("styles" in $$props2)
- $$invalidate(5, styles = $$props2.styles);
- };
- return [
- setting,
- min,
- max,
- maxInput,
- step,
- styles,
- $isLocked,
- $store,
- store,
- isLocked,
- lock,
- input0_change_input_handler,
- input1_input_handler
- ];
- }
- class SliderInput extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$9, create_fragment$9, safe_not_equal, {
- setting: 0,
- lock: 10,
- min: 1,
- max: 2,
- maxInput: 3,
- step: 4,
- styles: 5
- });
- }
- }
- function create_fragment$8(ctx) {
- let div;
- let input;
- let input_disabled_value;
- let t0;
- let label_1;
- let t1_value = localize(
- /*setting*/
- ctx[0].label
- ) + "";
- let t1;
- let applyStyles_action;
- let mounted;
- let dispose;
- return {
- c() {
- div = element("div");
- input = element("input");
- t0 = space();
- label_1 = element("label");
- t1 = text$1(t1_value);
- attr(
- input,
- "id",
- /*id*/
- ctx[5]
- );
- input.disabled = input_disabled_value = /*$isLocked*/
- ctx[3] !== /*inverse*/
- ctx[1];
- set_style(input, "height", "15px");
- attr(input, "type", "checkbox");
- attr(
- label_1,
- "for",
- /*id*/
- ctx[5]
- );
- set_style(div, "display", "flex");
- set_style(div, "align-items", "center");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, input);
- input.checked = /*$store*/
- ctx[4];
- append(div, t0);
- append(div, label_1);
- append(label_1, t1);
- if (!mounted) {
- dispose = [
- listen(
- input,
- "change",
- /*input_change_handler*/
- ctx[10]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- div,
- /*styles*/
- ctx[2]
- ))
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*$isLocked, inverse*/
- 10 && input_disabled_value !== (input_disabled_value = /*$isLocked*/
- ctx2[3] !== /*inverse*/
- ctx2[1])) {
- input.disabled = input_disabled_value;
- }
- if (dirty & /*$store*/
- 16) {
- input.checked = /*$store*/
- ctx2[4];
- }
- if (dirty & /*setting*/
- 1 && t1_value !== (t1_value = localize(
- /*setting*/
- ctx2[0].label
- ) + ""))
- set_data(t1, t1_value);
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
- 4)
- applyStyles_action.update.call(
- null,
- /*styles*/
- ctx2[2]
- );
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$8($$self, $$props, $$invalidate) {
- let $store;
- let $isLocked;
- let { setting } = $$props;
- let { label = false } = $$props;
- let { lock = false } = $$props;
- let { inverse = false } = $$props;
- let { styles = {} } = $$props;
- const id = "sequencer-input-" + randomID();
- const store = setting.store;
- component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
- const isLocked = lock ? lock.store : writable$1(inverse);
- component_subscribe($$self, isLocked, (value) => $$invalidate(3, $isLocked = value));
- function input_change_handler() {
- $store = this.checked;
- store.set($store);
- }
- $$self.$$set = ($$props2) => {
- if ("setting" in $$props2)
- $$invalidate(0, setting = $$props2.setting);
- if ("label" in $$props2)
- $$invalidate(8, label = $$props2.label);
- if ("lock" in $$props2)
- $$invalidate(9, lock = $$props2.lock);
- if ("inverse" in $$props2)
- $$invalidate(1, inverse = $$props2.inverse);
- if ("styles" in $$props2)
- $$invalidate(2, styles = $$props2.styles);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*$isLocked, inverse*/
- 10) {
- {
- if ($isLocked !== inverse) {
- set_store_value(store, $store = false, $store);
- }
- }
- }
- };
- return [
- setting,
- inverse,
- styles,
- $isLocked,
- $store,
- id,
- store,
- isLocked,
- label,
- lock,
- input_change_handler
- ];
- }
- class Checkbox extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$8, create_fragment$8, safe_not_equal, {
- setting: 0,
- label: 8,
- lock: 9,
- inverse: 1,
- styles: 2
- });
- }
- }
- const NumberInput_svelte_svelte_type_style_lang = "";
- function create_if_block$1(ctx) {
- let label;
- let t_value = localize(
- /*setting*/
- ctx[0].label
- ) + "";
- let t;
- return {
- c() {
- label = element("label");
- t = text$1(t_value);
- attr(
- label,
- "for",
- /*id*/
- ctx[5]
- );
- attr(label, "class", "svelte-ese-ywsxq0");
- },
- m(target, anchor) {
- insert(target, label, anchor);
- append(label, t);
- },
- p(ctx2, dirty) {
- if (dirty & /*setting*/
- 1 && t_value !== (t_value = localize(
- /*setting*/
- ctx2[0].label
- ) + ""))
- set_data(t, t_value);
- },
- d(detaching) {
- if (detaching)
- detach(label);
- }
- };
- }
- function create_fragment$7(ctx) {
- let div;
- let show_if = localize(
- /*setting*/
- ctx[0].label
- );
- let t;
- let input;
- let input_disabled_value;
- let applyStyles_action;
- let mounted;
- let dispose;
- let if_block = show_if && create_if_block$1(ctx);
- return {
- c() {
- div = element("div");
- if (if_block)
- if_block.c();
- t = space();
- input = element("input");
- attr(
- input,
- "id",
- /*id*/
- ctx[5]
- );
- attr(input, "type", "number");
- input.disabled = input_disabled_value = /*$isLocked*/
- ctx[3] !== /*inverse*/
- ctx[1];
- attr(input, "class", "svelte-ese-ywsxq0");
- set_style(div, "display", "flex");
- set_style(div, "align-items", "center");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- if (if_block)
- if_block.m(div, null);
- append(div, t);
- append(div, input);
- set_input_value(
- input,
- /*$store*/
- ctx[4]
- );
- if (!mounted) {
- dispose = [
- listen(
- input,
- "input",
- /*input_input_handler*/
- ctx[9]
- ),
- listen(
- input,
- "change",
- /*change_handler*/
- ctx[10]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- div,
- /*styles*/
- ctx[2]
- ))
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*setting*/
- 1)
- show_if = localize(
- /*setting*/
- ctx2[0].label
- );
- if (show_if) {
- if (if_block) {
- if_block.p(ctx2, dirty);
- } else {
- if_block = create_if_block$1(ctx2);
- if_block.c();
- if_block.m(div, t);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- if (dirty & /*$isLocked, inverse*/
- 10 && input_disabled_value !== (input_disabled_value = /*$isLocked*/
- ctx2[3] !== /*inverse*/
- ctx2[1])) {
- input.disabled = input_disabled_value;
- }
- if (dirty & /*$store*/
- 16 && to_number(input.value) !== /*$store*/
- ctx2[4]) {
- set_input_value(
- input,
- /*$store*/
- ctx2[4]
- );
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
- 4)
- applyStyles_action.update.call(
- null,
- /*styles*/
- ctx2[2]
- );
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- if (if_block)
- if_block.d();
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$7($$self, $$props, $$invalidate) {
- let $isLocked;
- let $store;
- let { setting } = $$props;
- let { lock = false } = $$props;
- let { inverse = false } = $$props;
- let { styles = {} } = $$props;
- const id = "sequencer-input-" + randomID();
- const store = setting.store;
- component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
- const isLocked = lock ? lock.store : writable$1(inverse);
- component_subscribe($$self, isLocked, (value) => $$invalidate(3, $isLocked = value));
- function input_input_handler() {
- $store = to_number(this.value);
- store.set($store);
- }
- const change_handler = () => {
- if ($store === null)
- set_store_value(store, $store = 0, $store);
- };
- $$self.$$set = ($$props2) => {
- if ("setting" in $$props2)
- $$invalidate(0, setting = $$props2.setting);
- if ("lock" in $$props2)
- $$invalidate(8, lock = $$props2.lock);
- if ("inverse" in $$props2)
- $$invalidate(1, inverse = $$props2.inverse);
- if ("styles" in $$props2)
- $$invalidate(2, styles = $$props2.styles);
- };
- return [
- setting,
- inverse,
- styles,
- $isLocked,
- $store,
- id,
- store,
- isLocked,
- lock,
- input_input_handler,
- change_handler
- ];
- }
- class NumberInput extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$7, create_fragment$7, safe_not_equal, {
- setting: 0,
- lock: 8,
- inverse: 1,
- styles: 2
- });
- }
- }
- const SwitchToggle_svelte_svelte_type_style_lang = "";
- function create_fragment$6(ctx) {
- let div2;
- let div0;
- let span0;
- let t0_value = localize(
- /*setting*/
- ctx[0].label_off
- ) + "";
- let t0;
- let t1;
- let div1;
- let span1;
- let t2_value = localize(
- /*setting*/
- ctx[0].label_on
- ) + "";
- let t2;
- let applyStyles_action;
- let mounted;
- let dispose;
- return {
- c() {
- div2 = element("div");
- div0 = element("div");
- span0 = element("span");
- t0 = text$1(t0_value);
- t1 = space();
- div1 = element("div");
- span1 = element("span");
- t2 = text$1(t2_value);
- attr(div0, "class", "first svelte-ese-o0yoxs");
- toggle_class(div0, "active", !/*$store*/
- ctx[2]);
- attr(div1, "class", "second svelte-ese-o0yoxs");
- toggle_class(
- div1,
- "active",
- /*$store*/
- ctx[2]
- );
- set_style(div2, "display", "flex");
- set_style(div2, "align-items", "center");
- attr(div2, "class", "svelte-ese-o0yoxs");
- },
- m(target, anchor) {
- insert(target, div2, anchor);
- append(div2, div0);
- append(div0, span0);
- append(span0, t0);
- append(div2, t1);
- append(div2, div1);
- append(div1, span1);
- append(span1, t2);
- if (!mounted) {
- dispose = [
- listen(
- div0,
- "click",
- /*click_handler*/
- ctx[5]
- ),
- listen(
- div1,
- "click",
- /*click_handler_1*/
- ctx[6]
- ),
- action_destroyer(applyStyles_action = applyStyles.call(
- null,
- div2,
- /*finalStyles*/
- ctx[1]
- ))
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*setting*/
- 1 && t0_value !== (t0_value = localize(
- /*setting*/
- ctx2[0].label_off
- ) + ""))
- set_data(t0, t0_value);
- if (dirty & /*$store*/
- 4) {
- toggle_class(div0, "active", !/*$store*/
- ctx2[2]);
- }
- if (dirty & /*setting*/
- 1 && t2_value !== (t2_value = localize(
- /*setting*/
- ctx2[0].label_on
- ) + ""))
- set_data(t2, t2_value);
- if (dirty & /*$store*/
- 4) {
- toggle_class(
- div1,
- "active",
- /*$store*/
- ctx2[2]
- );
- }
- if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*finalStyles*/
- 2)
- applyStyles_action.update.call(
- null,
- /*finalStyles*/
- ctx2[1]
- );
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div2);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- const width = 5.75;
- function instance$6($$self, $$props, $$invalidate) {
- let finalStyles;
- let $store;
- let { setting } = $$props;
- let { styles = {} } = $$props;
- const store = setting.store;
- component_subscribe($$self, store, (value) => $$invalidate(2, $store = value));
- const click_handler = () => {
- set_store_value(store, $store = false, $store);
- };
- const click_handler_1 = () => {
- set_store_value(store, $store = true, $store);
- };
- $$self.$$set = ($$props2) => {
- if ("setting" in $$props2)
- $$invalidate(0, setting = $$props2.setting);
- if ("styles" in $$props2)
- $$invalidate(4, styles = $$props2.styles);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*styles*/
- 16) {
- $$invalidate(1, finalStyles = {
- ...styles,
- "--switch-width": `${width}em`,
- "--half-switch-width": `${width - 1.5}em`,
- "--half-switch-width-on": `${width - 1.7}em`
- });
- }
- };
- return [setting, finalStyles, $store, store, styles, click_handler, click_handler_1];
- }
- class SwitchToggle extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$6, create_fragment$6, safe_not_equal, { setting: 0, styles: 4 });
- }
- }
- const Player_svelte_svelte_type_style_lang = "";
- function get_each_context$2(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[20] = list[i];
- return child_ctx;
- }
- function get_each_context_1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[23] = list[i];
- return child_ctx;
- }
- function get_each_context_2(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[26] = list[i];
- return child_ctx;
- }
- function create_each_block_2(ctx) {
- let option;
- let t_value = (
- /*suggestion*/
- ctx[26] + ""
- );
- let t;
- let option_value_value;
- return {
- c() {
- option = element("option");
- t = text$1(t_value);
- option.__value = option_value_value = /*suggestion*/
- ctx[26];
- option.value = option.__value;
- },
- m(target, anchor) {
- insert(target, option, anchor);
- append(option, t);
- },
- p(ctx2, dirty) {
- if (dirty & /*suggestions*/
- 2 && t_value !== (t_value = /*suggestion*/
- ctx2[26] + ""))
- set_data(t, t_value);
- if (dirty & /*suggestions*/
- 2 && option_value_value !== (option_value_value = /*suggestion*/
- ctx2[26])) {
- option.__value = option_value_value;
- option.value = option.__value;
- }
- },
- d(detaching) {
- if (detaching)
- detach(option);
- }
- };
- }
- function create_each_block_1(key_1, ctx) {
- let option;
- let t_value = (
- /*user*/
- ctx[23].name + ""
- );
- let t;
- return {
- key: key_1,
- first: null,
- c() {
- option = element("option");
- t = text$1(t_value);
- option.__value = /*user*/
- ctx[23].id;
- option.value = option.__value;
- this.first = option;
- },
- m(target, anchor) {
- insert(target, option, anchor);
- append(option, t);
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- },
- d(detaching) {
- if (detaching)
- detach(option);
- }
- };
- }
- function create_each_block$2(ctx) {
- let option;
- let t_value = (
- /*preset*/
- ctx[20] + ""
- );
- let t;
- return {
- c() {
- option = element("option");
- t = text$1(t_value);
- option.__value = /*preset*/
- ctx[20];
- option.value = option.__value;
- },
- m(target, anchor) {
- insert(target, option, anchor);
- append(option, t);
- },
- p: noop,
- d(detaching) {
- if (detaching)
- detach(option);
- }
- };
- }
- function create_fragment$5(ctx) {
- let div16;
- let fieldset0;
- let legend0;
- let t1;
- let button0;
- let t3;
- let div0;
- let input;
- let t4;
- let button1;
- let t5;
- let datalist;
- let t6;
- let div1;
- let label;
- let t8;
- let select0;
- let option0;
- let each_blocks_1 = [];
- let each1_lookup = /* @__PURE__ */ new Map();
- let t10;
- let div4;
- let div2;
- let t12;
- let div3;
- let select1;
- let option1;
- let t14;
- let button2;
- let t15;
- let button3;
- let i2;
- let button3_disabled_value;
- let t16;
- let button4;
- let i3;
- let button4_disabled_value;
- let t17;
- let fieldset1;
- let legend1;
- let t19;
- let div11;
- let sliderinput0;
- let t20;
- let numberinput0;
- let t21;
- let numberinput1;
- let t22;
- let div5;
- let t23;
- let sliderinput1;
- let t24;
- let div6;
- let t25;
- let checkbox0;
- let t26;
- let div7;
- let t27;
- let div8;
- let t28;
- let checkbox1;
- let t29;
- let checkbox2;
- let t30;
- let checkbox3;
- let t31;
- let checkbox4;
- let t32;
- let div9;
- let t33;
- let numberinput2;
- let t34;
- let numberinput3;
- let t35;
- let checkbox5;
- let t36;
- let numberinput4;
- let t37;
- let checkbox6;
- let t38;
- let div10;
- let t39;
- let fieldset2;
- let legend2;
- let t41;
- let div15;
- let numberinput5;
- let t42;
- let numberinput6;
- let t43;
- let div12;
- let t44;
- let checkbox7;
- let t45;
- let numberinput7;
- let t46;
- let numberinput8;
- let t47;
- let numberinput9;
- let t48;
- let div13;
- let t49;
- let switchtoggle;
- let t50;
- let numberinput10;
- let t51;
- let div14;
- let t52;
- let checkbox8;
- let t53;
- let checkbox9;
- let t54;
- let checkbox10;
- let t55;
- let checkbox11;
- let t56;
- let checkbox12;
- let current;
- let mounted;
- let dispose;
- let each_value_2 = (
- /*suggestions*/
- ctx[1]
- );
- let each_blocks_2 = [];
- for (let i = 0; i < each_value_2.length; i += 1) {
- each_blocks_2[i] = create_each_block_2(get_each_context_2(ctx, each_value_2, i));
- }
- let each_value_1 = (
- /*users*/
- ctx[5]
- );
- const get_key = (ctx2) => (
- /*user*/
- ctx2[23].id
- );
- for (let i = 0; i < each_value_1.length; i += 1) {
- let child_ctx = get_each_context_1(ctx, each_value_1, i);
- let key = get_key(child_ctx);
- each1_lookup.set(key, each_blocks_1[i] = create_each_block_1(key, child_ctx));
- }
- let each_value = (
- /*presets*/
- ctx[8]
- );
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$2(get_each_context$2(ctx, each_value, i));
- }
- sliderinput0 = new SliderInput({
- props: {
- setting: PlayerSettings.scale,
- styles: { "grid-column": `1 / 5` }
- }
- });
- numberinput0 = new NumberInput({
- props: {
- setting: PlayerSettings.scaleIn,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput1 = new NumberInput({
- props: {
- setting: PlayerSettings.scaleOut,
- styles: { "grid-column": `3 / 5` }
- }
- });
- sliderinput1 = new SliderInput({
- props: {
- setting: PlayerSettings.rotation,
- lock: PlayerSettings.randomRotation,
- min: "-180",
- max: "180",
- styles: { "grid-column": `1 / 5` }
- }
- });
- checkbox0 = new Checkbox({
- props: {
- setting: PlayerSettings.randomRotation,
- styles: { "grid-column": `2 / 4` }
- }
- });
- checkbox1 = new Checkbox({
- props: {
- setting: PlayerSettings.mirrorX,
- styles: { "grid-column": `1 / 3` }
- }
- });
- checkbox2 = new Checkbox({
- props: {
- setting: PlayerSettings.mirrorY,
- styles: { "grid-column": `3 / 5` }
- }
- });
- checkbox3 = new Checkbox({
- props: {
- setting: PlayerSettings.randomMirrorX,
- styles: { "grid-column": `1 / 3` },
- lock: PlayerSettings.mirrorX,
- inverse: true
- }
- });
- checkbox4 = new Checkbox({
- props: {
- setting: PlayerSettings.randomMirrorY,
- styles: { "grid-column": `3 / 5` },
- lock: PlayerSettings.mirrorY,
- inverse: true
- }
- });
- numberinput2 = new NumberInput({
- props: {
- setting: PlayerSettings.offsetX,
- lock: PlayerSettings.randomOffset,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput3 = new NumberInput({
- props: {
- setting: PlayerSettings.offsetY,
- lock: PlayerSettings.randomOffset,
- styles: { "grid-column": `3 / 5` }
- }
- });
- checkbox5 = new Checkbox({
- props: {
- setting: PlayerSettings.randomOffset,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput4 = new NumberInput({
- props: {
- setting: PlayerSettings.randomOffsetAmount,
- lock: PlayerSettings.randomOffset,
- inverse: true,
- styles: { "grid-column": `3 / 5` }
- }
- });
- checkbox6 = new Checkbox({
- props: {
- setting: PlayerSettings.offsetGridUnits,
- styles: { "grid-column": `2 / 5` }
- }
- });
- numberinput5 = new NumberInput({
- props: {
- setting: PlayerSettings.fadeIn,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput6 = new NumberInput({
- props: {
- setting: PlayerSettings.fadeOut,
- styles: { "grid-column": `3 / 5` }
- }
- });
- checkbox7 = new Checkbox({
- props: {
- setting: PlayerSettings.repeat,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput7 = new NumberInput({
- props: {
- setting: PlayerSettings.repetitions,
- lock: PlayerSettings.repeat,
- inverse: true,
- styles: { "grid-column": `3 / 5` }
- }
- });
- numberinput8 = new NumberInput({
- props: {
- setting: PlayerSettings.repeatDelayMin,
- lock: PlayerSettings.repeat,
- inverse: true,
- styles: { "grid-column": `3 / 4` }
- }
- });
- numberinput9 = new NumberInput({
- props: {
- setting: PlayerSettings.repeatDelayMax,
- lock: PlayerSettings.repeat,
- inverse: true,
- styles: { "grid-column": `4 / 5` }
- }
- });
- switchtoggle = new SwitchToggle({
- props: {
- setting: PlayerSettings.moveTowards,
- styles: { "grid-column": `1 / 3` }
- }
- });
- numberinput10 = new NumberInput({
- props: {
- setting: PlayerSettings.moveSpeed,
- lock: PlayerSettings.moveTowards,
- inverse: true,
- styles: { "grid-column": `3 / 5` }
- }
- });
- checkbox8 = new Checkbox({
- props: {
- setting: PlayerSettings.attachTo,
- styles: { "grid-column": `1 / 5` }
- }
- });
- checkbox9 = new Checkbox({
- props: {
- setting: PlayerSettings.stretchToAttach,
- styles: { "grid-column": `1 / 5` }
- }
- });
- checkbox10 = new Checkbox({
- props: {
- setting: PlayerSettings.snapToGrid,
- styles: { "grid-column": `1 / 5` }
- }
- });
- checkbox11 = new Checkbox({
- props: {
- setting: PlayerSettings.persist,
- styles: { "grid-column": `1 / 5` }
- }
- });
- checkbox12 = new Checkbox({
- props: {
- setting: PlayerSettings.belowTokens,
- styles: { "grid-column": `1 / 5` }
- }
- });
- return {
- c() {
- div16 = element("div");
- fieldset0 = element("fieldset");
- legend0 = element("legend");
- legend0.textContent = "Effect";
- t1 = space();
- button0 = element("button");
- button0.textContent = `${localize("SEQUENCER.Player.SwitchToLayer")}`;
- t3 = space();
- div0 = element("div");
- input = element("input");
- t4 = space();
- button1 = element("button");
- button1.innerHTML = `<i class="fas fa-file-import svelte-ese-1ipnpu1"></i>`;
- t5 = space();
- datalist = element("datalist");
- for (let i = 0; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].c();
- }
- t6 = space();
- div1 = element("div");
- label = element("label");
- label.textContent = "Play for users:";
- t8 = space();
- select0 = element("select");
- option0 = element("option");
- option0.textContent = `${localize("SEQUENCER.Player.AllUsers")}`;
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].c();
- }
- t10 = space();
- div4 = element("div");
- div2 = element("div");
- div2.textContent = `${localize("SEQUENCER.Player.Presets")}`;
- t12 = space();
- div3 = element("div");
- select1 = element("select");
- option1 = element("option");
- option1.textContent = `${localize("SEQUENCER.Player.PresetsDefault")}`;
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- t14 = space();
- button2 = element("button");
- button2.innerHTML = `<i class="fas fa-download svelte-ese-1ipnpu1"></i>`;
- t15 = space();
- button3 = element("button");
- i2 = element("i");
- t16 = space();
- button4 = element("button");
- i3 = element("i");
- t17 = space();
- fieldset1 = element("fieldset");
- legend1 = element("legend");
- legend1.textContent = "Transform";
- t19 = space();
- div11 = element("div");
- create_component(sliderinput0.$$.fragment);
- t20 = space();
- create_component(numberinput0.$$.fragment);
- t21 = space();
- create_component(numberinput1.$$.fragment);
- t22 = space();
- div5 = element("div");
- t23 = space();
- create_component(sliderinput1.$$.fragment);
- t24 = space();
- div6 = element("div");
- t25 = space();
- create_component(checkbox0.$$.fragment);
- t26 = space();
- div7 = element("div");
- t27 = space();
- div8 = element("div");
- t28 = space();
- create_component(checkbox1.$$.fragment);
- t29 = space();
- create_component(checkbox2.$$.fragment);
- t30 = space();
- create_component(checkbox3.$$.fragment);
- t31 = space();
- create_component(checkbox4.$$.fragment);
- t32 = space();
- div9 = element("div");
- t33 = space();
- create_component(numberinput2.$$.fragment);
- t34 = space();
- create_component(numberinput3.$$.fragment);
- t35 = space();
- create_component(checkbox5.$$.fragment);
- t36 = space();
- create_component(numberinput4.$$.fragment);
- t37 = space();
- create_component(checkbox6.$$.fragment);
- t38 = space();
- div10 = element("div");
- t39 = space();
- fieldset2 = element("fieldset");
- legend2 = element("legend");
- legend2.textContent = "Behavior";
- t41 = space();
- div15 = element("div");
- create_component(numberinput5.$$.fragment);
- t42 = space();
- create_component(numberinput6.$$.fragment);
- t43 = space();
- div12 = element("div");
- t44 = space();
- create_component(checkbox7.$$.fragment);
- t45 = space();
- create_component(numberinput7.$$.fragment);
- t46 = space();
- create_component(numberinput8.$$.fragment);
- t47 = space();
- create_component(numberinput9.$$.fragment);
- t48 = space();
- div13 = element("div");
- t49 = space();
- create_component(switchtoggle.$$.fragment);
- t50 = space();
- create_component(numberinput10.$$.fragment);
- t51 = space();
- div14 = element("div");
- t52 = space();
- create_component(checkbox8.$$.fragment);
- t53 = space();
- create_component(checkbox9.$$.fragment);
- t54 = space();
- create_component(checkbox10.$$.fragment);
- t55 = space();
- create_component(checkbox11.$$.fragment);
- t56 = space();
- create_component(checkbox12.$$.fragment);
- attr(button0, "class", "activate-layer svelte-ese-1ipnpu1");
- attr(button0, "type", "button");
- attr(input, "class", "file-input flex3");
- attr(input, "list", "dblist");
- attr(input, "placeholder", localize("SEQUENCER.Player.PathInput"));
- attr(input, "type", "text");
- attr(button1, "class", "custom-file-picker small-button svelte-ese-1ipnpu1");
- attr(button1, "type", "button");
- attr(datalist, "id", "dblist");
- attr(div0, "class", "file-settings svelte-ese-1ipnpu1");
- attr(label, "for", "user-select");
- option0.selected = true;
- option0.__value = "all";
- option0.value = option0.__value;
- attr(select0, "class", "user-select");
- attr(select0, "id", "user-select");
- select0.multiple = true;
- if (
- /*$userStore*/
- ctx[3] === void 0
- )
- add_render_callback(() => (
- /*select0_change_handler*/
- ctx[11].call(select0)
- ));
- attr(div1, "class", "user-settings flexcol svelte-ese-1ipnpu1");
- attr(div2, "class", "row w-100");
- option1.__value = "default";
- option1.value = option1.__value;
- attr(select1, "class", "preset-select svelte-ese-1ipnpu1");
- if (
- /*selectedPreset*/
- ctx[2] === void 0
- )
- add_render_callback(() => (
- /*select1_change_handler*/
- ctx[12].call(select1)
- ));
- attr(button2, "class", "save-preset small-button svelte-ese-1ipnpu1");
- attr(button2, "data-tooltip", "Save Preset");
- attr(button2, "type", "button");
- attr(i2, "class", "fas fa-copy svelte-ese-1ipnpu1");
- attr(button3, "class", "copy-preset small-button svelte-ese-1ipnpu1");
- attr(button3, "data-tooltip", "Copy Preset");
- button3.disabled = button3_disabled_value = /*selectedPreset*/
- ctx[2] === "default";
- attr(button3, "type", "button");
- attr(i3, "class", "fas fa-times svelte-ese-1ipnpu1");
- attr(button4, "class", "delete-preset small-button svelte-ese-1ipnpu1");
- attr(button4, "data-tooltip", "Delete Preset");
- button4.disabled = button4_disabled_value = /*selectedPreset*/
- ctx[2] === "default";
- attr(button4, "type", "button");
- attr(div3, "class", "preset-container svelte-ese-1ipnpu1");
- attr(div4, "class", "flexcol");
- attr(div5, "class", "divider");
- attr(div8, "class", "divider");
- attr(div9, "class", "divider");
- attr(div11, "class", "effect-transform-container");
- attr(div12, "class", "divider");
- attr(div13, "class", "divider");
- attr(div14, "class", "divider");
- attr(div15, "class", "effect-transform-container");
- attr(div16, "class", "effect-player-container");
- },
- m(target, anchor) {
- insert(target, div16, anchor);
- append(div16, fieldset0);
- append(fieldset0, legend0);
- append(fieldset0, t1);
- append(fieldset0, button0);
- append(fieldset0, t3);
- append(fieldset0, div0);
- append(div0, input);
- set_input_value(
- input,
- /*$fileStore*/
- ctx[0]
- );
- append(div0, t4);
- append(div0, button1);
- append(div0, t5);
- append(div0, datalist);
- for (let i = 0; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].m(datalist, null);
- }
- append(fieldset0, t6);
- append(fieldset0, div1);
- append(div1, label);
- append(div1, t8);
- append(div1, select0);
- append(select0, option0);
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].m(select0, null);
- }
- select_options(
- select0,
- /*$userStore*/
- ctx[3]
- );
- append(fieldset0, t10);
- append(fieldset0, div4);
- append(div4, div2);
- append(div4, t12);
- append(div4, div3);
- append(div3, select1);
- append(select1, option1);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(select1, null);
- }
- select_option(
- select1,
- /*selectedPreset*/
- ctx[2]
- );
- append(div3, t14);
- append(div3, button2);
- append(div3, t15);
- append(div3, button3);
- append(button3, i2);
- append(div3, t16);
- append(div3, button4);
- append(button4, i3);
- append(div16, t17);
- append(div16, fieldset1);
- append(fieldset1, legend1);
- append(fieldset1, t19);
- append(fieldset1, div11);
- mount_component(sliderinput0, div11, null);
- append(div11, t20);
- mount_component(numberinput0, div11, null);
- append(div11, t21);
- mount_component(numberinput1, div11, null);
- append(div11, t22);
- append(div11, div5);
- append(div11, t23);
- mount_component(sliderinput1, div11, null);
- append(div11, t24);
- append(div11, div6);
- append(div11, t25);
- mount_component(checkbox0, div11, null);
- append(div11, t26);
- append(div11, div7);
- append(div11, t27);
- append(div11, div8);
- append(div11, t28);
- mount_component(checkbox1, div11, null);
- append(div11, t29);
- mount_component(checkbox2, div11, null);
- append(div11, t30);
- mount_component(checkbox3, div11, null);
- append(div11, t31);
- mount_component(checkbox4, div11, null);
- append(div11, t32);
- append(div11, div9);
- append(div11, t33);
- mount_component(numberinput2, div11, null);
- append(div11, t34);
- mount_component(numberinput3, div11, null);
- append(div11, t35);
- mount_component(checkbox5, div11, null);
- append(div11, t36);
- mount_component(numberinput4, div11, null);
- append(div11, t37);
- mount_component(checkbox6, div11, null);
- append(div11, t38);
- append(div11, div10);
- append(div16, t39);
- append(div16, fieldset2);
- append(fieldset2, legend2);
- append(fieldset2, t41);
- append(fieldset2, div15);
- mount_component(numberinput5, div15, null);
- append(div15, t42);
- mount_component(numberinput6, div15, null);
- append(div15, t43);
- append(div15, div12);
- append(div15, t44);
- mount_component(checkbox7, div15, null);
- append(div15, t45);
- mount_component(numberinput7, div15, null);
- append(div15, t46);
- mount_component(numberinput8, div15, null);
- append(div15, t47);
- mount_component(numberinput9, div15, null);
- append(div15, t48);
- append(div15, div13);
- append(div15, t49);
- mount_component(switchtoggle, div15, null);
- append(div15, t50);
- mount_component(numberinput10, div15, null);
- append(div15, t51);
- append(div15, div14);
- append(div15, t52);
- mount_component(checkbox8, div15, null);
- append(div15, t53);
- mount_component(checkbox9, div15, null);
- append(div15, t54);
- mount_component(checkbox10, div15, null);
- append(div15, t55);
- mount_component(checkbox11, div15, null);
- append(div15, t56);
- mount_component(checkbox12, div15, null);
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- button0,
- "click",
- /*click_handler*/
- ctx[9]
- ),
- listen(
- input,
- "input",
- /*input_input_handler*/
- ctx[10]
- ),
- listen(
- button1,
- "click",
- /*handleClick*/
- ctx[7]
- ),
- listen(
- select0,
- "change",
- /*select0_change_handler*/
- ctx[11]
- ),
- listen(
- select1,
- "change",
- /*select1_change_handler*/
- ctx[12]
- ),
- listen(
- select1,
- "change",
- /*change_handler*/
- ctx[13]
- ),
- listen(
- button2,
- "click",
- /*click_handler_1*/
- ctx[14]
- ),
- listen(
- button3,
- "click",
- /*click_handler_2*/
- ctx[15]
- ),
- listen(
- button4,
- "click",
- /*click_handler_3*/
- ctx[16]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (dirty & /*$fileStore*/
- 1 && input.value !== /*$fileStore*/
- ctx2[0]) {
- set_input_value(
- input,
- /*$fileStore*/
- ctx2[0]
- );
- }
- if (dirty & /*suggestions*/
- 2) {
- each_value_2 = /*suggestions*/
- ctx2[1];
- let i;
- for (i = 0; i < each_value_2.length; i += 1) {
- const child_ctx = get_each_context_2(ctx2, each_value_2, i);
- if (each_blocks_2[i]) {
- each_blocks_2[i].p(child_ctx, dirty);
- } else {
- each_blocks_2[i] = create_each_block_2(child_ctx);
- each_blocks_2[i].c();
- each_blocks_2[i].m(datalist, null);
- }
- }
- for (; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].d(1);
- }
- each_blocks_2.length = each_value_2.length;
- }
- if (dirty & /*users*/
- 32) {
- each_value_1 = /*users*/
- ctx2[5];
- each_blocks_1 = update_keyed_each(each_blocks_1, dirty, get_key, 1, ctx2, each_value_1, each1_lookup, select0, destroy_block, create_each_block_1, null, get_each_context_1);
- }
- if (dirty & /*$userStore, users*/
- 40) {
- select_options(
- select0,
- /*$userStore*/
- ctx2[3]
- );
- }
- if (dirty & /*presets*/
- 256) {
- each_value = /*presets*/
- ctx2[8];
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$2(ctx2, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- } else {
- each_blocks[i] = create_each_block$2(child_ctx);
- each_blocks[i].c();
- each_blocks[i].m(select1, null);
- }
- }
- for (; i < each_blocks.length; i += 1) {
- each_blocks[i].d(1);
- }
- each_blocks.length = each_value.length;
- }
- if (dirty & /*selectedPreset, presets*/
- 260) {
- select_option(
- select1,
- /*selectedPreset*/
- ctx2[2]
- );
- }
- if (!current || dirty & /*selectedPreset, presets*/
- 260 && button3_disabled_value !== (button3_disabled_value = /*selectedPreset*/
- ctx2[2] === "default")) {
- button3.disabled = button3_disabled_value;
- }
- if (!current || dirty & /*selectedPreset, presets*/
- 260 && button4_disabled_value !== (button4_disabled_value = /*selectedPreset*/
- ctx2[2] === "default")) {
- button4.disabled = button4_disabled_value;
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(sliderinput0.$$.fragment, local);
- transition_in(numberinput0.$$.fragment, local);
- transition_in(numberinput1.$$.fragment, local);
- transition_in(sliderinput1.$$.fragment, local);
- transition_in(checkbox0.$$.fragment, local);
- transition_in(checkbox1.$$.fragment, local);
- transition_in(checkbox2.$$.fragment, local);
- transition_in(checkbox3.$$.fragment, local);
- transition_in(checkbox4.$$.fragment, local);
- transition_in(numberinput2.$$.fragment, local);
- transition_in(numberinput3.$$.fragment, local);
- transition_in(checkbox5.$$.fragment, local);
- transition_in(numberinput4.$$.fragment, local);
- transition_in(checkbox6.$$.fragment, local);
- transition_in(numberinput5.$$.fragment, local);
- transition_in(numberinput6.$$.fragment, local);
- transition_in(checkbox7.$$.fragment, local);
- transition_in(numberinput7.$$.fragment, local);
- transition_in(numberinput8.$$.fragment, local);
- transition_in(numberinput9.$$.fragment, local);
- transition_in(switchtoggle.$$.fragment, local);
- transition_in(numberinput10.$$.fragment, local);
- transition_in(checkbox8.$$.fragment, local);
- transition_in(checkbox9.$$.fragment, local);
- transition_in(checkbox10.$$.fragment, local);
- transition_in(checkbox11.$$.fragment, local);
- transition_in(checkbox12.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(sliderinput0.$$.fragment, local);
- transition_out(numberinput0.$$.fragment, local);
- transition_out(numberinput1.$$.fragment, local);
- transition_out(sliderinput1.$$.fragment, local);
- transition_out(checkbox0.$$.fragment, local);
- transition_out(checkbox1.$$.fragment, local);
- transition_out(checkbox2.$$.fragment, local);
- transition_out(checkbox3.$$.fragment, local);
- transition_out(checkbox4.$$.fragment, local);
- transition_out(numberinput2.$$.fragment, local);
- transition_out(numberinput3.$$.fragment, local);
- transition_out(checkbox5.$$.fragment, local);
- transition_out(numberinput4.$$.fragment, local);
- transition_out(checkbox6.$$.fragment, local);
- transition_out(numberinput5.$$.fragment, local);
- transition_out(numberinput6.$$.fragment, local);
- transition_out(checkbox7.$$.fragment, local);
- transition_out(numberinput7.$$.fragment, local);
- transition_out(numberinput8.$$.fragment, local);
- transition_out(numberinput9.$$.fragment, local);
- transition_out(switchtoggle.$$.fragment, local);
- transition_out(numberinput10.$$.fragment, local);
- transition_out(checkbox8.$$.fragment, local);
- transition_out(checkbox9.$$.fragment, local);
- transition_out(checkbox10.$$.fragment, local);
- transition_out(checkbox11.$$.fragment, local);
- transition_out(checkbox12.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div16);
- destroy_each(each_blocks_2, detaching);
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].d();
- }
- destroy_each(each_blocks, detaching);
- destroy_component(sliderinput0);
- destroy_component(numberinput0);
- destroy_component(numberinput1);
- destroy_component(sliderinput1);
- destroy_component(checkbox0);
- destroy_component(checkbox1);
- destroy_component(checkbox2);
- destroy_component(checkbox3);
- destroy_component(checkbox4);
- destroy_component(numberinput2);
- destroy_component(numberinput3);
- destroy_component(checkbox5);
- destroy_component(numberinput4);
- destroy_component(checkbox6);
- destroy_component(numberinput5);
- destroy_component(numberinput6);
- destroy_component(checkbox7);
- destroy_component(numberinput7);
- destroy_component(numberinput8);
- destroy_component(numberinput9);
- destroy_component(switchtoggle);
- destroy_component(numberinput10);
- destroy_component(checkbox8);
- destroy_component(checkbox9);
- destroy_component(checkbox10);
- destroy_component(checkbox11);
- destroy_component(checkbox12);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- let lastInput = "";
- async function activateLayer() {
- ui.controls.initialize({
- control: "sequencer",
- tool: "play-effect"
- });
- canvas.sequencerInterfaceLayer.activate({ tool: "play-effect" });
- }
- function instance$5($$self, $$props, $$invalidate) {
- let $fileStore;
- let $userStore;
- const fileStore = PlayerSettings.file.store;
- component_subscribe($$self, fileStore, (value) => $$invalidate(0, $fileStore = value));
- const users2 = game.users.filter((user) => user.active);
- const userStore = PlayerSettings.users.store;
- component_subscribe($$self, userStore, (value) => $$invalidate(3, $userStore = value));
- let lastResults = [];
- let suggestions = [];
- const searchDebounce = foundry.utils.debounce(
- () => {
- const fileInput = get_store_value(fileStore).toLowerCase();
- if (!fileInput) {
- $$invalidate(1, suggestions = SequencerDatabase.publicModules);
- return;
- }
- if (lastInput === fileInput)
- return;
- let results = SequencerDatabase.searchFor(fileInput);
- if (lastResults.equals(results))
- return;
- lastResults = foundry.utils.duplicate(results);
- if (results.length === 1 && results[0].startsWith(fileInput))
- return;
- if (results.length > 100) {
- results = results.slice(0, 100);
- }
- $$invalidate(1, suggestions = foundry.utils.duplicate(results));
- },
- 200
- );
- let filePicker = false;
- function handleClick() {
- if (!filePicker) {
- const file = get_store_value(fileStore);
- const current = SequencerDatabase.getEntry(file, { softFail: true }) ? file : "";
- filePicker = new FilePicker({
- type: "imageVideo",
- current,
- callback: (path) => {
- fileStore.set(path);
- filePicker = false;
- }
- });
- }
- filePicker.render(true, { focus: true });
- }
- const presets = PlayerSettings.getPresets();
- let selectedPreset = "default";
- const click_handler = () => activateLayer();
- function input_input_handler() {
- $fileStore = this.value;
- fileStore.set($fileStore);
- }
- function select0_change_handler() {
- $userStore = select_multiple_value(this);
- userStore.set($userStore);
- $$invalidate(5, users2);
- }
- function select1_change_handler() {
- selectedPreset = select_value(this);
- $$invalidate(2, selectedPreset);
- $$invalidate(8, presets);
- }
- const change_handler = () => PlayerSettings.loadPreset(selectedPreset);
- const click_handler_1 = () => PlayerSettings.savePreset(selectedPreset);
- const click_handler_2 = () => PlayerSettings.copyPreset(selectedPreset);
- const click_handler_3 = () => PlayerSettings.deletePreset(selectedPreset);
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*$fileStore*/
- 1) {
- searchDebounce($fileStore);
- }
- };
- return [
- $fileStore,
- suggestions,
- selectedPreset,
- $userStore,
- fileStore,
- users2,
- userStore,
- handleClick,
- presets,
- click_handler,
- input_input_handler,
- select0_change_handler,
- select1_change_handler,
- change_handler,
- click_handler_1,
- click_handler_2,
- click_handler_3
- ];
- }
- class Player extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$5, create_fragment$5, safe_not_equal, {});
- }
- }
- const SequenceStatus_svelte_svelte_type_style_lang = "";
- function create_fragment$4(ctx) {
- let i0;
- let t;
- let i1;
- return {
- c() {
- i0 = element("i");
- t = space();
- i1 = element("i");
- attr(i0, "class", "fa-solid background-circle svelte-ese-1wkm0y3");
- toggle_class(
- i0,
- "invisible",
- /*$status*/
- ctx[1] === CONSTANTS.STATUS.READY
- );
- toggle_class(
- i0,
- "fa-arrow-right",
- /*$status*/
- ctx[1] === CONSTANTS.STATUS.RUNNING || /*$status*/
- ctx[1] === CONSTANTS.STATUS.READY
- );
- toggle_class(
- i0,
- "fa-check",
- /*$status*/
- ctx[1] === CONSTANTS.STATUS.COMPLETE
- );
- toggle_class(
- i0,
- "fa-arrow-down",
- /*$status*/
- ctx[1] === CONSTANTS.STATUS.SKIPPED
- );
- toggle_class(
- i0,
- "fa-times",
- /*$status*/
- ctx[1] === CONSTANTS.STATUS.ABORTED
- );
- attr(i1, "class", "fa-solid ");
- },
- m(target, anchor) {
- insert(target, i0, anchor);
- insert(target, t, anchor);
- insert(target, i1, anchor);
- },
- p(ctx2, [dirty]) {
- if (dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- i0,
- "invisible",
- /*$status*/
- ctx2[1] === CONSTANTS.STATUS.READY
- );
- }
- if (dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- i0,
- "fa-arrow-right",
- /*$status*/
- ctx2[1] === CONSTANTS.STATUS.RUNNING || /*$status*/
- ctx2[1] === CONSTANTS.STATUS.READY
- );
- }
- if (dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- i0,
- "fa-check",
- /*$status*/
- ctx2[1] === CONSTANTS.STATUS.COMPLETE
- );
- }
- if (dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- i0,
- "fa-arrow-down",
- /*$status*/
- ctx2[1] === CONSTANTS.STATUS.SKIPPED
- );
- }
- if (dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- i0,
- "fa-times",
- /*$status*/
- ctx2[1] === CONSTANTS.STATUS.ABORTED
- );
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(i0);
- if (detaching)
- detach(t);
- if (detaching)
- detach(i1);
- }
- };
- }
- function instance$4($$self, $$props, $$invalidate) {
- let $status, $$unsubscribe_status = noop, $$subscribe_status = () => ($$unsubscribe_status(), $$unsubscribe_status = subscribe(status, ($$value) => $$invalidate(1, $status = $$value)), status);
- $$self.$$.on_destroy.push(() => $$unsubscribe_status());
- let { status } = $$props;
- $$subscribe_status();
- $$self.$$set = ($$props2) => {
- if ("status" in $$props2)
- $$subscribe_status($$invalidate(0, status = $$props2.status));
- };
- return [status, $status];
- }
- class SequenceStatus extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$4, create_fragment$4, safe_not_equal, { status: 0 });
- }
- }
- const SequenceSection_svelte_svelte_type_style_lang = "";
- function create_fragment$3(ctx) {
- let div;
- let span0;
- let sequencestatus;
- let t0;
- let span1;
- let t2;
- let span2;
- let a;
- let current;
- let mounted;
- let dispose;
- sequencestatus = new SequenceStatus({ props: { status: (
- /*status*/
- ctx[2]
- ) } });
- return {
- c() {
- div = element("div");
- span0 = element("span");
- create_component(sequencestatus.$$.fragment);
- t0 = space();
- span1 = element("span");
- span1.textContent = `${/*sectionName*/
- ctx[3]}`;
- t2 = space();
- span2 = element("span");
- a = element("a");
- a.innerHTML = `<i class="fas fa-stop"></i>`;
- attr(span1, "class", "section-name svelte-ese-1ee9h3");
- attr(a, "class", "svelte-ese-1ee9h3");
- toggle_class(
- a,
- "section-done",
- /*$status*/
- ctx[1] > CONSTANTS.STATUS.READY
- );
- attr(span2, "class", "sequence-actions svelte-ese-1ee9h3");
- attr(span2, "data-tooltip", localize("SEQUENCER.Sequences.AbortSection"));
- attr(div, "class", "svelte-ese-1ee9h3");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, span0);
- mount_component(sequencestatus, span0, null);
- append(div, t0);
- append(div, span1);
- append(div, t2);
- append(div, span2);
- append(span2, a);
- current = true;
- if (!mounted) {
- dispose = listen(
- a,
- "click",
- /*click_handler*/
- ctx[4]
- );
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (!current || dirty & /*$status, CONSTANTS*/
- 2) {
- toggle_class(
- a,
- "section-done",
- /*$status*/
- ctx2[1] > CONSTANTS.STATUS.READY
- );
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(sequencestatus.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(sequencestatus.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(sequencestatus);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$3($$self, $$props, $$invalidate) {
- let $status;
- let { section } = $$props;
- const status = section.sectionStatus;
- component_subscribe($$self, status, (value) => $$invalidate(1, $status = value));
- const sectionName = (section?.constructor?.niceName ? section?.constructor?.niceName : section.constructor.name) + (section?._name ? " - " + section._name : "");
- const click_handler = () => {
- section._abortSection();
- };
- $$self.$$set = ($$props2) => {
- if ("section" in $$props2)
- $$invalidate(0, section = $$props2.section);
- };
- return [section, $status, status, sectionName, click_handler];
- }
- class SequenceSection extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$3, create_fragment$3, safe_not_equal, { section: 0 });
- }
- }
- const Sequence_svelte_svelte_type_style_lang = "";
- function get_each_context$1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[6] = list[i];
- return child_ctx;
- }
- function create_each_block$1(ctx) {
- let sequencesection;
- let current;
- sequencesection = new SequenceSection({ props: { section: (
- /*section*/
- ctx[6]
- ) } });
- return {
- c() {
- create_component(sequencesection.$$.fragment);
- },
- m(target, anchor) {
- mount_component(sequencesection, target, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const sequencesection_changes = {};
- if (dirty & /*sequence*/
- 1)
- sequencesection_changes.section = /*section*/
- ctx2[6];
- sequencesection.$set(sequencesection_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(sequencesection.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(sequencesection.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(sequencesection, detaching);
- }
- };
- }
- function create_fragment$2(ctx) {
- let div;
- let span0;
- let sequencestatus;
- let t0;
- let span1;
- let t1;
- let t2;
- let t3_value = (
- /*sequence*/
- ctx[0].moduleName ? ` (${/*sequence*/
- ctx[0].moduleName})` : ""
- );
- let t3;
- let t4;
- let span2;
- let a0;
- let i0;
- let t5;
- let a1;
- let i1;
- let t6;
- let each_1_anchor;
- let current;
- let mounted;
- let dispose;
- sequencestatus = new SequenceStatus({ props: { status: (
- /*status*/
- ctx[3]
- ) } });
- let each_value = (
- /*sequence*/
- ctx[0].sections
- );
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i));
- }
- const out = (i) => transition_out(each_blocks[i], 1, 1, () => {
- each_blocks[i] = null;
- });
- return {
- c() {
- div = element("div");
- span0 = element("span");
- create_component(sequencestatus.$$.fragment);
- t0 = space();
- span1 = element("span");
- t1 = text$1("Sequence ");
- t2 = text$1(
- /*index*/
- ctx[1]
- );
- t3 = text$1(t3_value);
- t4 = space();
- span2 = element("span");
- a0 = element("a");
- i0 = element("i");
- t5 = space();
- a1 = element("a");
- i1 = element("i");
- t6 = space();
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- each_1_anchor = empty();
- attr(span1, "class", "sequence-name svelte-ese-1dcwqos");
- attr(i0, "class", "fas fa-trash-can");
- attr(a0, "class", "clear-sequence svelte-ese-1dcwqos");
- attr(a0, "data-tooltip", localize("SEQUENCER.Sequences.Clear"));
- toggle_class(
- a0,
- "sequence-done-show",
- /*$status*/
- ctx[2] > CONSTANTS.STATUS.RUNNING
- );
- attr(i1, "class", "fas fa-stop");
- attr(a1, "data-tooltip", localize("SEQUENCER.Sequences.AbortSequence"));
- attr(a1, "class", "svelte-ese-1dcwqos");
- toggle_class(
- a1,
- "sequence-done-hide",
- /*$status*/
- ctx[2] > CONSTANTS.STATUS.RUNNING
- );
- attr(span2, "class", "sequence-actions svelte-ese-1dcwqos");
- attr(div, "class", "sequence-name-container svelte-ese-1dcwqos");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, span0);
- mount_component(sequencestatus, span0, null);
- append(div, t0);
- append(div, span1);
- append(span1, t1);
- append(span1, t2);
- append(span1, t3);
- append(div, t4);
- append(div, span2);
- append(span2, a0);
- append(a0, i0);
- append(span2, t5);
- append(span2, a1);
- append(a1, i1);
- insert(target, t6, anchor);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(target, anchor);
- }
- insert(target, each_1_anchor, anchor);
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- a0,
- "click",
- /*click_handler*/
- ctx[4]
- ),
- listen(
- a1,
- "click",
- /*click_handler_1*/
- ctx[5]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, [dirty]) {
- if (!current || dirty & /*index*/
- 2)
- set_data(
- t2,
- /*index*/
- ctx2[1]
- );
- if ((!current || dirty & /*sequence*/
- 1) && t3_value !== (t3_value = /*sequence*/
- ctx2[0].moduleName ? ` (${/*sequence*/
- ctx2[0].moduleName})` : ""))
- set_data(t3, t3_value);
- if (!current || dirty & /*$status, CONSTANTS*/
- 4) {
- toggle_class(
- a0,
- "sequence-done-show",
- /*$status*/
- ctx2[2] > CONSTANTS.STATUS.RUNNING
- );
- }
- if (!current || dirty & /*$status, CONSTANTS*/
- 4) {
- toggle_class(
- a1,
- "sequence-done-hide",
- /*$status*/
- ctx2[2] > CONSTANTS.STATUS.RUNNING
- );
- }
- if (dirty & /*sequence*/
- 1) {
- each_value = /*sequence*/
- ctx2[0].sections;
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$1(ctx2, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- transition_in(each_blocks[i], 1);
- } else {
- each_blocks[i] = create_each_block$1(child_ctx);
- each_blocks[i].c();
- transition_in(each_blocks[i], 1);
- each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);
- }
- }
- group_outros();
- for (i = each_value.length; i < each_blocks.length; i += 1) {
- out(i);
- }
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(sequencestatus.$$.fragment, local);
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- transition_out(sequencestatus.$$.fragment, local);
- each_blocks = each_blocks.filter(Boolean);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- destroy_component(sequencestatus);
- if (detaching)
- detach(t6);
- destroy_each(each_blocks, detaching);
- if (detaching)
- detach(each_1_anchor);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$2($$self, $$props, $$invalidate) {
- let $status;
- let { sequence } = $$props;
- let { index } = $$props;
- const status = sequence.status;
- component_subscribe($$self, status, (value) => $$invalidate(2, $status = value));
- const click_handler = () => {
- SequenceManager.RunningSequences.delete(sequence.id);
- };
- const click_handler_1 = () => {
- sequence._abort();
- };
- $$self.$$set = ($$props2) => {
- if ("sequence" in $$props2)
- $$invalidate(0, sequence = $$props2.sequence);
- if ("index" in $$props2)
- $$invalidate(1, index = $$props2.index);
- };
- return [sequence, index, $status, status, click_handler, click_handler_1];
- }
- let Sequence$2 = class Sequence2 extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$2, create_fragment$2, safe_not_equal, { sequence: 0, index: 1 });
- }
- };
- const Sequences_svelte_svelte_type_style_lang = "";
- function get_each_context(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[7] = list[i][0];
- child_ctx[8] = list[i][1];
- child_ctx[10] = i;
- return child_ctx;
- }
- function create_else_block(ctx) {
- let div0;
- let button0;
- let t1;
- let button1;
- let t3;
- let div1;
- let each_blocks = [];
- let each_1_lookup = /* @__PURE__ */ new Map();
- let current;
- let mounted;
- let dispose;
- let each_value = (
- /*runningSequences*/
- ctx[0]
- );
- const get_key = (ctx2) => (
- /*id*/
- ctx2[7]
- );
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context(ctx, each_value, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx));
- }
- return {
- c() {
- div0 = element("div");
- button0 = element("button");
- button0.textContent = `${localize("SEQUENCER.Sequences.ClearFinished")}`;
- t1 = space();
- button1 = element("button");
- button1.textContent = `${localize("SEQUENCER.Sequences.StopAll")}`;
- t3 = space();
- div1 = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(button0, "type", "button");
- attr(button0, "class", "svelte-ese-1ismzan");
- attr(button1, "type", "button");
- attr(button1, "class", "svelte-ese-1ismzan");
- attr(div0, "class", "sequence-button-header svelte-ese-1ismzan");
- attr(div1, "class", "running-sequences svelte-ese-1ismzan");
- },
- m(target, anchor) {
- insert(target, div0, anchor);
- append(div0, button0);
- append(div0, t1);
- append(div0, button1);
- insert(target, t3, anchor);
- insert(target, div1, anchor);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div1, null);
- }
- current = true;
- if (!mounted) {
- dispose = [
- listen(
- button0,
- "click",
- /*click_handler*/
- ctx[3]
- ),
- listen(
- button1,
- "click",
- /*click_handler_1*/
- ctx[4]
- )
- ];
- mounted = true;
- }
- },
- p(ctx2, dirty) {
- if (dirty & /*runningSequences*/
- 1) {
- each_value = /*runningSequences*/
- ctx2[0];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div1, outro_and_destroy_block, create_each_block, null, get_each_context);
- check_outros();
- }
- },
- i(local) {
- if (current)
- return;
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div0);
- if (detaching)
- detach(t3);
- if (detaching)
- detach(div1);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_if_block(ctx) {
- let div;
- let h2;
- return {
- c() {
- div = element("div");
- h2 = element("h2");
- h2.textContent = `${localize("SEQUENCER.Sequences.NoSequences")}`;
- attr(div, "class", "no-sequences");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, h2);
- },
- p: noop,
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching)
- detach(div);
- }
- };
- }
- function create_each_block(key_1, ctx) {
- let first;
- let sequence;
- let current;
- sequence = new Sequence$2({
- props: {
- sequence: (
- /*sequence*/
- ctx[8]
- ),
- index: (
- /*index*/
- ctx[10] + 1
- )
- }
- });
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- create_component(sequence.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(sequence, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const sequence_changes = {};
- if (dirty & /*runningSequences*/
- 1)
- sequence_changes.sequence = /*sequence*/
- ctx[8];
- if (dirty & /*runningSequences*/
- 1)
- sequence_changes.index = /*index*/
- ctx[10] + 1;
- sequence.$set(sequence_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(sequence.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(sequence.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(first);
- destroy_component(sequence, detaching);
- }
- };
- }
- function create_fragment$1(ctx) {
- let div;
- let current_block_type_index;
- let if_block;
- let current;
- const if_block_creators = [create_if_block, create_else_block];
- const if_blocks = [];
- function select_block_type(ctx2, dirty) {
- if (!/*runningSequences*/
- ctx2[0].length)
- return 0;
- return 1;
- }
- current_block_type_index = select_block_type(ctx);
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
- return {
- c() {
- div = element("div");
- if_block.c();
- attr(div, "class", "sequence-container svelte-ese-1ismzan");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- if_blocks[current_block_type_index].m(div, null);
- current = true;
- },
- p(ctx2, [dirty]) {
- let previous_block_index = current_block_type_index;
- current_block_type_index = select_block_type(ctx2);
- if (current_block_type_index === previous_block_index) {
- if_blocks[current_block_type_index].p(ctx2, dirty);
- } else {
- group_outros();
- transition_out(if_blocks[previous_block_index], 1, 1, () => {
- if_blocks[previous_block_index] = null;
- });
- check_outros();
- if_block = if_blocks[current_block_type_index];
- if (!if_block) {
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
- if_block.c();
- } else {
- if_block.p(ctx2, dirty);
- }
- transition_in(if_block, 1);
- if_block.m(div, null);
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(if_block);
- current = true;
- },
- o(local) {
- transition_out(if_block);
- current = false;
- },
- d(detaching) {
- if (detaching)
- detach(div);
- if_blocks[current_block_type_index].d();
- }
- };
- }
- function instance$1($$self, $$props, $$invalidate) {
- let runningSequences;
- let $RunningSequences;
- const RunningSequences = SequenceManager.RunningSequences;
- component_subscribe($$self, RunningSequences, (value) => $$invalidate(2, $RunningSequences = value));
- onDestroy(() => {
- SequenceManager.RunningSequences.clearFinishedSequences();
- });
- const click_handler = () => {
- SequenceManager.RunningSequences.clearFinishedSequences();
- };
- const click_handler_1 = () => {
- SequenceManager.RunningSequences.stopAll();
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*$RunningSequences*/
- 4) {
- Object.values($RunningSequences);
- }
- if ($$self.$$.dirty & /*$RunningSequences*/
- 4) {
- $$invalidate(0, runningSequences = Object.entries($RunningSequences));
- }
- };
- return [
- runningSequences,
- RunningSequences,
- $RunningSequences,
- click_handler,
- click_handler_1
- ];
- }
- class Sequences extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$1, create_fragment$1, safe_not_equal, {});
- }
- }
- function create_default_slot(ctx) {
- let tabs_1;
- let updating_activeTab;
- let t;
- let switch_instance;
- let switch_instance_anchor;
- let current;
- function tabs_1_activeTab_binding(value) {
- ctx[4](value);
- }
- let tabs_1_props = { tabs: (
- /*tabs*/
- ctx[3]
- ) };
- if (
- /*activeTab*/
- ctx[1] !== void 0
- ) {
- tabs_1_props.activeTab = /*activeTab*/
- ctx[1];
- }
- tabs_1 = new Tabs({ props: tabs_1_props });
- binding_callbacks.push(() => bind(tabs_1, "activeTab", tabs_1_activeTab_binding));
- var switch_value = (
- /*component*/
- ctx[2]
- );
- function switch_props(ctx2) {
- return {};
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- }
- return {
- c() {
- create_component(tabs_1.$$.fragment);
- t = space();
- if (switch_instance)
- create_component(switch_instance.$$.fragment);
- switch_instance_anchor = empty();
- },
- m(target, anchor) {
- mount_component(tabs_1, target, anchor);
- insert(target, t, anchor);
- if (switch_instance)
- mount_component(switch_instance, target, anchor);
- insert(target, switch_instance_anchor, anchor);
- current = true;
- },
- p(ctx2, dirty) {
- const tabs_1_changes = {};
- if (!updating_activeTab && dirty & /*activeTab*/
- 2) {
- updating_activeTab = true;
- tabs_1_changes.activeTab = /*activeTab*/
- ctx2[1];
- add_flush_callback(() => updating_activeTab = false);
- }
- tabs_1.$set(tabs_1_changes);
- if (switch_value !== (switch_value = /*component*/
- ctx2[2])) {
- if (switch_instance) {
- group_outros();
- const old_component = switch_instance;
- transition_out(old_component.$$.fragment, 1, 0, () => {
- destroy_component(old_component, 1);
- });
- check_outros();
- }
- if (switch_value) {
- switch_instance = construct_svelte_component(switch_value, switch_props());
- create_component(switch_instance.$$.fragment);
- transition_in(switch_instance.$$.fragment, 1);
- mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
- } else {
- switch_instance = null;
- }
- }
- },
- i(local) {
- if (current)
- return;
- transition_in(tabs_1.$$.fragment, local);
- if (switch_instance)
- transition_in(switch_instance.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(tabs_1.$$.fragment, local);
- if (switch_instance)
- transition_out(switch_instance.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(tabs_1, detaching);
- if (detaching)
- detach(t);
- if (detaching)
- detach(switch_instance_anchor);
- if (switch_instance)
- destroy_component(switch_instance, detaching);
- }
- };
- }
- function create_fragment(ctx) {
- let applicationshell;
- let updating_elementRoot;
- let current;
- function applicationshell_elementRoot_binding(value) {
- ctx[5](value);
- }
- let applicationshell_props = {
- $$slots: { default: [create_default_slot] },
- $$scope: { ctx }
- };
- if (
- /*elementRoot*/
- ctx[0] !== void 0
- ) {
- applicationshell_props.elementRoot = /*elementRoot*/
- ctx[0];
- }
- applicationshell = new ApplicationShell({ props: applicationshell_props });
- binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding));
- return {
- c() {
- create_component(applicationshell.$$.fragment);
- },
- m(target, anchor) {
- mount_component(applicationshell, target, anchor);
- current = true;
- },
- p(ctx2, [dirty]) {
- const applicationshell_changes = {};
- if (dirty & /*$$scope, component, activeTab*/
- 134) {
- applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
- }
- if (!updating_elementRoot && dirty & /*elementRoot*/
- 1) {
- updating_elementRoot = true;
- applicationshell_changes.elementRoot = /*elementRoot*/
- ctx2[0];
- add_flush_callback(() => updating_elementRoot = false);
- }
- applicationshell.$set(applicationshell_changes);
- },
- i(local) {
- if (current)
- return;
- transition_in(applicationshell.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(applicationshell.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(applicationshell, detaching);
- }
- };
- }
- function instance($$self, $$props, $$invalidate) {
- let component;
- const { application } = getContext("#external");
- let { elementRoot } = $$props;
- let tabs = [
- {
- value: "player",
- label: localize("SEQUENCER.Player.Title"),
- icon: "fas fa-play-circle",
- component: Player
- },
- {
- value: "manager",
- label: localize("SEQUENCER.Manager.Title"),
- icon: "fas fa-film",
- component: Manager
- },
- {
- value: "sequences",
- label: localize("SEQUENCER.Sequences.Title"),
- icon: "fas fa-play",
- component: Sequences
- },
- {
- value: "howto",
- label: localize("SEQUENCER.HowTo.Title"),
- icon: "fas fa-chalkboard-teacher",
- component: HowTo
- }
- ];
- let activeTab = application.options.tab ?? "manager";
- function tabs_1_activeTab_binding(value) {
- activeTab = value;
- $$invalidate(1, activeTab);
- }
- function applicationshell_elementRoot_binding(value) {
- elementRoot = value;
- $$invalidate(0, elementRoot);
- }
- $$self.$$set = ($$props2) => {
- if ("elementRoot" in $$props2)
- $$invalidate(0, elementRoot = $$props2.elementRoot);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & /*activeTab*/
- 2) {
- $$invalidate(2, component = tabs.find((tab) => tab.value === activeTab).component);
- }
- };
- return [
- elementRoot,
- activeTab,
- component,
- tabs,
- tabs_1_activeTab_binding,
- applicationshell_elementRoot_binding
- ];
- }
- class Effects_ui_shell extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance, create_fragment, safe_not_equal, { elementRoot: 0 });
- }
- get elementRoot() {
- return this.$$.ctx[0];
- }
- set elementRoot(elementRoot) {
- this.$$set({ elementRoot });
- flush();
- }
- }
- class EffectsUIApp extends SvelteApplication {
- static get defaultOptions() {
- return foundry.utils.mergeObject(super.defaultOptions, {
- title: game.i18n.localize("SEQUENCER.ManagerUI"),
- classes: ["dialog"],
- width: "auto",
- height: "auto",
- top: 65,
- left: 120,
- resizable: false,
- svelte: {
- class: Effects_ui_shell,
- target: document.body
- }
- });
- }
- static getActiveApp() {
- return Object.values(ui.windows).find((app) => {
- return app instanceof this && app._state > Application.RENDER_STATES.CLOSED;
- });
- }
- static async show(options = {}) {
- const existingApp = this.getActiveApp();
- if (existingApp)
- return existingApp.render(false, { focus: true });
- return new Promise((resolve) => {
- options.resolve = resolve;
- new this(options).render(true, { focus: true });
- });
- }
- }
- function registerSettings() {
- game.settings.register(CONSTANTS.MODULE_NAME, "enable-fix-pixi", {
- name: "SEQUENCER.Setting.EnablePixiFix.Title",
- hint: "SEQUENCER.Setting.EnablePixiFix.Label",
- scope: "client",
- config: true,
- default: false,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "enable-global-fix-pixi", {
- name: "SEQUENCER.Setting.EnableGlobalPixiFix.Title",
- hint: "SEQUENCER.Setting.EnableGlobalPixiFix.Label",
- scope: "client",
- config: true,
- default: false,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "enable-above-ui-screenspace", {
- name: "SEQUENCER.Setting.EnableAboveUIScreenspace.Title",
- hint: "SEQUENCER.Setting.EnableAboveUIScreenspace.Label",
- scope: "client",
- config: true,
- default: true,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "debug", {
- name: "SEQUENCER.Setting.Debug.Title",
- hint: "SEQUENCER.Setting.Debug.Label",
- scope: "client",
- config: true,
- default: false,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "showSidebarTools", {
- name: "SEQUENCER.Setting.ShowTools.Title",
- hint: "SEQUENCER.Setting.ShowTools.Label",
- scope: "client",
- config: true,
- default: true,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "showTokenSidebarTools", {
- name: "SEQUENCER.Setting.ShowTokenTools.Title",
- hint: "SEQUENCER.Setting.ShowTokenTools.Label",
- scope: "client",
- config: true,
- default: true,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "effectsEnabled", {
- name: "SEQUENCER.Setting.EnableEffects.Title",
- hint: "SEQUENCER.Setting.EnableEffects.Label",
- scope: "client",
- config: true,
- default: true,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "soundsEnabled", {
- name: "SEQUENCER.Setting.EnableSounds.Title",
- hint: "SEQUENCER.Setting.EnableSounds.Label",
- scope: "client",
- config: true,
- default: true,
- requiresReload: true,
- type: Boolean
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "user-effect-opacity", {
- name: "SEQUENCER.Setting.ExternalEffectOpacity.Title",
- hint: "SEQUENCER.Setting.ExternalEffectOpacity.Label",
- scope: "client",
- config: true,
- default: 50,
- type: Number,
- range: {
- min: 0,
- max: 100,
- step: 1
- }
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "db-list-view", {
- scope: "client",
- config: false,
- default: false,
- type: Boolean
- });
- const permissionLevels = [
- game.i18n.localize("SEQUENCER.Permission.Player"),
- game.i18n.localize("SEQUENCER.Permission.Trusted"),
- game.i18n.localize("SEQUENCER.Permission.Assistant"),
- game.i18n.localize("SEQUENCER.Permission.GM")
- ];
- game.settings.register(CONSTANTS.MODULE_NAME, "permissions-effect-create", {
- name: "SEQUENCER.Setting.Permission.EffectCreate.Title",
- hint: "SEQUENCER.Setting.Permission.EffectCreate.Label",
- scope: "world",
- config: true,
- default: 0,
- type: Number,
- choices: permissionLevels,
- requiresReload: true
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "permissions-effect-delete", {
- name: "SEQUENCER.Setting.Permission.EffectDelete.Title",
- hint: "SEQUENCER.Setting.Permission.EffectDelete.Label",
- scope: "world",
- config: true,
- default: 2,
- type: Number,
- choices: permissionLevels,
- requiresReload: true
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "permissions-sound-create", {
- name: "SEQUENCER.Setting.Permission.SoundCreate.Title",
- hint: "SEQUENCER.Setting.Permission.SoundCreate.Label",
- scope: "world",
- config: true,
- default: 0,
- type: Number,
- choices: permissionLevels,
- requiresReload: true
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "permissions-preload", {
- name: "SEQUENCER.Setting.Permission.PreloadClients.Title",
- hint: "SEQUENCER.Setting.Permission.PreloadClients.Label",
- scope: "world",
- config: true,
- default: 1,
- type: Number,
- choices: permissionLevels,
- requiresReload: true
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "permissions-sidebar-tools", {
- name: "SEQUENCER.Setting.Permission.UseSidebarTools.Title",
- hint: "SEQUENCER.Setting.Permission.UseSidebarTools.Label",
- scope: "world",
- config: true,
- default: 0,
- type: Number,
- choices: permissionLevels,
- requiresReload: true
- });
- game.settings.register(CONSTANTS.MODULE_NAME, "effectPresets", {
- scope: "client",
- default: {},
- type: Object
- });
- Hooks.on("getSceneControlButtons", (controls) => {
- if (!game.settings.get(CONSTANTS.MODULE_NAME, "showSidebarTools"))
- return;
- const selectTool = {
- icon: "fas fa-expand",
- name: "select-effect",
- title: "SEQUENCER.SidebarButtons.Select",
- visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools")
- };
- const playTool = {
- icon: "fas fa-play",
- name: "play-effect",
- title: "SEQUENCER.SidebarButtons.Play",
- visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
- onClick: () => {
- EffectsUIApp.show({ inFocus: true, tab: "player" });
- }
- };
- const viewer = {
- icon: "fas fa-film",
- name: "effectviewer",
- title: "SEQUENCER.SidebarButtons.Manager",
- button: true,
- visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
- onClick: () => {
- EffectsUIApp.show({ inFocus: true, tab: "manager" });
- }
- };
- const database = {
- icon: "fas fa-database",
- name: "effectdatabase",
- title: "SEQUENCER.SidebarButtons.Database",
- button: true,
- visible: user_can_do("permissions-sidebar-tools"),
- onClick: () => {
- DatabaseViewerApp.show();
- }
- };
- controls.push({
- name: CONSTANTS.MODULE_NAME,
- title: "Sequencer Layer",
- icon: "fas fa-list-ol",
- layer: "sequencerInterfaceLayer",
- visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
- activeTool: "select-effect",
- tools: [selectTool, playTool, database, viewer]
- });
- if (!game.settings.get(CONSTANTS.MODULE_NAME, "showTokenSidebarTools"))
- return;
- const bar = controls.find((c) => c.name === "token");
- bar.tools.push(database);
- bar.tools.push(viewer);
- });
- debug("Sequencer | Registered settings");
- }
- async function migrateSettings() {
- const oldScreenspaceSetting = game.settings.storage.get("client").getItem("sequencer.disable-above-ui-screenspace");
- if (oldScreenspaceSetting) {
- const value = oldScreenspaceSetting === "true";
- game.settings.storage.get("client").removeItem("sequencer.disable-above-ui-screenspace");
- await game.settings.set(
- CONSTANTS.MODULE_NAME,
- "enable-above-ui-screenspace",
- !value
- );
- }
- }
- function registerLayers() {
- CONFIG.Canvas.layers = foundry.utils.mergeObject(Canvas.layers, {
- sequencerEffects: {
- layerClass: BaseEffectsLayer,
- group: "primary"
- },
- sequencerInterfaceLayer: {
- layerClass: SequencerInterfaceLayer,
- group: "interface"
- },
- sequencerEffectsUILayer: {
- layerClass: UIEffectsLayer,
- group: "interface"
- }
- });
- if (!Object.is(Canvas.layers, CONFIG.Canvas.layers)) {
- const layers = Canvas.layers;
- Object.defineProperty(Canvas, "layers", {
- get: function() {
- return foundry.utils.mergeObject(layers, CONFIG.Canvas.layers);
- }
- });
- }
- debug("Registered Layers");
- }
- const hotkeys = {
- get _ready() {
- return canvas.ready && canvas.sequencerInterfaceLayer.active;
- },
- playTool: {
- playManySequencedDown: () => {
- if (!hotkeys._ready)
- return;
- EffectPlayer.playManySequenced = true;
- },
- playManySequencedUp: () => {
- if (!hotkeys._ready)
- return;
- EffectPlayer.playManySequenced = false;
- if (!EffectPlayer.isActive)
- return;
- EffectPlayer.playManyUp();
- },
- playManyDown: () => {
- if (!hotkeys._ready)
- return;
- EffectPlayer.playMany = true;
- },
- playManyUp: () => {
- if (!hotkeys._ready)
- return;
- EffectPlayer.playMany = false;
- if (!EffectPlayer.isActive)
- return;
- EffectPlayer.playManyUp();
- },
- attachToDown: () => {
- if (!hotkeys._ready)
- return;
- PlayerSettings.attachTo.store.set(true);
- PlayerSettings.stretchToAttach.store.set(true);
- },
- attachToUp: () => {
- if (!hotkeys._ready)
- return;
- PlayerSettings.attachTo.store.set(false);
- PlayerSettings.stretchToAttach.store.set(false);
- }
- },
- selectTool: {
- snapToGridDown: () => {
- if (!hotkeys._ready)
- return;
- SelectionManager.snapToGrid = true;
- },
- snapToGridUp: () => {
- if (!hotkeys._ready)
- return;
- SelectionManager.snapToGrid = false;
- },
- attachToTargetDown: () => {
- if (!hotkeys._ready)
- return;
- if (!SelectionManager.isActive)
- return;
- PlayerSettings.attachTo.store.set(true);
- PlayerSettings.stretchToAttach.store.set(true);
- },
- attachToTargetUp: () => {
- if (!hotkeys._ready)
- return;
- PlayerSettings.attachTo.store.set(false);
- PlayerSettings.stretchToAttach.store.set(false);
- },
- deleteDown: () => {
- if (!hotkeys._ready)
- return;
- SelectionManager.delete();
- }
- }
- };
- function registerHotkeys() {
- game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-control", {
- name: "SEQUENCER.Hotkeys.PlayTool.Control",
- editable: [{ key: "ControlLeft" }],
- onDown: hotkeys.playTool.playManySequencedDown,
- onUp: hotkeys.playTool.playManySequencedUp
- });
- game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-shift", {
- name: "SEQUENCER.Hotkeys.PlayTool.Shift",
- editable: [{ key: "ShiftLeft" }],
- onDown: hotkeys.playTool.playManyDown,
- onUp: hotkeys.playTool.playManyUp
- });
- game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-alt", {
- name: "SEQUENCER.Hotkeys.PlayTool.Alt",
- editable: [{ key: "AltLeft" }],
- onDown: hotkeys.playTool.attachToDown,
- onUp: hotkeys.playTool.attachToDown
- });
- game.keybindings.register(
- CONSTANTS.MODULE_NAME,
- "select-tool-hotkey-control",
- {
- name: "SEQUENCER.Hotkeys.SelectTool.Control",
- editable: [{ key: "ControlLeft" }],
- onDown: hotkeys.selectTool.snapToGridDown,
- onUp: hotkeys.selectTool.snapToGridUp
- }
- );
- game.keybindings.register(CONSTANTS.MODULE_NAME, "select-tool-hotkey-alt", {
- name: "SEQUENCER.Hotkeys.SelectTool.Alt",
- editable: [{ key: "AltLeft" }],
- onDown: hotkeys.selectTool.attachToTargetDown,
- onUp: hotkeys.selectTool.attachToTargetUp
- });
- game.keybindings.register(
- CONSTANTS.MODULE_NAME,
- "select-tool-hotkey-delete",
- {
- name: "SEQUENCER.Hotkeys.SelectTool.Delete",
- editable: [{ key: "Delete" }],
- onDown: hotkeys.selectTool.deleteDown
- }
- );
- }
- async function registerTypes(register) {
- fetch("modules/sequencer/typings/types.d.ts").then((response) => response.text()).then((content) => register("sequencer/types.d.ts", content));
- }
- const presetMap = /* @__PURE__ */ new Map();
- class SequencerPresets {
- /**
- * Adds a preset that can then be used in sequences
- *
- * @param {string} inName
- * @param {Function} inFunction
- * @param {boolean} [overwrite=false] overwrite
- * @returns {Map<string, Function>}
- */
- static add(inName, inFunction, overwrite = false) {
- if (typeof inName !== "string") {
- throw custom_error(
- "Sequencer",
- `SequencerPresets | inName must be of type string`
- );
- }
- if (!is_function$1(inFunction)) {
- throw custom_error(
- "Sequencer",
- `SequencerPresets | inFunction must be of type function`
- );
- }
- if (presetMap.get(inName) && !overwrite) {
- throw custom_error(
- "Sequencer",
- `SequencerPresets | Preset "${inName}" already exists`
- );
- }
- presetMap.set(inName, inFunction);
- debug(`Sequencer | Presets | Added "${inName}" preset`);
- return presetMap;
- }
- /**
- * Retrieves all presets
- *
- * @returns {Map<string, Function>}
- */
- static getAll() {
- return presetMap;
- }
- /**
- * Retrieves preset based on its name
- *
- * @param {string} name
- * @returns {Function}
- */
- static get(name) {
- return presetMap.get(name);
- }
- }
- class Section {
- constructor(inSequence) {
- this.sequence = inSequence;
- this._applyTraits();
- this._sectionStatus = writable$1(CONSTANTS.STATUS.READY);
- this._playIf = true;
- this._waitUntilFinished = false;
- this._async = false;
- this._waitUntilFinishedDelay = [0, 0];
- this._repetitions = 1;
- this._currentRepetition = 0;
- this._repeatDelayMin = 0;
- this._repeatDelayMax = 0;
- this._repeatDelay = 0;
- this._delayMin = 0;
- this._delayMax = 0;
- this._basicDelay = 0;
- this._duration = false;
- }
- static niceName = "Section";
- /**
- * @protected
- */
- get _shouldAsync() {
- return this._async || this._waitAnyway;
- }
- /**
- * @protected
- */
- get shouldWaitUntilFinished() {
- return this._waitUntilFinished || this._waitAnyway;
- }
- /**
- * @protected
- */
- get _waitAnyway() {
- return (this._async || this._waitUntilFinished) && this._isLastRepetition || this._isLastRepetition && this._isLastSection;
- }
- /**
- * @protected
- */
- get _isLastSection() {
- return this.sequence.sections.length - 1 === this.sequence.sections.indexOf(this);
- }
- /** ------------------------------------------------------------------------------------------------------------------------------ *
- * Methods below this point should NOT be overridden by child instances of the class, they are integral to the sequence functioning
- * ------------------------------------------------------------------------------------------------------------------------------- */
- /**
- * @protected
- */
- get _isLastRepetition() {
- return this._repetitions === 1 || this._repetitions === this._currentRepetition + 1;
- }
- /**
- * @protected
- */
- get _currentWaitTime() {
- let waitUntilFinishedDelay = this._waitAnyway ? random_int_between(...this._waitUntilFinishedDelay) : 0;
- return waitUntilFinishedDelay + this._repeatDelay;
- }
- /**
- * Method overwritten by inheriting classes, which is called just before the "run" method is called (see below)
- *
- * @returns {Promise<void>}
- * @protected
- */
- async preRun() {
- }
- /**
- * Method overwritten by inheriting classes, which is called when this section is executed by the Sequence
- *
- * @returns {Promise<void>}
- * @protected
- */
- async run() {
- }
- /**
- * Method overwritten by inheriting classes, which is called when this section is serialized by the Sequence
- *
- * @returns {object}
- * @private
- */
- async _serialize() {
- return {
- async: this._async,
- delay: [this._delayMin, this._delayMax],
- waitUntilFinished: this._waitUntilFinished,
- waitUntilFinishedDelay: this._waitUntilFinishedDelay,
- repetitions: this._repetitions,
- repetitionsDelay: [this._repeatDelayMin, this._repeatDelayMax]
- };
- }
- _deserialize(data) {
- this._async = data.async;
- this._waitUntilFinished = data.waitUntilFinished;
- this._waitUntilFinishedDelay = data.waitUntilFinishedDelay;
- this._repetitions = data.repetitions;
- this._repeatDelayMin = data.repetitionsDelay[0];
- this._repeatDelayMax = data.repetitionsDelay[1];
- return this;
- }
- /**
- * Method overwritten by inheriting classes, which stores data or prepares data before the Sequence executes it (see EffectsSection)
- *
- * @protected
- */
- async _initialize() {
- }
- /**
- * Method overwritten by inheriting classes. Inheriting classes uses the following to apply traits to themselves:
- * - Object.assign(this.constructor.prototype, trait)
- *
- * @protected
- */
- _applyTraits() {
- }
- /**
- * Causes the section to be repeated n amount of times, with an optional delay. If given inRepeatDelayMin
- * and inRepeatDelayMax, a random repetition delay will be picked for every repetition
- *
- * @param {number} inRepetitions
- * @param {number} inRepeatDelayMin
- * @param {number} inRepeatDelayMax
- * @returns {Section} this
- */
- repeats(inRepetitions, inRepeatDelayMin = 0, inRepeatDelayMax) {
- if (!is_real_number(inRepetitions))
- throw this.sequence._customError(
- this,
- "repeats",
- "inRepetitions must be of type number"
- );
- if (!is_real_number(inRepeatDelayMin))
- throw this.sequence._customError(
- this,
- "repeats",
- "repeatDelayMin must be of type number"
- );
- if (inRepeatDelayMax && !is_real_number(inRepeatDelayMax)) {
- throw this.sequence._customError(
- this,
- "repeats",
- "repeatDelayMax must be of type number"
- );
- }
- this._repetitions = inRepetitions;
- this._repeatDelayMin = Math.min(
- inRepeatDelayMin,
- inRepeatDelayMax ?? inRepeatDelayMin
- );
- this._repeatDelayMax = Math.max(
- inRepeatDelayMin,
- inRepeatDelayMax ?? inRepeatDelayMin
- );
- return this;
- }
- /**
- * Causes the effect or sound to not play, and skip all delays, repetitions, waits, etc. If you pass a function,
- * the function should return something false-y if you do not want the effect or sound to play.
- *
- * @param {boolean|function} inCondition
- * @returns {Section} this
- */
- playIf(inCondition) {
- this._playIf = inCondition;
- return this;
- }
- /**
- * Causes the section to finish running before starting the next section.
- *
- * @param {number|boolean} [minDelay=0] minDelay
- * @param {number/null} [maxDelay=null] maxDelay
- * @returns {Section} this
- */
- waitUntilFinished(minDelay = 0, maxDelay = null) {
- if (minDelay === false)
- return this;
- if (!is_real_number(minDelay))
- throw this.sequence._customError(
- this,
- "waitUntilFinished",
- "minDelay must be of type number"
- );
- if (maxDelay !== null && !is_real_number(maxDelay))
- throw this.sequence._customError(
- this,
- "waitUntilFinished",
- "maxDelay must be of type number"
- );
- this._waitUntilFinished = true;
- this._waitUntilFinishedDelay = [
- Math.min(minDelay, maxDelay ?? minDelay),
- Math.max(minDelay, maxDelay ?? minDelay)
- ];
- return this;
- }
- /**
- * Causes each effect or sound to finish playing before the next one starts playing. This differs from
- * .waitUntilFinished() in the sense that this is for each repetition, whilst .waitUntilFinished() is
- * for the entire section.
- *
- * @returns {Section} this
- */
- async() {
- this._async = true;
- return this;
- }
- /**
- * Delays the effect or sound from being played for a set amount of milliseconds. If given a second number, a
- * random delay between the two numbers will be generated.
- *
- * @param {number} [msMin=1] minMs
- * @param {number} [msMax=1] maxMs
- * @returns {Section} this
- */
- delay(msMin, msMax) {
- if (!is_real_number(msMin))
- throw this.sequence._customError(
- this,
- "delay",
- "msMin must be of type number"
- );
- if (msMax && !is_real_number(msMax))
- throw this.sequence._customError(
- this,
- "delay",
- "msMax must be of type number"
- );
- this._delayMin = Math.min(msMin, msMax ?? msMin);
- this._delayMax = Math.max(msMin, msMax ?? msMin);
- return this;
- }
- /**
- * Overrides the duration of this section
- *
- * @param {number} inDuration
- * @returns {Section} this
- */
- duration(inDuration) {
- if (!is_real_number(inDuration))
- throw this.sequence._customError(
- this,
- "duration",
- "inDuration must be of type number"
- );
- this._duration = inDuration;
- return this;
- }
- /**
- * Applies a preset to the current section
- *
- * @param {string} presetName
- * @param {*} args
- * @returns {Section|FunctionSection|EffectSection|AnimationSection|SoundSection}
- */
- preset(presetName, ...args) {
- if (typeof presetName !== "string") {
- throw this.sequence._customError(
- this,
- "name",
- `inName must be of type string`
- );
- }
- const preset = SequencerPresets.get(presetName);
- if (!preset) {
- custom_warning(
- "Sequencer",
- `preset | Could not find preset with name "${presetName}"`
- );
- return this;
- }
- return preset(this, ...args);
- }
- /**
- * @protected
- */
- async _shouldPlay() {
- return is_function$1(this._playIf) ? await this._playIf() : this._playIf;
- }
- /**
- * @protected
- */
- _validateLocation(inLocation) {
- inLocation = validate_document(inLocation);
- if (typeof inLocation === "string") {
- inLocation = get_object_from_scene(inLocation) ?? inLocation;
- }
- if (typeof inLocation === "string") {
- inLocation = safe_str(inLocation);
- }
- return inLocation;
- }
- /**
- * @protected
- */
- async _execute() {
- if (!await this._shouldPlay()) {
- this.sectionStatus = CONSTANTS.STATUS.SKIPPED;
- return;
- }
- this._basicDelay = random_float_between(this._delayMin, this._delayMax);
- return new Promise(async (resolve) => {
- setTimeout(async () => {
- this.sectionStatus = CONSTANTS.STATUS.RUNNING;
- for (let i = 0; i < this._repetitions; i++) {
- if (get_store_value(this.sectionStatus) === CONSTANTS.STATUS.ABORTED) {
- resolve();
- return;
- }
- this._currentRepetition = i;
- this._repeatDelay = i !== this._repetitions - 1 ? random_float_between(
- this._repeatDelayMin,
- this._repeatDelayMax
- ) : 0;
- await this.preRun();
- if (this._shouldAsync) {
- await this.run();
- } else {
- this.run();
- }
- if (this._repetitions > 1 && i !== this._repetitions - 1) {
- await this._delayBetweenRepetitions();
- }
- }
- resolve();
- }, this._basicDelay);
- }).then(() => {
- this.sectionStatus = CONSTANTS.STATUS.COMPLETE;
- });
- }
- set sectionStatus(inStatus) {
- this._sectionStatus.update((currentStatus) => {
- if (currentStatus === CONSTANTS.STATUS.READY || currentStatus === CONSTANTS.STATUS.RUNNING && inStatus !== CONSTANTS.STATUS.ABORTED) {
- return inStatus;
- }
- return currentStatus;
- });
- }
- get sectionStatus() {
- return this._sectionStatus;
- }
- _abortSection() {
- this.sectionStatus = CONSTANTS.STATUS.ABORTED;
- }
- /**
- * @protected
- */
- async _delayBetweenRepetitions() {
- let self = this;
- return new Promise((resolve) => {
- setTimeout(resolve, self._repeatDelay);
- });
- }
- }
- class FunctionSection extends Section {
- constructor(inSequence, inFunc) {
- super(inSequence);
- if (!is_function$1(inFunc))
- this._customError(
- "create",
- "The given function needs to be an actual function"
- );
- this._func = inFunc;
- this._waitUntilFinished = inFunc.constructor.name === "AsyncFunction";
- }
- static niceName = "Function";
- /**
- * @returns {Promise<void>}
- */
- async run() {
- debug("Running function");
- await this._func();
- }
- /**
- * @returns {Promise}
- * @private
- */
- async _execute() {
- await this.run();
- }
- }
- const animation = {
- /**
- * Base properties
- */
- _animations: null,
- /**
- * Animates a property on the target of the animation.
- *
- * @param {string} inTarget
- * @param {string} inPropertyName
- * @param {object} inOptions
- * @param {Number} inOptions.from - a single number from which to animate
- * @param {Number} inOptions.to - a single number to which to animate
- * @param {Number} inOptions.duration - how long in ms the animation should take
- * @param {Number} inOptions.delay - inserts a delay in ms before the animation starts
- * @param {String} inOptions.ease - what type of easing the animation should use
- * @param {Boolean} inOptions.gridUnits - if animating width or height, this will set it to work in the scene's grid units
- * @param {Boolean} inOptions.fromEnd - makes this animation play from the end, like fadeOut, scaleOut, etc
- *
- * @returns this
- */
- animateProperty(inTarget, inPropertyName, inOptions = {}) {
- if (!this._animations)
- this._animations = [];
- const result = validateAnimation(
- inTarget,
- inPropertyName,
- inOptions
- );
- if (typeof result === "string") {
- throw this.sequence._customError(this, "animateProperty", result);
- }
- this._animations.push(result);
- return this;
- },
- /**
- * Loops a property between a set of values on the target
- *
- * @param {string} inTarget
- * @param {string} inPropertyName
- * @param {object} inOptions
- * @param {Number} inOptions.from - a single number from which to loop
- * @param {Number} inOptions.to - a single number to which to loop
- * @param {Number} inOptions.values - an array of values to loop between
- * @param {Number} inOptions.duration - how long in ms the loop should take
- * @param {Number} inOptions.loops - how many loops in total this animation should go through - if none are specified, the loop is indefinite
- * @param {Number} inOptions.delay - inserts a delay in ms before the animation starts
- * @param {String} inOptions.ease - what type of easing the animation should use
- * @param {Boolean} inOptions.pingPong - sets whether loop should interpolate to the first value after it reaches the first value, or simply set it to the first value
- * @param {Boolean} inOptions.gridUnits - if animating width or height, this will set it to work in the scene's grid units
- *
- * @returns this
- */
- loopProperty(inTarget, inPropertyName, inOptions = {}) {
- if (!this._animations)
- this._animations = [];
- const result = validateLoopingAnimation(
- inTarget,
- inPropertyName,
- inOptions
- );
- if (typeof result === "string") {
- throw this.sequence._customError(this, "loopProperty", result);
- }
- this._animations.push(result);
- return this;
- }
- };
- const audio = {
- /**
- * Base properties
- */
- _volume: null,
- _fadeInAudio: null,
- _fadeOutAudio: null,
- /**
- * Sets the volume of the sound.
- *
- * @param {number} inVolume
- * @returns this
- */
- volume(inVolume) {
- if (!is_real_number(inVolume))
- throw this.sequence._customError(
- this,
- "volume",
- "inVolume must be of type number"
- );
- this._volume = Math.max(0, Math.min(1, inVolume));
- return this;
- },
- /**
- * Causes the animated section to fade in its audio (if any) when played
- *
- * @param {number} duration How long the fade should be
- * @param {object} [options] Additional options, such as easing and delay
- * @returns this
- */
- fadeInAudio(duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "fadeInAudio",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "fadeInAudio",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "fadeInAudio",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "fadeInAudio",
- "options.delay must be of type number"
- );
- this._fadeInAudio = {
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- },
- /**
- * Causes the audio to fade out at the end of the animated section's duration
- *
- * @param {number} duration How long the fade should be
- * @param {object} [options] Additional options, such as easing and delay
- * @returns this
- */
- fadeOutAudio(duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "fadeOutAudio",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "fadeOutAudio",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "fadeOutAudio",
- "ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "fadeOutAudio",
- "delay must be of type number"
- );
- this._fadeOutAudio = {
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- }
- };
- const files = {
- /**
- * Base properties
- */
- _file: "",
- _fileOptions: false,
- _baseFolder: "",
- _mustache: null,
- /**
- * Declares which file to be played. This may also be an array of paths, which will be randomly picked from each
- * time the section is played.
- *
- * @param {string|array} inFile
- * @returns this
- */
- file(inFile) {
- this._file = inFile;
- return this;
- },
- /**
- * Defines the base folder that will prepend to the file path. This is mainly just useful to make the file
- * path easier to manage.
- *
- * @param {string} inBaseFolder
- * @returns this
- */
- baseFolder(inBaseFolder) {
- if (typeof inBaseFolder !== "string")
- throw this.sequence._customError(
- this,
- "baseFolder",
- "inBaseFolder must be of type string"
- );
- this._baseFolder = inBaseFolder + (inBaseFolder.endsWith("/") ? "" : "/");
- return this;
- },
- /**
- * Sets the Mustache of the filepath. This is applied after the randomization of the filepath, if available.
- *
- * @param {object} inMustache
- * @returns this
- */
- setMustache(inMustache) {
- if (typeof inMustache !== "object")
- throw this.sequence._customError(
- this,
- "setMustache",
- "inMustache must be of type object"
- );
- this._mustache = inMustache;
- return this;
- },
- async _determineFile(inFile) {
- if (!Array.isArray(inFile) && typeof inFile === "object") {
- return this._validateCustomRange(inFile);
- }
- if (Array.isArray(inFile))
- inFile = random_array_element(inFile, { recurse: true });
- inFile = this._applyMustache(inFile);
- if (Sequencer.Database.entryExists(inFile)) {
- return this._determineDatabaseFile(inFile);
- }
- const determinedFile = await this._processFile(inFile);
- return { file: determinedFile, forcedIndex: false, customRange: false };
- },
- async _processFile(inFile) {
- inFile = this._applyMustache(inFile);
- inFile = this._applyBaseFolder(inFile);
- inFile = await this._applyWildcard(inFile);
- if (Array.isArray(inFile))
- inFile = random_array_element(inFile, { recurse: true });
- return inFile;
- },
- async _validateCustomRange(inFile) {
- const finalFiles = {};
- const validRanges = Object.keys(SequencerFileRangeFind.ftToDistanceMap);
- for (const [range, rangeFile] of Object.entries(inFile)) {
- if (!validRanges.includes(range)) {
- throw this.sequence._customError(
- this,
- "file",
- `a file-distance key map must only contain the following keys: ${validRanges.join(
- ", "
- )}`
- );
- }
- finalFiles[range] = await this._processFile(rangeFile);
- }
- return { file: finalFiles, forcedIndex: false, customRange: true };
- },
- _determineDatabaseFile(inFile) {
- const entries = Sequencer.Database.getEntry(inFile);
- const entry = Array.isArray(entries) ? random_array_element(entries) : entries;
- const match = inFile.match(/(\d)+$/);
- return {
- file: entry,
- forcedIndex: match ? Number(match[1]) : false,
- customRange: false
- };
- },
- _applyBaseFolder(inFile) {
- if (Array.isArray(inFile))
- return inFile.map((file) => this._applyBaseFolder(file));
- return inFile.startsWith(this._baseFolder) ? inFile : this._baseFolder + inFile;
- },
- _applyMustache(inFile) {
- if (!this._mustache)
- return inFile;
- let template = Handlebars.compile(inFile);
- return template(this._mustache);
- },
- async _applyWildcard(inFile) {
- if (!inFile.includes("*"))
- return inFile;
- if (Array.isArray(inFile))
- return inFile.map(async (file) => await this._applyWildcard(file));
- inFile = this._applyBaseFolder(inFile);
- return getFiles(inFile, {
- applyWildCard: true,
- softFail: this.sequence.softFail
- });
- }
- };
- const moves = {
- /**
- * Base properties
- */
- _moveTowards: null,
- _moveSpeed: null,
- /**
- * Sets the location to move the target object to
- *
- * @param {object|string} inTarget
- * @param {object} options
- * @returns this
- */
- moveTowards(inTarget, options = {}) {
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0,
- rotate: true,
- cacheLocation: false
- },
- options
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "moveTowards",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "moveTowards",
- "options.delay must be of type number"
- );
- if (typeof options.rotate !== "boolean")
- throw this.sequence._customError(
- this,
- "moveTowards",
- "options.rotate must be of type boolean"
- );
- if (typeof options.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "moveTowards",
- "options.cacheLocation must be of type boolean"
- );
- options.target = this._validateLocation(inTarget);
- if (!options.target)
- throw this.sequence._customError(
- this,
- "moveTowards",
- "could not find position of given object"
- );
- options.target = options.cacheLocation ? get_object_position(options.cacheLocation, { measure: true }) : options.target;
- this._moveTowards = options;
- return this;
- },
- /**
- * Sets the speed (pixels per frame) to move the target object
- *
- * @param {number} inSpeed
- * @returns this
- */
- moveSpeed(inSpeed) {
- if (!is_real_number(inSpeed))
- throw this.sequence._customError(
- this,
- "moveSpeed",
- "inSpeed must be of type number"
- );
- this._moveSpeed = inSpeed;
- return this;
- }
- };
- const opacity = {
- /**
- * Base properties
- */
- _opacity: null,
- _fadeIn: null,
- _fadeOut: null,
- /**
- * Sets the opacity of the effect. If used with ._fadeIn() and/or ._fadeOut(), this defines what the effect will fade to/from
- *
- * @param {number} inOpacity
- * @returns this
- */
- opacity(inOpacity) {
- if (!is_real_number(inOpacity))
- throw this.sequence._customError(
- this,
- "opacity",
- "inOpacity must be of type number"
- );
- this._opacity = inOpacity;
- return this;
- },
- /**
- * Causes the effect to fade in when played
- *
- * @param {number} duration How long the fade should be
- * @param {object} [options] Additional options, such as easing and delay
- * @returns this
- */
- fadeIn(duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "fadeIn",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "fadeIn",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "fadeIn",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "fadeIn",
- "options.delay must be of type number"
- );
- this._fadeIn = {
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- },
- /**
- * Causes the effect to fade out at the end of the effect's duration
- *
- * @param {number} duration How long the fade should be
- * @param {object} [options] Additional options, such as easing and delay
- * @returns this
- */
- fadeOut(duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "fadeOut",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "fadeOut",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "fadeOut",
- "ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "fadeOut",
- "delay must be of type number"
- );
- this._fadeOut = {
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- }
- };
- const rotation = {
- /**
- * Base properties
- */
- _angle: null,
- _rotateIn: null,
- _rotateOut: null,
- _randomRotation: null,
- _rotateTowards: null,
- /**
- * The object gets a random rotation, which means it should not be used with .stretchTo()
- *
- * @param {boolean} [inBool=true] inBool
- * @returns this
- */
- randomRotation(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "randomRotation",
- "inBool must be of type boolean"
- );
- this._randomRotation = inBool;
- return this;
- },
- /**
- * Sets the rotation of the object, which is added on top of the calculated rotation after .rotateTowards() or .randomRotation()
- *
- * @param {number} inRotation
- * @returns this
- */
- rotate(inRotation) {
- if (!is_real_number(inRotation))
- throw this.sequence._customError(
- this,
- "opacity",
- "inRotation must be of type number"
- );
- this._angle = inRotation;
- return this;
- },
- /**
- * Causes the object to rotate when it starts playing
- *
- * @param {number} degrees
- * @param {number} duration
- * @param {object} [options] options
- * @returns this
- */
- rotateIn(degrees, duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "rotateIn",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(degrees))
- throw this.sequence._customError(
- this,
- "rotateOut",
- "degrees must be of type number"
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "rotateOut",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "rotateIn",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "rotateIn",
- "options.delay must be of type number"
- );
- this._rotateIn = {
- value: degrees,
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- },
- /**
- * Causes the object to rotate at the end of the effect's duration
- *
- * @param {number} degrees
- * @param {number} duration
- * @param {object} [options] options
- * @returns this
- */
- rotateOut(degrees, duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "rotateOut",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(degrees))
- throw this.sequence._customError(
- this,
- "rotateOut",
- "degrees must be of type number"
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "rotateOut",
- "duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "rotateOut",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "rotateOut",
- "options.delay must be of type number"
- );
- this._rotateOut = {
- value: degrees,
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- }
- };
- const scale = {
- _scaleMin: null,
- _scaleMax: null,
- _scaleIn: null,
- _scaleOut: null,
- /**
- * A method that can take the following:
- * - A number to set the scale uniformly
- * - An object with x and y for non-uniform scaling
- * - Two numbers which the Sequencer will randomly pick a uniform scale between
- *
- * @param {number|object} inScaleMin
- * @param {number} [inScaleMax] inScaleMax
- * @returns this
- */
- scale(inScaleMin, inScaleMax) {
- if (!is_real_number(inScaleMin) && typeof inScaleMin !== "object")
- throw this.sequence._customError(
- this,
- "scale",
- "inScale must be of type number or object"
- );
- if (is_real_number(inScaleMin)) {
- if (inScaleMax && !is_real_number(inScaleMax)) {
- throw this.sequence._customError(
- this,
- "scale",
- "if inScaleMin is a number, inScaleMax must also be of type number"
- );
- }
- }
- this._scaleMin = inScaleMin;
- this._scaleMax = inScaleMax ?? false;
- return this;
- },
- /**
- * Causes the effect to scale when it starts playing
- *
- * @param {number|object} scale
- * @param {number} duration
- * @param {object} [options] options
- * @returns this
- */
- scaleIn(scale2, duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "scaleIn",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "scaleIn",
- "duration must be of type number"
- );
- if (!is_real_number(scale2) && typeof scale2 !== "object")
- throw this.sequence._customError(
- this,
- "scaleIn",
- "scale must be of type number or object"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "scaleIn",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "scaleIn",
- "options.delay must be of type number"
- );
- this._scaleIn = {
- value: scale2,
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- },
- /**
- * Causes the effect to scale at the end of the effect's duration
- *
- * @param {number|object} scale
- * @param {number} duration
- * @param {object} [options] options
- * @returns this
- */
- scaleOut(scale2, duration, options = {}) {
- if (typeof options !== "object")
- throw this.sequence._customError(
- this,
- "scaleOut",
- "options must be of type object"
- );
- options = foundry.utils.mergeObject(
- {
- ease: "linear",
- delay: 0
- },
- options
- );
- if (!is_real_number(duration))
- throw this.sequence._customError(
- this,
- "scaleOut",
- "duration must be of type number"
- );
- if (!is_real_number(scale2) && typeof scale2 !== "object")
- throw this.sequence._customError(
- this,
- "scaleOut",
- "scale must be of type number or object"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "scaleOut",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "scaleOut",
- "options.delay must be of type number"
- );
- this._scaleOut = {
- value: scale2,
- duration,
- ease: options.ease,
- delay: options.delay
- };
- return this;
- }
- };
- const time = {
- _hasTime: true,
- _isRange: false,
- _startTime: null,
- _startPerc: null,
- _endTime: null,
- _endPerc: null,
- /**
- * Sets the start and end time of the section, playing only that range
- *
- * @param {number} inMsStart
- * @param {number} inMsEnd
- * @returns this
- */
- timeRange(inMsStart, inMsEnd) {
- if (!is_real_number(inMsStart))
- throw this.sequence._customError(
- this,
- "timeRange",
- "inMsStart must be of type number"
- );
- if (!is_real_number(inMsEnd))
- throw this.sequence._customError(
- this,
- "timeRange",
- "inMsEnd must be of type number"
- );
- this._startTime = inMsStart;
- this._endTime = inMsEnd;
- this._isRange = true;
- return this;
- },
- /**
- * Sets the start time of the section.
- *
- * @param {number} inMs
- * @returns this
- */
- startTime(inMs) {
- if (!is_real_number(inMs))
- throw this.sequence._customError(
- this,
- "startTime",
- "inMs must be of type number"
- );
- this._startTime = inMs;
- this._startPerc = false;
- this._isRange = false;
- return this;
- },
- /**
- * Sets the start time of the section based on a percentage from its total duration.
- *
- * @param {number} inPercentage
- * @returns this
- */
- startTimePerc(inPercentage) {
- if (!is_real_number(inPercentage))
- throw this.sequence._customError(
- this,
- "startTimePerc",
- "inPercentage must be of type number"
- );
- this._startTime = inPercentage;
- this._startPerc = true;
- this._isRange = false;
- return this;
- },
- /**
- * Sets the ending time of the section (from the end).
- *
- * @param {number} inMs
- * @returns this
- */
- endTime(inMs) {
- if (!is_real_number(inMs))
- throw this.sequence._customError(
- this,
- "endTime",
- "inMs must be of type number"
- );
- this._endTime = inMs;
- this._endPerc = false;
- this._isRange = false;
- return this;
- },
- /**
- * Sets the ending time of the section based on a percentage from the total duration.
- *
- * @param {number} inPercentage
- * @returns this
- */
- endTimePerc(inPercentage) {
- if (!is_real_number(inPercentage))
- throw this.sequence._customError(
- this,
- "endTimePerc",
- "inPercentage must be of type number"
- );
- this._endTime = inPercentage;
- this._endPerc = true;
- this._isRange = false;
- return this;
- }
- };
- const users = {
- _users: null,
- _addUser(inUser) {
- if (!this._users)
- this._users = [];
- if (typeof inUser !== "string")
- throw this.sequence._customError(
- this,
- "_addUser",
- "inUser must be of type string"
- );
- if (!game.users.has(inUser)) {
- if (game.users.getName(inUser)) {
- inUser = game.users.getName(inUser).id;
- } else {
- throw this.sequence._customError(
- this,
- "_addUser",
- `user with id or name "${inUser}" does not exist!`
- );
- }
- }
- if (!this._users.includes(inUser))
- this._users.push(inUser);
- },
- _deleteUser(inUser) {
- if (!this._users)
- this._users = [];
- if (this._users.includes(inUser)) {
- let index = this._users.indexOf(inUser);
- this._users.splice(index, 1);
- }
- },
- /**
- * Causes section to be executed only locally, and not push to other connected clients.
- *
- * @param {boolean} inLocally
- * @returns this
- */
- locally(inLocally = true) {
- if (inLocally)
- this._addUser(game.userId);
- else
- this._deleteUser(game.userId);
- return this;
- },
- /**
- * Causes the section to be executed for only a set of users.
- *
- * @param {string|User|array<string|User>} inUsers
- * @returns this
- */
- forUsers(inUsers) {
- if (!Array.isArray(inUsers)) {
- if (typeof inUsers !== "string")
- throw this.sequence._customError(
- this,
- "forUsers",
- "inUser must be of type string"
- );
- inUsers = [inUsers];
- }
- inUsers.forEach((u) => this._addUser(u));
- return this;
- }
- };
- const filter = {
- _filters: null,
- _addFilter(inFilterName, inData, inName = false) {
- if (!this._filters)
- this._filters = [];
- this._filters.push({
- className: inFilterName,
- name: inName,
- data: inData
- });
- },
- _testFilter(inFilterName, inData) {
- let filter2 = new filters[inFilterName](inData);
- if (!filter2.isValid)
- throw this.sequence._customError(
- this,
- "filter",
- `Could not create ${inFilterName} filter - data is malformed!`
- );
- },
- filter(inFilterName, inData = {}, inName = "") {
- if (typeof inFilterName !== "string")
- throw this.sequence._customError(
- this,
- "filter",
- `inFilterName must be of type string`
- );
- if (!Object.keys(filters).includes(inFilterName))
- throw this.sequence._customError(
- this,
- "filter",
- `"${inFilterName}" does not exist`
- );
- this._testFilter(inFilterName, inData);
- this._addFilter(inFilterName, inData, inName);
- return this;
- }
- };
- const tint = {
- _tint: null,
- /**
- * Tints the target of this section by the color given to the
- *
- * @param {number|string} inColor
- * @returns this
- */
- tint(inColor) {
- if (!is_real_number(inColor) && typeof inColor !== "string")
- throw this.sequence._customError(
- this,
- "tint",
- `inColor must be of type string (hexadecimal) or number (decimal)!`
- );
- this._tint = parseColor(inColor);
- return this;
- }
- };
- const location = {
- /**
- * Base properties
- */
- _source: null,
- /**
- * A smart method that can take a reference to an object, or a direct on the canvas to play the effect at,
- * or a string reference (see .name())
- *
- * @param {Object|String} inLocation
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- atLocation(inLocation, inOptions = {}) {
- if (!(typeof inLocation === "object" || typeof inLocation === "string")) {
- throw this.sequence._customError(
- this,
- "atLocation",
- `inLocation is invalid, and must be of type of object, string, placeable object, or document`
- );
- }
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "atLocation",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- cacheLocation: false,
- offset: false,
- randomOffset: false,
- gridUnits: false,
- local: false
- },
- inOptions
- );
- inLocation = this._validateLocation(inLocation);
- if (inLocation === void 0)
- throw this.sequence._customError(
- this,
- "atLocation",
- "could not find position of given object"
- );
- if (typeof inOptions.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "atLocation",
- "inOptions.cacheLocation must be of type boolean"
- );
- if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
- throw this.sequence._customError(
- this,
- "atLocation",
- "inOptions.randomOffset must be of type boolean or number"
- );
- this._temporaryEffect = this._temporaryEffect || (inLocation instanceof foundry.abstract.Document ? !is_UUID(inLocation?.uuid) : false);
- if (inOptions.offset) {
- const offsetData = this._validateOffset(
- "atLocation",
- inOptions.offset,
- inOptions
- );
- this._offset = {
- source: offsetData,
- target: this._offset?.target ?? false
- };
- }
- this._randomOffset = {
- source: inOptions.randomOffset,
- target: this._randomOffset?.target ?? false
- };
- this._source = inOptions.cacheLocation && typeof inLocation !== "string" ? get_object_canvas_data(inLocation) : inLocation;
- return this;
- }
- };
- const offset = {
- _offset: null,
- _randomOffset: null,
- _validateOffset(functionName, inOffset, inOptions = {}) {
- inOffset = foundry.utils.mergeObject(
- {
- x: 0,
- y: 0
- },
- inOffset
- );
- inOptions = foundry.utils.mergeObject(
- {
- gridUnits: false,
- local: false
- },
- inOptions
- );
- if (typeof inOptions.gridUnits !== "boolean")
- throw this.sequence._customError(
- this,
- functionName,
- "inOptions.gridUnits must be of type boolean"
- );
- if (typeof inOptions.local !== "boolean")
- throw this.sequence._customError(
- this,
- functionName,
- "inOptions.local must be of type boolean"
- );
- if (!is_real_number(inOffset.x))
- throw this.sequence._customError(
- this,
- functionName,
- `inOffset.x must be of type number!`
- );
- if (!is_real_number(inOffset.y))
- throw this.sequence._customError(
- this,
- functionName,
- `inOffset.y must be of type number!`
- );
- return {
- ...inOffset,
- ...inOptions
- };
- }
- };
- const text = {
- _text: null,
- /**
- * Creates a text element, attached to the sprite. The options for the text are available here:
- * https://pixijs.io/pixi-text-style/
- *
- * @param {String} inText
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- text(inText, inOptions = {}) {
- if (typeof inText !== "string")
- throw this.sequence._customError(
- this,
- "text",
- "inText must be of type string"
- );
- this._text = foundry.utils.mergeObject(
- {
- text: inText
- },
- inOptions
- );
- return this;
- }
- };
- const traits = {
- animation,
- audio,
- files,
- moves,
- opacity,
- rotation,
- scale,
- time,
- users,
- filter,
- tint,
- location,
- offset,
- text
- };
- class EffectSection extends Section {
- constructor(inSequence, inFile = "") {
- super(inSequence);
- this._deserializedData = null;
- this._file = inFile;
- this._text = null;
- this._source = null;
- this._stretchTo = null;
- this._attachTo = null;
- this._from = null;
- this._origin = null;
- this._anchor = null;
- this._spriteAnchor = null;
- this._randomOffset = null;
- this._missed = null;
- this._private = null;
- this._randomMirrorX = null;
- this._randomMirrorY = null;
- this._mirrorX = null;
- this._mirrorY = null;
- this._playbackRate = null;
- this._template = null;
- this._overrides = [];
- this._name = null;
- this._zIndex = null;
- this._offset = null;
- this._spriteOffset = null;
- this._size = null;
- this._persist = null;
- this._persistOptions = null;
- this._zeroSpriteRotation = null;
- this._extraEndDuration = null;
- this._noLoop = null;
- this._tilingTexture = null;
- this._snapToGrid = null;
- this._scaleToObject = null;
- this._screenSpace = null;
- this._screenSpaceAboveUI = null;
- this._screenSpaceAnchor = null;
- this._screenSpacePosition = null;
- this._screenSpaceScale = null;
- this._elevation = null;
- this._masks = [];
- this._tiedDocuments = [];
- this._selfMask = false;
- this._temporaryEffect = false;
- this._spriteRotation = 0;
- this._randomSpriteRotation = false;
- this._isRangedEffect = null;
- this._offsetLegacy = null;
- this._randomOffsetLegacy = null;
- this._aboveLighting = null;
- this._aboveInterface = null;
- this._spriteScaleMin = 1;
- this._spriteScaleMax = null;
- this._isometric = null;
- this._shapes = [];
- this._xray = null;
- this._playEffect = true;
- }
- static niceName = "Effect";
- /**
- * @private
- */
- get _target() {
- return this._stretchTo || this._rotateTowards || this._moveTowards || false;
- }
- static debounceWarning() {
- custom_warning(
- "Sequencer",
- "Effect | This user does not have permissions to play effects. This can be configured in Sequencer's module settings."
- );
- }
- /**
- * Causes the effect's position to be stored and can then be used with .atLocation(), .stretchTowards(),
- * and .rotateTowards() to refer to previous effects' locations
- *
- * @param {String} inName
- * @returns {EffectSection}
- */
- name(inName) {
- if (typeof inName !== "string")
- throw this.sequence._customError(
- this,
- "name",
- "inName must be of type string"
- );
- this._name = safe_str(inName);
- return this;
- }
- /**
- * Causes the effect to persist indefinitely on the canvas until _ended via SequencerEffectManager.endAllEffects() or
- * name the effect with .name() and then end it through SequencerEffectManager.endEffect()
- *
- * @param {Boolean} [inBool=true] inBool
- * @param {Object} [inOptions={}] inOptions
- * @returns {EffectSection}
- */
- persist(inBool = true, inOptions = {}) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "persist",
- "inBool must be of type boolean"
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "persist",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- id: randomID(),
- persistTokenPrototype: false
- },
- inOptions
- );
- if (typeof inOptions.persistTokenPrototype !== "boolean")
- throw this.sequence._customError(
- this,
- "persist",
- "inOptions.persistTokenPrototype must be of type boolean"
- );
- this._persist = inBool;
- this._persistOptions = inOptions;
- return this;
- }
- /**
- * Causes the effect to become temporary, which means it will not be stored in the flags of any object,
- * even if it .persist() is called
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- temporary(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "temporary",
- "inBool must be of type boolean"
- );
- this._temporaryEffect = inBool || this._temporaryEffect;
- return this;
- }
- /**
- * Sets the effect's playback rate. A playback rate of 2.0 would make it play 2x as fast, 0.5 would make
- * it play half as fast.
- *
- * @param {Number} inNumber
- * @returns {EffectSection}
- */
- playbackRate(inNumber = 1) {
- if (!is_real_number(inNumber))
- throw this.sequence._customError(
- this,
- "playbackRate",
- "inNumber must be of type number"
- );
- this._playbackRate = inNumber;
- return this;
- }
- /**
- * Causes the effect to target a location close to the .stretchTowards() location, but not on it.
- *
- * @param {Boolean} [inBool=true] inBool
- * @returns {EffectSection}
- */
- missed(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "missed",
- "inBool must be of type boolean"
- );
- this._missed = inBool;
- return this;
- }
- /**
- * Adds a function that will run at the end of the effect serialization step, but before it is played. Allows direct
- * modifications of effect's data. For example, it could be manipulated to change which file will be used based
- * on the distance to the target.
- *
- * @param {Function} inFunc
- * @returns {EffectSection}
- */
- addOverride(inFunc) {
- if (!is_function$1(inFunc))
- throw this.sequence._customError(
- this,
- "addOverride",
- "The given function needs to be an actual function."
- );
- this._overrides.push(inFunc);
- return this;
- }
- /**
- * A smart method that can take a reference to an object, or a direct on the canvas to attach an effect to,
- * or a string reference (see .name())
- *
- * @param {Object|String} inObject
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- attachTo(inObject, inOptions = {}) {
- if (!(typeof inObject === "object" || typeof inObject === "string")) {
- throw this.sequence._customError(
- this,
- "attachTo",
- `inObject is invalid, and must be of type of object, string, placeable object, or document`
- );
- }
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "attachTo",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- align: "center",
- edge: "on",
- bindVisibility: true,
- bindAlpha: true,
- bindElevation: true,
- followRotation: true,
- offset: false,
- randomOffset: false,
- gridUnits: false,
- local: false
- },
- inOptions
- );
- const validatedObject = this._validateLocation(inObject);
- if (validatedObject === void 0)
- throw this.sequence._customError(
- this,
- "attachTo",
- "could not find given object"
- );
- let isValidObject = true;
- if (typeof inObject === "string") {
- isValidObject = validatedObject instanceof Token || validatedObject instanceof TokenDocument || validatedObject instanceof Tile || validatedObject instanceof TileDocument || validatedObject instanceof Drawing || validatedObject instanceof DrawingDocument || validatedObject instanceof MeasuredTemplate || validatedObject instanceof MeasuredTemplateDocument || validatedObject instanceof CanvasEffect;
- if (!isValidObject) {
- this.sequence._showWarning(
- this,
- "attachTo",
- "Only Tokens, Tiles, Drawings, and MeasuredTemplates may have attached effects - will play effect on target's location"
- );
- }
- }
- const aligns = Object.keys(alignments);
- if (typeof inOptions.align !== "string" || !aligns.includes(inOptions.align)) {
- throw this.sequence._customError(
- this,
- "attachTo",
- `inOptions.align must be of type string, one of: ${aligns.join(", ")}`
- );
- }
- if (typeof inOptions.edge !== "string" || !(inOptions.edge === "on" || inOptions.edge === "inner" || inOptions.edge === "outer")) {
- throw this.sequence._customError(
- this,
- "attachTo",
- `inOptions.edge must of type string with the value of either "on", "inner", or "outer"`
- );
- }
- if (typeof inOptions.bindVisibility !== "boolean")
- throw this.sequence._customError(
- this,
- "attachTo",
- `inOptions.bindVisibility must be of type boolean`
- );
- if (typeof inOptions.followRotation !== "boolean")
- throw this.sequence._customError(
- this,
- "attachTo",
- `inOptions.followRotation must be of type boolean`
- );
- if (typeof inOptions.bindAlpha !== "boolean")
- throw this.sequence._customError(
- this,
- "attachTo",
- "inOptions.bindAlpha must be of type boolean"
- );
- if (typeof inOptions.bindElevation !== "boolean")
- throw this.sequence._customError(
- this,
- "attachTo",
- "inOptions.bindElevation must be of type boolean"
- );
- if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
- throw this.sequence._customError(
- this,
- "attachTo",
- "inOptions.randomOffset must be of type boolean or number"
- );
- this._source = validatedObject;
- this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document || validatedObject instanceof MeasuredTemplate ? !is_UUID(validatedObject?.uuid) : this._temporaryEffect || false);
- if (inOptions.offset) {
- const offsetData = this._validateOffset(
- "attachTo",
- inOptions.offset,
- inOptions
- );
- this._offset = {
- source: offsetData,
- target: this._offset?.target ?? false
- };
- }
- this._randomOffset = {
- source: inOptions.randomOffset,
- target: this._randomOffset?.target ?? false
- };
- this._attachTo = {
- active: isValidObject,
- align: inOptions.align,
- edge: inOptions.edge,
- bindVisibility: inOptions.bindVisibility,
- bindAlpha: inOptions.bindAlpha,
- bindElevation: inOptions.bindElevation,
- followRotation: inOptions.followRotation
- };
- return this;
- }
- /**
- * Causes the effect to be rotated and stretched towards an object, or a direct on the canvas to play the effect at, or a string reference (see .name())
- * This effectively calculates the proper X scale for the effect to reach the target
- *
- * @param {Object|String} inLocation
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- stretchTo(inLocation, inOptions = {}) {
- if (!(typeof inLocation === "object" || typeof inLocation === "string")) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- `inLocation is invalid, and must be of type of object, string, placeable object, or document`
- );
- }
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "stretchTo",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- cacheLocation: false,
- attachTo: false,
- onlyX: false,
- tiling: false,
- offset: false,
- randomOffset: false,
- gridUnits: false,
- local: false,
- requiresLineOfSight: false,
- hideLineOfSight: false
- },
- inOptions
- );
- const validatedObject = this._validateLocation(inLocation);
- if (validatedObject === void 0)
- throw this.sequence._customError(
- this,
- "stretchTo",
- "could not find position of given object"
- );
- if (typeof inOptions.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "stretchTo",
- "inOptions.cacheLocation must be of type boolean"
- );
- if (typeof inOptions.attachTo !== "boolean")
- throw this.sequence._customError(
- this,
- "stretchTo",
- "inOptions.attachTo must be of type boolean"
- );
- if (typeof inOptions.onlyX !== "boolean")
- throw this.sequence._customError(
- this,
- "stretchTo",
- "inOptions.onlyX must be of type boolean"
- );
- if (typeof inOptions.tiling !== "boolean")
- throw this.sequence._customError(
- this,
- "stretchTo",
- "inOptions.tiling must be of type boolean"
- );
- if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
- throw this.sequence._customError(
- this,
- "stretchTo",
- "inOptions.randomOffset must be of type boolean or number"
- );
- if (inOptions.cacheLocation && inOptions.attachTo) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "cacheLocation and attachTo cannot both be true - pick one or the other"
- );
- }
- if (typeof inOptions.requiresLineOfSight !== "boolean") {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "requiresLineOfSight must be of type boolean"
- );
- }
- if (!inOptions.attachTo && inOptions.requiresLineOfSight) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "requiresLineOfSight requires that attachTo is true"
- );
- }
- if (typeof inOptions.hideLineOfSight !== "boolean") {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "hideLineOfSight must be of type boolean"
- );
- }
- if (!inOptions.requiresLineOfSight && inOptions.hideLineOfSight) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "hideLineOfSight requires that requiresLineOfSight is true"
- );
- }
- if (inOptions.tiling)
- this.tilingTexture();
- this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document ? !is_UUID(validatedObject?.uuid) : this._temporaryEffect || false);
- if (inOptions.offset) {
- const offsetData = this._validateOffset(
- "stretchTo",
- inOptions.offset,
- inOptions
- );
- this._offset = {
- source: this._offset?.source ?? false,
- target: offsetData
- };
- }
- this._randomOffset = {
- source: this._randomOffset?.source ?? false,
- target: inOptions.randomOffset
- };
- this._stretchTo = {
- target: inOptions.cacheLocation ? get_object_canvas_data(validatedObject, { measure: true }) : validatedObject,
- attachTo: inOptions.attachTo,
- onlyX: inOptions.onlyX,
- requiresLineOfSight: inOptions.requiresLineOfSight,
- hideLineOfSight: inOptions.hideLineOfSight
- };
- return this;
- }
- /**
- * Sets the location to rotate the object to
- *
- * @param {object|string} inLocation
- * @param {object} inOptions
- * @returns this
- */
- rotateTowards(inLocation, inOptions = {}) {
- if (!(typeof inLocation === "object" || typeof inLocation === "string")) {
- throw this.sequence._customError(
- this,
- "inLocation",
- `inLocation is invalid, and must be of type of object, string, placeable object, or document`
- );
- }
- inOptions = foundry.utils.mergeObject(
- {
- rotationOffset: 0,
- cacheLocation: false,
- attachTo: false,
- offset: false,
- randomOffset: false,
- local: false,
- gridUnits: false
- },
- inOptions
- );
- if (!is_real_number(inOptions.rotationOffset))
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "inOptions.rotationOffset must be of type number"
- );
- if (typeof inOptions.attachTo !== "boolean")
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "inOptions.attachTo must be of type boolean"
- );
- if (typeof inOptions.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "inOptions.cacheLocation must be of type boolean"
- );
- const validatedObject = this._validateLocation(inLocation);
- if (!validatedObject)
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "could not find position of given object"
- );
- this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document ? !is_UUID(validatedObject?.uuid) : this._temporaryEffect || false);
- if (inOptions.offset) {
- const offsetData = this._validateOffset(
- "attachTo",
- inOptions.offset,
- inOptions
- );
- this._offset = {
- source: offsetData,
- target: this._offset?.target ?? false
- };
- }
- this._randomOffset = {
- source: inOptions.randomOffset,
- target: this._randomOffset?.target ?? false
- };
- this._rotateTowards = {
- target: inOptions.cacheLocation ? get_object_canvas_data(validatedObject, { measure: true }) : validatedObject,
- rotationOffset: inOptions.rotationOffset,
- cacheLocation: inOptions.cacheLocation,
- attachTo: inOptions.attachTo
- };
- return this;
- }
- /**
- * Create an effect based on the given object, effectively copying the object as an effect. Useful when you want to do some effect magic on tokens or tiles.
- *
- * @param {Object} inObject
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- from(inObject, inOptions = {}) {
- if (!(inObject instanceof Token || inObject instanceof Tile || inObject instanceof TokenDocument || inObject instanceof TileDocument)) {
- throw this.sequence._customError(
- this,
- "from",
- "inObject must be of type Token, Tile, TokenDocument, or TileDocument"
- );
- }
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "from",
- `inOptions must be of type object`
- );
- inObject = inObject.document ?? inObject;
- if (!inObject?.texture?.src)
- throw this.sequence._customError(
- this,
- "from",
- "could not find the image for the given object"
- );
- inOptions = foundry.utils.mergeObject(
- {
- cacheLocation: false,
- offset: false,
- randomOffset: false,
- local: false,
- gridUnits: false
- },
- inOptions
- );
- if (typeof inOptions.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "from",
- "inOptions.cacheLocation must be of type boolean"
- );
- if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
- throw this.sequence._customError(
- this,
- "from",
- "inOptions.randomOffset must be of type boolean or number"
- );
- this._temporaryEffect = this._temporaryEffect || (inObject instanceof foundry.abstract.Document ? !is_UUID(inObject?.uuid) : this._temporaryEffect || false);
- if (inOptions.offset) {
- const offsetData = this._validateOffset(
- "attachTo",
- inOptions.offset,
- inOptions
- );
- this._offset = {
- source: offsetData,
- target: this._offset?.target ?? false
- };
- }
- this._randomOffset = {
- source: inOptions.randomOffset,
- target: this._randomOffset?.target ?? false
- };
- this._from = {
- object: inObject,
- options: inOptions
- };
- return this;
- }
- shape(inType, inOptions = {}) {
- if (typeof inType !== "string")
- throw this.sequence._customError(
- this,
- "shape",
- "type must be of type string"
- );
- if (!Object.values(CONSTANTS.SHAPES).includes(inType)) {
- throw this.sequence._customError(
- this,
- "shape",
- "type must be one of: " + Object.values(CONSTANTS.SHAPES).join(", ")
- );
- }
- if (inType === CONSTANTS.SHAPES.POLY) {
- if (!Array.isArray(inOptions.points)) {
- throw this.sequence._customError(
- this,
- "shape",
- "if creating polygon, inOptions.points must be of type array"
- );
- }
- inOptions.points = inOptions.points.map((point) => {
- if (Array.isArray(point)) {
- if (!is_real_number(point[0]) || !is_real_number(point[1])) {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.points must be an array, containing an array of two numbers or objects with x and y number properties"
- );
- }
- return point;
- }
- if (typeof point === "object") {
- if (!is_real_number(point?.x) || !is_real_number(point?.y)) {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.points must be an array, containing an array of two numbers or objects with x and y number properties"
- );
- }
- return [point.x, point.y];
- }
- });
- } else if (inType === CONSTANTS.SHAPES.CIRC) {
- if (typeof inOptions.radius !== "number") {
- throw this.sequence._customError(
- this,
- "shape",
- "if creating circle, inOptions.radius must be of type number"
- );
- }
- } else if (inType === CONSTANTS.SHAPES.RECT || inType === CONSTANTS.SHAPES.RREC || inType === CONSTANTS.SHAPES.ELIP) {
- if (inOptions.width ^ inOptions.height) {
- inOptions.width = inOptions.width ?? inOptions.height;
- inOptions.height = inOptions.height ?? inOptions.width;
- }
- if (typeof inOptions.width !== "number") {
- throw this.sequence._customError(
- this,
- "shape",
- `if creating rectangle, rounded rectangle, or an ellipse, inOptions.width must be of type number`
- );
- }
- if (typeof inOptions.height !== "number") {
- throw this.sequence._customError(
- this,
- "shape",
- "if creating rectangle, rounded rectangle, or an ellipse, inOptions.height must be of type number"
- );
- }
- if (inType === CONSTANTS.SHAPES.RREC && typeof inOptions.radius !== "number") {
- throw this.sequence._customError(
- this,
- "shape",
- "if creating rounded border rectangle, inOptions.radius must be of type number"
- );
- }
- }
- if (inOptions.gridUnits !== void 0 && typeof inOptions.gridUnits !== "boolean") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.gridUnits must be of type boolean"
- );
- }
- if (inOptions.name && typeof inOptions.name !== "string") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.name must be of type string"
- );
- }
- if (inOptions.fillColor && !is_real_number(inOptions.fillColor) && typeof inOptions.fillColor !== "string") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.fillColor must be of type string (hexadecimal) or number (decimal)"
- );
- } else {
- inOptions.fillColor = parseColor(inOptions.fillColor).decimal;
- }
- if (inOptions.fillAlpha && !is_real_number(inOptions.fillAlpha)) {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.fillAlpha must be of type number"
- );
- }
- if (inOptions.alpha && !is_real_number(inOptions.alpha)) {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.alpha must be of type number"
- );
- }
- if (inOptions.lineSize && !is_real_number(inOptions.lineSize)) {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.lineSize must be of type number"
- );
- }
- if (inOptions.lineColor && !is_real_number(inOptions.lineColor) && typeof inOptions.lineColor !== "string") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.lineColor must be of type string (hexadecimal) or number (decimal)"
- );
- } else {
- inOptions.lineColor = parseColor(inOptions.lineColor).decimal;
- }
- if (inOptions.offset) {
- inOptions.offset = this._validateOffset(
- "shape",
- inOptions.offset,
- inOptions.offset
- );
- }
- if (inOptions.texture !== void 0 && typeof inOptions.texture !== "string") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.texture must be of type string"
- );
- }
- if (inOptions.isMask !== void 0 && typeof inOptions.isMask !== "boolean") {
- throw this.sequence._customError(
- this,
- "shape",
- "inOptions.isMask must be of type boolean"
- );
- }
- this._shapes.push({
- ...inOptions,
- type: inType
- });
- return this;
- }
- /**
- * Causes the effect to be offset relative to its location based on a given vector
- *
- * @param {Object} inOffset
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- offset(inOffset, inOptions = {}) {
- this.sequence._showWarning(
- this,
- "offset",
- "This method is becoming deprecated, please use the secondary offset option in atLocation, attachTo, stretchTo instead.",
- true
- );
- if (inOffset === void 0)
- throw this.sequence._customError(
- this,
- "offset",
- "inOffset must not be undefined"
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "offset",
- "options must be of type object"
- );
- this._offsetLegacy = this._validateOffset("offset", inOffset, inOptions);
- return this;
- }
- /**
- * Causes the effect's sprite to be offset relative to its location based on a given vector
- *
- * @param {Object} inOffset
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- spriteOffset(inOffset, inOptions = {}) {
- if (inOffset === void 0)
- throw this.sequence._customError(
- this,
- "spriteOffset",
- "inOffset must not be undefined"
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "spriteOffset",
- "options must be of type object"
- );
- this._spriteOffset = this._validateOffset(
- "spriteOffset",
- inOffset,
- inOptions
- );
- return this;
- }
- /**
- * Causes the final effect location to be snapped to the grid
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- snapToGrid(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "snapToGrid",
- "inBool must be of type boolean"
- );
- this._snapToGrid = inBool;
- return this;
- }
- /**
- * Causes the effect to be scaled to the target object's width
- *
- * @param {Number} inScale
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- scaleToObject(inScale = 1, inOptions = {}) {
- if (!is_real_number(inScale))
- throw this.sequence._customError(
- this,
- "scaleToObject",
- `inScale must be of type number!`
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "scaleToObject",
- "inOptions must be of type object"
- );
- inOptions = foundry.utils.mergeObject(
- {
- scale: inScale,
- considerTokenScale: false,
- uniform: false
- },
- inOptions
- );
- if (typeof inOptions.uniform !== "boolean")
- throw this.sequence._customError(
- this,
- "scaleToObject",
- "inBool must be of type boolean"
- );
- this._scaleToObject = inOptions;
- return this;
- }
- /**
- * Sets the width and the height of the effect in pixels, this size is set before any scaling
- *
- * @param {Number|Object<{width: {Number}, height: {Number}}>} inSize
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- size(inSize, inOptions = {}) {
- if (!is_real_number(inSize) && typeof inSize !== "object")
- throw this.sequence._customError(
- this,
- "size",
- "inSize must be of type number or object"
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "size",
- "inOptions must be of type object"
- );
- if (is_real_number(inSize)) {
- inSize = {
- width: inSize,
- height: inSize
- };
- }
- if (inSize.width === void 0 ^ inSize.height === void 0) {
- if (inSize.width) {
- if (!is_real_number(inSize.width))
- throw this.sequence._customError(
- this,
- "size",
- "inSize.width must be of type number or string 'auto'"
- );
- inSize["height"] = "auto";
- } else {
- if (!is_real_number(inSize.height))
- throw this.sequence._customError(
- this,
- "size",
- "inSize.height must be of type number or string 'auto'"
- );
- inSize["width"] = "auto";
- }
- }
- inOptions = foundry.utils.mergeObject(
- {
- gridUnits: false
- },
- inOptions
- );
- if (!is_real_number(inSize.width) && inSize.width !== "auto")
- throw this.sequence._customError(
- this,
- "size",
- "inSize.width must be of type number or string 'auto'"
- );
- if (!is_real_number(inSize.height) && inSize.height !== "auto")
- throw this.sequence._customError(
- this,
- "size",
- "inSize.height must be of type number or string 'auto'"
- );
- if (typeof inOptions.gridUnits !== "boolean")
- throw this.sequence._customError(
- this,
- "size",
- "inOptions.gridUnits must be of type boolean"
- );
- this._size = {
- width: inSize.width ?? canvas.grid.size,
- height: inSize.height ?? canvas.grid.size,
- ...inOptions
- };
- return this;
- }
- /**
- * This scales the sprite of the effect, and this method can take the following:
- * - A number to set the scale uniformly
- * - An object with x and y for non-uniform scaling
- * - Two numbers which the Sequencer will randomly pick a uniform scale between
- *
- * @param {number|object} inScaleMin
- * @param {number} [inScaleMax] inScaleMax
- * @returns this
- */
- spriteScale(inScaleMin, inScaleMax) {
- if (!is_real_number(inScaleMin) && typeof inScaleMin !== "object")
- throw this.sequence._customError(
- this,
- "spriteScale",
- "inScale must be of type number or object"
- );
- if (is_real_number(inScaleMin)) {
- if (inScaleMax && !is_real_number(inScaleMax)) {
- throw this.sequence._customError(
- this,
- "spriteScale",
- "if inScaleMin is a number, inScaleMax must also be of type number"
- );
- }
- }
- this._spriteScaleMin = inScaleMin;
- this._spriteScaleMax = inScaleMax ?? false;
- return this;
- }
- /**
- * This defines the internal padding of this effect. Gridsize determines the internal grid size of this effect which will determine how big it is on the canvas
- * relative to the canvas's grid size. Start and end point defines padding at the left and right of the effect
- *
- * @param {Number} gridSize
- * @param {Number} startPoint
- * @param {Number} endPoint
- * @returns {EffectSection}
- */
- template({ gridSize, startPoint, endPoint } = {}) {
- if (gridSize && !is_real_number(gridSize))
- throw this.sequence._customError(
- this,
- "template",
- "gridSize must be of type number"
- );
- if (startPoint && !is_real_number(startPoint))
- throw this.sequence._customError(
- this,
- "template",
- "startPoint must be of type number"
- );
- if (endPoint && !is_real_number(endPoint))
- throw this.sequence._customError(
- this,
- "template",
- "endPoint must be of type number"
- );
- if (!gridSize && !startPoint && !endPoint)
- throw this.sequence._customError(
- this,
- "template",
- "You need to define at least one parameter!"
- );
- if (!this._template)
- this._template = {};
- if (gridSize)
- this._template["gridSize"] = gridSize;
- if (startPoint)
- this._template["startPoint"] = startPoint;
- if (endPoint)
- this._template["endPoint"] = endPoint;
- return this;
- }
- /**
- * This makes the texture of the effect tile, effectively repeat itself within the sprite's dimensions
- *
- * @param {Object|Number} scale
- * @param {Object} position
- * @returns {EffectSection}
- */
- tilingTexture(scale2 = { x: 1, y: 1 }, position = { x: 0, y: 0 }) {
- if (is_real_number(scale2)) {
- scale2 = { x: scale2, y: scale2 };
- }
- scale2 = { x: scale2?.x ?? 1, y: scale2?.y ?? 1 };
- if (!is_real_number(scale2.x))
- throw this.sequence._customError(
- this,
- "tilingTexture",
- `scale.x must be of type number!`
- );
- if (!is_real_number(scale2.y))
- throw this.sequence._customError(
- this,
- "tilingTexture",
- `scale.y must be of type number!`
- );
- position = { x: position?.x ?? 0, y: position?.y ?? 0 };
- if (!is_real_number(position.x))
- throw this.sequence._customError(
- this,
- "tilingTexture",
- `position.x must be of type number!`
- );
- if (!is_real_number(position.y))
- throw this.sequence._customError(
- this,
- "tilingTexture",
- `position.y must be of type number!`
- );
- this._tilingTexture = {
- scale: scale2,
- position
- };
- return this;
- }
- /**
- * Anchors the sprite's container according to the given x and y coordinates, or uniformly based on a single number
- *
- * @param {Number|Object} inAnchor
- * @returns {EffectSection}
- */
- anchor(inAnchor) {
- if (is_real_number(inAnchor)) {
- inAnchor = {
- x: inAnchor,
- y: inAnchor
- };
- }
- inAnchor = {
- x: inAnchor?.x ?? 0.5,
- y: inAnchor?.y ?? 0.5
- };
- if (!is_real_number(inAnchor.x))
- throw this.sequence._customError(
- this,
- "anchor",
- `inAnchor.x must be of type number!`
- );
- if (!is_real_number(inAnchor.y))
- throw this.sequence._customError(
- this,
- "anchor",
- `inAnchor.y must be of type number!`
- );
- this._anchor = inAnchor;
- return this;
- }
- /**
- * Anchors the sprite according to the given x and y coordinates, or uniformly based on a single number
- *
- * @param {Number|Object} inAnchor
- * @returns {EffectSection}
- */
- spriteAnchor(inAnchor) {
- if (is_real_number(inAnchor)) {
- inAnchor = {
- x: inAnchor,
- y: inAnchor
- };
- }
- inAnchor = {
- x: inAnchor?.x ?? 0.5,
- y: inAnchor?.y ?? 0.5
- };
- if (!is_real_number(inAnchor.x))
- throw this.sequence._customError(
- this,
- "anchor",
- `inAnchor.x must be of type number!`
- );
- if (!is_real_number(inAnchor.y))
- throw this.sequence._customError(
- this,
- "anchor",
- `inAnchor.y must be of type number!`
- );
- this._spriteAnchor = inAnchor;
- return this;
- }
- /**
- * Centers the sprite, effectively giving it an anchor of {x: 0.5, y: 0.5}
- *
- * Note: If this is used, it will override the anchor set by Aim Towards, which sets the sprite's anchor to the
- * outermost edge of the location the sprite is played at
- *
- * @returns {EffectSection}
- */
- center() {
- this.anchor(0.5);
- return this;
- }
- /**
- * The sprite gets a random offset on its target location, usually within the object's bounds. The optional parameter
- * scales how much offset should be added. Defaults to 1.0, which covers the entire target position, 0.5 would cover half.
- *
- * @param {Number} inOffsetScale
- * @returns {EffectSection}
- */
- randomOffset(inOffsetScale = 1) {
- this.sequence._showWarning(
- this,
- "randomOffset",
- "This method has been deprecated, please use randomOffset as a second parameter on atLocation, stretchTo, etc.",
- true
- );
- if (!is_real_number(inOffsetScale))
- throw this.sequence._customError(
- this,
- "randomOffset",
- "inBool must be of type number"
- );
- this._randomOffsetLegacy = inOffsetScale;
- return this;
- }
- /**
- * The sprite gets a randomized flipped X scale. If the scale on that axis was 1, it can
- * become 1 or -1, effectively mirroring the sprite on its horizontal axis
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- randomizeMirrorX(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "randomizeMirrorX",
- "inBool must be of type boolean"
- );
- this._randomMirrorX = inBool;
- return this;
- }
- /**
- * The sprite gets a randomized flipped Y scale. If the scale on that axis was 1, it can
- * become 1 or -1, effectively mirroring the sprite on its vertical axis
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- randomizeMirrorY(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "randomizeMirrorY",
- "inBool must be of type boolean"
- );
- this._randomMirrorY = inBool;
- return this;
- }
- /**
- * The sprite gets a flipped X scale. If the scale on that axis was 1, it will become 1 or -1, effectively
- * mirroring the sprite on its horizontal axis
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- mirrorX(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "mirrorX",
- "inBool must be of type boolean"
- );
- this._mirrorX = inBool;
- return this;
- }
- /**
- * The sprite gets a flipped Y scale. If the scale on that axis was 1, it will become 1 or -1, effectively
- * mirroring the sprite on its vertical axis
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- mirrorY(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "mirrorY",
- "inBool must be of type boolean"
- );
- this._mirrorY = inBool;
- return this;
- }
- /**
- * Causes the effect to play beneath most tokens
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- belowTokens(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "belowTokens",
- "inBool must be of type boolean"
- );
- if (!inBool)
- return this;
- return this.elevation(0, { absolute: true });
- }
- /**
- * Causes the effect to play beneath most tiles
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- belowTiles(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "belowTokens",
- "inBool must be of type boolean"
- );
- if (!inBool)
- return this;
- return this.elevation(-1, { absolute: true });
- }
- /**
- * Causes the effect to be played on top of the vision mask
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- aboveLighting(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "aboveLighting",
- "inBool must be of type boolean"
- );
- this._aboveLighting = inBool;
- return this;
- }
- /**
- * Causes the effect to be played on top of interface
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- aboveInterface(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "aboveInterface",
- "inBool must be of type boolean"
- );
- this._aboveInterface = inBool;
- return this;
- }
- /**
- * Changes the effect's elevation
- *
- * @param {Number} inElevation
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- elevation(inElevation, inOptions = {}) {
- if (typeof inElevation !== "number")
- throw this.sequence._customError(
- this,
- "elevation",
- "inElevation must be of type number"
- );
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "elevation",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- elevation: 1,
- absolute: false
- },
- inOptions
- );
- if (typeof inOptions.absolute !== "boolean")
- throw this.sequence._customError(
- this,
- "elevation",
- "inOptions.absolute must be of type boolean"
- );
- this._elevation = {
- elevation: inElevation,
- absolute: inOptions.absolute
- };
- return this;
- }
- /**
- * Sets the zIndex of the effect, potentially displaying it on top of other effects the same elevation
- *
- * @param {Number} inZIndex
- * @returns {EffectSection}
- */
- zIndex(inZIndex) {
- if (!is_real_number(inZIndex))
- throw this.sequence._customError(
- this,
- "zIndex",
- "inZIndex must be of type number"
- );
- this._zIndex = inZIndex;
- return this;
- }
- /**
- * This method only modifies .persist()ed effects and causes them to not immediately end, but stick around for the given duration passed to this method.
- *
- * @param {Number} inExtraDuration
- * @returns {EffectSection}
- */
- extraEndDuration(inExtraDuration) {
- if (!is_real_number(inExtraDuration))
- throw this.sequence._customError(
- this,
- "extraEndDuration",
- "inExtraDuration must be of type number"
- );
- this._extraEndDuration = inExtraDuration;
- return this;
- }
- /**
- * Rotates the sprite
- *
- * @param {Number} inAngle
- * @returns {EffectSection}
- */
- spriteRotation(inAngle) {
- if (!is_real_number(inAngle))
- throw this.sequence._customError(
- this,
- "spriteRotation",
- "inAngle must be of type number"
- );
- this._spriteRotation = inAngle;
- return this;
- }
- /**
- * Rotates the sprite
- *
- * @param {Boolean} inBool
- * @returns {EffectSection}
- */
- randomSpriteRotation(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "randomSpriteRotation",
- "inBool must be of type boolean"
- );
- this._randomSpriteRotation = inBool;
- return this;
- }
- /**
- * Causes the effect to not rotate should its container rotate
- *
- * @param {Boolean} [inBool=true] inBool
- * @returns {EffectSection}
- */
- zeroSpriteRotation(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "zeroSpriteRotation",
- "inBool must be of type boolean"
- );
- this._zeroSpriteRotation = inBool;
- return this;
- }
- /**
- * If the effect would loop due to its duration or persistence, this causes it not to
- *
- * @param {Boolean} [inBool=true] inBool
- * @returns {EffectSection}
- */
- noLoop(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "noLoop",
- "inBool must be of type boolean"
- );
- this._noLoop = inBool;
- return this;
- }
- /**
- * Causes the effect to not show up in the Effect Manager UI - DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING
- *
- * @param inBool
- * @returns {EffectSection}
- */
- private(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "private",
- "inBool must be of type boolean"
- );
- this._private = inBool;
- return this;
- }
- /**
- * Causes the effect to be played in screen space instead of world space (where tokens are)
- *
- * @param {Boolean} [inBool=true] inBool
- * @returns {EffectSection}
- */
- screenSpace(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpace",
- "inBool must be of type boolean"
- );
- this._screenSpace = inBool;
- this._screenSpaceAnchor = this._screenSpaceAnchor ?? { x: 0.5, y: 0.5 };
- return this;
- }
- /**
- * Causes the effect to be played above all of the UI elements
- *
- * @param {Boolean} [inBool=true] inBool
- * @returns {EffectSection}
- */
- screenSpaceAboveUI(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpaceAboveUI",
- "inBool must be of type boolean"
- );
- this._screenSpaceAboveUI = inBool;
- return this;
- }
- /**
- * Positions the effect in a screen space position, offset from its .screenSpaceAnchor()
- *
- * @param {Object} inPosition
- * @returns {EffectSection}
- */
- screenSpacePosition(inPosition) {
- inPosition = {
- x: inPosition?.x ?? 0,
- y: inPosition?.y ?? 0
- };
- if (!is_real_number(inPosition.x))
- throw this.sequence._customError(
- this,
- "screenSpacePosition",
- `inPosition.x must be of type number!`
- );
- if (!is_real_number(inPosition.y))
- throw this.sequence._customError(
- this,
- "screenSpacePosition",
- `inPosition.y must be of type number!`
- );
- this._screenSpacePosition = inPosition;
- return this;
- }
- /**
- * Anchors the sprite according to the given x and y coordinates, or uniformly based on a single number in screen space
- *
- * @param {Number|Object} inAnchor
- * @returns {EffectSection}
- */
- screenSpaceAnchor(inAnchor) {
- if (is_real_number(inAnchor)) {
- inAnchor = {
- x: inAnchor,
- y: inAnchor
- };
- }
- inAnchor = {
- x: inAnchor?.x ?? 0.5,
- y: inAnchor?.y ?? 0.5
- };
- if (!is_real_number(inAnchor.x))
- throw this.sequence._customError(
- this,
- "screenSpaceAnchor",
- `inAnchor.x must be of type number!`
- );
- if (!is_real_number(inAnchor.y))
- throw this.sequence._customError(
- this,
- "screenSpaceAnchor",
- `inAnchor.y must be of type number!`
- );
- this._screenSpaceAnchor = inAnchor;
- return this;
- }
- /**
- * Sets up various properties relating to scale of the effect on the screen
- *
- * @param {Object} inOptions
- * @returns {EffectSection}
- */
- screenSpaceScale(inOptions) {
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- x: 1,
- y: 1,
- fitX: false,
- fitY: false,
- ratioX: false,
- ratioY: false
- },
- inOptions
- );
- if (!is_real_number(inOptions.x))
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- `inOptions.x must be of type number!`
- );
- if (!is_real_number(inOptions.y))
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- `inOptions.y must be of type number!`
- );
- if (typeof inOptions.fitX !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- "inOptions.fitX must be of type boolean"
- );
- if (typeof inOptions.fitY !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- "inOptions.fitY must be of type boolean"
- );
- if (typeof inOptions.ratioX !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- "inOptions.ratioX must be of type boolean"
- );
- if (typeof inOptions.ratioY !== "boolean")
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- "inOptions.ratioY must be of type boolean"
- );
- if (inOptions.ratioX && inOptions.ratioY)
- throw this.sequence._customError(
- this,
- "screenSpaceScale",
- "both ratioX and ratioY cannot be true, one axis must fit or be set directly"
- );
- this._screenSpaceScale = inOptions;
- return this;
- }
- /**
- * This is for adding extra information to an effect, like the origin of the effect in the form of the item's uuid.
- * The method accepts a string or a Document that has an UUID.
- *
- * @param {string|document} inOrigin
- * @returns {Section}
- */
- origin(inOrigin) {
- inOrigin = validate_document(inOrigin);
- if (inOrigin instanceof foundry.abstract.Document) {
- inOrigin = inOrigin?.uuid;
- if (!inOrigin)
- throw this.sequence._customError(
- this,
- "origin",
- "could not find the UUID for the given Document"
- );
- }
- if (typeof inOrigin !== "string")
- throw this.sequence._customError(
- this,
- "origin",
- "inOrigin must be of type string"
- );
- this._origin = inOrigin;
- return this;
- }
- /**
- * Ties the effect to any number of documents in Foundry - if those get deleted, the effect is ended.
- *
- * @param {String|PlaceableObject|foundry.abstract.Document|Array<String|PlaceableObject|foundry.abstract.Document>} inDocuments
- * @returns {EffectSection}
- */
- tieToDocuments(inDocuments) {
- if (!Array.isArray(inDocuments)) {
- inDocuments = [inDocuments];
- }
- for (let doc of inDocuments) {
- if (typeof doc !== "string" && !(doc instanceof PlaceableObject) && !(doc instanceof foundry.abstract.Document)) {
- throw this.sequence._customError(
- this,
- "tieToDocument",
- "inOrigin must be of type string, PlaceableObject, or Document, or an array thereof"
- );
- }
- if (typeof doc === "string") {
- const obj = fromUuidSync(doc);
- if (!obj)
- throw this.sequence._customError(
- this,
- "tieToDocument",
- `could not find document with UUID "${doc}"`
- );
- } else {
- doc = validate_document(doc);
- if (doc instanceof foundry.abstract.Document) {
- doc = doc?.uuid;
- if (!doc)
- throw this.sequence._customError(
- this,
- "tieToDocument",
- "could not find the UUID for the given object"
- );
- }
- }
- this._tiedDocuments.push(doc);
- }
- return this;
- }
- /**
- * Masks the effect to the given object or objects. If no object is given, the effect will be masked to the source
- * of the effect.
- *
- * @param {Token/TokenDocument/Tile/TileDocument/Drawing/DrawingDocument/MeasuredTemplate/MeasuredTemplateDocument/Array} inObject
- * @returns {Section}
- */
- mask(inObject) {
- if (!inObject) {
- this._selfMask = true;
- return this;
- }
- if (Array.isArray(inObject)) {
- for (let obj of inObject) {
- this.mask(obj);
- }
- return this;
- }
- const validatedObject = this._validateLocation(inObject);
- const isValidObject = validatedObject instanceof TokenDocument || validatedObject instanceof TileDocument || validatedObject instanceof DrawingDocument || validatedObject instanceof MeasuredTemplateDocument;
- if (!isValidObject) {
- throw this.sequence._customError(
- this,
- "mask",
- "A foundry object was provided, but only Tokens, Tiles, Drawings, and MeasuredTemplates may be used to create effect masks"
- );
- }
- this._masks.push(get_object_identifier(validatedObject));
- return this;
- }
- /**
- * Causes the effect to be visible through walls
- *
- * @param inBool
- * @returns {EffectSection}
- */
- xray(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "xray",
- "inBool must be of type boolean"
- );
- this._xray = inBool;
- return this;
- }
- /**
- * Configures the isometric configuration of this effect
- *
- * @param inOptions
- * @returns {EffectSection}
- */
- isometric(inOptions = {}) {
- if (typeof inOptions !== "object")
- throw this.sequence._customError(
- this,
- "isometric",
- `inOptions must be of type object`
- );
- inOptions = foundry.utils.mergeObject(
- {
- overlay: false
- },
- inOptions
- );
- if (typeof inOptions?.overlay !== "boolean")
- throw this.sequence._customError(
- this,
- "isometric",
- "inOptions.overlay must be of type boolean"
- );
- this._isometric = inOptions;
- return this;
- }
- /**
- * @private
- */
- _expressWarnings() {
- if (this._stretchTo && this._anchor?.x) {
- this.sequence._showWarning(
- this,
- "stretchTo",
- "you have called .stretchTo() and .anchor() - stretchTo will manually set the X axis of the anchor and may not behave like you expect.",
- true
- );
- }
- if (this._stretchTo && this._scaleToObject) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "You're trying to stretch towards an object, while scaling to fit another??? Make up your mind!"
- );
- }
- if (this._stretchTo && this._randomRotation) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "You're trying to stretch towards an object, while trying to randomly rotate the effect? What?"
- );
- }
- if (this._stretchTo && this._moveTowards) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "You're trying to stretch towards an object, while moving towards it? You're insane."
- );
- }
- if (this._attachTo && this._stretchTo?.attachTo && (this._startTime || this._endTime) && this._isRangedEffect) {
- throw this.sequence._customError(
- this,
- "stretchTo",
- "Dual-attached range-finding effects combined while using any of the time methods is stable - modern web browsers cannot handle it and it may crash them, so this feature has been disabled."
- );
- }
- const source = this._getSourceObject();
- const target = this._getTargetObject();
- if (!this._screenSpace && this._persistOptions?.persistTokenPrototype && this._masks.filter((uuid) => uuid !== source).length > 0) {
- this.sequence._showWarning(
- this,
- "persist",
- "You have applied persistTokenPrototype with multiple masks from objects in the scene - these will not be persisted across scenes!",
- true
- );
- }
- if (!source && !target && !this._screenSpace) {
- throw this.sequence._customError(
- this,
- "play",
- "Could not determine where to play the effect!"
- );
- }
- }
- /**
- * @OVERRIDE
- */
- async preRun() {
- if (this._from) {
- this._file = this._file || this._from.object?.texture?.src;
- if (this._source === null) {
- this._source = this._validateLocation(this._from.object);
- }
- if (this._size === null) {
- const size = get_object_dimensions(this._from.object);
- this._size = {
- width: size?.width ?? canvas.grid.size,
- height: size?.height ?? canvas.grid.size,
- gridUnits: false
- };
- }
- if (this._mirrorX === null && (this._from.object.mirrorX || this._from.object?.tile && this._from.object?.tile.scale.x < 0)) {
- this._mirrorX = true;
- }
- if (this._mirrorY === null && (this._from.object.mirrorY || this._from.object?.tile && this._from.object?.tile.scale.y < 0)) {
- this._mirrorY = true;
- }
- if (this._angle === null && this._from.object?.rotation) {
- this._angle = -this._from.object.rotation;
- }
- this._randomOffset = {
- source: this._randomOffset?.source ?? this._from.options.randomOffset,
- target: this._randomOffset?.target ?? false
- };
- }
- }
- /**
- * @OVERRIDE
- * @returns {Promise<void>}
- */
- async run() {
- if (!user_can_do("permissions-effect-create") || !this._playEffect) {
- if (!user_can_do("permissions-effect-create")) {
- debounce(EffectSection.debounceWarning, 1e3);
- }
- return new Promise((resolve) => {
- resolve();
- });
- }
- if (!this._deserializedData)
- this._expressWarnings();
- const data = await this._sanitizeEffectData();
- if (Hooks.call("preCreateSequencerEffect", data) === false)
- return;
- let push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
- let canvasEffectData = await Sequencer.EffectManager.play(data, push);
- let totalDuration = this._currentWaitTime;
- if (this._persist) {
- totalDuration += await canvasEffectData.promise;
- } else {
- totalDuration += await canvasEffectData.duration;
- }
- await new Promise((resolve) => setTimeout(resolve, totalDuration));
- }
- /**
- * @private
- */
- _applyTraits() {
- Object.assign(this.constructor.prototype, traits.files);
- Object.assign(this.constructor.prototype, traits.audio);
- Object.assign(this.constructor.prototype, traits.moves);
- Object.assign(this.constructor.prototype, traits.opacity);
- Object.assign(this.constructor.prototype, traits.rotation);
- Object.assign(this.constructor.prototype, traits.scale);
- Object.assign(this.constructor.prototype, traits.time);
- Object.assign(this.constructor.prototype, traits.users);
- Object.assign(this.constructor.prototype, traits.animation);
- Object.assign(this.constructor.prototype, traits.filter);
- Object.assign(this.constructor.prototype, traits.tint);
- Object.assign(this.constructor.prototype, traits.location);
- Object.assign(this.constructor.prototype, traits.offset);
- Object.assign(this.constructor.prototype, traits.text);
- }
- /**
- * @private
- */
- async _initialize() {
- if (this._name) {
- if (!this.sequence.nameOffsetMap) {
- this.sequence.nameOffsetMap = {};
- }
- if (!this.sequence.nameOffsetMap[this._name]) {
- const source = this._getSourceObject();
- const target = this._getTargetObject();
- if (this._offsetLegacy && !this._offset) {
- this._offset = {
- source: !target ? this._offsetLegacy : false,
- target: !!target ? this._offsetLegacy : false
- };
- }
- if (this._randomOffsetLegacy && !this._randomOffset) {
- this._randomOffset = {
- source: !target ? this._randomOffsetLegacy : false,
- target: !!target ? this._randomOffsetLegacy : false
- };
- }
- this.sequence.nameOffsetMap[this._name] = {
- seed: `${this._name}-${randomID()}`,
- source,
- target,
- randomOffset: this._randomOffset,
- missed: this._missed,
- offset: this._offset,
- repetitions: this._repetitions,
- twister: {}
- };
- }
- }
- if (!this._file && !this._from && !this._text && !this._shapes.length && this.sequence.softFail) {
- this._playEffect = false;
- return;
- }
- let fileData = this._file ? await this._determineFile(this._file) : {
- file: this._file,
- forcedIndex: false,
- customRange: false
- };
- this._isRangedEffect = fileData?.file?.rangeFind;
- if (fileData.customRange || fileData.file?.dbPath)
- return;
- let exists = false;
- try {
- exists = await SequencerFileCache.srcExists(fileData.file);
- } catch (err) {
- }
- if (!exists) {
- if (this.sequence.softFail) {
- this._playEffect = false;
- return;
- }
- throw this.sequence._customError(
- this,
- "Play",
- `Could not find file:<br>${fileData.file}`
- );
- }
- }
- /**
- * @private
- */
- _getSourceObject() {
- if (!this._source || typeof this._source !== "object")
- return this._source;
- if (this._source?.cachedLocation || !this._attachTo) {
- return get_object_canvas_data(this._source);
- }
- return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
- }
- /**
- * @private
- */
- _getTargetObject() {
- if (!this._target?.target)
- return this._target;
- if (typeof this._target.target !== "object")
- return this._target.target;
- if (this._target?.target?.cachedLocation || !(this._stretchTo?.attachTo || this._rotateTowards?.attachTo)) {
- return get_object_canvas_data(this._target.target, true);
- }
- return get_object_identifier(this._target.target) ?? get_object_canvas_data(this._target.target, true);
- }
- /**
- * @private
- */
- async _sanitizeEffectData() {
- if (this._deserializedData) {
- this._deserializedData.creationTimestamp = +new Date();
- this._deserializedData.remote = true;
- return this._deserializedData;
- }
- const { file, forcedIndex, customRange } = this._file && this._playEffect ? await this._determineFile(this._file) : {
- file: this._file,
- forcedIndex: false,
- customRange: false
- };
- const source = this._getSourceObject();
- const target = this._getTargetObject();
- if (this._offsetLegacy) {
- this._offset = {
- source: !target && this._offset?.source ? this._offsetLegacy : this._offset?.source,
- target: !!target && this._offset?.target ? this._offsetLegacy : this._offset?.target
- };
- }
- if (this._randomOffsetLegacy) {
- this._randomOffset = {
- source: !target && this._randomOffset?.source ? this._randomOffsetLegacy : this._randomOffset?.source,
- target: !!target && this._randomOffset?.target ? this._randomOffsetLegacy : this._randomOffset?.target
- };
- }
- if (this._selfMask) {
- this._masks.push(
- get_object_identifier(this._source) ?? get_object_canvas_data(this._source)
- );
- }
- let sceneId = game.user.viewedScene;
- if (is_UUID(source)) {
- const potentialSceneId = source.split(".")[1];
- if (game.scenes.get(potentialSceneId)) {
- sceneId = potentialSceneId;
- }
- } else if (is_UUID(target)) {
- const potentialSceneId = target.split(".")[1];
- if (game.scenes.get(potentialSceneId)) {
- sceneId = potentialSceneId;
- }
- }
- let data = foundry.utils.duplicate({
- /**
- * Core properties
- */
- _id: randomID(),
- flagVersion: flagManager.latestFlagVersion,
- sequenceId: this.sequence.id,
- creationTimestamp: +new Date(),
- sceneId,
- creatorUserId: game.userId,
- moduleName: this.sequence.moduleName,
- users: this._users ? Array.from(this._users) : false,
- name: this._name,
- origin: this._origin,
- index: this.sequence.effectIndex,
- repetition: this._currentRepetition,
- private: this._private,
- temporary: this._temporaryEffect,
- tiedDocuments: Array.from(new Set(this._tiedDocuments)),
- /**
- * Source/target properties
- */
- source,
- target,
- rotateTowards: this._rotateTowards,
- stretchTo: this._stretchTo ? {
- attachTo: this._stretchTo.attachTo,
- onlyX: this._stretchTo.onlyX,
- requiresLineOfSight: this._stretchTo.requiresLineOfSight,
- hideLineOfSight: this._stretchTo.hideLineOfSight
- } : false,
- moveTowards: this._moveTowards ? {
- ease: this._moveTowards.ease,
- rotate: this._moveTowards.rotate
- } : false,
- attachTo: this._attachTo,
- missed: this._missed,
- /**
- * Sprite properties
- */
- file: file?.dbPath ?? file,
- customRange,
- forcedIndex,
- text: this._text,
- tilingTexture: this._tilingTexture,
- masks: Array.from(new Set(this._masks)),
- shapes: this._shapes,
- volume: this._volume,
- isometric: this._isometric,
- // Transforms
- scale: this._getCalculatedScale("scale"),
- spriteScale: this._getCalculatedScale("spriteScale"),
- angle: this._angle,
- size: this._size,
- offset: this._offset,
- anchor: this._anchor,
- spriteOffset: this._spriteOffset,
- spriteAnchor: this._spriteAnchor,
- template: this._template,
- zeroSpriteRotation: this._zeroSpriteRotation,
- randomOffset: this._randomOffset,
- randomRotation: this._randomRotation,
- scaleToObject: this._scaleToObject,
- elevation: this._elevation,
- aboveLighting: this._aboveLighting,
- aboveInterface: this._aboveInterface,
- xray: this._xray,
- // Appearance
- zIndex: this._zIndex,
- opacity: is_real_number(this._opacity) ? this._opacity : 1,
- filters: this._filters,
- noLoop: this._noLoop,
- spriteRotation: this._spriteRotation,
- randomSpriteRotation: this._randomSpriteRotation,
- tint: this._tint?.decimal,
- flipX: this._mirrorX || this._randomMirrorX && Math.random() < 0.5,
- flipY: this._mirrorY || this._randomMirrorY && Math.random() < 0.5,
- /**
- * Time properties
- */
- duration: this._duration,
- persist: this._persist,
- persistOptions: this._persistOptions,
- playbackRate: this._playbackRate,
- extraEndDuration: this._extraEndDuration,
- time: this._startTime || this._endTime ? {
- start: is_real_number(this._startTime) ? {
- value: this._startTime,
- isPerc: this._startPerc
- } : false,
- end: is_real_number(this._endTime) ? {
- value: this._endTime,
- isPerc: this._endPerc
- } : false,
- isRange: this._isRange
- } : false,
- /**
- * Animation properties
- */
- moves: this._moveTowards,
- moveSpeed: this._moveSpeed,
- fadeIn: this._fadeIn,
- fadeOut: this._fadeOut,
- scaleIn: this._scaleIn,
- scaleOut: this._scaleOut,
- rotateIn: this._rotateIn,
- rotateOut: this._rotateOut,
- fadeInAudio: this._fadeInAudio,
- fadeOutAudio: this._fadeOutAudio,
- animations: this._animations,
- /**
- * Screenspace properties
- */
- screenSpace: this._screenSpace,
- screenSpaceAboveUI: this._screenSpaceAboveUI,
- screenSpaceAnchor: this._screenSpaceAnchor,
- screenSpacePosition: this._screenSpacePosition,
- screenSpaceScale: this._screenSpaceScale,
- nameOffsetMap: this.sequence.nameOffsetMap
- });
- for (let override of this._overrides) {
- data = await override(this, data);
- }
- if ((typeof data.file !== "string" || data.file === "") && !data.text && !data.shapes && !data.customRange) {
- throw this.sequence._customError(
- this,
- "file",
- "an effect must have a file, text, or have a shape!"
- );
- }
- return data;
- }
- async _serialize() {
- const data = await super._serialize();
- await this.preRun();
- const sectionData = await this._sanitizeEffectData();
- return {
- ...data,
- type: "effect",
- sectionData
- };
- }
- async _deserialize(data) {
- this._deserializedData = data.sectionData;
- return super._deserialize(data);
- }
- /**
- * @private
- */
- _getCalculatedScale(type) {
- const min = this["_" + type + "Min"];
- const max = this["_" + type + "Max"];
- let scale2 = min;
- if (is_real_number(min)) {
- if (max && is_real_number(max)) {
- scale2 = random_float_between(min, max);
- }
- scale2 = {
- x: scale2,
- y: scale2
- };
- }
- return {
- x: scale2?.x ?? 1,
- y: scale2?.y ?? 1
- };
- }
- }
- class SoundSection extends Section {
- constructor(inSequence, inFile = "") {
- super(inSequence);
- this._file = inFile;
- this._volume = 0.8;
- this._overrides = [];
- }
- static niceName = "Sound";
- /**
- * Adds a function that will run at the end of the sound serialization step, but before it is played. Allows direct
- * modifications of sound's data.
- *
- * @param {function} inFunc
- * @returns {SoundSection}
- */
- addOverride(inFunc) {
- if (!is_function$1(inFunc))
- throw this.sequence._customError(
- this,
- "addOverride",
- "The given function needs to be an actual function."
- );
- this._overrides.push(inFunc);
- return this;
- }
- /**
- * @private
- */
- _applyTraits() {
- Object.assign(this.constructor.prototype, traits.files);
- Object.assign(this.constructor.prototype, traits.audio);
- Object.assign(this.constructor.prototype, traits.time);
- Object.assign(this.constructor.prototype, traits.users);
- }
- /**
- * @OVERRIDE
- * @returns {Promise}
- */
- async run() {
- const playData = await this._sanitizeSoundData();
- if (!playData.play && this.sequence.softFail) {
- return new Promise((reject2) => {
- reject2();
- });
- }
- if (!playData?.play) {
- this.sequence._customError(
- this,
- "Play",
- `File not found: ${playData.src}`
- );
- return new Promise((reject2) => reject2());
- }
- if (Hooks.call("preCreateSequencerSound", playData) === false)
- return;
- let push = !(playData?.users?.length === 1 && playData?.users?.includes(game.userId)) && !this.sequence.localOnly;
- SequencerAudioHelper.play(playData, push);
- await new Promise(
- (resolve) => setTimeout(resolve, this._currentWaitTime + playData.duration)
- );
- }
- /**
- * @returns {Promise}
- * @private
- */
- async _sanitizeSoundData() {
- if (this._deserializedData) {
- return this._deserializedData;
- }
- if (!this._file) {
- return {
- play: false,
- src: false
- };
- }
- let { file, forcedIndex } = await this._determineFile(this._file);
- if (!file) {
- return {
- play: false,
- src: false
- };
- }
- if (file instanceof SequencerFileBase) {
- file.forcedIndex = forcedIndex;
- if (file.timeRange) {
- [this._startTime, this._endTime] = file.timeRange;
- this._isRange = true;
- }
- file = file.getFile();
- }
- let soundFile = await AudioHelper.preloadSound(file);
- if (!soundFile || soundFile.failed) {
- return {
- play: false,
- src: this._file
- };
- }
- let duration = soundFile.duration * 1e3;
- let startTime = (this._startTime ? !this._startPerc ? this._startTime : this._startTime * duration : 0) / 1e3;
- if (this._endTime) {
- duration = !this._endPerc ? Number(
- this._isRange ? this._endTime - this._startTime : duration - this._endTime
- ) : this._endTime * duration;
- }
- let data = {
- id: randomID(),
- play: true,
- src: file,
- loop: this._duration > duration,
- volume: this._volume,
- fadeIn: this._fadeInAudio,
- fadeOut: this._fadeOutAudio,
- startTime,
- duration: this._duration || duration,
- sceneId: game.user.viewedScene,
- users: this._users ? Array.from(this._users) : null
- };
- for (let override of this._overrides) {
- data = await override(this, data);
- }
- if (typeof data.src !== "string" || data.src === "") {
- throw this.sequence._customError(
- this,
- "file",
- "a sound must have a src of type string!"
- );
- }
- return data;
- }
- async _serialize() {
- const data = await super._serialize();
- const sectionData = await this._sanitizeSoundData();
- return {
- ...data,
- type: "sound",
- sectionData
- };
- }
- async _deserialize(data) {
- this._deserializedData = data.sectionData;
- return super._deserialize(data);
- }
- }
- class AnimationSection extends Section {
- constructor(inSequence, inTarget) {
- super(inSequence);
- this._teleportTo = false;
- this._originObject = false;
- this._moveSpeed = 23;
- this._offset = { x: 0, y: 0 };
- this._closestSquare = false;
- this._snapToGrid = false;
- this._hide = void 0;
- if (inTarget)
- this.on(inTarget);
- }
- static niceName = "Animation";
- /**
- * Sets the target object to be animated
- *
- * @param {object|string} inTarget
- * @returns {AnimationSection}
- */
- on(inTarget) {
- inTarget = this._validateLocation(inTarget);
- if (!inTarget)
- throw this.sequence._customError(
- this,
- "on",
- "could not find position of given object"
- );
- this._originObject = this._validateLocation(inTarget);
- return this;
- }
- /**
- * Sets the location to teleport the target object to
- *
- * @param {object|string} inTarget
- * @param {object} options
- * @returns {AnimationSection}
- */
- teleportTo(inTarget, options = {}) {
- options = foundry.utils.mergeObject(
- {
- delay: 0,
- relativeToCenter: false
- },
- options
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "teleportTo",
- "options.delay must be of type number"
- );
- inTarget = this._validateLocation(inTarget);
- if (!inTarget)
- throw this.sequence._customError(
- this,
- "teleportTo",
- "could not find position of given object"
- );
- options.target = this._validateLocation(inTarget);
- this._teleportTo = options;
- return this;
- }
- /**
- * Sets the location to rotate the object to
- *
- * @param {object|string} inLocation
- * @param {object} options
- * @returns this
- */
- rotateTowards(inLocation, options = {}) {
- options = foundry.utils.mergeObject(
- {
- duration: 0,
- ease: "linear",
- delay: 0,
- rotationOffset: 0,
- towardsCenter: true,
- cacheLocation: false
- },
- options
- );
- if (!is_real_number(options.duration))
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.duration must be of type number"
- );
- if (typeof options.ease !== "string")
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.ease must be of type string"
- );
- if (!is_real_number(options.delay))
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.delay must be of type number"
- );
- if (!is_real_number(options.rotationOffset))
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.rotationOffset must be of type number"
- );
- if (typeof options.towardsCenter !== "boolean")
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.towardsCenter must be of type boolean"
- );
- if (typeof options.cacheLocation !== "boolean")
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "options.cacheLocation must be of type boolean"
- );
- options.target = this._validateLocation(inLocation);
- if (!options.target)
- throw this.sequence._customError(
- this,
- "rotateTowards",
- "could not find position of given object"
- );
- options.target = options.cacheLocation ? get_object_position(options.target, { measure: true }) : options.target;
- this._rotateTowards = options;
- return this;
- }
- /**
- * Causes the movement or teleportation to be offset in the X and/or Y axis
- *
- * @param {object} inOffset
- * @returns {AnimationSection}
- */
- offset(inOffset) {
- inOffset = foundry.utils.mergeObject({ x: 0, y: 0 }, inOffset);
- this._offset = this._validateLocation(inOffset);
- return this;
- }
- /**
- * Causes the movement or teleportation to pick the closest non-intersecting square, if the target is a token or tile
- *
- * @param {boolean} inBool
- * @returns {AnimationSection}
- */
- closestSquare(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "closestSquare",
- "inBool must be of type boolean"
- );
- this._closestSquare = inBool;
- return this;
- }
- /**
- * Causes the final location to be snapped to the grid
- *
- * @param {boolean} inBool
- * @returns {AnimationSection}
- */
- snapToGrid(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "snapToGrid",
- "inBool must be of type boolean"
- );
- this._snapToGrid = inBool;
- return this;
- }
- /**
- * Causes the object to become hidden
- *
- * @param {boolean} inBool
- * @returns {AnimationSection}
- */
- hide(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "hide",
- "inBool must be of type boolean"
- );
- this._hide = inBool;
- return this;
- }
- /**
- * Causes the object to become visible
- *
- * @param {boolean} inBool
- * @returns {AnimationSection}
- */
- show(inBool = true) {
- if (typeof inBool !== "boolean")
- throw this.sequence._customError(
- this,
- "show",
- "inBool must be of type boolean"
- );
- this._hide = !inBool;
- return this;
- }
- /**
- * @private
- */
- async run() {
- return this._runAnimate();
- }
- /**
- * @private
- */
- _applyTraits() {
- Object.assign(this.constructor.prototype, traits.moves);
- Object.assign(this.constructor.prototype, traits.opacity);
- Object.assign(this.constructor.prototype, traits.rotation);
- Object.assign(this.constructor.prototype, traits.audio);
- Object.assign(this.constructor.prototype, traits.tint);
- }
- /**
- * @private
- */
- async _updateObject(obj, updates, animate = false, animation2 = {}) {
- const uuid = obj?.uuid ?? obj?.document?.uuid;
- await sequencerSocket.executeAsGM(
- SOCKET_HANDLERS.UPDATE_DOCUMENT,
- uuid,
- updates,
- { animate, animation: animation2 }
- );
- }
- /**
- * @private
- */
- async _waitForTokenRefresh(obj) {
- let token;
- if (obj instanceof Token) {
- token = obj;
- }
- if (obj instanceof TokenDocument) {
- token = obj.object;
- }
- if (token == null || token.mesh != null) {
- return;
- }
- let refreshTokenID;
- return await new Promise((resolve) => {
- refreshTokenID = Hooks.on("refreshToken", async (tokenDoc) => {
- if (tokenDoc.document.actorId !== token.document.actorId || !token.mesh)
- return;
- Hooks.off("refreshToken", refreshTokenID);
- resolve();
- });
- });
- }
- /**
- * @private
- */
- async _execute() {
- if (!await this._shouldPlay())
- return;
- let self = this;
- this._basicDelay = random_float_between(this._delayMin, this._delayMax);
- return new Promise(async (resolve) => {
- setTimeout(async () => {
- await this._waitForTokenRefresh(this._originObject);
- if (this._shouldAsync) {
- await self.run();
- } else {
- self.run();
- }
- resolve();
- }, this._basicDelay);
- });
- }
- /**
- * @private
- */
- _getClosestSquare(origin, target) {
- let originLoc = get_object_position(origin, { exact: true });
- let targetLoc = get_object_position(target, { exact: true });
- let originDimensions = get_object_dimensions(origin);
- let targetDimensions = get_object_dimensions(target);
- let originBottom = Math.max(
- originDimensions.width - canvas.grid.size,
- canvas.grid.size
- );
- let originRight = Math.max(
- originDimensions.height - canvas.grid.size,
- canvas.grid.size
- );
- let ray = new Ray(originLoc, targetLoc);
- let dx = ray.dx;
- let dy = ray.dy;
- if (dx > 0 && Math.abs(dx) > originRight) {
- dx -= originDimensions.width;
- } else if (dx < 0 && Math.abs(dx) > targetDimensions.width) {
- dx += targetDimensions.height;
- } else {
- dx = 0;
- }
- if (dy > 0 && Math.abs(dy) > originBottom) {
- dy -= originDimensions.height;
- } else if (dy < 0 && Math.abs(dy) > targetDimensions.height) {
- dy += targetDimensions.height;
- } else {
- dy = 0;
- }
- const pos = {
- x: originLoc.x + dx,
- y: originLoc.y + dy,
- elevation: targetLoc?.elevation
- };
- if (!pos.elevation) {
- delete pos["elevation"];
- }
- return pos;
- }
- /**
- * @private
- */
- _snapLocationToGrid(inLocation) {
- return canvas.grid.getSnappedPosition(inLocation.x, inLocation.y);
- }
- /**
- * This needs a rewrite, jeesus.
- */
- async _runAnimate() {
- let animData = {
- attributes: [],
- maxFPS: 1e3 / game.settings.get("core", "maxFPS"),
- lastTimespan: performance.now(),
- totalDt: 0
- };
- let overallDuration = this._duration ? this._duration : 0;
- const originLocation = get_object_position(this._originObject, {
- exact: true
- });
- if (this._rotateTowards) {
- let offset2 = (this._angle ? this._angle : 0) + this._rotateTowards.rotationOffset;
- let targetLoc = this._moveTowards?.target || this._teleportTo?.target || this._originObject;
- targetLoc = this._closestSquare ? this._getClosestSquare(this._originObject, targetLoc) : get_object_position(targetLoc, { exact: true });
- targetLoc.x += this._offset.x;
- targetLoc.y += this._offset.y;
- if (this._snapToGrid) {
- targetLoc = this._snapLocationToGrid(targetLoc);
- }
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- let startLocation = this._originObject.object?.center ?? targetLoc;
- let targetLocation = this._rotateTowards.target?.object ?? this._rotateTowards.target;
- if (this._rotateTowards.towardsCenter) {
- targetLocation = targetLocation?.center ?? targetLocation;
- }
- let ray = new Ray(startLocation, targetLocation);
- let angle = Math.normalizeDegrees(ray.angle * 180 / Math.PI - 90);
- angle += offset2;
- await this._updateObject(
- this._originObject,
- { rotation: angle },
- this._rotateTowards.duration > 0,
- {
- duration: this._rotateTowards.duration,
- easing: this._rotateTowards.ease
- }
- );
- }, this._rotateTowards.delay ?? 0);
- } else {
- animData.attributes.push({
- name: "rotationTowards",
- offset: offset2,
- origin: this._originObject,
- originLocation: targetLoc,
- target: this._rotateTowards.target?.object ?? this._rotateTowards.target,
- towardsCenter: this._rotateTowards.towardsCenter,
- from: false,
- to: false,
- progress: 0,
- done: false,
- duration: this._rotateTowards.duration,
- durationDone: 0,
- delay: this._rotateTowards.delay,
- ease: this._rotateTowards.ease
- });
- }
- let rotateDuration = this._rotateTowards.duration + this._rotateTowards.delay;
- overallDuration = overallDuration > rotateDuration ? overallDuration : rotateDuration;
- }
- if (this._fadeIn) {
- let to = is_real_number(this._opacity) ? this._opacity : 1;
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- await this._updateObject(this._originObject, { alpha: to }, true, {
- duration: this._fadeIn.duration,
- easing: this._fadeIn.ease
- });
- }, this._fadeIn.delay ?? 0);
- } else {
- animData.attributes.push({
- name: "alpha",
- from: 0,
- to,
- progress: 0,
- done: false,
- duration: this._fadeIn.duration,
- durationDone: 0,
- delay: this._fadeIn.delay,
- ease: this._fadeIn.ease
- });
- }
- let fadeDuration = this._fadeIn.duration + this._fadeIn.delay;
- overallDuration = overallDuration > fadeDuration ? overallDuration : fadeDuration;
- }
- if (this._fadeInAudio && this._originObject?.video?.volume !== void 0) {
- let to = is_real_number(this._volume) ? this._volume : 1;
- animData.attributes.push({
- name: "video.volume",
- from: 0,
- to,
- progress: 0,
- done: false,
- duration: this._fadeInAudio.duration,
- durationDone: 0,
- delay: this._fadeInAudio.delay,
- ease: this._fadeInAudio.ease
- });
- let fadeDuration = this._fadeInAudio.duration + this._fadeInAudio.delay;
- overallDuration = overallDuration > fadeDuration ? overallDuration : fadeDuration;
- }
- if (this._rotateIn) {
- let from = this._angle ? this._angle : this._originObject.rotation;
- let to = this._rotateIn.value;
- if (Math.abs(from - to) > 180) {
- if (to < 0) {
- to += 360;
- } else if (from > to) {
- from -= 360;
- }
- }
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- if (this._originObject.rotation !== from) {
- await this._updateObject(
- this._originObject,
- { rotation: from },
- false
- );
- }
- await this._updateObject(this._originObject, { rotation: to }, true, {
- duration: this._rotateIn.duration,
- easing: this._rotateIn.ease
- });
- }, this._rotateIn.delay ?? 0);
- } else {
- animData.attributes.push({
- name: "rotation",
- from,
- to,
- progress: 0,
- done: false,
- duration: this._rotateIn.duration,
- durationDone: 0,
- delay: this._rotateIn.delay,
- ease: this._rotateIn.ease
- });
- }
- let rotateDuration = this._rotateIn.duration + this._rotateIn.delay;
- overallDuration = overallDuration > rotateDuration ? overallDuration : rotateDuration;
- }
- if (this._moveTowards) {
- let originLocation2 = get_object_position(this._originObject, {
- exact: true
- });
- let targetLocation = this._closestSquare ? this._getClosestSquare(this._originObject, this._moveTowards.target) : get_object_position(this._moveTowards.target, {
- exact: true
- });
- targetLocation.x += this._offset.x;
- targetLocation.y += this._offset.y;
- targetLocation.elevation = targetLocation?.elevation ?? this._originObject?.elevation;
- if (this._moveTowards.relativeToCenter) {
- const dimensions = get_object_dimensions(this._originObject);
- targetLocation.x -= dimensions.width / 2;
- targetLocation.y -= dimensions.height / 2;
- if (this._snapToGrid) {
- targetLocation.x -= 0.01;
- targetLocation.y -= 0.01;
- }
- }
- if (this._snapToGrid) {
- targetLocation = this._snapLocationToGrid(targetLocation);
- }
- let originalDx = targetLocation.x - originLocation2.x;
- let originalDy = targetLocation.y - originLocation2.y;
- let originalDistance = Math.sqrt(
- originalDx * originalDx + originalDy * originalDy
- );
- let duration = this._duration ? this._duration : originalDistance / this._moveSpeed * animData.maxFPS;
- let moveDuration = duration + this._moveTowards.delay;
- overallDuration = overallDuration > moveDuration ? overallDuration : moveDuration;
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- await this._updateObject(this._originObject, targetLocation, true, {
- movementSpeed: this._moveSpeed,
- duration,
- easing: this._moveTowards.ease
- });
- }, this._moveTowards.delay ?? 0);
- } else {
- if (!(duration === 0 || originalDistance === 0)) {
- animData.attributes.push({
- name: "position",
- origin: originLocation2,
- target: targetLocation,
- originalDistance,
- currentDistance: 0,
- progress: 0,
- speed: 0,
- duration,
- done: false,
- ease: this._moveTowards.ease,
- delay: this._moveTowards.delay
- });
- }
- }
- }
- if (this._fadeOut) {
- let from = is_real_number(this._opacity) ? this._opacity : this._originObject.alpha ?? 1;
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- await this._updateObject(this._originObject, { alpha: 0 }, true, {
- duration: this._fadeOut.duration,
- easing: this._fadeOut.ease
- });
- }, this._fadeOut.delay ?? 0);
- } else {
- animData.attributes.push({
- name: "alpha",
- from,
- to: 0,
- progress: 0,
- done: false,
- duration: this._fadeOut.duration,
- durationDone: 0,
- delay: overallDuration - this._fadeOut.duration,
- ease: this._fadeOut.ease
- });
- }
- let fadeOutDuration = this._fadeOut.duration + this._fadeOut.delay;
- overallDuration = overallDuration > fadeOutDuration ? overallDuration : fadeOutDuration;
- }
- if (this._fadeOutAudio && this._originObject?.video?.volume !== void 0) {
- let from = is_real_number(this._volume) ? this._volume : this._originObject.video.volume;
- animData.attributes.push({
- name: "video.volume",
- from,
- to: 0,
- progress: 0,
- done: false,
- duration: this._fadeOutAudio.duration,
- durationDone: 0,
- delay: overallDuration - this._fadeOutAudio.duration,
- ease: this._fadeOutAudio.ease
- });
- let fadeOutAudioDuration = this._fadeOutAudio.duration + this._fadeOutAudio.delay;
- overallDuration = overallDuration > fadeOutAudioDuration ? overallDuration : fadeOutAudioDuration;
- }
- if (this._rotateOut) {
- let from = this._rotateOut.value;
- let to = this._angle ? this._angle : this._originObject.rotation;
- if (this._rotateIn)
- from += this._rotateIn.value;
- if (Math.abs(from - to) > 180) {
- if (to < 0) {
- to += 360;
- } else if (from > to) {
- from -= 360;
- }
- }
- if (this._originObject instanceof TokenDocument) {
- setTimeout(async () => {
- if (this._originObject.rotation !== from) {
- await this._updateObject(
- this._originObject,
- { rotation: from },
- false
- );
- }
- await this._updateObject(this._originObject, { rotation: to }, true, {
- duration: this._rotateOut.duration,
- easing: this._rotateOut.ease
- });
- }, this._rotateOut.delay ?? 0);
- } else {
- animData.attributes.push({
- name: "rotation",
- from,
- to,
- progress: 0,
- done: false,
- duration: this._rotateOut.duration,
- durationDone: 0,
- delay: overallDuration - this._rotateOut.duration,
- ease: this._rotateOut.ease
- });
- }
- let rotateOutDuration = this._rotateOut.duration + this._rotateOut.delay;
- overallDuration = overallDuration > rotateOutDuration ? overallDuration : rotateOutDuration;
- }
- if (this._teleportTo) {
- setTimeout(async () => {
- let targetLocation = this._closestSquare ? this._getClosestSquare(this._originObject, this._teleportTo.target) : get_object_position(this._teleportTo.target, {
- exact: true
- });
- if (targetLocation.x === void 0)
- targetLocation.x = originLocation.x;
- if (targetLocation.y === void 0)
- targetLocation.y = originLocation.y;
- if (targetLocation.elevation === void 0)
- targetLocation.elevation = originLocation.elevation;
- targetLocation.x += this._offset.x;
- targetLocation.y += this._offset.y;
- targetLocation.elevation = targetLocation?.elevation ?? this._originObject?.elevation;
- const dimensions = get_object_dimensions(this._originObject);
- if (this._teleportTo.relativeToCenter) {
- targetLocation.x -= dimensions.width / 2;
- targetLocation.y -= dimensions.height / 2;
- if (this._snapToGrid) {
- targetLocation.x -= 0.01;
- targetLocation.y -= 0.01;
- }
- }
- if (this._snapToGrid) {
- targetLocation.x -= dimensions.width / 2;
- targetLocation.y -= dimensions.height / 2;
- targetLocation = this._snapLocationToGrid(targetLocation);
- }
- await this._updateObject(this._originObject, targetLocation, false);
- }, this._teleportTo.delay);
- if (overallDuration <= this._teleportTo.delay) {
- this._waitUntilFinished = true;
- }
- overallDuration = overallDuration > this._teleportTo.delay ? overallDuration : this._teleportTo.delay;
- }
- let updateAttributes = {};
- if (is_real_number(this._angle) && !this._rotateIn && !this._rotateOut) {
- updateAttributes["rotation"] = this._angle;
- }
- if (is_real_number(this._opacity) && !this._fadeIn && !this._fadeOut) {
- updateAttributes["alpha"] = this._opacity;
- }
- if (is_real_number(this._volume) && !this._fadeInAudio && !this._fadeOutAudio && this._originObject?.video?.volume !== void 0) {
- updateAttributes["video.volume"] = this._volume;
- }
- if (this._tint) {
- updateAttributes["tint"] = this._tint.hexadecimal;
- }
- if (this._hide !== void 0) {
- updateAttributes["hidden"] = this._hide;
- }
- if (Object.keys(updateAttributes).length) {
- await wait$1(1);
- await this._updateObject(this._originObject, updateAttributes);
- await wait$1(1);
- }
- return new Promise(async (resolve) => {
- this._animate(animData, resolve);
- setTimeout(
- resolve,
- Math.max(0, overallDuration + this._currentWaitTime + animData.maxFPS)
- );
- });
- }
- /**
- * @private
- */
- async _animate(animData, resolve, timespan) {
- if (timespan) {
- let animatedAttributes = {};
- let dt = timespan - animData.lastTimespan;
- if (dt >= animData.maxFPS) {
- animData.totalDt += dt;
- for (let attribute of animData.attributes) {
- if (attribute.done)
- continue;
- if (animData.totalDt < attribute.delay)
- continue;
- if (attribute.name === "position") {
- attribute.speed = attribute.originalDistance / (attribute.duration / dt);
- attribute.currentDistance += attribute.speed;
- attribute.progress = attribute.currentDistance / attribute.originalDistance;
- let x = interpolate(
- attribute.origin.x,
- attribute.target.x,
- attribute.progress,
- attribute.ease
- );
- let y = interpolate(
- attribute.origin.y,
- attribute.target.y,
- attribute.progress,
- attribute.ease
- );
- if (attribute.currentDistance >= attribute.originalDistance) {
- x = attribute.target.x;
- y = attribute.target.y;
- attribute.done = true;
- }
- animatedAttributes["x"] = x;
- animatedAttributes["y"] = y;
- } else {
- if (attribute.name === "rotationTowards" && !attribute.from && !attribute.to) {
- let target = attribute.target;
- if (this._rotateTowards.towardsCenter)
- target = target?.center ?? target;
- let ray = new Ray(attribute.originLocation, target);
- let angle = ray.angle * 180 / Math.PI - 90;
- angle += attribute.offset;
- attribute.from = attribute.origin.rotation;
- attribute.to = angle;
- if (Math.abs(attribute.from - attribute.to) > 180) {
- if (attribute.to < 0) {
- attribute.to += 360;
- } else if (attribute.from > attribute.to) {
- attribute.from -= 360;
- }
- }
- attribute.name = "rotation";
- }
- attribute.durationDone += dt;
- attribute.progress = attribute.durationDone / attribute.duration;
- let val = interpolate(
- attribute.from,
- attribute.to,
- attribute.progress,
- attribute.ease
- );
- if (attribute.progress >= 1) {
- val = attribute.to;
- attribute.done = true;
- }
- animatedAttributes[attribute.name] = val;
- }
- }
- if (Object.keys(animatedAttributes).length > 0) {
- await this._updateObject(this._originObject, animatedAttributes);
- }
- animData.attributes = animData.attributes.filter((a) => !a.done);
- if (animData.attributes.length === 0)
- return;
- animData.lastTimespan = timespan;
- }
- }
- let self = this;
- requestAnimationFrame(function(timespan2) {
- self._animate(animData, resolve, timespan2);
- });
- }
- }
- class ScrollingTextSection extends Section {
- constructor(inSequence, target, text2, textOptions) {
- super(inSequence);
- this._deserializedData = null;
- this._source = null;
- this._text = "";
- this._duration = 2e3;
- this._distance = null;
- this._jitter = 0;
- this._anchor = null;
- this._direction = null;
- this._seed = get_hash(randomID());
- if (target) {
- this.atLocation(target);
- }
- if (text2) {
- this.text(text2, textOptions);
- }
- }
- static niceName = "Scrolling Text";
- /**
- * @private
- */
- _applyTraits() {
- Object.assign(this.constructor.prototype, traits.users);
- Object.assign(this.constructor.prototype, traits.location);
- Object.assign(this.constructor.prototype, traits.offset);
- Object.assign(this.constructor.prototype, traits.text);
- }
- direction(inDirection) {
- if (!(typeof inDirection === "string" || is_real_number(inDirection))) {
- throw this.sequence._customError(
- this,
- "direction",
- "inDirection must be of type string (CONST.TEXT_ANCHOR_POINTS) or number"
- );
- }
- if (typeof inDirection === "string" && !CONST.TEXT_ANCHOR_POINTS[inDirection]) {
- throw this.sequence._customError(
- this,
- "direction",
- `${inDirection} does not exist in CONST.TEXT_ANCHOR_POINTS!`
- );
- } else if (typeof inDirection === "string") {
- this._direction = CONST.TEXT_ANCHOR_POINTS[inDirection];
- } else {
- this._direction = inDirection;
- }
- return this;
- }
- anchor(inAnchor) {
- if (!(typeof inAnchor === "string" || is_real_number(inAnchor))) {
- throw this.sequence._customError(
- this,
- "direction",
- "inAnchor must be of type string (CONST.TEXT_ANCHOR_POINTS) or number"
- );
- }
- if (typeof inAnchor === "string" && !CONST.TEXT_ANCHOR_POINTS[inAnchor] || is_real_number(inAnchor) && !Object.values(CONST.TEXT_ANCHOR_POINTS).includes(inAnchor)) {
- throw this.sequence._customError(
- this,
- "direction",
- `${inAnchor} does not exist in CONST.TEXT_ANCHOR_POINTS!`
- );
- } else if (typeof inAnchor === "string") {
- this._anchor = CONST.TEXT_ANCHOR_POINTS[inAnchor];
- } else {
- this._anchor = inAnchor;
- }
- return this;
- }
- jitter(inJitter) {
- if (!(is_real_number(inJitter) && inJitter >= 0 && inJitter <= 1)) {
- throw this.sequence._customError(
- this,
- "jitter",
- "inJitter must be of type number between 0 and 1"
- );
- }
- this._jitter = inJitter;
- return this;
- }
- async run() {
- const data = await this._sanitizeTextData();
- if (Hooks.call("preCreateScrollingText", data) === false)
- return;
- const push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
- const duration = SequencerFoundryReplicator.playScrollingText(data, push);
- await new Promise(
- (resolve) => setTimeout(resolve, this._currentWaitTime + duration)
- );
- }
- _getSourceObject() {
- if (!this._source || typeof this._source !== "object")
- return this._source;
- return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
- }
- async _sanitizeTextData() {
- if (this._deserializedData) {
- return this._deserializedData;
- }
- return {
- sceneId: game.user.viewedScene,
- seed: this._seed,
- sequenceId: this.sequence.id,
- creatorUserId: game.userId,
- users: this._users ? Array.from(this._users) : false,
- moduleName: this.sequence.moduleName,
- source: this._getSourceObject(),
- offset: this._offset?.source ?? false,
- randomOffset: this._randomOffset?.source ?? false,
- content: this._text?.text ?? "",
- options: {
- anchor: this._anchor,
- direction: this._direction,
- duration: this._duration,
- distance: this._distance,
- jitter: this._jitter,
- ...this._text
- }
- };
- }
- async _serialize() {
- const data = await super._serialize();
- const sectionData = await this._sanitizeTextData();
- return {
- ...data,
- type: "scrollingText",
- sectionData
- };
- }
- async _deserialize(data) {
- this._deserializedData = data.sectionData;
- return super._deserialize(data);
- }
- }
- class CanvasPanSection extends Section {
- constructor(inSequence, target, duration, scale2) {
- super(inSequence);
- this._deserializedData = null;
- this._source = null;
- this._duration = duration ?? 250;
- this._speed = null;
- this._scale = scale2 ?? 1;
- this._lockView = null;
- this._shake = null;
- this._seed = get_hash(randomID());
- if (target) {
- this.atLocation(target);
- }
- }
- static niceName = "Canvas Pan";
- /**
- * @private
- */
- _applyTraits() {
- Object.assign(this.constructor.prototype, traits.users);
- Object.assign(this.constructor.prototype, traits.location);
- Object.assign(this.constructor.prototype, traits.offset);
- }
- /**
- * Sets the speed (pixels per frame) of the canvas pan
- *
- * @param {number} inSpeed
- * @returns this
- */
- speed(inSpeed) {
- if (!is_real_number(inSpeed))
- throw this.sequence._customError(
- this,
- "speed",
- "inSpeed must be of type number"
- );
- if (inSpeed < 0) {
- throw this.sequence._customError(
- this,
- "speed",
- "inSpeed must be greater or equal to 0"
- );
- }
- this._speed = inSpeed;
- return this;
- }
- /**
- * Sets the zoom level of the canvas pan
- *
- * @param {number} inScale
- * @returns this
- */
- scale(inScale) {
- if (!is_real_number(inScale))
- throw this.sequence._customError(
- this,
- "scale",
- "inScale must be of type number"
- );
- if (inScale <= 0) {
- throw this.sequence._customError(
- this,
- "scale",
- "inScale must be greater than 0"
- );
- }
- this._scale = inScale;
- return this;
- }
- /**
- * Locks the canvas at the given location for the given duration
- *
- * @param {number} inDuration
- * @returns this
- */
- lockView(inDuration) {
- if (!is_real_number(inDuration))
- throw this.sequence._customError(
- this,
- "lockView",
- "inDuration must be of type number"
- );
- if (inDuration < 0) {
- throw this.sequence._customError(
- this,
- "lockView",
- "inDuration must be greater or equal to 0"
- );
- }
- this._lockView = inDuration;
- return this;
- }
- /**
- * Shakes the canvas
- *
- * @param {number} duration
- * @param {number} strength
- * @param {number} frequency
- * @param {number} fadeInDuration
- * @param {number} fadeOutDuration
- * @param {boolean} rotation
- * @returns this
- */
- shake({
- duration = 250,
- strength = 20,
- frequency = 10,
- fadeInDuration = 0,
- fadeOutDuration = 200,
- rotation: rotation2 = true
- } = {}) {
- if (!is_real_number(duration)) {
- throw this.sequence._customError(
- this,
- "shake",
- "duration must be of type number"
- );
- }
- if (!is_real_number(strength)) {
- throw this.sequence._customError(
- this,
- "shake",
- "strength must be of type number"
- );
- }
- if (!is_real_number(strength)) {
- throw this.sequence._customError(
- this,
- "shake",
- "frequency must be of type number"
- );
- }
- if (!is_real_number(fadeInDuration)) {
- throw this.sequence._customError(
- this,
- "shake",
- "fadeInDuration must be of type number"
- );
- }
- if (!is_real_number(fadeOutDuration)) {
- throw this.sequence._customError(
- this,
- "shake",
- "fadeOutDuration must be of type number"
- );
- }
- if (typeof rotation2 !== "boolean") {
- throw this.sequence._customError(
- this,
- "shake",
- "rotation must be of type boolean"
- );
- }
- this._shake = {
- duration,
- strength,
- frequency,
- fadeInDuration,
- fadeOutDuration,
- rotation: rotation2
- };
- return this;
- }
- async run() {
- const data = await this._sanitizeData();
- if (Hooks.call("preCanvasPan", data) === false)
- return;
- const push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
- const duration = SequencerFoundryReplicator.panCanvas(data, push);
- await new Promise(
- (resolve) => setTimeout(resolve, this._currentWaitTime + duration)
- );
- }
- _getSourceObject() {
- if (!this._source || typeof this._source !== "object")
- return this._source;
- return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
- }
- async _sanitizeData() {
- if (this._deserializedData) {
- return this._deserializedData;
- }
- return {
- sceneId: game.user.viewedScene,
- seed: this._seed,
- sequenceId: this.sequence.id,
- creatorUserId: game.userId,
- users: this._users ? Array.from(this._users) : false,
- moduleName: this.sequence.moduleName,
- source: this._getSourceObject(),
- offset: this._offset?.source ?? false,
- randomOffset: this._randomOffset?.source ?? false,
- duration: this._duration,
- speed: this._speed,
- scale: this._scale,
- lockView: this._lockView,
- shake: this._shake
- };
- }
- async _serialize() {
- const data = await super._serialize();
- const sectionData = await this._sanitizeData();
- return {
- ...data,
- type: "canvasPan",
- sectionData
- };
- }
- async _deserialize(data) {
- this._deserializedData = data.sectionData;
- return super._deserialize(data);
- }
- }
- class WaitSection extends Section {
- constructor(inSequence, msMin, msMax) {
- super(inSequence);
- this._waitUntilFinished = true;
- this._waitDuration = random_int_between(msMin, Math.max(msMin, msMax));
- }
- static niceName = "Wait";
- /**
- * @returns {Promise<void>}
- */
- async run() {
- debug("Running wait");
- await new Promise(async (resolve) => {
- setTimeout(resolve, this._waitDuration);
- });
- }
- /**
- * @returns {Promise}
- * @private
- */
- async _execute() {
- await this.run();
- }
- async _serialize() {
- const data = await super._serialize();
- return {
- ...data,
- type: "wait",
- sectionData: {
- waitDuration: this._waitDuration
- }
- };
- }
- async _deserialize(data) {
- this._waitDuration = data.sectionData.waitDuration;
- return super._deserialize(data);
- }
- }
- let Sequence$1 = class Sequence3 {
- constructor(options = {
- moduleName: "Sequencer",
- softFail: false
- }, softFail = false) {
- this.id = randomID();
- this.moduleName = typeof options === "string" ? options : options?.moduleName ?? "Sequencer";
- this.softFail = options?.softFail ?? softFail;
- this.sections = [];
- this.nameOffsetMap = false;
- this.effectIndex = 0;
- this.sectionToCreate = void 0;
- this.localOnly = false;
- this._status = writable$1(CONSTANTS.STATUS.READY);
- return sequence_proxy_wrap(this);
- }
- /**
- * Plays all of this sequence's sections
- *
- * @returns {Promise}
- */
- async play({ remote = false } = {}) {
- if (remote) {
- this.localOnly = true;
- const data = await this.toJSON();
- sequencerSocket.executeForOthers(
- SOCKET_HANDLERS.RUN_SEQUENCE_LOCALLY,
- data
- );
- return new Sequence3().fromJSON(data).play();
- }
- Hooks.callAll("createSequencerSequence", this);
- debug("Initializing sections");
- for (let section of this.sections) {
- await section._initialize();
- }
- SequenceManager.RunningSequences.add(this.id, this);
- this.effectIndex = 0;
- debug("Playing sections");
- this.status = CONSTANTS.STATUS.RUNNING;
- const promises = [];
- for (let section of this.sections) {
- if (section instanceof EffectSection)
- this.effectIndex++;
- if (section.shouldWaitUntilFinished) {
- promises.push(await section._execute());
- } else {
- promises.push(section._execute());
- }
- if (get_store_value(this.status) === CONSTANTS.STATUS.ABORTED) {
- continue;
- }
- if (!section._isLastSection) {
- await new Promise((resolve) => setTimeout(resolve, 1));
- }
- }
- return Promise.allSettled(promises).then(() => {
- Hooks.callAll("endedSequencerSequence");
- debug("Finished playing sections");
- this.status = CONSTANTS.STATUS.COMPLETE;
- });
- }
- /**
- * Creates a section that will run a function.
- *
- * @param {function} inFunc
- * @returns {Sequence} this
- */
- thenDo(inFunc) {
- const func2 = section_proxy_wrap(new FunctionSection(this, inFunc));
- this.sections.push(func2);
- return func2;
- }
- /**
- * Creates a section that will run a macro based on a name or a direct reference to a macro.
- *
- * @param {string|Macro} inMacro
- * @param {object} args
- * @returns {Sequence} this
- */
- macro(inMacro, ...args) {
- let macro;
- let compendium = false;
- if (typeof inMacro === "string") {
- if (inMacro.startsWith("Compendium")) {
- let packArray = inMacro.split(".");
- let pack = game.packs.get(`${packArray[1]}.${packArray[2]}`);
- if (!pack) {
- if (this.softFail) {
- return this;
- }
- throw custom_error(
- this.moduleName,
- `macro - Compendium '${packArray[1]}.${packArray[2]}' was not found`
- );
- }
- macro = packArray;
- compendium = pack;
- } else {
- macro = game.macros.getName(inMacro);
- if (!macro) {
- if (this.softFail) {
- return this;
- }
- throw custom_error(
- this.moduleName,
- `macro - Macro '${inMacro}' was not found`
- );
- }
- }
- } else if (inMacro instanceof Macro) {
- macro = inMacro;
- } else {
- throw custom_error(
- this.moduleName,
- `macro - inMacro must be of instance string or Macro`
- );
- }
- if (isNewerVersion(game.version, "11")) {
- args = args.length ? args?.[0] : {};
- if (typeof args !== "object") {
- throw custom_error(
- this.moduleName,
- `macro - Secondary argument must be an object`
- );
- }
- } else if (args && args.length && !game.modules.get("advanced-macros")?.active) {
- custom_warning(
- this.moduleName,
- `macro - Supplying macros with arguments require the advanced-macros module to be active`,
- true
- );
- }
- const func2 = section_proxy_wrap(
- new FunctionSection(
- this,
- async () => {
- if (compendium) {
- const macroData = (await compendium.getDocuments()).find((i) => i.name === macro[3])?.toObject();
- if (!macroData) {
- if (this.softFail) {
- return;
- }
- throw custom_error(
- this.moduleName,
- `macro - Macro '${macro[3]}' was not found in compendium '${macro[1]}.${macro[2]}'`
- );
- }
- macro = new Macro(macroData);
- macro.ownership.default = CONST.DOCUMENT_PERMISSION_LEVELS.OWNER;
- }
- if (isNewerVersion(game.version, "11")) {
- await macro.execute(args);
- } else {
- const version = game.modules.get("advanced-macros")?.version;
- const bugAdvancedMacros = game.modules.get("advanced-macros")?.active && isNewerVersion(
- version.startsWith("v") ? version.slice(1) : version,
- "1.18.2"
- ) && !isNewerVersion(
- version.startsWith("v") ? version.slice(1) : version,
- "1.19.1"
- );
- if (bugAdvancedMacros) {
- await macro.execute([...args]);
- } else {
- await macro.execute(...args);
- }
- }
- },
- true
- )
- );
- this.sections.push(func2);
- return this;
- }
- /**
- * Creates an effect section. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Effect section.
- *
- * @param {string} [inFile] inFile
- * @returns {Section}
- */
- effect(inFile = "") {
- const effect = section_proxy_wrap(new EffectSection(this, inFile));
- this.sections.push(effect);
- return effect;
- }
- /**
- * Creates a sound section. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Sound section.
- *
- * @param {string} [inFile] inFile
- * @returns {Section}
- */
- sound(inFile = "") {
- const sound = section_proxy_wrap(new SoundSection(this, inFile));
- this.sections.push(sound);
- return sound;
- }
- /**
- * Creates an animation. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Animation section.
- *
- * @param {Token|Tile} [inTarget=false] inTarget
- * @returns {AnimationSection}
- */
- animation(inTarget) {
- const animation2 = section_proxy_wrap(
- new AnimationSection(this, inTarget)
- );
- this.sections.push(animation2);
- return animation2;
- }
- /**
- * Creates a scrolling text. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Scrolling Text section.
- *
- * @param {Object|String|Boolean} [inTarget=false] inTarget
- * @param {String|Boolean} [inText=false] inText
- * @param {Object} [inTextOptions={}] inTextOptions
- * @returns {AnimationSection}
- */
- scrollingText(inTarget = false, inText = false, inTextOptions = {}) {
- const scrolling = section_proxy_wrap(
- new ScrollingTextSection(this, inTarget, inText, inTextOptions)
- );
- this.sections.push(scrolling);
- return scrolling;
- }
- /**
- * Pans the canvas text. Until you call any other sections you'll be working on the Canvas Pan section.
- *
- * @param {Object|String|Boolean} [inTarget=false] inTarget
- * @param {Boolean|Number} inDuration
- * @param {Boolean|Number} inSpeed
- * @returns {AnimationSection}
- */
- canvasPan(inTarget = false, inDuration = null, inSpeed = null) {
- const panning = section_proxy_wrap(
- new CanvasPanSection(this, inTarget)
- );
- this.sections.push(panning);
- return panning;
- }
- /**
- * Causes the sequence to wait after the last section for as many milliseconds as you pass to this method. If given
- * a second number, a random wait time between the two given numbers will be generated.
- *
- * @param {number} [msMin=1] minMs
- * @param {number} [msMax=1] maxMs
- * @returns {Sequence} this
- */
- wait(msMin = 1, msMax = 1) {
- if (msMin < 1)
- throw custom_error(
- this.moduleName,
- `wait - Wait ms cannot be less than 1`
- );
- if (msMax < 1)
- throw custom_error(
- this.moduleName,
- `wait - Max wait ms cannot be less than 1`
- );
- const section = section_proxy_wrap(new WaitSection(this, msMin, msMax));
- this.sections.push(section);
- return this;
- }
- /**
- * Applies a preset to the sequence
- *
- * @param {string} presetName
- * @param {*} args
- * @returns {Sequence|FunctionSection|EffectSection|AnimationSection|SoundSection}
- */
- preset(presetName, ...args) {
- if (typeof presetName !== "string") {
- throw this._customError(this, "name", `inName must be of type string`);
- }
- const preset = SequencerPresets.get(presetName);
- if (!preset) {
- custom_warning(
- "Sequencer",
- `preset | Could not find preset with name "${presetName}"`
- );
- return this;
- }
- const lastSection = this.sections[this.sections.length - 1];
- return preset(lastSection, ...args);
- }
- /**
- * Adds the sections from a given Sequence to this Sequence
- *
- * @param {Sequence|FunctionSection|EffectSection|AnimationSection|SoundSection} inSequence
- * @returns {Sequence} this
- */
- addSequence(inSequence) {
- if (inSequence instanceof Section)
- inSequence = inSequence.sequence;
- if (!(inSequence instanceof Sequence3)) {
- throw custom_error(
- this.moduleName,
- `addSequence - could not find the sequence from the given parameter`
- );
- }
- const newSections = inSequence.sections.map((section) => {
- const newSection = Object.assign(
- Object.create(Object.getPrototypeOf(section)),
- section
- );
- newSection.sequence = this;
- return newSection;
- });
- this.sections = this.sections.concat(newSections);
- return this;
- }
- async toJSON() {
- const data = {
- options: { moduleName: this.moduleName, softFail: this.softFail },
- sections: []
- };
- for (const section of this.sections) {
- const sectionData = await section._serialize();
- if (!sectionData.type) {
- throw new Error(
- `Sequencer | toJson | ${section.constructor.name} does not support serialization!`
- );
- }
- data.sections.push(sectionData);
- }
- return data;
- }
- fromJSON(data) {
- this.moduleName = data.options.moduleName;
- this.softFail = data.options.softFail;
- this.localOnly = true;
- for (const section of data.sections) {
- this[section.type]()._deserialize(section);
- }
- return this;
- }
- _createCustomSection(...args) {
- const func2 = section_proxy_wrap(
- new this.sectionToCreate(this, ...args)
- );
- this.sectionToCreate = void 0;
- this.sections.push(func2);
- return func2;
- }
- _showWarning(self, func2, warning, notify) {
- custom_warning(
- this.moduleName,
- `${self.constructor.name.replace("Section", "")} | ${func2} - ${warning}`,
- notify
- );
- }
- _customError(self, func2, error) {
- return custom_error(
- this.moduleName,
- `${self.constructor.name.replace("Section", "")} | ${func2} - ${error}`
- );
- }
- set status(inStatus) {
- this._status.update((currentStatus) => {
- if (currentStatus === CONSTANTS.STATUS.READY || currentStatus === CONSTANTS.STATUS.RUNNING) {
- return inStatus;
- }
- return currentStatus;
- });
- }
- get status() {
- return this._status;
- }
- _abort() {
- this.status = CONSTANTS.STATUS.ABORTED;
- for (const section of this.sections) {
- section._abortSection();
- }
- }
- };
- const SequencerPreloader = {
- _usersToRespond: /* @__PURE__ */ new Set(),
- _clientsDone: [],
- _resolve: () => {
- },
- /**
- * Caches provided file(s) locally, vastly improving loading speed of those files.
- *
- * @param {Array|String} inSrcs
- * @param {Boolean} showProgressBar
- * @returns {Promise<void>}
- */
- preload(inSrcs, showProgressBar = false) {
- if (Array.isArray(inSrcs)) {
- inSrcs.forEach((str) => {
- if (typeof str !== "string") {
- throw custom_error(
- "Sequencer",
- "preload | each entry in inSrcs must be of type string"
- );
- }
- });
- } else if (typeof inSrcs !== "string") {
- throw custom_error(
- "Sequencer",
- "preload | inSrcs must be of type string or array of strings"
- );
- }
- if (typeof showProgressBar !== "boolean") {
- throw custom_error(
- "Sequencer",
- "preload | showProgressBar must be of type of boolean"
- );
- }
- const srcs = this._cleanSrcs(inSrcs);
- if (srcs.length === 0)
- return;
- return this._preloadLocal(srcs, showProgressBar);
- },
- /**
- * Causes each connected client (including the caller) to fetch and cache the provided file(s) locally, vastly
- * improving loading speed of those files.
- *
- * @param {Array|String} inSrcs
- * @param {Boolean} showProgressBar
- * @returns {Promise<void>}
- */
- preloadForClients(inSrcs, showProgressBar = false) {
- if (Array.isArray(inSrcs)) {
- inSrcs.forEach((str) => {
- if (typeof str !== "string") {
- throw custom_error(
- "Sequencer",
- "preloadForClients | each entry in inSrcs must be of type string"
- );
- }
- });
- } else if (typeof inSrcs !== "string") {
- throw custom_error(
- "Sequencer",
- "preloadForClients | inSrcs must be of type string or array of strings"
- );
- }
- if (typeof showProgressBar !== "boolean") {
- throw custom_error(
- "Sequencer",
- "preloadForClients | showProgressBar must be of type of boolean"
- );
- }
- const srcs = this._cleanSrcs(inSrcs);
- if (srcs.length === 0)
- return;
- if (!user_can_do("permissions-preload")) {
- custom_warning(
- "Sequencer",
- "preloadForClients - You do not have permission to force other clients to preload. Preloading locally instead."
- );
- return this._preloadLocal(srcs, showProgressBar);
- }
- const promise2 = new Promise((resolve) => {
- this._resolve = resolve;
- });
- this._usersToRespond = new Set(
- game.users.filter((user) => user.active).map((user) => user.id)
- );
- sequencerSocket.executeForEveryone(
- SOCKET_HANDLERS.PRELOAD,
- game.user.id,
- srcs,
- showProgressBar
- );
- return promise2;
- },
- async respond(inSenderId, inSrcs, showProgressBar) {
- const numFilesFailedToLoad = await this._preloadLocal(
- inSrcs,
- showProgressBar
- );
- return sequencerSocket.executeAsUser(
- SOCKET_HANDLERS.PRELOAD_RESPONSE,
- inSenderId,
- game.user.id,
- numFilesFailedToLoad
- );
- },
- handleResponse(inUserId, numFilesFailedToLoad) {
- this._usersToRespond.delete(inUserId);
- this._clientsDone.push({
- userId: inUserId,
- numFilesFailedToLoad
- });
- if (this._usersToRespond.size > 0)
- return;
- this._clientsDone.forEach((user) => {
- if (user.numFilesFailedToLoad > 0) {
- debug(
- `${game.users.get(user.userId).name} preloaded files, failed to preload ${user.numFilesFailedToLoad} files`
- );
- } else {
- debug(
- `${game.users.get(user.userId).name} preloaded files successfully`
- );
- }
- });
- debug(`All clients responded to file preloads`);
- this._resolve();
- this._usersToRespond = /* @__PURE__ */ new Set();
- this._clientsDone = [];
- this._resolve = () => {
- };
- },
- /**
- * Filters and cleans up file paths given to the preload methods
- *
- * @private
- */
- _cleanSrcs(inSrcs) {
- if (!Array.isArray(inSrcs)) {
- inSrcs = [inSrcs];
- }
- if (inSrcs.length === 0) {
- custom_warning("Sequencer", "You need to provide files to preload");
- return [];
- }
- inSrcs = make_array_unique(
- inSrcs.filter(Boolean).map((src) => {
- if (Sequencer.Database.entryExists(src)) {
- return Sequencer.Database.getAllFileEntries(src);
- }
- return src;
- })
- ).deepFlatten();
- if (inSrcs.length >= 750) {
- custom_warning(
- "Sequencer",
- "You are preloading over 750 files, you are most likely preloading more files than the system can cache.",
- true
- );
- }
- return inSrcs;
- },
- /**
- * The method that actually preloads files locally, with an optional progress bar
- *
- * @private
- */
- _preloadLocal(inSrcs, showProgressBar) {
- let startTime = performance.now();
- let numFilesToLoad = inSrcs.length;
- debug(`Preloading ${numFilesToLoad} files...`);
- if (showProgressBar)
- LoadingBar.init(
- `Sequencer - Preloading ${numFilesToLoad} files`,
- numFilesToLoad
- );
- return new Promise(async (resolve) => {
- let numFilesFailedToLoad = 0;
- for (let src of inSrcs) {
- const blob = await SequencerFileCache.loadFile(src, true);
- if (showProgressBar)
- LoadingBar.incrementProgress();
- if (!blob) {
- numFilesFailedToLoad++;
- }
- }
- const timeTaken = (performance.now() - startTime) / 1e3;
- let failedToLoad = ` (${numFilesFailedToLoad} failed to load)`;
- debug(
- `Preloading ${numFilesToLoad} files took ${timeTaken}s` + failedToLoad
- );
- resolve(numFilesFailedToLoad);
- });
- }
- };
- class SequencerSectionManager {
- constructor() {
- this.externalSections = {};
- }
- /**
- * Registers a class by a name that will then be available through the Sequencer
- *
- * @param {String} inModuleName
- * @param {String} inMethodName
- * @param {Class} inClass
- * @param {Boolean} overwrite
- * @returns {Boolean} Whether the registration succeeded
- */
- registerSection(inModuleName, inMethodName, inClass, overwrite = false) {
- if (!(inClass.prototype instanceof Section)) {
- throw custom_error(
- inModuleName,
- `inClass must be instance of Sequencer.BaseSection`
- );
- }
- let coreMethods = Object.getOwnPropertyNames(Sequence.prototype).filter(
- (method) => {
- return !method.startsWith("_") && method !== "constructor";
- }
- );
- if (coreMethods.includes(inMethodName)) {
- throw custom_error(
- inModuleName,
- `${inMethodName} is an existing protected method of the Sequence class - please register with another method name!`
- );
- }
- if (this.externalSections[inMethodName] && !overwrite) {
- throw custom_error(
- inModuleName,
- `${inMethodName} is already a registered Section with the class ${this.externalSections[inMethodName].constructor.name}`
- );
- }
- coreMethods = coreMethods.concat(Object.keys(this.externalSections));
- const clashingMethods = Object.getOwnPropertyNames(
- inClass.prototype
- ).filter((method) => coreMethods.includes(method));
- if (clashingMethods.length) {
- let errors = clashingMethods.join(", ");
- throw custom_error(
- inModuleName,
- `${inMethodName} cannot contain the following methods: ${errors}<br>These methods are existing methods on the Sequence or from already registered Sections. Please rename these methods to avoid conflicts.`
- );
- }
- debug(
- `SectionManager | Successfully registered ${inMethodName} with Sequencer!`
- );
- this.externalSections[inMethodName] = inClass;
- return true;
- }
- }
- let libWrapper = void 0;
- const TGT_SPLIT_RE = new RegExp(
- `([^.[]+|\\[('([^'\\\\]|\\\\.)+?'|"([^"\\\\]|\\\\.)+?")\\])`,
- "g"
- );
- const TGT_CLEANUP_RE = new RegExp(`(^\\['|'\\]$|^\\["|"\\]$)`, "g");
- Hooks.once("init", () => {
- if (globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
- libWrapper = globalThis.libWrapper;
- return;
- }
- libWrapper = class {
- static get is_fallback() {
- return true;
- }
- static get WRAPPER() {
- return "WRAPPER";
- }
- static get MIXED() {
- return "MIXED";
- }
- static get OVERRIDE() {
- return "OVERRIDE";
- }
- static register(package_id, target, fn, type = "MIXED", { chain = void 0, bind: bind2 = [] } = {}) {
- const is_setter = target.endsWith("#set");
- target = !is_setter ? target : target.slice(0, -4);
- const split = target.match(TGT_SPLIT_RE).map((x) => x.replace(/\\(.)/g, "$1").replace(TGT_CLEANUP_RE, ""));
- const root_nm = split.splice(0, 1)[0];
- let obj, fn_name;
- if (split.length == 0) {
- obj = globalThis;
- fn_name = root_nm;
- } else {
- const _eval = eval;
- fn_name = split.pop();
- obj = split.reduce(
- (x, y) => x[y],
- globalThis[root_nm] ?? _eval(root_nm)
- );
- }
- let iObj = obj;
- let descriptor = null;
- while (iObj) {
- descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
- if (descriptor)
- break;
- iObj = Object.getPrototypeOf(iObj);
- }
- if (!descriptor || descriptor?.configurable === false)
- throw new Error(
- `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`
- );
- let original = null;
- const wrapper = chain ?? (type.toUpperCase?.() != "OVERRIDE" && type != 3) ? function(...args) {
- return fn.call(this, original.bind(this), ...bind2, ...args);
- } : function(...args) {
- return fn.call(this, ...bind2, ...args);
- };
- if (!is_setter) {
- if (descriptor.value) {
- original = descriptor.value;
- descriptor.value = wrapper;
- } else {
- original = descriptor.get;
- descriptor.get = wrapper;
- }
- } else {
- if (!descriptor.set)
- throw new Error(
- `libWrapper Shim: '${target}' does not have a setter`
- );
- original = descriptor.set;
- descriptor.set = wrapper;
- }
- descriptor.configurable = true;
- Object.defineProperty(obj, fn_name, descriptor);
- }
- };
- });
- function registerLibwrappers() {
- const override = isNewerVersion(game.version, "11") ? "PIXI.BaseImageResource.prototype.upload" : "PIXI.resources.BaseImageResource.prototype.upload";
- libWrapper.register(CONSTANTS.MODULE_NAME, override, PIXIUPLOAD);
- }
- function PIXIUPLOAD(wrapped, ...args) {
- let baseTexture = args[1];
- if (baseTexture.sequencer_patched || !game.settings.get(CONSTANTS.MODULE_NAME, "enable-global-fix-pixi")) {
- return wrapped(...args);
- }
- let source = args[3];
- source = source || this.source;
- const isVideo = !!source.videoWidth;
- if (isVideo) {
- baseTexture.alphaMode = PIXI.ALPHA_MODES.PREMULTIPLIED_ALPHA;
- baseTexture.sequencer_patched = true;
- }
- return wrapped(...args);
- }
- async function runMigrations() {
- const sortedMigrations = Object.entries(migrations).sort((a, b) => {
- return isNewerVersion(b[0], a[0]) ? -1 : 1;
- });
- for (const [version, migration] of sortedMigrations) {
- try {
- await migration(version);
- } catch (err) {
- custom_warning(
- "Sequencer",
- `Something went wrong when migrating to version ${version}. Please check the console for the error!`,
- true
- );
- console.error(err);
- }
- }
- }
- function getSequencerEffectTokens(version, tokenFilter = false) {
- return Array.from(game.scenes).map((scene) => [
- scene,
- Array.from(scene.tokens).filter((token) => token.isOwner).filter((token, index) => {
- if (tokenFilter) {
- return tokenFilter(token, index);
- }
- const effects = getProperty(token, CONSTANTS.EFFECTS_FLAG) ?? [];
- const effectsOutOfDate = effects.filter(
- (e) => isNewerVersion(version, e[1].flagVersion)
- );
- return effectsOutOfDate.length;
- })
- ]).filter(([_, tokens]) => tokens.length);
- }
- function getSequencerEffectActors(version, actorFilter = false) {
- return Array.from(game.actors).filter((actor) => actor.isOwner).filter((actor, index) => {
- if (actorFilter) {
- return actorFilter(actor, index);
- }
- const effects = getProperty(actor, CONSTANTS.EFFECTS_FLAG) ?? [];
- const effectsOutOfDate = effects.filter(
- (e) => isNewerVersion(version, e[1].flagVersion)
- );
- return effectsOutOfDate.length;
- });
- }
- const migrations = {
- "3.0.0": async (version) => {
- const actorsToUpdate = getSequencerEffectActors(version, (actor) => {
- const effects = getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
- const effectsOutOfDate = effects.filter(
- (e) => isNewerVersion(version, e[1].flagVersion)
- );
- return effectsOutOfDate.length;
- });
- const actorUpdateArray = actorsToUpdate.map((actor) => {
- const effectsToMoveFromTokenPrototype = getProperty(
- actor.prototypeToken,
- CONSTANTS.EFFECTS_FLAG
- ).filter(([_, effect]) => {
- return effect.persistOptions?.persistTokenPrototype;
- }).map(([id, effect]) => {
- effect.flagVersion = version;
- return [id, effect];
- });
- const effectsToKeepOnTokenPrototype = getProperty(
- actor.prototypeToken,
- CONSTANTS.EFFECTS_FLAG
- ).filter(([_, effect]) => {
- return !effect.persistOptions?.persistTokenPrototype;
- }).map(([id, effect]) => {
- effect.flagVersion = version;
- return [id, effect];
- });
- return {
- _id: actor.id,
- [CONSTANTS.EFFECTS_FLAG]: effectsToMoveFromTokenPrototype,
- ["prototypeToken." + CONSTANTS.EFFECTS_FLAG]: effectsToKeepOnTokenPrototype
- };
- });
- const tokensOnScenes = getSequencerEffectTokens(version, (t) => {
- let actor;
- try {
- actor = t.actor;
- } catch (err) {
- return false;
- }
- const effects = getProperty(t, CONSTANTS.EFFECTS_FLAG) ?? [];
- const prototypeTokenEffects = getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
- const effectsOutOfDate = effects.filter(
- (e) => isNewerVersion(version, e[1].flagVersion)
- );
- const prototypeEffectsOutOfDate = prototypeTokenEffects.filter(
- (e) => isNewerVersion(version, e[1].flagVersion)
- );
- return t.actorLink && (effectsOutOfDate.length || prototypeEffectsOutOfDate.length);
- });
- for (const [scene, tokens] of tokensOnScenes) {
- const updates = [];
- for (const token of tokens) {
- const effectsToKeepOnToken = getProperty(token, CONSTANTS.EFFECTS_FLAG).filter(([_, effect]) => {
- return !effect.persistOptions?.persistTokenPrototype;
- }).map(([id, effect]) => {
- effect.flagVersion = version;
- return [id, effect];
- });
- updates.push({
- _id: token.id,
- [CONSTANTS.EFFECTS_FLAG]: effectsToKeepOnToken
- });
- }
- if (updates.length) {
- debug(
- `Sequencer | Updated ${updates.length} tokens' effects on scene ${scene.id} to version ${version}`
- );
- await scene.updateEmbeddedDocuments("Token", updates);
- }
- }
- if (actorUpdateArray.length) {
- debug(
- `Sequencer | Updated ${actorUpdateArray.length} actors' effects to version ${version}`
- );
- await Actor.updateDocuments(actorUpdateArray);
- }
- }
- };
- let moduleValid = false;
- let moduleReady = false;
- let canvasReady = false;
- Hooks.once("init", async function() {
- if (!game.modules.get("socketlib")?.active)
- return;
- moduleValid = true;
- CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE = false;
- initializeModule();
- registerSocket();
- });
- Hooks.once("socketlib.ready", registerSocket);
- Hooks.once("ready", async function() {
- if (!game.modules.get("socketlib")?.active) {
- ui.notifications.error(
- "Sequencer requires the SocketLib module to be active and will not work without it!",
- { console: true }
- );
- return;
- }
- for (const [name, func2] of Object.entries(easeFunctions)) {
- if (!CanvasAnimation[name]) {
- CanvasAnimation[name] = func2;
- }
- }
- if (game.user.isGM) {
- await runMigrations();
- await migrateSettings();
- await PlayerSettings.migrateOldPresets();
- }
- SequencerFoundryReplicator.registerHooks();
- InteractionManager.initialize();
- });
- Hooks.on("canvasTearDown", () => {
- canvasReady = false;
- SequencerEffectManager.tearDownPersists();
- });
- const setupModule = debounce(() => {
- if (!moduleValid)
- return;
- if (!moduleReady) {
- moduleReady = true;
- debug("Ready to go!");
- Hooks.callAll("sequencer.ready");
- Hooks.callAll("sequencerReady");
- }
- if (!canvasReady) {
- canvasReady = true;
- SequencerEffectManager.initializePersistentEffects();
- }
- }, 25);
- Hooks.on("canvasReady", () => {
- setTimeout(() => {
- setupModule();
- }, 450);
- });
- Hooks.on("refreshToken", setupModule);
- Hooks.on("refreshDrawing", setupModule);
- Hooks.on("refreshTile", setupModule);
- Hooks.on("refreshMeasuredTemplate", setupModule);
- function initializeModule() {
- window.Sequence = Sequence$1;
- window.Sequencer = {
- Player: EffectPlayer,
- Presets: SequencerPresets,
- Database: SequencerDatabase,
- DatabaseViewer: DatabaseViewerApp,
- Preloader: SequencerPreloader,
- EffectManager: SequencerEffectManager,
- SectionManager: new SequencerSectionManager(),
- registerEase,
- BaseSection: Section,
- CONSTANTS: {
- EASE
- },
- Helpers: {
- wait: wait$1,
- clamp,
- interpolate,
- random_float_between,
- random_int_between,
- shuffle_array,
- random_array_element,
- random_object_element,
- make_array_unique
- }
- };
- registerSettings();
- registerLayers();
- registerHotkeys();
- registerLibwrappers();
- SequencerAboveUILayer.setup();
- SequencerEffectManager.setup();
- }
- Hooks.once("monaco-editor.ready", registerTypes);
- //# sourceMappingURL=module.js.map
|