|
|
- import { __classPrivateFieldSet, __classPrivateFieldGet, Fuse, SvelteComponent, init, safe_not_equal, empty, insert, noop, detach, createEventDispatcher, afterUpdate, element, attr, update_keyed_each, space, text, toggle_class, append, listen, set_data, destroy_each, run_all, binding_callbacks, destroy_block, stop_propagation, src_url_equal, HtmlTag } from './vendor.js';
-
- const MODULE_NAME = "quick-insert";
- function registerSetting(setting, callback, { ...options }) {
- game.settings.register(MODULE_NAME, setting, {
- config: true,
- scope: "client",
- ...options,
- onChange: callback || undefined,
- });
- }
- function getSetting(setting) {
- return game.settings.get(MODULE_NAME, setting);
- }
- function setSetting(setting, value) {
- return game.settings.set(MODULE_NAME, setting, value);
- }
- function registerMenu({ menu, ...options }) {
- game.settings.registerMenu(MODULE_NAME, menu, options);
- }
-
- const SAVE_SETTINGS_REVISION = 1;
- var ModuleSetting;
- (function (ModuleSetting) {
- // QUICKOPEN = "quickOpen", // dead setting
- ModuleSetting["ENABLE_GLOBAL_CONTEXT"] = "enableGlobalContext";
- ModuleSetting["INDEXING_DISABLED"] = "indexingDisabled";
- ModuleSetting["FILTERS_CLIENT"] = "filtersClient";
- ModuleSetting["FILTERS_WORLD"] = "filtersWorld";
- ModuleSetting["FILTERS_SHEETS"] = "filtersSheets";
- ModuleSetting["FILTERS_SHEETS_ENABLED"] = "filtersSheetsEnabled";
- ModuleSetting["GM_ONLY"] = "gmOnly";
- ModuleSetting["AUTOMATIC_INDEXING"] = "automaticIndexing";
- ModuleSetting["INDEX_TIMEOUT"] = "indexTimeout";
- ModuleSetting["SEARCH_BUTTON"] = "searchButton";
- ModuleSetting["KEY_BIND"] = "keyBind";
- ModuleSetting["DEFAULT_ACTION_SCENE"] = "defaultSceneAction";
- ModuleSetting["DEFAULT_ACTION_ROLL_TABLE"] = "defaultActionRollTable";
- ModuleSetting["DEFAULT_ACTION_MACRO"] = "defaultActionMacro";
- ModuleSetting["SEARCH_TOOLTIPS"] = "searchTooltips";
- ModuleSetting["EMBEDDED_INDEXING"] = "embeddedIndexing";
- })(ModuleSetting || (ModuleSetting = {}));
-
- const i18n = (name, replacements) => {
- let namespace = "QUICKINSERT";
- if (name.includes(".")) {
- [namespace, name] = name.split(".", 2);
- }
- if (replacements) {
- return game.i18n.format(`${namespace}.${name}`, replacements);
- }
- return game.i18n.localize(`${namespace}.${name}`);
- };
- function isTextInputElement(element) {
- return (element.tagName == "TEXTAREA" ||
- (element.tagName == "INPUT" && element.type == "text"));
- }
- // General utils
- const ALPHA = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- function randomId(idLength = 10) {
- const values = new Uint8Array(idLength);
- window.crypto.getRandomValues(values);
- return String.fromCharCode(...values.map((x) => ALPHA.charCodeAt(x % ALPHA.length)));
- }
- // Some black magic from the internet,
- // places caret at end of contenteditable
- function placeCaretAtEnd(el) {
- if (!el)
- return;
- el.focus();
- const range = document.createRange();
- range.selectNodeContents(el);
- range.collapse(false);
- const sel = window.getSelection();
- sel?.removeAllRanges();
- sel?.addRange(range);
- }
- // Simple utility function for async waiting
- // Nicer to await waitFor(100) than nesting setTimeout callback hell
- function resolveAfter(msec) {
- return new Promise((res) => setTimeout(res, msec));
- }
- class TimeoutError extends Error {
- constructor(timeoutMsec) {
- super(`did not complete within ${timeoutMsec}ms`);
- }
- }
- function withDeadline(p, timeoutMsec) {
- return Promise.race([
- p,
- new Promise((res, rej) => setTimeout(() => rej(new TimeoutError(timeoutMsec)), timeoutMsec)),
- ]);
- }
- function permissionListEq(a, b) {
- return a.length === b.length && [...a].every((value) => b.includes(value));
- }
- // Match keybinds even if it's in input fields or with explicit context
- function customKeybindHandler(evt, context) {
- if (evt.isComposing || (!evt.key && !evt.code)) {
- return;
- }
- if (!context && !game.keyboard?.hasFocus)
- return;
- const ctx = KeyboardManager.getKeyboardEventContext(evt, false);
- if (ctx.event.target?.dataset?.engine === "prosemirror") {
- return;
- }
- if (context) {
- ctx._quick_insert_extra = { context };
- }
- //@ts-expect-error using private, I know
- const actions = KeyboardManager._getMatchingActions(ctx)
- .map((action) => game.keybindings.actions.get(action.action))
- .filter((action) => action?.textInput);
- if (!actions.length)
- return;
- let handled = false;
- for (const action of actions) {
- //@ts-expect-error using private, I know
- handled = KeyboardManager._executeKeybind(action, ctx);
- if (handled)
- break;
- }
- if (handled) {
- evt.preventDefault();
- evt.stopPropagation();
- }
- }
-
- var _EmbeddedEntitySearchItem_tagline, _EmbeddedCompendiumSearchItem_tagline;
- var DocumentType;
- (function (DocumentType) {
- DocumentType["ACTOR"] = "Actor";
- DocumentType["ITEM"] = "Item";
- DocumentType["JOURNALENTRY"] = "JournalEntry";
- DocumentType["MACRO"] = "Macro";
- DocumentType["ROLLTABLE"] = "RollTable";
- DocumentType["SCENE"] = "Scene";
- })(DocumentType || (DocumentType = {}));
- const IndexedDocumentTypes = [
- DocumentType.ACTOR,
- DocumentType.ITEM,
- DocumentType.JOURNALENTRY,
- DocumentType.MACRO,
- DocumentType.ROLLTABLE,
- DocumentType.SCENE,
- ];
- const EmbeddedDocumentTypes = {
- [DocumentType.JOURNALENTRY]: "JournalEntryPage",
- };
- const EmbeddedDocumentCollections = {
- [DocumentType.JOURNALENTRY]: "pages",
- };
- const DocumentMeta = {
- [DocumentType.ACTOR]: CONFIG.Actor.documentClass.metadata,
- [DocumentType.ITEM]: CONFIG.Item.documentClass.metadata,
- [DocumentType.JOURNALENTRY]: CONFIG.JournalEntry.documentClass.metadata,
- [DocumentType.MACRO]: CONFIG.Macro.documentClass.metadata,
- [DocumentType.ROLLTABLE]: CONFIG.RollTable.documentClass.metadata,
- [DocumentType.SCENE]: CONFIG.Scene.documentClass.metadata,
- };
- const documentIcons = {
- [DocumentType.ACTOR]: "fa-user",
- [DocumentType.ITEM]: "fa-suitcase",
- [DocumentType.JOURNALENTRY]: "fa-book-open",
- [DocumentType.MACRO]: "fa-terminal",
- [DocumentType.ROLLTABLE]: "fa-th-list",
- [DocumentType.SCENE]: "fa-map",
- };
- function extractEmbeddedIndex(item, pack) {
- if (!("pages" in item))
- return;
- if (pack && item.pages.name) {
- return item.pages.name.map((name, i) => new EmbeddedCompendiumSearchItem(pack, {
- _id: item.pages._id[i],
- parentName: item.name,
- embeddedName: name,
- parentId: item._id,
- type: "JournalEntryPage",
- tagline: `Pg. ${i} - ${pack?.metadata?.label || pack.title}`,
- }));
- }
- // TODO: Index directory
- }
- function getCollectionFromType(type) {
- //@ts-expect-error not documented
- return CONFIG[type].collection.instance;
- }
- const ignoredFolderNames = { _fql_quests: true };
- function enabledDocumentTypes() {
- const disabled = getSetting(ModuleSetting.INDEXING_DISABLED);
- return IndexedDocumentTypes.filter((t) => !disabled?.entities?.[t]?.includes(game.user?.role));
- }
- function enabledEmbeddedDocumentTypes() {
- if (enabledDocumentTypes().includes(DocumentType.JOURNALENTRY) &&
- getSetting(ModuleSetting.EMBEDDED_INDEXING)) {
- return [EmbeddedDocumentTypes[DocumentType.JOURNALENTRY]];
- }
- return [];
- }
- function packEnabled(pack) {
- const disabled = getSetting(ModuleSetting.INDEXING_DISABLED);
- // Pack entity type enabled?
- if (disabled?.entities?.[pack.metadata.type]?.includes(game.user?.role)) {
- return false;
- }
- // Pack enabled?
- if (disabled?.packs?.[pack.collection]?.includes(game.user?.role)) {
- return false;
- }
- // Pack entity type indexed?
- if (!IndexedDocumentTypes.includes(pack.metadata.type)) {
- return false;
- }
- // Not hidden?
- //@ts-expect-error league types haven't caught up, I know
- return pack.visible || game.user?.isGM;
- }
- function getDirectoryName(type) {
- const documentLabel = DocumentMeta[type].labelPlural;
- return i18n("SIDEBAR.DirectoryTitle", {
- type: documentLabel ? i18n(documentLabel) : type,
- });
- }
- class SearchItem {
- constructor(data) {
- this.id = data.id;
- this.uuid = data.uuid;
- this.name = data.name;
- this.documentType = data.documentType;
- this.img = data.img;
- }
- // Get the drag data for drag operations
- get dragData() {
- return {};
- }
- // Get the html for an icon that represents the item
- get icon() {
- return "";
- }
- // Reference the entity in a journal, chat or other places that support it
- get journalLink() {
- return "";
- }
- // Reference the entity in a script
- get script() {
- return "";
- }
- // Short tagline that explains where/what this is
- get tagline() {
- return "";
- }
- // Additional details for result tooltips
- get tooltip() {
- const type = i18n(DocumentMeta[this.documentType]?.label);
- return `${type}, ${this.tagline}`;
- }
- // Show the sheet or equivalent of this search result
- async show() {
- return;
- }
- // Fetch the original object (or null if no longer available).
- // NEVER call as part of indexing or filtering.
- // It can be slow and most calls will cause a request to the database!
- // Call it once a decision is made, do not call for every SearchItem!
- async get() {
- return null;
- }
- }
- class EntitySearchItem extends SearchItem {
- constructor(data) {
- super(data);
- const folder = data.folder;
- if (folder) {
- this.folder = {
- id: folder.id,
- name: folder.name,
- };
- }
- }
- static fromEntities(entities) {
- return entities
- .filter((e) => {
- return (e.visible && !(e.folder?.name && ignoredFolderNames[e.folder.name]));
- })
- .map((doc) => {
- let embedded;
- if (EmbeddedDocumentTypes[doc.documentName] &&
- enabledEmbeddedDocumentTypes().includes(EmbeddedDocumentTypes[doc.documentName])) {
- const collection =
- //@ts-expect-error can't type this right now
- doc[EmbeddedDocumentCollections[doc.documentName]];
- embedded = collection.map(EmbeddedEntitySearchItem.fromDocument);
- }
- return embedded
- ? [...embedded, this.fromDocument(doc)]
- : [this.fromDocument(doc)];
- })
- .flat();
- }
- static fromDocument(doc) {
- if ("PDFoundry" in ui && "pdfoundry" in doc.data.flags) {
- return new PDFoundySearchItem({
- id: doc.id,
- uuid: doc.uuid,
- name: doc.name,
- documentType: doc.documentName,
- //@ts-expect-error data is merged wih doc
- img: doc.img,
- folder: doc.folder || undefined,
- });
- }
- return new EntitySearchItem({
- id: doc.id,
- uuid: doc.uuid,
- name: doc.name,
- documentType: doc.documentName,
- //@ts-expect-error data is merged wih doc
- img: doc.img,
- folder: doc.folder || undefined,
- });
- }
- // Get the drag data for drag operations
- get dragData() {
- return {
- type: this.documentType,
- uuid: this.uuid,
- };
- }
- get icon() {
- return `<i class="fas ${documentIcons[this.documentType]} entity-icon"></i>`;
- }
- // Reference the entity in a journal, chat or other places that support it
- get journalLink() {
- return `@${this.documentType}[${this.id}]{${this.name}}`;
- }
- // Reference the entity in a script
- get script() {
- return `game.${DocumentMeta[this.documentType].collection}.get("${this.id}")`;
- }
- // Short tagline that explains where/what this is
- get tagline() {
- if (this.folder) {
- return `${this.folder.name}`;
- }
- return `${getDirectoryName(this.documentType)}`;
- }
- async show() {
- (await this.get())?.sheet?.render(true);
- }
- async get() {
- return getCollectionFromType(this.documentType).get(this.id);
- }
- }
- class PDFoundySearchItem extends EntitySearchItem {
- get icon() {
- return `<img class="pdf-thumbnail" src="modules/pdfoundry/assets/pdf_icon.svg" alt="PDF Icon">`;
- }
- get journalLink() {
- return `@PDF[${this.name}|page=1]{${this.name}}`;
- }
- async show() {
- const entity = await this.get();
- ui?.PDFoundry.openPDFByName(this.name, { entity });
- }
- }
- class CompendiumSearchItem extends SearchItem {
- constructor(pack, item) {
- const packName = pack.collection;
- super({
- id: item._id,
- uuid: `Compendium.${packName}.${item._id}`,
- name: item.name,
- documentType: pack.metadata.type,
- img: item.img,
- });
- this.package = packName;
- this.packageName = pack?.metadata?.label || pack.title;
- this.documentType = pack.metadata.type;
- this.uuid = `Compendium.${this.package}.${this.id}`;
- }
- static fromCompendium(pack) {
- const cIndex = pack.index;
- return cIndex
- .map((item) => {
- const embedded = extractEmbeddedIndex(item, pack);
- const searchItem = new CompendiumSearchItem(pack, item);
- return embedded ? [searchItem, embedded] : searchItem;
- })
- .flat(2);
- }
- // Get the drag data for drag operations
- get dragData() {
- return {
- type: this.documentType,
- uuid: this.uuid,
- };
- }
- get icon() {
- return `<i class="fas ${documentIcons[this.documentType]} entity-icon"></i>`;
- }
- // Reference the entity in a journal, chat or other places that support it
- get journalLink() {
- return `@Compendium[${this.package}.${this.id}]{${this.name}}`;
- }
- // Reference the entity in a script
- get script() {
- return `fromUuid("${this.uuid}")`; // TODO: note that this is async somehow?
- }
- // Short tagline that explains where/what this is
- get tagline() {
- return `${this.packageName}`;
- }
- async show() {
- (await this.get())?.sheet?.render(true);
- }
- async get() {
- return (await fromUuid(this.uuid));
- }
- }
- class EmbeddedEntitySearchItem extends SearchItem {
- constructor(item) {
- super({
- id: item.id,
- uuid: item.uuid,
- name: `${item.embeddedName} | ${item.parentName}`,
- documentType: item.type,
- img: item.img,
- });
- _EmbeddedEntitySearchItem_tagline.set(this, void 0);
- __classPrivateFieldSet(this, _EmbeddedEntitySearchItem_tagline, item.tagline, "f");
- }
- static fromDocument(document) {
- if (!document.parent || !document.id) {
- throw new Error("Not properly embedded");
- }
- //@ts-expect-error There has to be an easier way...
- const number = [...document.parent[document.collectionName].keys()].indexOf(document.id);
- const parentType = document.parent.documentName;
- return new EmbeddedEntitySearchItem({
- id: document.id,
- uuid: document.uuid,
- parentName: document.parent.name || undefined,
- embeddedName: document.name,
- type: parentType,
- tagline: `Pg. ${number} - ${document.parent.folder?.name || getDirectoryName(parentType)}`,
- });
- }
- // Get the drag data for drag operations
- get dragData() {
- return {
- // TODO: Use type from index
- type: "JournalEntryPage",
- uuid: this.uuid,
- };
- }
- get icon() {
- // TODO: Add table tor subtypes
- return `<i class="fa-duotone fa-book-open entity-icon"></i>`;
- }
- // Reference the entity in a journal, chat or other places that support it
- get journalLink() {
- return `@UUID[${this.uuid}]{${this.name}}`;
- }
- // Reference the entity in a script
- get script() {
- return `fromUuid("${this.uuid}")`;
- }
- // Short tagline that explains where/what this is
- get tagline() {
- return __classPrivateFieldGet(this, _EmbeddedEntitySearchItem_tagline, "f") || "";
- }
- get tooltip() {
- const type = i18n(DocumentMeta[this.documentType]?.label);
- //@ts-expect-error Update types!
- const page = i18n(CONFIG.JournalEntryPage.documentClass.metadata.label);
- return `${type} ${page}, ${__classPrivateFieldGet(this, _EmbeddedEntitySearchItem_tagline, "f")}`;
- }
- async show() {
- //@ts-expect-error This is good enough for now
- (await this.get())?._onClickDocumentLink({
- currentTarget: { dataset: {} },
- });
- }
- async get() {
- return (await fromUuid(this.uuid));
- }
- }
- _EmbeddedEntitySearchItem_tagline = new WeakMap();
- class EmbeddedCompendiumSearchItem extends SearchItem {
- constructor(pack, item) {
- const packName = pack.collection;
- const uuid = `Compendium.${packName}.${item.parentId}.${item.type}.${item._id}`;
- super({
- id: item._id,
- uuid,
- name: `${item.embeddedName} | ${item.parentName}`,
- documentType: item.type,
- img: item.img,
- });
- // Inject overrides??
- _EmbeddedCompendiumSearchItem_tagline.set(this, void 0);
- this.uuid = uuid;
- this.package = packName;
- this.packageName = pack?.metadata?.label || pack.title;
- this.documentType = pack.metadata.type;
- __classPrivateFieldSet(this, _EmbeddedCompendiumSearchItem_tagline, item.tagline, "f");
- }
- static fromDocument(document) {
- if (!document.parent) {
- throw new Error("Document is not embedded");
- }
- if (!document.pack) {
- throw new Error("Document has no pack");
- }
- const pack = game.packs.get(document.pack);
- if (!pack) {
- throw new Error("Document has invalid pack");
- }
- //@ts-expect-error There has to be an easier way...
- const number = [...document.parent[document.collectionName].keys()].indexOf(document.id);
- return new EmbeddedCompendiumSearchItem(pack, {
- _id: document.id,
- parentName: document.parent.name || undefined,
- embeddedName: document.name,
- parentId: document.parent.id,
- type: "JournalEntryPage",
- tagline: `Pg. ${number} - ${pack?.metadata?.label || pack.title}`,
- });
- }
- // Get the drag data for drag operations
- get dragData() {
- return {
- // TODO: Use type from index
- type: "JournalEntryPage",
- uuid: this.uuid,
- };
- }
- get icon() {
- // TODO: Add table tor subtypes
- return `<i class="fa-duotone fa-book-open entity-icon"></i>`;
- }
- // Reference the entity in a journal, chat or other places that support it
- get journalLink() {
- return `@UUID[${this.uuid}]{${this.name}}`;
- }
- // Reference the entity in a script
- get script() {
- return `fromUuid("${this.uuid}")`; // TODO: note that this is async somehow?
- }
- // Short tagline that explains where/what this is
- get tagline() {
- return __classPrivateFieldGet(this, _EmbeddedCompendiumSearchItem_tagline, "f") || `${this.packageName}`;
- }
- get tooltip() {
- const type = i18n(DocumentMeta[this.documentType]?.label);
- //@ts-expect-error Update types!
- const page = i18n(CONFIG.JournalEntryPage.documentClass.metadata.label);
- return `${type} ${page}, ${__classPrivateFieldGet(this, _EmbeddedCompendiumSearchItem_tagline, "f")}`;
- }
- async show() {
- //@ts-expect-error This is good enough for now
- (await this.get())?._onClickDocumentLink({
- currentTarget: { dataset: {} },
- });
- }
- async get() {
- return (await fromUuid(this.uuid));
- }
- }
- _EmbeddedCompendiumSearchItem_tagline = new WeakMap();
- function searchItemFromDocument(document) {
- if (document.parent) {
- if (document.compendium) {
- return EmbeddedCompendiumSearchItem.fromDocument(document);
- }
- return EmbeddedEntitySearchItem.fromDocument(document);
- }
- if (document.compendium) {
- return new CompendiumSearchItem(document.compendium, {
- _id: document.id,
- name: document.name,
- //@ts-ignore
- img: document.img,
- });
- }
- return EntitySearchItem.fromDocument(document);
- }
- function isEntity(item) {
- return item instanceof EntitySearchItem;
- }
- function isCompendiumEntity(item) {
- return item instanceof CompendiumSearchItem;
- }
- class FuseSearchIndex {
- constructor() {
- this.fuse = new Fuse([], {
- keys: ["name"],
- includeMatches: true,
- threshold: 0.3,
- });
- }
- addAll(items) {
- for (const item of items) {
- this.fuse.add(item);
- }
- }
- add(item) {
- this.fuse.add(item);
- }
- removeByUuid(uuid) {
- this.fuse.remove((i) => i?.uuid == uuid);
- }
- search(query) {
- return this.fuse.search(query).map((res) => ({
- item: res.item,
- match: res.matches,
- }));
- }
- }
- class SearchLib {
- constructor() {
- this.index = new FuseSearchIndex();
- }
- indexCompendium(compendium) {
- if (!compendium)
- return;
- if (packEnabled(compendium)) {
- const index = CompendiumSearchItem.fromCompendium(compendium);
- this.index.addAll(index);
- }
- }
- async indexCompendiums() {
- if (!game.packs)
- return;
- for await (const res of loadIndexes()) {
- if (res.error) {
- console.log("Quick Insert | Index loading failure", res);
- continue;
- }
- console.log("Quick Insert | Index loading success", res);
- this.indexCompendium(game.packs.get(res.pack));
- }
- }
- indexDocuments() {
- for (const type of enabledDocumentTypes()) {
- this.index.addAll(EntitySearchItem.fromEntities(getCollectionFromType(type).contents));
- }
- }
- addItem(item) {
- this.index.add(item);
- }
- removeItem(entityUuid) {
- this.index.removeByUuid(entityUuid);
- }
- replaceItem(item) {
- this.removeItem(item.uuid);
- this.addItem(item);
- }
- search(text, filter, max) {
- if (filter) {
- return this.index.search(text).filter(filter).slice(0, max);
- }
- return this.index.search(text).slice(0, max);
- }
- }
- function formatMatch(result, formatFn) {
- const match = result.match[0];
- if (!match.value)
- return "";
- let text = match.value;
- [...match.indices].reverse().forEach(([start, end]) => {
- // if (start === end) return;
- text =
- text.substring(0, start) +
- formatFn(text.substring(start, end + 1)) +
- text.substring(end + 1);
- });
- return text;
- }
- async function* loadIndexes() {
- if (!game.packs) {
- console.error("Can't load indexes before packs are initialized");
- return;
- }
- // Information about failures
- const failures = {};
- const timeout = getSetting(ModuleSetting.INDEX_TIMEOUT);
- const packsRemaining = [];
- for (const pack of game.packs) {
- if (packEnabled(pack)) {
- failures[pack.collection] = { errors: 0 };
- packsRemaining.push(pack);
- }
- }
- while (packsRemaining.length > 0) {
- const pack = packsRemaining.shift();
- if (!pack)
- break;
- let promise;
- try {
- let options;
- if (getSetting(ModuleSetting.EMBEDDED_INDEXING)) {
- if (pack.documentClass.documentName === "JournalEntry") {
- options = { fields: ["pages.name", "pages._id"] };
- }
- }
- promise = failures[pack.collection].waiting ?? pack.getIndex(options);
- await withDeadline(promise, timeout * (failures[pack.collection].errors + 1));
- }
- catch (error) {
- ++failures[pack.collection].errors;
- if (error instanceof TimeoutError) {
- failures[pack.collection].waiting = promise;
- }
- else {
- delete failures[pack.collection].waiting;
- }
- yield {
- error: error,
- pack: pack.collection,
- packsLeft: packsRemaining.length,
- errorCount: failures[pack.collection].errors,
- };
- if (failures[pack.collection].errors <= 4) {
- // Pack failed, will be retried later.
- packsRemaining.push(pack);
- }
- else {
- console.warn(`Quick Insert | Package "${pack.collection}" could not be indexed `);
- }
- continue;
- }
- yield {
- pack: pack.collection,
- packsLeft: packsRemaining.length,
- errorCount: failures[pack.collection].errors,
- };
- }
- }
-
- function checkIndexed(document, embedded = false) {
- if (!document.visible)
- return false;
- // Check embedded state
- if ((embedded && !document.parent) || (!embedded && document.parent)) {
- return false;
- }
- // Check enabled types
- if (document.parent) {
- if (!enabledEmbeddedDocumentTypes().includes(document.documentName))
- return false;
- }
- else {
- if (!enabledDocumentTypes().includes(document.documentName))
- return false;
- }
- // Check disabled packs
- return !(document.pack && !packEnabled(document.compendium));
- }
- function setupDocumentHooks(quickInsert) {
- enabledDocumentTypes().forEach((type) => {
- Hooks.on(`create${type}`, (document) => {
- if (document.parent || !checkIndexed(document))
- return;
- quickInsert.searchLib?.addItem(searchItemFromDocument(document));
- });
- Hooks.on(`update${type}`, (document) => {
- if (document.parent)
- return;
- if (!checkIndexed(document)) {
- quickInsert.searchLib?.removeItem(document.uuid);
- return;
- }
- quickInsert.searchLib?.replaceItem(searchItemFromDocument(document));
- });
- Hooks.on(`delete${type}`, (document) => {
- if (document.parent || !checkIndexed(document))
- return;
- quickInsert.searchLib?.removeItem(document.uuid);
- });
- });
- enabledEmbeddedDocumentTypes().forEach((type) => {
- Hooks.on(`create${type}`, (document) => {
- if (!document.parent || !checkIndexed(document, true))
- return;
- const item = searchItemFromDocument(document);
- quickInsert.searchLib?.addItem(item);
- });
- Hooks.on(`update${type}`, (document) => {
- if (!document.parent)
- return;
- if (!checkIndexed(document, true)) {
- quickInsert.searchLib?.removeItem(document.uuid);
- return;
- }
- const item = searchItemFromDocument(document);
- quickInsert.searchLib?.replaceItem(item);
- });
- Hooks.on(`delete${type}`, (document) => {
- if (!document.parent || !checkIndexed(document, true))
- return;
- quickInsert.searchLib?.removeItem(document.uuid);
- });
- });
- }
-
- var FilterType;
- (function (FilterType) {
- FilterType[FilterType["Default"] = 0] = "Default";
- FilterType[FilterType["World"] = 1] = "World";
- FilterType[FilterType["Client"] = 2] = "Client";
- })(FilterType || (FilterType = {}));
-
- var ContextMode;
- (function (ContextMode) {
- ContextMode[ContextMode["Browse"] = 0] = "Browse";
- ContextMode[ContextMode["Insert"] = 1] = "Insert";
- })(ContextMode || (ContextMode = {}));
- class SearchContext {
- constructor() {
- this.mode = ContextMode.Insert;
- this.spawnCSS = {};
- this.allowMultiple = true;
- }
- onClose() {
- return;
- }
- }
- // Default browse context
- class BrowseContext extends SearchContext {
- constructor() {
- super();
- this.mode = ContextMode.Browse;
- this.startText = document.getSelection()?.toString();
- }
- onSubmit(item) {
- // Render the sheet for selected item
- item.show();
- }
- }
- class InputContext extends SearchContext {
- constructor(input) {
- super();
- this.selectionStart = null;
- this.selectionEnd = null;
- this.input = input;
- const targetRect = input.getBoundingClientRect();
- const bodyRect = document.body.getBoundingClientRect();
- const top = targetRect.top - bodyRect.top;
- // TODO: Real calculation!!!
- this.spawnCSS = {
- left: targetRect.left + 5,
- bottom: bodyRect.height - top - 30,
- width: targetRect.width - 10,
- };
- this.selectionStart = input.selectionStart;
- this.selectionEnd = input.selectionEnd;
- if (this.selectionStart !== null && this.selectionEnd !== null) {
- if (this.selectionStart != this.selectionEnd) {
- this.startText = this.input.value.slice(this.selectionStart, this.selectionEnd);
- }
- }
- $(input).addClass("quick-insert-context");
- }
- insertResult(result) {
- if (this.selectionStart !== null && this.selectionEnd !== null) {
- this.input.value =
- this.input.value.slice(0, this.selectionStart) +
- result +
- this.input.value.slice(this.selectionEnd);
- }
- else {
- this.input.value = result;
- }
- }
- onSubmit(item) {
- if (typeof item == "string") {
- this.insertResult(item);
- }
- else {
- this.insertResult(item.journalLink);
- }
- }
- onClose() {
- $(this.input).removeClass("quick-insert-context");
- this.input.focus();
- }
- }
- class ScriptMacroContext extends InputContext {
- onSubmit(item) {
- if (typeof item == "string") {
- this.insertResult(`"${item}"`);
- }
- else {
- this.insertResult(item.script);
- }
- }
- }
- class RollTableContext extends InputContext {
- constructor(input) {
- super(input);
- this.allowMultiple = false;
- // Set filter depending on selected dropdown!
- // const resultRow = this.input.closest("li.table-result")
- }
- onSubmit(item) {
- if (typeof item == "string") {
- this.insertResult(item);
- return;
- }
- const row = $(this.input).closest(".table-result");
- const resultId = row.data("result-id");
- const appId = row.closest(".window-app").data("appid");
- const app = ui.windows[parseInt(appId)];
- if (isEntity(item)) {
- app.object.updateEmbeddedDocuments("TableResult", [
- {
- _id: resultId,
- collection: item.documentType,
- type: 1,
- resultId: item.id,
- text: item.name,
- img: item.img || null,
- },
- ]);
- }
- else if (isCompendiumEntity(item)) {
- app.object.updateEmbeddedDocuments("TableResult", [
- {
- _id: resultId,
- collection: item.package,
- type: 2,
- resultId: item.id,
- text: item.name,
- img: item.img || null,
- },
- ]);
- }
- }
- }
- class TinyMCEContext extends SearchContext {
- constructor(editor) {
- super();
- const targetRect = editor.selection.getBoundingClientRect();
- const bodyRect = document.body.getBoundingClientRect();
- const containerRect = editor.contentAreaContainer.getBoundingClientRect();
- const top = containerRect.top + targetRect.top;
- this.spawnCSS = {
- left: containerRect.left + targetRect.left,
- bottom: bodyRect.height - top - 20,
- width: targetRect.width,
- maxHeight: top + 20,
- };
- this.editor = editor;
- this.startText = editor.selection.getContent().trim();
- }
- onSubmit(item) {
- if (typeof item == "string") {
- this.editor.insertContent(item);
- }
- else {
- this.editor.insertContent(item.journalLink);
- }
- }
- onClose() {
- this.editor.focus();
- }
- }
- class ProseMirrorContext extends SearchContext {
- constructor(state, dispatch, view) {
- super();
- this.state = state;
- this.dispatch = dispatch;
- this.view = view;
- this.startText = document.getSelection()?.toString();
- const start = view.coordsAtPos(state.selection.from);
- const end = view.coordsAtPos(state.selection.to);
- const bodyRect = document.body.getBoundingClientRect();
- const bottom = bodyRect.height - start.top - 22;
- this.spawnCSS = {
- left: start.left,
- bottom,
- width: end.left - start.left,
- maxHeight: bodyRect.height - bottom,
- };
- }
- onSubmit(item) {
- const tr = this.state.tr;
- const text = typeof item == "string" ? item : item.journalLink;
- const textNode = this.state.schema.text(text);
- tr.replaceSelectionWith(textNode);
- this.dispatch(tr);
- this.view.focus();
- }
- onClose() {
- this.view.focus();
- }
- }
- class CharacterSheetContext extends SearchContext {
- constructor(documentSheet, anchor) {
- super();
- this.restrictTypes = [DocumentType.ITEM];
- this.documentSheet = documentSheet;
- this.anchor = anchor;
- const targetRect = anchor.get()[0].getBoundingClientRect();
- const bodyRect = document.body.getBoundingClientRect();
- const top = bodyRect.top + targetRect.top;
- this.spawnCSS = {
- left: targetRect.left - 280,
- bottom: bodyRect.height - top - 23,
- width: 300,
- maxHeight: top + 23,
- };
- }
- onSubmit(item) {
- if (typeof item == "string")
- return;
- //@ts-ignore
- return this.documentSheet._onDropItem({}, {
- type: item.documentType,
- uuid: item.uuid,
- });
- }
- }
- function identifyContext(target) {
- if (target && isTextInputElement(target)) {
- if (target.name === "command") {
- if (target
- .closest(".macro-sheet")
- ?.querySelector('select[name="type"]')?.value === "script") {
- return new ScriptMacroContext(target);
- }
- return new InputContext(target);
- }
- else if (target.name.startsWith("results.") &&
- target.closest(".result-details")) {
- return new RollTableContext(target);
- }
- // Right now, only allow in chat!
- if (target.id === "chat-message") {
- return new InputContext(target);
- }
- }
- // No/unknown context, browse only.
- if (getSetting(ModuleSetting.ENABLE_GLOBAL_CONTEXT) === true) {
- return new BrowseContext();
- }
- return null;
- }
- class EmbeddedContext extends BrowseContext {
- constructor() {
- super(...arguments);
- this.spawnCSS = {
- top: "unset",
- left: "0",
- bottom: "0",
- "max-height": "100%",
- width: "100%",
- "box-shadow": "none",
- };
- }
- onSubmit() {
- return;
- }
- }
-
- class SearchFilterCollection {
- constructor() {
- this.disabled = [];
- this.dirty = true;
- this.defaultFilters = [];
- this.clientFilters = [];
- this.worldFilters = [];
- this.combinedFilters = [];
- }
- get filters() {
- if (this.dirty) {
- this.combinedFilters = [
- ...this.defaultFilters,
- ...this.worldFilters,
- ...this.clientFilters,
- ];
- this.combinedFilters.forEach((f) => (f.disabled = this.disabled.includes(f.id)));
- this.dirty = false;
- }
- return this.combinedFilters;
- }
- // Someone changed the filters, will be saved etc.
- filtersChanged(which) {
- if (which === FilterType.Client) {
- this.saveClient();
- }
- else if (which === FilterType.World) {
- this.saveWorld();
- }
- else {
- this.save();
- }
- }
- search(query) {
- if (!query) {
- return [...this.filters];
- }
- return this.filters.filter((f) => f.tag.includes(query));
- }
- getFilter(id) {
- return this.filters.find((f) => f.id == id);
- }
- getFilterByTag(tag) {
- return this.filters.filter((f) => !f.disabled).find((f) => f.tag == tag);
- }
- addFilter(filter) {
- if (filter.type == FilterType.World) {
- this.worldFilters.push(filter);
- this.filtersChanged(filter.type);
- }
- else if (filter.type == FilterType.Client) {
- this.clientFilters.push(filter);
- this.filtersChanged(filter.type);
- }
- }
- deleteFilter(id) {
- const f = this.filters.find((f) => f.id === id);
- if (!f)
- return;
- if (f.type == FilterType.World) {
- const x = this.worldFilters.findIndex((f) => f.id === id);
- if (x != -1) {
- this.worldFilters.splice(x, 1);
- }
- }
- else if (f.type == FilterType.Client) {
- const x = this.clientFilters.findIndex((f) => f.id === id);
- if (x != -1) {
- this.clientFilters.splice(x, 1);
- }
- }
- this.filtersChanged(f.type);
- }
- resetFilters() {
- this.defaultFilters = [];
- this.clientFilters = [];
- this.worldFilters = [];
- this.combinedFilters = [];
- this.dirty = false;
- }
- loadDefaultFilters() {
- this.loadCompendiumFilters();
- // this.loadDirectoryFilters();
- this.loadEntityFilters();
- this.dirty = true;
- }
- loadEntityFilters() {
- this.defaultFilters = this.defaultFilters.concat(enabledDocumentTypes().map((type) => {
- const metadata = DocumentMeta[type];
- return {
- id: metadata.collection,
- type: FilterType.Default,
- tag: metadata.collection,
- subTitle: `${game.i18n.localize(metadata.label)}`,
- filterConfig: {
- folders: "any",
- compendiums: "any",
- entities: [metadata.name],
- },
- };
- }));
- }
- loadDirectoryFilters() {
- // TODO: find a way to find directories that the user is allowed to see
- if (!game.user?.isGM)
- return;
- this.defaultFilters = this.defaultFilters.concat(enabledDocumentTypes().map((type) => {
- const metadata = DocumentMeta[type];
- return {
- id: `dir.${metadata.collection}`,
- type: FilterType.Default,
- tag: `dir.${metadata.collection}`,
- subTitle: getCollectionFromType(type).directory?.title,
- filterConfig: {
- folders: "any",
- compendiums: [],
- entities: [metadata.name],
- },
- };
- }));
- }
- loadCompendiumFilters() {
- if (!game.packs)
- return;
- this.defaultFilters = this.defaultFilters.concat(game.packs.filter(packEnabled).map((pack) => {
- return {
- id: pack.collection,
- type: FilterType.Default,
- tag: pack.collection,
- subTitle: pack.metadata.label,
- filterConfig: {
- folders: [],
- compendiums: [pack.collection],
- entities: "any",
- },
- };
- }));
- }
- loadClientSave() {
- const clientSave = getSetting(ModuleSetting.FILTERS_CLIENT);
- this.disabled = clientSave.disabled || [];
- this.clientFilters = clientSave.filters || [];
- this.dirty = true;
- }
- loadWorldSave() {
- const worldSave = getSetting(ModuleSetting.FILTERS_WORLD);
- this.worldFilters = worldSave.filters || [];
- this.dirty = true;
- }
- loadSave() {
- this.loadClientSave();
- this.loadWorldSave();
- Hooks.call("QuickInsert:FiltersUpdated");
- }
- saveWorld() {
- if (!game.user?.isGM)
- return;
- const worldSave = {
- filters: [],
- };
- for (const filter of this.worldFilters) {
- delete filter.disabled;
- worldSave.filters.push(filter);
- }
- setSetting(ModuleSetting.FILTERS_WORLD, worldSave);
- }
- saveClient() {
- const clientSave = {
- disabled: [],
- filters: [],
- };
- for (const filter of [
- ...this.defaultFilters,
- ...this.worldFilters,
- ...this.clientFilters,
- ]) {
- if (filter.disabled) {
- clientSave.disabled.push(filter.id);
- }
- if (filter.type === FilterType.Client) {
- clientSave.filters.push(filter);
- }
- }
- setSetting(ModuleSetting.FILTERS_CLIENT, clientSave);
- }
- save() {
- this.saveClient();
- this.saveWorld();
- }
- }
- // Is parentFolder inside targetFolder?
- function isInFolder(parentFolder, targetFolder) {
- while (parentFolder) {
- if (parentFolder === targetFolder)
- return true;
- //@ts-expect-error "parent" migrated to "folder"
- parentFolder = game.folders?.get(parentFolder)?.folder;
- }
- return false;
- }
- function matchFilterConfig(config, item) {
- let folderMatch = false;
- let compendiumMatch = false;
- let entityMatch = true;
- if (isEntity(item.item)) {
- if (config.folders === "any") {
- folderMatch = true;
- }
- else {
- for (const f of config.folders) {
- if (isInFolder(item.item.folder?.id, f)) {
- folderMatch = true;
- break;
- }
- }
- }
- }
- else if (isCompendiumEntity(item.item)) {
- if (config.compendiums == "any") {
- compendiumMatch = true;
- }
- else {
- compendiumMatch = config.compendiums.includes(item.item.package);
- }
- }
- if (config.entities == "any") {
- entityMatch = true;
- }
- else {
- entityMatch = config.entities.includes(item.item.documentType);
- }
- return (folderMatch || compendiumMatch) && entityMatch;
- }
-
- // Module singleton class that contains everything
- class QuickInsertCore {
- constructor() {
- this.filters = new SearchFilterCollection();
- }
- get hasIndex() {
- return Boolean(this.searchLib?.index);
- }
- /**
- * Incorrect to match like this with new keybinds!
- * @deprecated
- */
- matchBoundKeyEvent() {
- return false;
- }
- // If the global key binds are not enough - e.g. in a custom editor,
- // include the custom search context!
- handleKeybind(evt, context) {
- if (!context)
- throw new Error("A custom context is required!");
- customKeybindHandler(evt, context);
- }
- open(context) {
- this.app?.render(true, { context });
- }
- toggle(context) {
- if (this.app?.open) {
- this.app.closeDialog();
- }
- else {
- this.open(context);
- }
- }
- search(text, filter = null, max = 100) {
- return this.searchLib?.search(text, filter, max) || [];
- }
- async forceIndex() {
- return loadSearchIndex();
- }
- }
- const QuickInsert = new QuickInsertCore();
- // Ensure that only one loadSearchIndex function is running at any one time.
- let isLoading = false;
- async function loadSearchIndex() {
- if (isLoading)
- return;
- isLoading = true;
- console.log("Quick Insert | Preparing search index...");
- const start = performance.now();
- QuickInsert.searchLib = new SearchLib();
- QuickInsert.searchLib.indexDocuments();
- QuickInsert.filters.resetFilters();
- QuickInsert.filters.loadDefaultFilters();
- QuickInsert.filters.loadSave();
- console.log(`Quick Insert | Indexing compendiums with timeout set to ${getSetting(ModuleSetting.INDEX_TIMEOUT)}ms`);
- await QuickInsert.searchLib.indexCompendiums();
- console.log(`Quick Insert | Search index and filters completed. Indexed ${
- // @ts-ignore
- QuickInsert.searchLib?.index?.fuse._docs.length || 0} items in ${performance.now() - start}ms`);
- isLoading = false;
- Hooks.callAll("QuickInsert:IndexCompleted", QuickInsert);
- }
-
- function parseFilterConfig(collections) {
- const filters = {
- folders: [],
- compendiums: [],
- entities: [],
- };
- for (const coll of collections) {
- const x = coll.indexOf(".");
- const base = coll.slice(0, x);
- const rest = coll.slice(x + 1);
- if (base === "Folder") {
- if (rest === "Any") {
- filters.folders = "any";
- }
- else if (!(typeof filters.folders === "string")) {
- filters.folders.push(rest);
- }
- }
- else if (base === "Compendium") {
- if (rest === "Any") {
- filters.compendiums = "any";
- }
- else if (!(typeof filters.compendiums === "string")) {
- filters.compendiums.push(rest);
- }
- }
- else if (base === "Document" || base === "Entity") {
- if (rest === "Any") {
- filters.entities = "any";
- }
- else if (!(typeof filters.entities === "string")) {
- filters.entities.push(rest);
- }
- }
- }
- return filters;
- }
- class FilterEditor extends Application {
- constructor(filter) {
- super({
- title: i18n("FilterEditorTitle"),
- classes: ["filter-editor"],
- template: "modules/quick-insert/templates/filter-editor.hbs",
- resizable: true,
- width: 550,
- height: 560,
- scrollY: [
- ".collection-list.compendium-list",
- ".collection-list.directory-list",
- ".collection-list.entity-list",
- ],
- });
- this.searchInput = "";
- this.filter = filter;
- this.idPrefix = new RegExp(`^${this.filter.id}_`);
- }
- get element() {
- return super.element;
- }
- prefix(name) {
- return `${this.filter.id}_${name}`;
- }
- unPrefix(name) {
- return name.replace(this.idPrefix, "");
- }
- render(force, options) {
- return super.render(force, options);
- }
- isEditable() {
- return Boolean(this.filter.type == FilterType.Client ||
- (this.filter.type == FilterType.World && game.user?.isGM));
- }
- fixAny(type, form, formData) {
- form
- .find(`input[name^="${this.filter.id}_${type}."].disabled`)
- .removeClass("disabled");
- const selectedAny = formData.find((r) => r.name.endsWith(".Any"));
- if (selectedAny) {
- const other = form.find(`input[name^="${this.filter.id}_${type}."]:not(input[name="${this.filter.id}_${selectedAny.name}"])`);
- other.prop("checked", false);
- other.addClass("disabled");
- }
- }
- close() {
- if (this.element.find(".quick-insert").length > 0 && QuickInsert.app) {
- QuickInsert.app.embeddedMode = false;
- QuickInsert.app.closeDialog();
- }
- return super.close();
- }
- processForm() {
- const form = this.element.find("form");
- let formData = form.serializeArray();
- formData.forEach((d) => {
- d.name = this.unPrefix(d.name);
- });
- const name = formData.find((p) => p.name == "name")?.value.trim();
- const title = formData.find((p) => p.name == "title")?.value;
- formData = formData.filter((p) => p.name != "name" && p.name != "title");
- const compendiums = formData.filter((r) => r.name.startsWith("Compendium."));
- const folders = formData.filter((r) => r.name.startsWith("Folder."));
- const entity = formData.filter((r) => r.name.startsWith("Document."));
- this.fixAny("Compendium", form, compendiums);
- this.fixAny("Folder", form, folders);
- this.fixAny("Document", form, entity);
- return {
- name,
- title,
- formData,
- };
- }
- formChange() {
- if (!this.isEditable())
- return;
- const { name, title, formData } = this.processForm();
- const config = parseFilterConfig(formData.map((x) => x.name));
- const oldTag = this.filter.tag;
- if (name != "") {
- this.filter.tag = name;
- }
- this.filter.subTitle = title;
- this.filter.filterConfig = config;
- // Hacky way to keep/update state of input
- this.searchInput =
- QuickInsert.app?.input?.text().replace(`@${oldTag}`, "").trim() || "";
- QuickInsert.filters.filtersChanged(this.filter.type);
- }
- attachQuickInsert() {
- const context = new EmbeddedContext();
- context.filter = this.filter;
- context.startText = this.searchInput;
- if (!QuickInsert.app)
- return;
- if (QuickInsert.app.embeddedMode) {
- this.element.find(".example-out").append(QuickInsert.app.element);
- }
- else {
- Hooks.once(`render${QuickInsert.app?.constructor.name}`, (app) => {
- this.element.find(".example-out").append(app.element);
- });
- }
- QuickInsert.app.embeddedMode = true;
- QuickInsert.app.render(true, { context });
- }
- activateListeners() {
- this.attachQuickInsert();
- const form = this.element.find("form");
- form.on("change", () => {
- this.formChange();
- });
- this.processForm();
- if (this.filter.type == FilterType.Default ||
- (this.filter.type == FilterType.World && !game.user?.isGM)) {
- this.element.find("input").prop("disabled", true);
- }
- this.element.find(".open-here").on("click", (evt) => {
- evt.preventDefault();
- this.attachQuickInsert();
- });
- }
- getData() {
- let folders = [];
- if (!game.packs)
- return {};
- if (game.user?.isGM) {
- folders =
- game.folders?.map((folder) => ({
- label: folder.name,
- name: this.prefix(`Folder.${folder.id}`),
- selected: this.filter.filterConfig?.folders.includes(folder.id),
- })) || [];
- }
- return {
- tag: this.filter.tag,
- subTitle: this.filter.subTitle,
- isDefault: this.filter.type === FilterType.Default,
- forbiddenWorld: this.filter.type == FilterType.World && !game.user?.isGM,
- collections: [
- {
- name: this.prefix("Compendium.Any"),
- label: i18n("FilterEditorCompendiumAny"),
- selected: this.filter.filterConfig?.compendiums === "any",
- },
- ...game.packs
- .filter((pack) => packEnabled(pack))
- .map((pack) => ({
- name: this.prefix(`Compendium.${pack.collection}`),
- label: `${pack.metadata.label} - ${pack.collection}`,
- selected: this.filter.filterConfig?.compendiums.includes(pack.collection),
- })),
- ],
- documentTypes: [
- {
- name: this.prefix("Document.Any"),
- label: i18n("FilterEditorEntityAny"),
- selected: this.filter.filterConfig?.entities === "any",
- },
- ...enabledDocumentTypes().map((type) => ({
- name: this.prefix(`Document.${type}`),
- label: game.i18n.localize(`DOCUMENT.${type}`),
- selected: this.filter.filterConfig?.entities.includes(type),
- })),
- ],
- folders: [
- {
- name: this.prefix("Folder.Any"),
- label: i18n("FilterEditorFolderAny"),
- selected: this.filter.filterConfig?.folders === "any",
- },
- ...folders,
- ],
- };
- }
- }
-
- const typeIcons = {
- [FilterType.Default]: `<i class="fas fa-lock" title="Default filter"></i>`,
- [FilterType.World]: `<i class="fas fa-globe" title="World filter"></i>`,
- [FilterType.Client]: `<i class="fas fa-user" title="Client filter"></i>`,
- };
- function cloneFilterConfig(original) {
- const res = {
- compendiums: "any",
- folders: "any",
- entities: "any",
- };
- if (typeof original.compendiums !== "string") {
- res.compendiums = [...original.compendiums];
- }
- if (typeof original.folders !== "string") {
- res.folders = [...original.folders];
- }
- if (typeof original.entities !== "string") {
- res.entities = [...original.entities];
- }
- return res;
- }
- class FilterList extends FormApplication {
- constructor() {
- super(...arguments);
- this.filterEditors = {};
- this.onFiltersUpdated = () => {
- this.render(true);
- Object.entries(this.filterEditors).forEach(([id, editor]) => {
- const filter = QuickInsert.filters.getFilter(id);
- if (filter)
- editor.filter = filter;
- editor.rendered && editor.render(true);
- });
- };
- }
- static get defaultOptions() {
- return {
- ...super.defaultOptions,
- title: i18n("FilterListTitle"),
- id: "filter-list",
- template: "modules/quick-insert/templates/filter-list.hbs",
- resizable: true,
- height: 500,
- width: 350,
- scrollY: [".table-container"],
- };
- }
- getData() {
- return {
- filters: [
- ...QuickInsert.filters.filters.map((filter) => ({
- id: filter.id,
- icon: typeIcons[filter.type],
- tag: filter.tag,
- subTitle: filter.subTitle,
- disabled: filter.disabled,
- deletable: filter.type == FilterType.Client ||
- (filter.type == FilterType.World && game.user?.isGM),
- })),
- ],
- };
- }
- render(force, options) {
- if (this._state <= 0) {
- Hooks.on("QuickInsert:FiltersUpdated", this.onFiltersUpdated);
- }
- return super.render(force, options);
- }
- close() {
- Hooks.off("QuickInsert:FiltersUpdated", this.onFiltersUpdated);
- return super.close();
- }
- activateListeners() {
- this.element.find(".create-filter").on("click", () => {
- this.newFilter();
- });
- this.element.find("i.delete").on("click", (evt) => {
- const id = evt.target.closest("tr")?.dataset["id"];
- if (id)
- QuickInsert.filters.deleteFilter(id);
- });
- this.element.find("i.edit").on("click", (evt) => {
- const id = evt.target.closest("tr")?.dataset["id"];
- if (id)
- this.editFilter(id);
- });
- this.element.find("i.duplicate").on("click", (evt) => {
- const id = evt.target.closest("tr")?.dataset["id"];
- this.newFilter(QuickInsert.filters.filters.find((f) => f.id === id));
- });
- this.element.find("i.enable").on("click", (evt) => {
- const id = evt.target.closest("tr")?.dataset["id"];
- const filter = QuickInsert.filters.filters.find((f) => f.id === id);
- if (filter)
- filter.disabled = false;
- QuickInsert.filters.filtersChanged(FilterType.Client);
- });
- this.element.find("i.disable").on("click", (evt) => {
- const id = evt.target.closest("tr")?.dataset["id"];
- const filter = QuickInsert.filters.filters.find((f) => f.id === id);
- if (filter)
- filter.disabled = true;
- QuickInsert.filters.filtersChanged(FilterType.Client);
- });
- }
- editFilter(id) {
- if (!this.filterEditors[id]) {
- const filter = QuickInsert.filters.filters.find((f) => f.id === id);
- if (filter)
- this.filterEditors[id] = new FilterEditor(filter);
- }
- this.filterEditors[id].render(true);
- }
- newFilter(original) {
- const scope = `
- <p>
- <label>${i18n("FilterListFilterScope")}</label>
- <select>
- <option value="world">${i18n("FilterListFilterScopeWorld")}</option>
- <option value="client">${i18n("FilterListFilterScopeClient")}</option>
- </select>
- </p>`;
- const newDialog = new Dialog({
- title: original
- ? i18n("FilterListDuplicateFilterTitle", { original: original.tag })
- : i18n("FilterListNewFilterTitle"),
- content: `
- <div class="new-filter-name">
- @<input type="text" name="name" id="name" value="" placeholder="${i18n("FilterListFilterTagPlaceholder")}" pattern="[A-Za-z0-9\\._-]+" minlength="1">
- </div>
- ${game.user?.isGM ? scope : ""}
- `,
- buttons: {
- apply: {
- icon: "<i class='fas fa-plus'></i>",
- label: i18n("FilterListCreateFilter"),
- callback: async (html) => {
- if (!("find" in html))
- return;
- const input = html.find("input");
- const val = html.find("input").val();
- const selected = html.find("select").val();
- if (input.get(0)?.checkValidity() && val !== "") {
- this.createFilter(val, selected === "world" ? FilterType.World : FilterType.Client, original);
- }
- else {
- ui.notifications?.error(`Incorrect filter tag: "${val}"`);
- }
- },
- },
- },
- default: "apply",
- close: () => {
- return;
- },
- });
- newDialog.render(true);
- }
- createFilter(tag, scope, original) {
- const newId = randomId(30);
- if (original) {
- QuickInsert.filters.addFilter({
- id: newId,
- type: scope,
- tag,
- subTitle: `${original.subTitle} (Copy)`,
- filterConfig: original.filterConfig && cloneFilterConfig(original.filterConfig),
- });
- return;
- }
- else {
- QuickInsert.filters.addFilter({
- id: newId,
- type: scope,
- tag,
- subTitle: tag,
- filterConfig: {
- compendiums: [],
- folders: [],
- entities: "any",
- },
- });
- }
- if (scope == FilterType.Client) {
- this.editFilter(newId);
- }
- else {
- Hooks.once("QuickInsert:FiltersUpdated", () => this.editFilter(newId));
- }
- }
- async _updateObject() {
- return;
- }
- }
-
- class SheetFilters extends FormApplication {
- get element() {
- return super.element;
- }
- static get defaultOptions() {
- return {
- ...super.defaultOptions,
- title: i18n("SheetFiltersTitle"),
- id: "sheet-filters",
- template: "modules/quick-insert/templates/sheet-filters.hbs",
- resizable: true,
- };
- }
- getData() {
- const filters = QuickInsert.filters.filters;
- const customFilters = getSetting(ModuleSetting.FILTERS_SHEETS).baseFilters;
- return {
- filters: Object.entries(customFilters).map(([key, filter]) => ({
- key,
- noFilter: filter === "",
- options: filters.map((f) => ({
- ...f,
- selected: filter === f.tag || filter === f.id,
- })),
- })),
- };
- }
- activateListeners(html) {
- super.activateListeners(html);
- }
- async _updateObject(event, formData) {
- setSetting(ModuleSetting.FILTERS_SHEETS, {
- baseFilters: formData,
- });
- }
- }
-
- async function importSystemIntegration() {
- let system = null;
- switch (game.system.id) {
- case "dnd5e":
- system = await import('./dnd5e.js');
- break;
- case "pf2e":
- system = await import('./pf2e.js');
- break;
- case "swade":
- system = await import('./swade.js');
- break;
- case "wfrp4e":
- system = await import('./wfrp4e.js');
- break;
- case "sfrpg":
- system = await import('./sfrpg.js');
- break;
- case "demonlord":
- system = await import('./demonlord.js');
- break;
- default:
- return;
- }
- return {
- id: game.system.id,
- ...system,
- };
- }
-
- function registerTinyMCEPlugin() {
- // TinyMCE addon registration
- tinymce.PluginManager.add("quickinsert", function (editor) {
- editor.on("keydown", (evt) => {
- const context = new TinyMCEContext(editor);
- customKeybindHandler(evt, context);
- });
- editor.ui.registry.addButton("quickinsert", {
- tooltip: "Quick Insert",
- icon: "search",
- onAction: function () {
- if (QuickInsert.app?.embeddedMode)
- return;
- // Open window
- QuickInsert.open(new TinyMCEContext(editor));
- },
- });
- });
- CONFIG.TinyMCE.plugins = CONFIG.TinyMCE.plugins + " quickinsert";
- CONFIG.TinyMCE.toolbar = CONFIG.TinyMCE.toolbar + " quickinsert";
- }
-
- const DOCUMENTACTIONS = {
- show: (item) => item.show(),
- roll: (item) => item.get().then((d) => d.draw()),
- viewScene: (item) => item.get().then((d) => d.view()),
- activateScene: (item) => item.get().then((d) => {
- game.user?.isGM && d.activate();
- }),
- execute: (item) => item.get().then((d) => d.execute()),
- insert: (item) => item,
- rollInsert: (item) => item.get().then(async (d) => {
- const roll = await d.roll();
- for (const data of roll.results) {
- if (!data.documentId) {
- return data.text;
- }
- if (data.documentCollection.includes(".")) {
- const pack = game.packs.get(data.documentCollection);
- if (!pack)
- return data.text;
- const indexItem = game.packs
- .get(data.documentCollection)
- ?.index.find((i) => i._id === data.documentId);
- return indexItem
- ? new CompendiumSearchItem(pack, indexItem)
- : data.text;
- }
- else {
- const entity = getCollectionFromType(data.documentCollection).get(data.documentId);
- return entity ? new EntitySearchItem(entity) : data.text;
- }
- }
- }),
- };
- const BrowseDocumentActions = (() => {
- const actions = {
- [DocumentType.SCENE]: [
- {
- id: "activateScene",
- icon: "fas fa-bullseye",
- title: "Activate",
- },
- {
- id: "viewScene",
- icon: "fas fa-eye",
- title: "View",
- },
- {
- id: "show",
- icon: "fas fa-cogs",
- title: "Configure",
- },
- ],
- [DocumentType.ROLLTABLE]: [
- {
- id: "roll",
- icon: "fas fa-dice-d20",
- title: "Roll",
- },
- {
- id: "show",
- icon: `fas ${documentIcons[DocumentType.ROLLTABLE]}`,
- title: "Edit",
- },
- ],
- [DocumentType.MACRO]: [
- {
- id: "execute",
- icon: "fas fa-play",
- title: "Execute",
- },
- {
- id: "show",
- icon: `fas ${documentIcons[DocumentType.ROLLTABLE]}`,
- title: "Edit",
- },
- ],
- };
- IndexedDocumentTypes.forEach((type) => {
- if (type in actions)
- return;
- actions[type] = [
- {
- id: "show",
- icon: `fas ${documentIcons[type]}`,
- title: "Show",
- },
- ];
- });
- return actions;
- })();
- // Same for all inserts
- const insertAction = {
- id: "insert",
- icon: `fas fa-plus`,
- title: "Insert",
- };
- const InsertDocumentActions = (() => {
- const actions = {
- [DocumentType.SCENE]: [
- {
- id: "show",
- icon: "fas fa-cogs",
- title: "Configure",
- },
- ],
- [DocumentType.ROLLTABLE]: [
- {
- id: "rollInsert",
- icon: "fas fa-play",
- title: "Roll and Insert",
- },
- {
- id: "show",
- icon: `fas ${documentIcons[DocumentType.ROLLTABLE]}`,
- title: "Show",
- },
- ],
- };
- // Add others
- IndexedDocumentTypes.forEach((type) => {
- if (!actions[type]) {
- // If nothing else, add "Show"
- actions[type] = [
- {
- id: "show",
- icon: `fas ${documentIcons[type]}`,
- title: "Show",
- },
- ];
- }
- actions[type].push(insertAction);
- });
- return actions;
- })();
- function getActions(type, isInsertContext) {
- return isInsertContext
- ? InsertDocumentActions[type]
- : BrowseDocumentActions[type];
- }
- function defaultAction(type, isInsertContext) {
- if (!isInsertContext) {
- switch (type) {
- case DocumentType.SCENE:
- return getSetting(ModuleSetting.DEFAULT_ACTION_SCENE);
- case DocumentType.ROLLTABLE:
- return getSetting(ModuleSetting.DEFAULT_ACTION_ROLL_TABLE);
- case DocumentType.MACRO:
- return getSetting(ModuleSetting.DEFAULT_ACTION_MACRO);
- }
- }
- const actions = getActions(type, isInsertContext);
- return actions[actions.length - 1].id;
- }
-
- /* src/app/SearchResults.svelte generated by Svelte v3.49.0 */
-
- function get_each_context$1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[13] = list[i].item;
- child_ctx[14] = list[i].match;
- child_ctx[15] = list[i].actions;
- child_ctx[16] = list[i].defaultAction;
- child_ctx[18] = i;
- return child_ctx;
- }
-
- function get_each_context_1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[19] = list[i];
- return child_ctx;
- }
-
- // (52:0) {#if active}
- function create_if_block$1(ctx) {
- let ul;
- let each_blocks = [];
- let each_1_lookup = new Map();
- let each_value = /*results*/ ctx[2];
- const get_key = ctx => /*item*/ ctx[13].uuid;
-
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context$1(ctx, each_value, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block$1(key, child_ctx));
- }
-
- return {
- c() {
- ul = element("ul");
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
-
- attr(ul, "class", "quick-insert-result");
- attr(ul, "data-tooltip-direction", /*tooltips*/ ctx[0]);
- },
- m(target, anchor) {
- insert(target, ul, anchor);
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(ul, null);
- }
-
- /*ul_binding*/ ctx[11](ul);
- },
- p(ctx, dirty) {
- if (dirty & /*getTooltip, results, tooltips, selectedIndex, JSON, callAction, selectedAction, formatMatch*/ 221) {
- each_value = /*results*/ ctx[2];
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, ul, destroy_block, create_each_block$1, null, get_each_context$1);
- }
-
- if (dirty & /*tooltips*/ 1) {
- attr(ul, "data-tooltip-direction", /*tooltips*/ ctx[0]);
- }
- },
- d(detaching) {
- if (detaching) detach(ul);
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
-
- /*ul_binding*/ ctx[11](null);
- }
- };
- }
-
- // (77:10) {:else}
- function create_else_block(ctx) {
- let html_tag;
- let raw_value = /*item*/ ctx[13].icon + "";
- let html_anchor;
-
- return {
- c() {
- html_tag = new HtmlTag(false);
- html_anchor = empty();
- html_tag.a = html_anchor;
- },
- m(target, anchor) {
- html_tag.m(raw_value, target, anchor);
- insert(target, html_anchor, anchor);
- },
- p(ctx, dirty) {
- if (dirty & /*results*/ 4 && raw_value !== (raw_value = /*item*/ ctx[13].icon + "")) html_tag.p(raw_value);
- },
- d(detaching) {
- if (detaching) detach(html_anchor);
- if (detaching) html_tag.d();
- }
- };
- }
-
- // (75:10) {#if item.img}
- function create_if_block_1(ctx) {
- let img;
- let img_src_value;
-
- return {
- c() {
- img = element("img");
- if (!src_url_equal(img.src, img_src_value = /*item*/ ctx[13].img)) attr(img, "src", img_src_value);
- },
- m(target, anchor) {
- insert(target, img, anchor);
- },
- p(ctx, dirty) {
- if (dirty & /*results*/ 4 && !src_url_equal(img.src, img_src_value = /*item*/ ctx[13].img)) {
- attr(img, "src", img_src_value);
- }
- },
- d(detaching) {
- if (detaching) detach(img);
- }
- };
- }
-
- // (88:12) {#each actions as action}
- function create_each_block_1(ctx) {
- let i;
- let i_class_value;
- let i_title_value;
- let i_data_action_id_value;
- let mounted;
- let dispose;
-
- function click_handler(...args) {
- return /*click_handler*/ ctx[8](/*action*/ ctx[19], /*item*/ ctx[13], ...args);
- }
-
- return {
- c() {
- i = element("i");
- attr(i, "class", i_class_value = "" + (/*action*/ ctx[19].icon + " action-icon"));
- attr(i, "title", i_title_value = "" + (/*action*/ ctx[19].title + " '" + /*item*/ ctx[13].name + "'"));
- attr(i, "data-action-id", i_data_action_id_value = /*action*/ ctx[19].id);
-
- toggle_class(i, "selected", /*i*/ ctx[18] === /*selectedIndex*/ ctx[3] && (/*selectedAction*/ ctx[4]
- ? /*action*/ ctx[19].id === /*selectedAction*/ ctx[4]
- : /*action*/ ctx[19].id == /*defaultAction*/ ctx[16]));
- },
- m(target, anchor) {
- insert(target, i, anchor);
-
- if (!mounted) {
- dispose = listen(i, "click", stop_propagation(click_handler));
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
-
- if (dirty & /*results*/ 4 && i_class_value !== (i_class_value = "" + (/*action*/ ctx[19].icon + " action-icon"))) {
- attr(i, "class", i_class_value);
- }
-
- if (dirty & /*results*/ 4 && i_title_value !== (i_title_value = "" + (/*action*/ ctx[19].title + " '" + /*item*/ ctx[13].name + "'"))) {
- attr(i, "title", i_title_value);
- }
-
- if (dirty & /*results*/ 4 && i_data_action_id_value !== (i_data_action_id_value = /*action*/ ctx[19].id)) {
- attr(i, "data-action-id", i_data_action_id_value);
- }
-
- if (dirty & /*results, results, selectedIndex, selectedAction*/ 28) {
- toggle_class(i, "selected", /*i*/ ctx[18] === /*selectedIndex*/ ctx[3] && (/*selectedAction*/ ctx[4]
- ? /*action*/ ctx[19].id === /*selectedAction*/ ctx[4]
- : /*action*/ ctx[19].id == /*defaultAction*/ ctx[16]));
- }
- },
- d(detaching) {
- if (detaching) detach(i);
- mounted = false;
- dispose();
- }
- };
- }
-
- // (58:4) {#each results as { item, match, actions, defaultAction }
- function create_each_block$1(key_1, ctx) {
- let li;
- let a;
- let t0;
- let span0;
-
- let raw_value = formatMatch(
- {
- item: /*item*/ ctx[13],
- match: /*match*/ ctx[14]
- },
- func
- ) + "";
-
- let t1;
- let span1;
- let t2_value = /*item*/ ctx[13].tagline + "";
- let t2;
- let t3;
- let span2;
- let a_title_value;
- let t4;
- let li_data_tooltip_value;
- let mounted;
- let dispose;
-
- function select_block_type(ctx, dirty) {
- if (/*item*/ ctx[13].img) return create_if_block_1;
- return create_else_block;
- }
-
- let current_block_type = select_block_type(ctx);
- let if_block = current_block_type(ctx);
- let each_value_1 = /*actions*/ ctx[15];
- let each_blocks = [];
-
- for (let i = 0; i < each_value_1.length; i += 1) {
- each_blocks[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i));
- }
-
- function dragstart_handler(...args) {
- return /*dragstart_handler*/ ctx[9](/*item*/ ctx[13], ...args);
- }
-
- function click_handler_1(...args) {
- return /*click_handler_1*/ ctx[10](/*defaultAction*/ ctx[16], /*item*/ ctx[13], ...args);
- }
-
- return {
- key: key_1,
- first: null,
- c() {
- li = element("li");
- a = element("a");
- if_block.c();
- t0 = space();
- span0 = element("span");
- t1 = space();
- span1 = element("span");
- t2 = text(t2_value);
- t3 = space();
- span2 = element("span");
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
-
- t4 = space();
- attr(span0, "class", "title");
- attr(span1, "class", "sub");
- attr(span2, "class", "action-icons");
- attr(a, "draggable", "true");
- attr(a, "title", a_title_value = "" + (/*item*/ ctx[13].name + ", " + /*item*/ ctx[13].tagline));
- attr(li, "data-tooltip", li_data_tooltip_value = /*getTooltip*/ ctx[7](/*item*/ ctx[13], /*tooltips*/ ctx[0]));
- toggle_class(li, "search-selected", /*i*/ ctx[18] === /*selectedIndex*/ ctx[3]);
- this.first = li;
- },
- m(target, anchor) {
- insert(target, li, anchor);
- append(li, a);
- if_block.m(a, null);
- append(a, t0);
- append(a, span0);
- span0.innerHTML = raw_value;
- append(a, t1);
- append(a, span1);
- append(span1, t2);
- append(a, t3);
- append(a, span2);
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(span2, null);
- }
-
- append(li, t4);
-
- if (!mounted) {
- dispose = [
- listen(a, "dragstart", dragstart_handler),
- listen(a, "click", stop_propagation(click_handler_1))
- ];
-
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
-
- if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) {
- if_block.p(ctx, dirty);
- } else {
- if_block.d(1);
- if_block = current_block_type(ctx);
-
- if (if_block) {
- if_block.c();
- if_block.m(a, t0);
- }
- }
-
- if (dirty & /*results*/ 4 && raw_value !== (raw_value = formatMatch(
- {
- item: /*item*/ ctx[13],
- match: /*match*/ ctx[14]
- },
- func
- ) + "")) span0.innerHTML = raw_value;
- if (dirty & /*results*/ 4 && t2_value !== (t2_value = /*item*/ ctx[13].tagline + "")) set_data(t2, t2_value);
-
- if (dirty & /*results, selectedIndex, selectedAction, callAction*/ 92) {
- each_value_1 = /*actions*/ ctx[15];
- let i;
-
- for (i = 0; i < each_value_1.length; i += 1) {
- const child_ctx = get_each_context_1(ctx, each_value_1, i);
-
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- } else {
- each_blocks[i] = create_each_block_1(child_ctx);
- each_blocks[i].c();
- each_blocks[i].m(span2, null);
- }
- }
-
- for (; i < each_blocks.length; i += 1) {
- each_blocks[i].d(1);
- }
-
- each_blocks.length = each_value_1.length;
- }
-
- if (dirty & /*results*/ 4 && a_title_value !== (a_title_value = "" + (/*item*/ ctx[13].name + ", " + /*item*/ ctx[13].tagline))) {
- attr(a, "title", a_title_value);
- }
-
- if (dirty & /*results, tooltips*/ 5 && li_data_tooltip_value !== (li_data_tooltip_value = /*getTooltip*/ ctx[7](/*item*/ ctx[13], /*tooltips*/ ctx[0]))) {
- attr(li, "data-tooltip", li_data_tooltip_value);
- }
-
- if (dirty & /*results, selectedIndex*/ 12) {
- toggle_class(li, "search-selected", /*i*/ ctx[18] === /*selectedIndex*/ ctx[3]);
- }
- },
- d(detaching) {
- if (detaching) detach(li);
- if_block.d();
- destroy_each(each_blocks, detaching);
- mounted = false;
- run_all(dispose);
- }
- };
- }
-
- function create_fragment$1(ctx) {
- let if_block_anchor;
- let if_block = /*active*/ ctx[1] && create_if_block$1(ctx);
-
- return {
- c() {
- if (if_block) if_block.c();
- if_block_anchor = empty();
- },
- m(target, anchor) {
- if (if_block) if_block.m(target, anchor);
- insert(target, if_block_anchor, anchor);
- },
- p(ctx, [dirty]) {
- if (/*active*/ ctx[1]) {
- if (if_block) {
- if_block.p(ctx, dirty);
- } else {
- if_block = create_if_block$1(ctx);
- if_block.c();
- if_block.m(if_block_anchor.parentNode, if_block_anchor);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (if_block) if_block.d(detaching);
- if (detaching) detach(if_block_anchor);
- }
- };
- }
-
- const func = str => `<strong>${str}</strong>`;
-
- function instance$1($$self, $$props, $$invalidate) {
- const dispatch = createEventDispatcher();
- let { tooltips = "LEFT" } = $$props;
- let { active = false } = $$props;
- let { results = [] } = $$props;
- let { selectedIndex = 0 } = $$props;
- let { selectedAction = "show" } = $$props;
- let resultList;
-
- afterUpdate(() => {
- const tooltipMode = getSetting(ModuleSetting.SEARCH_TOOLTIPS);
-
- if (resultList?.children[selectedIndex]) {
- const selected = resultList.children[selectedIndex];
- selected.scrollIntoView({ block: "nearest" });
-
- if (tooltipMode !== "off" && selected.dataset?.tooltip) {
- //@ts-expect-error update types...
- game.tooltip.activate(selected);
- } else {
- //@ts-expect-error update types...
- game.tooltip.deactivate();
- }
- } else {
- if (tooltipMode !== "off") {
- //@ts-expect-error update types...
- game.tooltip.deactivate();
- }
- }
- });
-
- function callAction(actionId, item, shiftKey) {
- dispatch("callAction", { actionId, item, shiftKey });
- }
-
- function getTooltip(item, side) {
- const tooltipMode = getSetting(ModuleSetting.SEARCH_TOOLTIPS);
- if (tooltipMode === "off") return "";
- const showImage = tooltipMode === "full" || tooltipMode === "image";
-
- const img = showImage && item.img
- ? `<img src=${item.img} style="max-width: 120px; float:${side === "LEFT" ? "right" : "left"};"/>`
- : "";
-
- const text = tooltipMode !== "image"
- ? `<p style='margin:0;text-align:left'>${item.icon} ${item.name}</p>
- <p style='font-size: 90%; opacity:0.8;margin:0;'>${item.tooltip}</p>`
- : "";
-
- return text + img;
- }
-
- const click_handler = (action, item, e) => callAction(action.id, item, e.shiftKey);
- const dragstart_handler = (item, event) => event.dataTransfer?.setData("text/plain", JSON.stringify(item.dragData));
- const click_handler_1 = (defaultAction, item, e) => callAction(defaultAction, item, e.shiftKey);
-
- function ul_binding($$value) {
- binding_callbacks[$$value ? 'unshift' : 'push'](() => {
- resultList = $$value;
- $$invalidate(5, resultList);
- });
- }
-
- $$self.$$set = $$props => {
- if ('tooltips' in $$props) $$invalidate(0, tooltips = $$props.tooltips);
- if ('active' in $$props) $$invalidate(1, active = $$props.active);
- if ('results' in $$props) $$invalidate(2, results = $$props.results);
- if ('selectedIndex' in $$props) $$invalidate(3, selectedIndex = $$props.selectedIndex);
- if ('selectedAction' in $$props) $$invalidate(4, selectedAction = $$props.selectedAction);
- };
-
- return [
- tooltips,
- active,
- results,
- selectedIndex,
- selectedAction,
- resultList,
- callAction,
- getTooltip,
- click_handler,
- dragstart_handler,
- click_handler_1,
- ul_binding
- ];
- }
-
- class SearchResults extends SvelteComponent {
- constructor(options) {
- super();
-
- init(this, options, instance$1, create_fragment$1, safe_not_equal, {
- tooltips: 0,
- active: 1,
- results: 2,
- selectedIndex: 3,
- selectedAction: 4
- });
- }
- }
-
- /* src/app/SearchFiltersResults.svelte generated by Svelte v3.49.0 */
-
- function get_each_context(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[8] = list[i];
- child_ctx[10] = i;
- return child_ctx;
- }
-
- // (15:0) {#if active}
- function create_if_block(ctx) {
- let ul;
- let each_blocks = [];
- let each_1_lookup = new Map();
- let each_value = /*results*/ ctx[1];
- const get_key = ctx => /*item*/ ctx[8].id;
-
- 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() {
- ul = element("ul");
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
-
- attr(ul, "class", "quick-insert-result");
- },
- m(target, anchor) {
- insert(target, ul, anchor);
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(ul, null);
- }
-
- /*ul_binding*/ ctx[6](ul);
- },
- p(ctx, dirty) {
- if (dirty & /*results, selectedIndex, selected*/ 22) {
- each_value = /*results*/ ctx[1];
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, ul, destroy_block, create_each_block, null, get_each_context);
- }
- },
- d(detaching) {
- if (detaching) detach(ul);
-
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
-
- /*ul_binding*/ ctx[6](null);
- }
- };
- }
-
- // (17:4) {#each results as item, i (item.id)}
- function create_each_block(key_1, ctx) {
- let li;
- let a;
- let span0;
- let t0;
- let t1_value = /*item*/ ctx[8].tag + "";
- let t1;
- let t2;
- let span1;
- let t3_value = /*item*/ ctx[8].subTitle + "";
- let t3;
- let t4;
- let mounted;
- let dispose;
-
- function click_handler() {
- return /*click_handler*/ ctx[5](/*i*/ ctx[10]);
- }
-
- return {
- key: key_1,
- first: null,
- c() {
- li = element("li");
- a = element("a");
- span0 = element("span");
- t0 = text("@");
- t1 = text(t1_value);
- t2 = space();
- span1 = element("span");
- t3 = text(t3_value);
- t4 = space();
- attr(span0, "class", "title");
- attr(span1, "class", "sub");
- toggle_class(li, "search-selected", /*i*/ ctx[10] === /*selectedIndex*/ ctx[2]);
- this.first = li;
- },
- m(target, anchor) {
- insert(target, li, anchor);
- append(li, a);
- append(a, span0);
- append(span0, t0);
- append(span0, t1);
- append(a, t2);
- append(a, span1);
- append(span1, t3);
- append(li, t4);
-
- if (!mounted) {
- dispose = listen(a, "click", click_handler);
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- if (dirty & /*results*/ 2 && t1_value !== (t1_value = /*item*/ ctx[8].tag + "")) set_data(t1, t1_value);
- if (dirty & /*results*/ 2 && t3_value !== (t3_value = /*item*/ ctx[8].subTitle + "")) set_data(t3, t3_value);
-
- if (dirty & /*results, selectedIndex*/ 6) {
- toggle_class(li, "search-selected", /*i*/ ctx[10] === /*selectedIndex*/ ctx[2]);
- }
- },
- d(detaching) {
- if (detaching) detach(li);
- mounted = false;
- dispose();
- }
- };
- }
-
- function create_fragment(ctx) {
- let if_block_anchor;
- let if_block = /*active*/ ctx[0] && create_if_block(ctx);
-
- return {
- c() {
- if (if_block) if_block.c();
- if_block_anchor = empty();
- },
- m(target, anchor) {
- if (if_block) if_block.m(target, anchor);
- insert(target, if_block_anchor, anchor);
- },
- p(ctx, [dirty]) {
- if (/*active*/ ctx[0]) {
- if (if_block) {
- if_block.p(ctx, dirty);
- } else {
- if_block = create_if_block(ctx);
- if_block.c();
- if_block.m(if_block_anchor.parentNode, if_block_anchor);
- }
- } else if (if_block) {
- if_block.d(1);
- if_block = null;
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (if_block) if_block.d(detaching);
- if (detaching) detach(if_block_anchor);
- }
- };
- }
-
- function instance($$self, $$props, $$invalidate) {
- const dispatch = createEventDispatcher();
- let { active = false } = $$props;
- let { results = [] } = $$props;
- let { selectedIndex = 0 } = $$props;
- let resultList;
-
- afterUpdate(() => {
- resultList?.children[selectedIndex]?.scrollIntoView({ block: "nearest" });
- });
-
- function selected(index) {
- dispatch("selected", { index });
- }
-
- const click_handler = i => selected(i);
-
- function ul_binding($$value) {
- binding_callbacks[$$value ? 'unshift' : 'push'](() => {
- resultList = $$value;
- $$invalidate(3, resultList);
- });
- }
-
- $$self.$$set = $$props => {
- if ('active' in $$props) $$invalidate(0, active = $$props.active);
- if ('results' in $$props) $$invalidate(1, results = $$props.results);
- if ('selectedIndex' in $$props) $$invalidate(2, selectedIndex = $$props.selectedIndex);
- };
-
- return [
- active,
- results,
- selectedIndex,
- resultList,
- selected,
- click_handler,
- ul_binding
- ];
- }
-
- class SearchFiltersResults extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance, create_fragment, safe_not_equal, { active: 0, results: 1, selectedIndex: 2 });
- }
- }
-
- // A search controller controls a specific search output.
- // This lets us implement multiple different searches with the same search app,
- // e.g. entities and filters, or maybe in the future; commands, open windows, etc.
- class SearchController {
- constructor(app) {
- this.results = [];
- this.selectedIndex = -1;
- this.selectedAction = null;
- this.app = app;
- }
- get isInsertMode() {
- return (this.app.attachedContext?.mode == undefined ||
- this.app.attachedContext.mode == ContextMode.Insert);
- }
- activate() {
- const left = this.app.attachedContext?.spawnCSS?.left;
- const tooltipSide = left !== undefined && left < 300 ? "RIGHT" : "LEFT";
- this.view?.$$set?.({ active: true, tooltips: tooltipSide });
- }
- deactivate() {
- this.view?.$$set?.({ active: false });
- }
- selectNext() {
- this.selectedIndex = (this.selectedIndex + 1) % this.results.length;
- this.view?.$$set?.({
- selectedIndex: this.selectedIndex,
- selectedAction: (this.selectedAction = null),
- });
- }
- selectPrevious() {
- this.selectedIndex =
- this.selectedIndex > 0 ? this.selectedIndex - 1 : this.results.length - 1;
- this.view?.$$set?.({
- selectedIndex: this.selectedIndex,
- selectedAction: (this.selectedAction = null),
- });
- }
- }
- class DocumentController extends SearchController {
- constructor() {
- super(...arguments);
- this.results = [];
- this.selectedAction = null; // null means use defaultAction
- this.search = (textInput) => {
- if (!QuickInsert.searchLib)
- return;
- textInput = textInput.trim();
- if (textInput.length == 0) {
- this.view?.$$set?.({
- results: [],
- selectedIndex: (this.selectedIndex = -1),
- });
- return;
- }
- // Set a lower maximum if search is single char (single-character search is fast, but rendering is slow).
- const max = textInput.length == 1 ? 20 : 100;
- let results = [];
- if (this.app.selectedFilter) {
- if (this.app.selectedFilter.filterConfig) {
- results = QuickInsert.searchLib.search(textInput, (item) => this.app.selectedFilter?.filterConfig
- ? matchFilterConfig(this.app.selectedFilter.filterConfig, item)
- : true, max);
- }
- }
- else {
- results = QuickInsert.searchLib.search(textInput, null, max);
- }
- if (this.app.attachedContext &&
- this.app.attachedContext.restrictTypes &&
- this.app.attachedContext.restrictTypes.length > 0) {
- results = results.filter((i) => this.app.attachedContext?.restrictTypes?.includes(i.item.documentType));
- }
- this.results = results.map((res) => ({
- item: res.item,
- match: res.match,
- actions: getActions(res.item.documentType, this.isInsertMode),
- defaultAction: defaultAction(res.item.documentType, this.isInsertMode),
- }));
- this.view?.$$set?.({
- results: this.results.reverse(),
- selectedIndex: (this.selectedIndex = this.results.length - 1),
- selectedAction: (this.selectedAction = null),
- });
- };
- }
- onTab(index) {
- const actions = this.results[index].actions;
- if (actions.length == 0)
- return;
- let idx;
- if (this.selectedAction) {
- idx = actions.findIndex((a) => a.id == this.selectedAction);
- }
- else {
- idx = actions.findIndex((a) => a.id == this.results[index].defaultAction);
- }
- const nextIdx = (idx + 1) % actions.length;
- this.view?.$$set?.({
- selectedAction: (this.selectedAction = actions[nextIdx].id),
- });
- }
- onEnter(index, evt) {
- // TODO: get selected action
- this.onAction(this.selectedAction || this.results[index].defaultAction, this.results[index].item, Boolean(evt.shiftKey));
- }
- async onAction(actionId, item, shiftKey) {
- console.info(`Quick Insert | Invoked Action [${actionId}] on [${item.name}] shiftKey:${shiftKey}`);
- const val = await DOCUMENTACTIONS[actionId](item);
- if (val && this.isInsertMode) {
- this.app.keepOpen = shiftKey; // Keep open until onSubmit completes
- this.app.attachedContext?.onSubmit(val);
- }
- if (this.app.attachedContext?.allowMultiple === false || !shiftKey) {
- this.app.closeDialog();
- }
- this.app.keepOpen = false;
- }
- }
- class FilterController extends SearchController {
- constructor() {
- super(...arguments);
- this.results = [];
- }
- onTab(index) {
- this.onEnter(index);
- }
- onEnter(index) {
- this.selectFilter(this.results[index]);
- }
- selectFilter(filter) {
- this.app.setFilterTag(filter);
- this.app.selectedFilter = filter;
- this.deactivate();
- this.app.showHint(`Searching: ${filter.subTitle}`);
- }
- onClick(index) {
- this.onEnter(index);
- this.app.focusInput();
- }
- search(textInput) {
- const cleanedInput = textInput.toLowerCase().trim();
- if (/\s$/g.test(textInput)) {
- // User has added a space after tag -> selected
- const matchingFilter = QuickInsert.filters.getFilterByTag(cleanedInput);
- if (matchingFilter) {
- this.selectFilter(matchingFilter);
- return;
- }
- }
- this.results = QuickInsert.filters.filters
- .filter((f) => !f.disabled)
- .filter((f) => f.tag.includes(cleanedInput));
- this.view?.$$set?.({
- results: this.results,
- selectedIndex: (this.selectedIndex = this.results.length - 1),
- });
- }
- }
- var ActiveMode;
- (function (ActiveMode) {
- ActiveMode[ActiveMode["Search"] = 1] = "Search";
- ActiveMode[ActiveMode["Filter"] = 2] = "Filter";
- })(ActiveMode || (ActiveMode = {}));
- class SearchApp extends Application {
- constructor() {
- super({
- template: "modules/quick-insert/templates/quick-insert.html",
- popOut: false,
- });
- this.debug = false;
- this.mouseFocus = false;
- this.inputFocus = false;
- this.keepOpen = false;
- this.mode = ActiveMode.Search;
- this.selectedFilter = null;
- this.attachedContext = null;
- this.embeddedMode = false;
- this.filterController = new FilterController(this);
- this.documentController = new DocumentController(this);
- this._checkFocus = () => {
- if (this.debug || this.embeddedMode)
- return;
- if (!this.mouseFocus && !this.inputFocus && !this.keepOpen) {
- this.closeDialog();
- }
- };
- this._onKeyTab = (evt) => {
- evt.preventDefault();
- if (!this.embeddedMode)
- this.controller.onTab(this.controller.selectedIndex);
- };
- this._onKeyEsc = (evt) => {
- if (this.embeddedMode)
- return;
- evt.preventDefault();
- evt.stopPropagation();
- this.closeDialog();
- };
- this._onKeyDown = (evt) => {
- evt.preventDefault();
- this.selectNext();
- };
- this._onKeyUp = (evt) => {
- evt.preventDefault();
- this.selectPrevious();
- };
- this._onKeyEnter = (evt) => {
- evt.preventDefault();
- evt.stopImmediatePropagation();
- if (this.controller.selectedIndex > -1) {
- this.controller.onEnter(this.controller.selectedIndex, evt);
- }
- };
- }
- get open() {
- return this._state > 0;
- }
- get controller() {
- if (this.mode === ActiveMode.Filter) {
- return this.filterController;
- }
- return this.documentController;
- }
- activateMode(mode) {
- this.controller?.deactivate();
- this.mode = mode;
- this.controller?.activate();
- }
- resetInput(full = false) {
- if (!full && this.selectedFilter) {
- this.setFilterTag(this.selectedFilter);
- }
- else {
- this.input?.html("");
- }
- this.text = undefined;
- this.focusInput();
- }
- selectNext() {
- this.controller?.selectNext();
- }
- selectPrevious() {
- this.controller?.selectPrevious();
- }
- setFilterTag(filter) {
- if (!this.input)
- return;
- const focus = this.input.is(":focus");
- this.input.html("");
- const editable = this.embeddedMode ? `contenteditable="false"` : "";
- $(`<span class="search-tag" ${editable}>@${filter.tag}</span>`).prependTo(this.input);
- $('<span class="breaker"> </span>').appendTo(this.input);
- if (focus) {
- this.focusInput();
- }
- }
- closeDialog() {
- if (this.embeddedMode)
- return;
- this.attachedContext?.onClose?.();
- this.selectedFilter = null;
- //@ts-expect-error tooltip not in types yet
- game.tooltip.deactivate();
- this.close();
- }
- render(force, options) {
- if (options && options.context) {
- this.attachedContext = options.context;
- return super.render(force, options);
- }
- // Try to infer context
- const target = document.activeElement;
- if (target) {
- this.attachedContext = identifyContext(target);
- }
- if (!this.attachedContext) {
- return null;
- }
- return super.render(force, options);
- }
- showHint(notice) {
- this.hint?.html(notice);
- }
- focusInput() {
- if (!this.input)
- return;
- placeCaretAtEnd(this.input.get(0));
- this.inputFocus = true;
- }
- activateListeners(html) {
- // (Re-)set position
- html.removeAttr("style");
- if (this.attachedContext?.spawnCSS) {
- html.css(this.attachedContext.spawnCSS);
- }
- if (this.attachedContext?.classes) {
- html.addClass(this.attachedContext.classes);
- }
- this.input = html.find(".search-editable-input");
- this.hint = html.find(".quick-insert-hint");
- this.input.on("input", () => {
- this.searchInput();
- });
- this.input.on("dragstart", (evt) => evt.stopPropagation());
- this.input.on("keydown", (evt) => {
- switch (evt.which) {
- case 13:
- return this._onKeyEnter(evt);
- case 40:
- return this._onKeyDown(evt);
- case 38:
- return this._onKeyUp(evt);
- case 27:
- return this._onKeyEsc(evt);
- case 9:
- return this._onKeyTab(evt);
- }
- });
- $(this.element).hover(() => {
- this.mouseFocus = true;
- this._checkFocus();
- }, (e) => {
- if (e.originalEvent?.shiftKey)
- return;
- this.mouseFocus = false;
- this._checkFocus();
- });
- $(this.element).on("focusout", () => {
- this.inputFocus = false;
- this._checkFocus();
- });
- $(this.element).on("focusin", () => {
- this.inputFocus = true;
- this._checkFocus();
- });
- this.focusInput();
- const node = this.element.get(0);
- if (node) {
- this.documentController.view = new SearchResults({
- target: node,
- });
- this.filterController.view = new SearchFiltersResults({
- target: node,
- });
- }
- this.documentController.view?.$on("callAction", (data) => {
- const { actionId, item, shiftKey } = data.detail;
- this.documentController.onAction(actionId, item, shiftKey);
- });
- this.filterController.view?.$on("selected", (data) => {
- const { index } = data.detail;
- this.filterController.onClick(index);
- });
- if (this.attachedContext?.filter) {
- this.activateMode(ActiveMode.Filter);
- if (typeof this.attachedContext.filter === "string") {
- const found = QuickInsert.filters.getFilterByTag(this.attachedContext.filter) ??
- QuickInsert.filters.getFilter(this.attachedContext.filter);
- if (found) {
- this.filterController.selectFilter(found);
- }
- }
- else {
- this.filterController.selectFilter(this.attachedContext.filter);
- }
- }
- if (this.attachedContext?.startText) {
- this.input.append(this.attachedContext.startText);
- this.focusInput();
- this.searchInput();
- }
- if (!QuickInsert.searchLib) {
- this.showHint(`<i class="fas fa-spinner"></i> Loading index...`);
- loadSearchIndex()
- .then(() => {
- if (this.input?.text().trim().length) {
- this.searchInput();
- }
- else {
- this.showHint(`Index loaded successfully`);
- }
- })
- .catch((reason) => {
- this.showHint(`Failed to load index ${reason}`);
- });
- // @ts-ignore
- }
- else if (QuickInsert.searchLib?.index?.fuse._docs.length == 0) {
- this.showHint(`Search index is empty for some reason`);
- }
- }
- searchInput() {
- if (!this.input)
- return;
- const text = this.input.text();
- this.text = text;
- const breaker = $(this.input).find(".breaker");
- this.showHint("");
- if (this.selectedFilter) {
- // Text was changed or breaker was removed
- if (!text.startsWith(`@${this.selectedFilter.tag}`) ||
- breaker.length === 0 ||
- breaker.is(":empty") ||
- breaker.html() === "<br>") {
- if (this.embeddedMode) {
- this.setFilterTag(this.selectedFilter);
- return;
- }
- // Selectedfilter doesn't match any more :(
- this.input.html(text);
- this.focusInput();
- this.selectedFilter = null;
- this.activateMode(ActiveMode.Filter);
- this.filterController.search(text.substr(1).trim());
- }
- else {
- this.activateMode(ActiveMode.Search);
- const search = text.replace(`@${this.selectedFilter.tag}`, "").trim();
- this.documentController.search(search);
- }
- }
- else if (text.startsWith("@")) {
- this.activateMode(ActiveMode.Filter);
- this.filterController.search(text.substr(1));
- }
- else {
- this.activateMode(ActiveMode.Search);
- this.documentController.search(text);
- }
- }
- }
-
- class IndexingSettings extends FormApplication {
- static get defaultOptions() {
- return {
- ...super.defaultOptions,
- title: i18n("IndexingSettingsTitle"),
- id: "indexing-settings",
- template: "modules/quick-insert/templates/indexing-settings.hbs",
- resizable: true,
- width: 660,
- };
- }
- getData() {
- if (!game.packs)
- return null;
- const disabled = getSetting(ModuleSetting.INDEXING_DISABLED);
- return {
- documentTypes: IndexedDocumentTypes.map((type) => ({
- type,
- title: `DOCUMENT.${type}`,
- values: [1, 2, 3, 4].map((role) => ({
- role,
- disabled: disabled?.entities?.[type]?.includes(role),
- })),
- })),
- compendiums: [...game.packs.keys()].map((pack) => ({
- pack,
- values: [1, 2, 3, 4].map((role) => ({
- role,
- disabled: disabled?.packs?.[pack]?.includes(role),
- })),
- })),
- };
- }
- activateListeners(html) {
- super.activateListeners(html);
- // Set initial state for all
- const disabled = getSetting(ModuleSetting.INDEXING_DISABLED);
- Object.entries(disabled.packs).forEach(([pack, val]) => {
- const check = html.find(`[data-disable="${pack}"]`);
- if (permissionListEq(val, [1, 2, 3, 4])) {
- check.prop("checked", false);
- }
- else {
- check.prop("indeterminate", true);
- }
- });
- // Root check change -> updates regular checks
- html.find("input.disable-pack").on("change", function () {
- const compendium = this.dataset.disable;
- html
- .find(`input[name^="${compendium}."]`)
- .prop("checked", this.checked);
- });
- // Regular check change -> updates root check
- html.find(".form-fields input").on("change", function () {
- const compendium = this.name.slice(0, -2);
- const checks = html
- .find(`input[name^="${compendium}."]`)
- .toArray();
- if (checks.every((e) => e.checked)) {
- html
- .find(`[data-disable="${compendium}"]`)
- .prop("checked", true)
- .prop("indeterminate", false);
- }
- else if (checks.every((e) => !e.checked)) {
- html
- .find(`[data-disable="${compendium}"]`)
- .prop("checked", false)
- .prop("indeterminate", false);
- }
- else {
- html
- .find(`[data-disable="${compendium}"]`)
- .prop("checked", checks.some((e) => e.checked))
- .prop("indeterminate", true);
- }
- });
- // Deselect all button
- html.find("button.deselect-all").on("click", (e) => {
- e.preventDefault();
- e.stopPropagation();
- html
- .find(`.form-group.pack input[type="checkbox"]`)
- .prop("checked", false)
- .prop("indeterminate", false);
- });
- // Select all button
- html.find("button.select-all").on("click", (e) => {
- e.preventDefault();
- e.stopPropagation();
- html
- .find(`.form-group.pack input[type="checkbox"]`)
- .prop("checked", true)
- .prop("indeterminate", false);
- });
- }
- async _updateObject(event, formData) {
- const res = {
- entities: {},
- packs: {},
- };
- for (const [name, checked] of Object.entries(formData)) {
- if (!checked) {
- const [base, middle, last] = name.split(".");
- if (last) {
- const pack = `${base}.${middle}`;
- res.packs[pack] = res.packs[pack] || [];
- res.packs[pack].push(parseInt(last));
- }
- else {
- const type = base;
- res.entities[type] = res.entities[type] || [];
- res.entities[type].push(parseInt(middle));
- }
- }
- }
- setSetting(ModuleSetting.INDEXING_DISABLED, res);
- }
- }
-
- const moduleSettings = {
- [ModuleSetting.GM_ONLY]: {
- setting: ModuleSetting.GM_ONLY,
- name: "QUICKINSERT.SettingsGmOnly",
- hint: "QUICKINSERT.SettingsGmOnlyHint",
- type: Boolean,
- default: false,
- scope: "world",
- },
- [ModuleSetting.FILTERS_SHEETS_ENABLED]: {
- setting: ModuleSetting.FILTERS_SHEETS_ENABLED,
- name: "QUICKINSERT.SettingsFiltersSheetsEnabled",
- hint: "QUICKINSERT.SettingsFiltersSheetsEnabledHint",
- type: Boolean,
- default: true,
- scope: "world",
- },
- [ModuleSetting.AUTOMATIC_INDEXING]: {
- setting: ModuleSetting.AUTOMATIC_INDEXING,
- name: "QUICKINSERT.SettingsAutomaticIndexing",
- hint: "QUICKINSERT.SettingsAutomaticIndexingHint",
- type: Number,
- choices: {
- 3000: "QUICKINSERT.SettingsAutomaticIndexing3s",
- 5000: "QUICKINSERT.SettingsAutomaticIndexing5s",
- 10000: "QUICKINSERT.SettingsAutomaticIndexing10s",
- "-1": "QUICKINSERT.SettingsAutomaticIndexingOnFirstOpen",
- },
- default: -1,
- scope: "client",
- },
- [ModuleSetting.INDEX_TIMEOUT]: {
- setting: ModuleSetting.INDEX_TIMEOUT,
- name: "QUICKINSERT.SettingsIndexTimeout",
- hint: "QUICKINSERT.SettingsIndexTimeoutHint",
- type: Number,
- choices: {
- 1500: "QUICKINSERT.SettingsIndexTimeout1_5s",
- 3000: "QUICKINSERT.SettingsIndexTimeout3s",
- 7000: "QUICKINSERT.SettingsIndexTimeout7s",
- 9500: "QUICKINSERT.SettingsIndexTimeou9_5s",
- },
- default: 1500,
- scope: "world",
- },
- [ModuleSetting.SEARCH_BUTTON]: {
- setting: ModuleSetting.SEARCH_BUTTON,
- name: "QUICKINSERT.SettingsSearchButton",
- hint: "QUICKINSERT.SettingsSearchButtonHint",
- type: Boolean,
- default: false,
- scope: "client",
- },
- [ModuleSetting.ENABLE_GLOBAL_CONTEXT]: {
- setting: ModuleSetting.ENABLE_GLOBAL_CONTEXT,
- name: "QUICKINSERT.SettingsEnableGlobalContext",
- hint: "QUICKINSERT.SettingsEnableGlobalContextHint",
- type: Boolean,
- default: true,
- },
- [ModuleSetting.DEFAULT_ACTION_SCENE]: {
- setting: ModuleSetting.DEFAULT_ACTION_SCENE,
- name: "QUICKINSERT.SettingsDefaultActionScene",
- hint: "QUICKINSERT.SettingsDefaultActionSceneHint",
- type: String,
- choices: {
- show: "SCENES.Configure",
- viewScene: "SCENES.View",
- activateScene: "SCENES.Activate",
- },
- default: "show",
- },
- [ModuleSetting.DEFAULT_ACTION_ROLL_TABLE]: {
- setting: ModuleSetting.DEFAULT_ACTION_ROLL_TABLE,
- name: "QUICKINSERT.SettingsDefaultActionRollTable",
- hint: "QUICKINSERT.SettingsDefaultActionRollTableHint",
- type: String,
- choices: {
- show: "QUICKINSERT.ActionEdit",
- roll: "TABLE.Roll",
- },
- default: "show",
- },
- [ModuleSetting.DEFAULT_ACTION_MACRO]: {
- setting: ModuleSetting.DEFAULT_ACTION_MACRO,
- name: "QUICKINSERT.SettingsDefaultActionMacro",
- hint: "QUICKINSERT.SettingsDefaultActionMacroHint",
- type: String,
- choices: {
- show: "QUICKINSERT.ActionEdit",
- execute: "QUICKINSERT.ActionExecute",
- },
- default: "show",
- },
- [ModuleSetting.SEARCH_TOOLTIPS]: {
- setting: ModuleSetting.SEARCH_TOOLTIPS,
- name: "QUICKINSERT.SettingsSearchTooltips",
- hint: "QUICKINSERT.SettingsSearchTooltipsHint",
- type: String,
- choices: {
- off: "QUICKINSERT.SettingsSearchTooltipsValueOff",
- text: "QUICKINSERT.SettingsSearchTooltipsValueText",
- image: "QUICKINSERT.SettingsSearchTooltipsValueImage",
- full: "QUICKINSERT.SettingsSearchTooltipsValueFull",
- },
- default: "text",
- },
- [ModuleSetting.EMBEDDED_INDEXING]: {
- setting: ModuleSetting.EMBEDDED_INDEXING,
- name: "QUICKINSERT.SettingsEmbeddedIndexing",
- hint: "QUICKINSERT.SettingsEmbeddedIndexingHint",
- type: Boolean,
- default: false,
- scope: "world",
- },
- [ModuleSetting.INDEXING_DISABLED]: {
- setting: ModuleSetting.INDEXING_DISABLED,
- name: "Things that have indexing disabled",
- type: Object,
- default: {
- entities: {
- Macro: [1, 2],
- Scene: [1, 2],
- Playlist: [1, 2],
- RollTable: [1, 2],
- },
- packs: {},
- },
- scope: "world",
- config: false, // Doesn't show up in config
- },
- [ModuleSetting.FILTERS_CLIENT]: {
- setting: ModuleSetting.FILTERS_CLIENT,
- name: "Own filters",
- type: Object,
- default: {
- saveRev: SAVE_SETTINGS_REVISION,
- disabled: [],
- filters: [],
- },
- config: false, // Doesn't show up in config
- },
- [ModuleSetting.FILTERS_WORLD]: {
- setting: ModuleSetting.FILTERS_WORLD,
- name: "World filters",
- type: Object,
- default: {
- saveRev: SAVE_SETTINGS_REVISION,
- filters: [],
- },
- scope: "world",
- config: false, // Doesn't show up in config
- },
- [ModuleSetting.FILTERS_SHEETS]: {
- setting: ModuleSetting.FILTERS_SHEETS,
- name: "Sheet filters",
- type: Object,
- default: {},
- scope: "world",
- config: false, // Doesn't show up in config
- },
- };
- function registerSettings(callbacks = {}) {
- Object.entries(moduleSettings).forEach(([setting, item]) => {
- registerSetting(setting, (value) => {
- callbacks[item.setting]?.(value);
- }, item);
- });
- }
-
- function mapKey(key) {
- if (key.startsWith("Key")) {
- return key[key.length - 1].toLowerCase();
- }
- return key;
- }
- function registerProseMirrorKeys() {
- const binds = game?.keybindings?.bindings?.get("quick-insert." + ModuleSetting.KEY_BIND);
- if (!binds?.length) {
- console.info("Quick Insert | ProseMirror extension found no key binding");
- return;
- }
- function keyCallback(state, dispatch, view) {
- if (QuickInsert.app?.embeddedMode)
- return false;
- // Open window
- QuickInsert.open(new ProseMirrorContext(state, dispatch, view));
- return true;
- }
- const keyMap = Object.fromEntries(binds.map((bind) => {
- return [
- `${bind.modifiers?.map((m) => m + "-").join("")}${mapKey(bind.key)}`,
- keyCallback,
- ];
- }));
- ProseMirror.defaultPlugins.QuickInsert = ProseMirror.keymap(keyMap);
- }
-
- function quickInsertDisabled() {
- return !game.user?.isGM && getSetting(ModuleSetting.GM_ONLY);
- }
- // Client is currently reindexing?
- let reIndexing = false;
- Hooks.once("init", async function () {
- registerMenu({
- menu: "indexingSettings",
- name: "QUICKINSERT.SettingsIndexingSettings",
- label: "QUICKINSERT.SettingsIndexingSettingsLabel",
- icon: "fas fa-search",
- type: IndexingSettings,
- restricted: false,
- });
- registerMenu({
- menu: "filterMenu",
- name: "QUICKINSERT.SettingsFilterMenu",
- label: "QUICKINSERT.SettingsFilterMenuLabel",
- icon: "fas fa-filter",
- type: FilterList,
- restricted: false,
- });
- registerSettings({
- [ModuleSetting.FILTERS_WORLD]: () => {
- if (quickInsertDisabled())
- return;
- QuickInsert.filters.loadSave();
- },
- [ModuleSetting.FILTERS_CLIENT]: () => {
- if (quickInsertDisabled())
- return;
- QuickInsert.filters.loadSave();
- },
- [ModuleSetting.INDEXING_DISABLED]: async () => {
- if (quickInsertDisabled())
- return;
- // Active users will start reindexing in deterministic order, once per 300ms
- if (reIndexing)
- return;
- reIndexing = true;
- if (game.users && game.userId !== null) {
- const order = [...game.users.contents]
- .filter((u) => u.active)
- .map((u) => u.id)
- .indexOf(game.userId);
- await resolveAfter(order * 300);
- }
- await QuickInsert.forceIndex();
- reIndexing = false;
- },
- });
- game.keybindings.register("quick-insert", ModuleSetting.KEY_BIND, {
- name: "QUICKINSERT.SettingsQuickOpen",
- textInput: true,
- editable: [
- { key: "Space", modifiers: [KeyboardManager.MODIFIER_KEYS.CONTROL] },
- ],
- onDown: (ctx) => {
- QuickInsert.toggle(ctx._quick_insert_extra?.context);
- return true;
- },
- precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL,
- });
- });
- Hooks.once("ready", function () {
- if (quickInsertDisabled())
- return;
- console.log("Quick Insert | Initializing...");
- // Initialize application base
- QuickInsert.filters = new SearchFilterCollection();
- QuickInsert.app = new SearchApp();
- registerTinyMCEPlugin();
- registerProseMirrorKeys();
- importSystemIntegration().then((systemIntegration) => {
- if (systemIntegration) {
- QuickInsert.systemIntegration = systemIntegration;
- QuickInsert.systemIntegration.init();
- if (QuickInsert.systemIntegration.defaultSheetFilters) {
- registerMenu({
- menu: "sheetFilters",
- name: "QUICKINSERT.SettingsSheetFilters",
- label: "QUICKINSERT.SettingsSheetFiltersLabel",
- icon: "fas fa-filter",
- type: SheetFilters,
- restricted: false,
- });
- }
- }
- });
- document.addEventListener("keydown", (evt) => {
- // Allow in input fields...
- customKeybindHandler(evt);
- });
- setupDocumentHooks(QuickInsert);
- console.log("Quick Insert | Search Application ready");
- const indexDelay = getSetting(ModuleSetting.AUTOMATIC_INDEXING);
- if (indexDelay != -1) {
- setTimeout(() => {
- console.log("Quick Insert | Automatic indexing initiated");
- loadSearchIndex();
- }, indexDelay);
- }
- });
- Hooks.on("renderSceneControls", (controls, html) => {
- if (!getSetting(ModuleSetting.SEARCH_BUTTON))
- return;
- const searchBtn = $(`<li class="scene-control" title="Quick Insert" class="quick-insert-open">
- <i class="fas fa-search"></i>
- </li>`);
- html.children(".main-controls").append(searchBtn);
- searchBtn.on("click", () => QuickInsert.open());
- });
- // Exports and API usage
- //@ts-ignore
- globalThis.QuickInsert = QuickInsert;
-
- export { CharacterSheetContext, ModuleSetting, QuickInsert, SearchContext, getSetting, setSetting };
- //# sourceMappingURL=quick-insert.js.map
|