/** * Export data content to be saved to a local file * @param {string} data Data content converted to a string * @param {string} type The type of * @param {string} filename The filename of the resulting download */ function saveDataToFile(data, type, filename) { const blob = new Blob([data], {type: type}); // Create an element to trigger the download let a = document.createElement('a'); a.href = window.URL.createObjectURL(blob); a.download = filename; // Dispatch a click event to the element a.dispatchEvent(new MouseEvent("click", {bubbles: true, cancelable: true, view: window})); setTimeout(() => window.URL.revokeObjectURL(a.href), 100); } /* -------------------------------------------- */ /** * Read text data from a user provided File object * @param {File} file A File object * @return {Promise.} A Promise which resolves to the loaded text data */ function readTextFromFile(file) { const reader = new FileReader(); return new Promise((resolve, reject) => { reader.onload = ev => { resolve(reader.result); }; reader.onerror = ev => { reader.abort(); reject(); }; reader.readAsText(file); }); } /* -------------------------------------------- */ /** * Retrieve a Document by its Universally Unique Identifier (uuid). * @param {string} uuid The uuid of the Document to retrieve. * @param {object} [options] Options to configure how a UUID is resolved. * @param {Document} [options.relative] A Document to resolve relative UUIDs against. * @param {boolean} [options.invalid=false] Allow retrieving an invalid Document. * @returns {Promise} Returns the Document if it could be found, otherwise null. */ async function fromUuid(uuid, options={}) { if ( !uuid ) return null; /** @deprecated since v11 */ if ( foundry.utils.getType(options) !== "Object" ) { foundry.utils.logCompatibilityWarning("Passing a relative document as the second parameter to fromUuid is " + "deprecated. Please pass it within an options object instead.", {since: 11, until: 13}); options = {relative: options}; } const {relative, invalid=false} = options; let {type, id, primaryId, collection, embedded, doc} = foundry.utils.parseUuid(uuid, {relative}); if ( collection instanceof CompendiumCollection ) { if ( type === "Folder" ) return collection.folders.get(id); doc = await collection.getDocument(primaryId ?? id); } else doc = doc ?? collection?.get(primaryId ?? id, {invalid}); if ( embedded.length ) doc = _resolveEmbedded(doc, embedded, {invalid}); return doc || null; } /* -------------------------------------------- */ /** * Retrieve a Document by its Universally Unique Identifier (uuid) synchronously. If the uuid resolves to a compendium * document, that document's index entry will be returned instead. * @param {string} uuid The uuid of the Document to retrieve. * @param {object} [options] Options to configure how a UUID is resolved. * @param {Document} [options.relative] A Document to resolve relative UUIDs against. * @param {boolean} [options.invalid=false] Allow retrieving an invalid Document. * @param {boolean} [options.strict=true] Throw an error if the UUID cannot be resolved synchronously. * @returns {Document|object|null} The Document or its index entry if it resides in a Compendium, otherwise * null. * @throws If the uuid resolves to a Document that cannot be retrieved synchronously, and the strict option is true. */ function fromUuidSync(uuid, options={}) { if ( !uuid ) return null; /** @deprecated since v11 */ if ( foundry.utils.getType(options) !== "Object" ) { foundry.utils.logCompatibilityWarning("Passing a relative document as the second parameter to fromUuidSync is " + "deprecated. Please pass it within an options object instead.", {since: 11, until: 13}); options = {relative: options}; } const {relative, invalid=false, strict=true} = options; let {type, id, primaryId, collection, embedded, doc} = foundry.utils.parseUuid(uuid, {relative}); if ( (collection instanceof CompendiumCollection) && embedded.length ) { if ( !strict ) return null; throw new Error( `fromUuidSync was invoked on UUID '${uuid}' which references an Embedded Document and cannot be retrieved ` + "synchronously."); } const baseId = primaryId ?? id; if ( collection instanceof CompendiumCollection ) { if ( type === "Folder" ) return collection.folders.get(id); doc = doc ?? collection.get(baseId, {invalid}) ?? collection.index.get(baseId); if ( doc ) doc.pack = collection.collection; } else { doc = doc ?? collection?.get(baseId, {invalid}); if ( embedded.length ) doc = _resolveEmbedded(doc, embedded, {invalid}); } return doc || null; } /* -------------------------------------------- */ /** * Resolve a series of embedded document UUID parts against a parent Document. * @param {Document} parent The parent Document. * @param {string[]} parts A series of Embedded Document UUID parts. * @param {object} [options] Additional options to configure Embedded Document resolution. * @param {boolean} [options.invalid=false] Allow retrieving an invalid Embedded Document. * @returns {Document} The resolved Embedded Document. * @private */ function _resolveEmbedded(parent, parts, {invalid=false}={}) { let doc = parent; while ( doc && (parts.length > 1) ) { const [embeddedName, embeddedId] = parts.splice(0, 2); doc = doc.getEmbeddedDocument(embeddedName, embeddedId, {invalid}); } return doc; } /* -------------------------------------------- */ /** * Return a reference to the Document class implementation which is configured for use. * @param {string} documentName The canonical Document name, for example "Actor" * @returns {typeof foundry.abstract.Document} The configured Document class implementation */ function getDocumentClass(documentName) { return CONFIG[documentName]?.documentClass; }