From 6b71a832f905420e988c194d6bae3575737d56c3 Mon Sep 17 00:00:00 2001 From: Michael Leahy Date: Thu, 18 Jul 2024 12:54:06 -0700 Subject: [PATCH] FQL Reunification (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enhancement for Issue #124: added completed or failed button to either state to move between these quest states directly. * Enhancement for Issue #122: Added context menu to quest tracker to select content entity link / primary quest. * Update to French translation for `v0.7.7` * Added message when no primary quest is available. * Update for French translation. * Enhancement issue #120: `lib-themer` support for entity link color. * Add more default font sizes for TinyMCE. Added back default `p` margin. * Updated German translation * Packs added back * Initial QuestTracker view management / docking * Updated German translation * v0.7.7 ko.json added new strings * Update icon styles and context menu support. * Initial docking support * Integrated questTrackerManaged setting. * Update macros on startup based on FQL client settings with image state. * Created HandlerTracker for event callbacks. Also documentation. * Added copy quest ID option to context menu; updated English / French language files. * removed unused styles * updated German translation * v0.7.7 ko.json * Match Foundry CSS classes for FQL app * Remove `Close` label from quest tracker header button. Add some padding for message when no primary quests are available in the quest tracker. * Removed questTrackerManaged setting. The QuestTracker will always be managed. * Moved render tracking for QuestTracker to SidebarManager and QuestPreview to ViewManager. * FoundryUIManager - now also controls SceneNavigation for QuestTracker pinning. * Comments * Add primary quest icon to management / subquests. * README / Changelog updates * 0.7.7 release * v0.7.7 ko.json edited false name & weird translation * updated 0.7.7 ko.json I'm sorry. This is the last fix. 😢 * Fixes an edge case due to timing of hooks for Mac / Chrome w/ Minimal UI. * Enhancement #137: Make QuestPreview minimizable. * Enhancement #138: Part 1 / QuestTracker constraints in hook. * Enhancement #138: Part 2 / QuestLog constraints in hook. * Added 'top' as a whitelisted variable * Enhancement #138: QuestTracker hook can also set show primary state. * Correct handlebar helper name to prevent conflicts Renamed the custom Handlebars Helper from `format` to `fql_format` to prevent potential conflicts with other modules. * Namespace custom handlebars helper * Fix for #140: url() usage in templates now includes quotes so filenames with parentheses render correctly. * 0.7.8 release * Patch to disable synthetic quest type registration for v9+ of Foundry preventing a hard crash of FQL. There is a replacement module / continuation of the quest log that is being released soon that will enable this functionality against with a different implementation. You can receive announcements when this is ready on the TyphonJS Discord server: https://discord.gg/mnbgN8f * Update changelog & README * Better version 9 check. * 0.7.9 release * update ja.json * Fix typos * Fix for Issue #13 - save state of quest before status change. * css dist update * add v9 "type" field to pack definitions. * 0.7.10 release * update for v10 `folder.contents` vs `folder.content`. * DataModel update for macroEntry access * Switch to CONST.DOCUMENT_PERMISSION_LEVELS * Added V10Compat for ownership access + TextEditor.enrichHTML * Update for editor handlebars helper v10 change. * Update for handling v10 UUID changes in drag and drop data transfer. * Update for handling macro drop data for v10. * Update for folder contents for v10. * added TinyMCE v6 oEmbed plugin * load TinyMCE v5 or v6 plugin. * TinyMCE options for v9 & v10 * quest link changed to journal entry link * update dev dependencies * add 'browserlist' to cut down on generated CSS * a few style tweaks for TinyMCE 6 * update CSS * fix sourcemap links * Move ViewManager init before DBMigrate * optional chaining for game.data.version * Remove unused QuestCollection * Handle reward item drag / only add 'data' for v9. * Added token and journal image compatibility support. * Explicitly render quest tracker if visible. * Update for ownership control dialog on v10. * Update for token & journal images for v10 * DB migration updates / added schema 3 for checking stale document link data and dnd5e v2 special handling. * comment * fix for content link selector * Fix for issue #14 - tracker app background w/ route prefix. * Added support for showing quest tracker background. * update styles * removed unused libthemer json config * Added show to players app header button for quest log and tracker for GMs. * added `isFQLMacroDataTransfer` * Fix FQL macro detection for compendium drops. * update for pt-BR lang translation * Fix hotbarDrop hook. * Firefox UX style fixes for thin scrollbar and quest tracker scrollbar color with transparent background. * update dist CSS * Added chat message summarizing any unlinked document data in DB migration. * fix chat message content. * normalize all translation data / add machine translation where necessary. * use localization for migration messaging * translation update * translation update * Update to Spanish translation thanks to ZRAAA78 (Raul) * Update zh-tw.json * Update zh-tw.json * Update zh-tw.json * Update zh-tw.json * initial machine translation * Add Finnish (fi-FI) translation * Make 'item' translation consistent * punctuation * Increased custom quest giver name length from 24 to 36 * refactor buttons / tooltips * Update localization references * Update localization references * Provide abbreviated reward button text. * Add Russian translation * update settings for objectives. * update status text * update status text * update templates for new lang keys * update min-width * style update * Added new language resources * Added auto height for FQLDialog * Allow dragging of quest from quest log from full 'li'. Add uuid in drop canvas hook. * Expand open quest hit box * organization refactor * code / template language organization refactor * language organization refactor status tooltips. * language organization refactor API keys. * language organization refactor top level labels. * language organization refactor DB migrate notifications. * language organization refactor quest details. * language organization refactor quest details. * punctuation * punctuation * punctuation * punctuation * punctuation * punctuation * remove QuestLog.Tabs in favor of QuestTypes.Labels * remove QuestLog.Tabs in favor of QuestTypes.Labels * punctuation. * punctuation. * corrections * punctuation * punctuation * add maximum compatibility: v10 * translation update. * Translated using Weblate (Finnish) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/fi/ * update CHANGELOG * update README * update README * fix quest tracker fill icon for v9 * fix for TinyMCE CSS URL / no need to apply `getRoute` as Foundry does automatically. * Translated using Weblate (Swedish) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/sv/ * fix for quest log copy link * remove unused dev dependencies * Fix for systems that overrode `or` handlebars helper. * Added translation using Weblate (Dutch) * Translated using Weblate (Dutch) Currently translated at 15.1% (23 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/nl/ * Translated using Weblate (Dutch) Currently translated at 88.8% (135 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/nl/ * add lock file * update Utils.copyTextToClipboard * comments * add error checking * protect against invalid data transfer * Switch to async TextEditor.enrichHTML * QuestLog render now accepts tabId parameter to open a specific quest status tab. * update CHANGELOG * update README * 0.7.11 release * Added override for MCE Everywhere. * 0.7.12 update * update Rollup v3 * update external libs * Rename V10Compat to FVTTCompat * CSS rebuild * Removed prior ownership compatibility dialog. * small fix to not force render main log. * Translated using Weblate (Spanish) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (152 of 152 strings) Translation: Forien's Quest Log/main Translate-URL: https://weblate.foundryvtt-hub.com/projects/forien-quest-log/main/es/ * update CHANGELOG * add for packs * v11 LevelDB packs * remove unused config. * update README * Replace DOCUMENT_PREMISSION_LEVELS with DOCUMENT_OWNERSHIP_LEVELS * Updated FVTTCompat. v9 / v10 shims removed. * ES2022 private variables * ESLint fixes * ESLint fixes * Allow actors (IE item piles) to be assigned as rewards. * `console.log` to `console.warn` * Allow all rewards to have associated image changed. * Update packs * Update reward select image selector. * Fix MCE select width for format paragraph. * Player notes feature. * Player notes feature / lang updates. * CSS Updates * Remove oembed MCE v5 support. * Update dependencies. * update config * Update packs * Update version * Update README * Update build scripts * Switched to ProseMirror editor. * Update config. * Update external libs * Switch to normal sanitize method. * Add `getEditorContent` to FVTTCompat. * Disable legacy DB migration. * Update comments for proper linking and recent Foundry API doc links. * Update authors * Remove loading TinyMCE plugin. * Refactor `module private` #1 * Refactor UI control code. * Refactor view classes for named exports. * Refactor model classes for named exports. * Refactor control classes for named exports. * Move FVTTCompat / ModuleSettings to control. * Named exports for external libraries. * Disable eslint. * Add private constructor for static classes. * Refactor for ES2022. * Group util control classes. * Update QuestDB to ES2022. * comments. * Update CHANGELOG * Update README --------- Co-authored-by: drdwing <66671688+drdwing@users.noreply.github.com> Co-authored-by: flamewave000 <3588046+flamewave000@users.noreply.github.com> Co-authored-by: BrotherSharper Co-authored-by: Sad Co-authored-by: Demian Wright Co-authored-by: Jonas Karlsson Co-authored-by: Kyra van den Berg Co-authored-by: Zaen8 Co-authored-by: Neil White --- .editorconfig | 315 ++++ .eslintignore | 7 + .eslintrc | 40 + .gitattributes | 1 + .github/workflows/main.yml | 41 + .../{release.yml => release.yml.bak} | 0 .gitignore | 6 +- AUTHORS | 26 + CONTRIBUTING.md | 46 + LICENSE | 21 + README.md | 123 +- assets-raw/icons/macros/icons-macros.xcf | Bin 0 -> 1227769 bytes .../icons/macros/svg/arrows-alt-h-solid.svg | 1 + .../icons/macros/svg/arrows-alt-solid.svg | 1 + assets-raw/icons/macros/svg/check-solid.svg | 1 + .../icons/macros/svg/check-square-regular.svg | 1 + .../icons/macros/svg/check-square-solid.svg | 1 + .../icons/macros/svg/exclamation-solid.svg | 1 + .../icons/macros/svg/eye-slash-solid.svg | 1 + assets-raw/icons/macros/svg/hashtag-solid.svg | 1 + assets-raw/icons/macros/svg/pen-nib-solid.svg | 1 + assets-raw/icons/macros/svg/scroll-solid.svg | 1 + .../icons/macros/svg/square-regular.svg | 1 + assets-raw/icons/macros/svg/star-solid.svg | 1 + assets-raw/icons/macros/svg/tasks-solid.svg | 1 + assets-raw/icons/macros/svg/trophy-solid.svg | 1 + .../icons/macros/svg/user-friends-solid.svg | 1 + assets-raw/icons/macros/svg/user-solid.svg | 1 + assets/fonts/almendra-v15-latin-regular.woff | Bin 0 -> 16052 bytes assets/fonts/almendra-v15-latin-regular.woff2 | Bin 0 -> 12236 bytes assets/fonts/audiowide-v9-latin-regular.woff | Bin 0 -> 17764 bytes assets/fonts/audiowide-v9-latin-regular.woff2 | Bin 0 -> 14036 bytes .../bilbo-swash-caps-v15-latin-regular.woff | Bin 0 -> 25040 bytes .../bilbo-swash-caps-v15-latin-regular.woff2 | Bin 0 -> 21320 bytes .../medievalsharp-v14-latin-regular.woff | Bin 0 -> 48304 bytes .../medievalsharp-v14-latin-regular.woff2 | Bin 0 -> 38772 bytes .../fonts/metamorphous-v13-latin-regular.woff | Bin 0 -> 28632 bytes .../metamorphous-v13-latin-regular.woff2 | Bin 0 -> 23108 bytes .../fonts/nova-square-v15-latin-regular.woff | Bin 0 -> 19556 bytes .../fonts/nova-square-v15-latin-regular.woff2 | Bin 0 -> 14644 bytes assets/icons/macros/DBMigration.png | Bin 0 -> 2050 bytes assets/icons/macros/allowPlayersAcceptOff.png | Bin 0 -> 4085 bytes assets/icons/macros/allowPlayersAcceptOn.png | Bin 0 -> 4231 bytes assets/icons/macros/allowPlayersCreateOff.png | Bin 0 -> 4584 bytes assets/icons/macros/allowPlayersCreateOn.png | Bin 0 -> 4732 bytes assets/icons/macros/allowPlayersDragOff.png | Bin 0 -> 4038 bytes assets/icons/macros/allowPlayersDragOn.png | Bin 0 -> 4193 bytes assets/icons/macros/countHiddenOff.png | Bin 0 -> 4332 bytes assets/icons/macros/countHiddenOn.png | Bin 0 -> 4477 bytes .../macros/defaultAbstractRewardImage.png | Bin 0 -> 28279 bytes assets/icons/macros/hideFQLFromPlayersOff.png | Bin 0 -> 3858 bytes assets/icons/macros/hideFQLFromPlayersOn.png | Bin 0 -> 4007 bytes assets/icons/macros/notifyRewardDropOff.png | Bin 0 -> 3107 bytes assets/icons/macros/notifyRewardDropOn.png | Bin 0 -> 3244 bytes assets/icons/macros/openQuestLog.png | Bin 0 -> 1706 bytes assets/icons/macros/questTrackerEnableOff.png | Bin 0 -> 2165 bytes assets/icons/macros/questTrackerEnableOn.png | Bin 0 -> 2328 bytes .../icons/macros/questTrackerResizableOff.png | Bin 0 -> 2937 bytes .../icons/macros/questTrackerResizableOn.png | Bin 0 -> 3080 bytes assets/icons/macros/trustedPlayerEditOff.png | Bin 0 -> 4399 bytes assets/icons/macros/trustedPlayerEditOn.png | Bin 0 -> 4545 bytes changelog.md | 161 +- css/init.css | 2 + css/init.css.map | 1 + database/DBMigration.js | 156 ++ database/schema/dbSchema_1.js | 200 +++ database/schema/dbSchema_2.js | 75 + database/schema/dbSchema_3.js | 296 ++++ database/schema/index.js | 3 + external/DOMPurify.js | 3 + external/DOMPurify.js.map | 1 + external/collect.js | 2 + external/collect.js.map | 1 + external/index.js | 2 + forien-quest-log.lock | 1 + lang/cn.json | 367 +++-- lang/de.json | 325 +++- lang/en.json | 381 +++-- lang/es.json | 367 +++-- lang/fi-FI.json | 256 +++ lang/fr.json | 370 +++-- lang/it.json | 256 +++ lang/ja.json | 370 +++-- lang/ko.json | 372 +++-- lang/missing/cn.json | 6 - lang/missing/de.json | 55 - lang/missing/en.json | 1 - lang/missing/es.json | 5 - lang/missing/fr.json | 5 - lang/missing/ja.json | 5 - lang/missing/ko.json | 5 - lang/missing/pl.json | 24 - lang/missing/pt-BR.json | 6 - lang/nl.json | 256 +++ lang/pl.json | 363 +++-- lang/pt-BR.json | 366 +++-- lang/ru.json | 256 +++ lang/sv.json | 256 +++ lang/zh-tw.json | 259 +++ module.json | 109 +- modules/api/hooks.js | 57 - modules/api/quest-api.mjs | 70 - modules/apps/quest-form.mjs | 280 ---- modules/apps/quest-log.mjs | 138 -- modules/apps/quest-preview.mjs | 525 ------ modules/constants.mjs | 5 - .../entities/collection/quests-collection.mjs | 41 - modules/entities/quest-folder.mjs | 41 - modules/entities/quest.mjs | 722 --------- modules/entities/reward.mjs | 60 - modules/entities/task.mjs | 87 - modules/init.mjs | 66 - modules/utility/config.mjs | 134 -- modules/utility/socket.mjs | 106 -- modules/utility/utils.mjs | 41 - package.json | 38 + packs/macro-gm/000046.ldb | Bin 0 -> 2034 bytes packs/macro-gm/000050.log | 0 packs/macro-gm/CURRENT | 1 + packs/macro-gm/LOCK | 0 packs/macro-gm/LOG | 3 + packs/macro-gm/LOG.old | 3 + packs/macro-gm/MANIFEST-000049 | Bin 0 -> 156 bytes packs/macro-player/000046.ldb | Bin 0 -> 849 bytes packs/macro-player/000050.log | 0 packs/macro-player/CURRENT | 1 + packs/macro-player/LOCK | 0 packs/macro-player/LOG | 3 + packs/macro-player/LOG.old | 3 + packs/macro-player/MANIFEST-000049 | Bin 0 -> 156 bytes rollup.config.js | 68 + scripts/prompt.js | 154 -- src/control/FQLHooks.js | 555 +++++++ src/control/ModuleSettings.js | 427 +++++ src/control/Socket.js | 727 +++++++++ src/control/db/Enrich.js | 497 ++++++ src/control/db/QuestDB.js | 1405 +++++++++++++++++ src/control/index.js | 6 + src/control/public/QuestAPI.js | 96 ++ src/control/public/QuestDBShim.js | 227 +++ src/control/public/index.js | 1 + src/control/ui/FoundryUIManager.js | 413 +++++ src/control/ui/UINotifications.js | 106 ++ src/control/ui/ViewManager.js | 395 +++++ src/control/ui/index.js | 2 + src/control/util/FVTTCompat.js | 186 +++ src/control/util/Utils.js | 472 ++++++ src/control/util/index.js | 2 + src/init.js | 4 + src/model/Quest.js | 1128 +++++++++++++ src/model/constants.js | 157 ++ src/model/index.js | 1 + src/typedefs.js | 55 + src/view/index.js | 4 + src/view/internal/FQLContextMenu.js | 68 + src/view/internal/FQLDialog.js | 306 ++++ .../internal/FQLDocumentOwnershipConfig.js | 33 + src/view/internal/index.js | 3 + src/view/log/HandlerLog.js | 99 ++ src/view/log/QuestLog.js | 320 ++++ src/view/preview/HandlerAny.js | 70 + src/view/preview/HandlerDetails.js | 1081 +++++++++++++ src/view/preview/HandlerManage.js | 139 ++ src/view/preview/QuestPreview.js | 723 +++++++++ src/view/preview/QuestPreviewShim.js | 65 + src/view/tracker/HandlerTracker.js | 174 ++ src/view/tracker/QuestTracker.js | 605 +++++++ styles/basicapp.scss | 84 + styles/global-mixin.scss | 89 ++ styles/global-variables.scss | 44 + styles/init.css | 820 ---------- styles/init.css.map | 7 - styles/init.scss | 13 +- styles/quest-form.scss | 125 -- styles/quest-general.scss | 207 ++- styles/quest-log.scss | 104 +- styles/quest-preview.scss | 434 ++--- styles/quest-tracker.scss | 246 +++ templates/partials/quest-form/task.html | 4 - templates/partials/quest-log/tab.html | 56 +- templates/partials/quest-preview/details.html | 218 ++- templates/partials/quest-preview/gmnotes.html | 6 +- .../partials/quest-preview/management.html | 78 +- .../partials/quest-preview/playernotes.html | 8 + templates/quest-form.html | 42 - templates/quest-log.html | 66 +- templates/quest-preview.html | 52 +- templates/quest-tracker.html | 58 + templates/welcome-screen.html | 206 --- 189 files changed, 17022 insertions(+), 5731 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .gitattributes create mode 100644 .github/workflows/main.yml rename .github/workflows/{release.yml => release.yml.bak} (100%) create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 assets-raw/icons/macros/icons-macros.xcf create mode 100644 assets-raw/icons/macros/svg/arrows-alt-h-solid.svg create mode 100644 assets-raw/icons/macros/svg/arrows-alt-solid.svg create mode 100644 assets-raw/icons/macros/svg/check-solid.svg create mode 100644 assets-raw/icons/macros/svg/check-square-regular.svg create mode 100644 assets-raw/icons/macros/svg/check-square-solid.svg create mode 100644 assets-raw/icons/macros/svg/exclamation-solid.svg create mode 100644 assets-raw/icons/macros/svg/eye-slash-solid.svg create mode 100644 assets-raw/icons/macros/svg/hashtag-solid.svg create mode 100644 assets-raw/icons/macros/svg/pen-nib-solid.svg create mode 100644 assets-raw/icons/macros/svg/scroll-solid.svg create mode 100644 assets-raw/icons/macros/svg/square-regular.svg create mode 100644 assets-raw/icons/macros/svg/star-solid.svg create mode 100644 assets-raw/icons/macros/svg/tasks-solid.svg create mode 100644 assets-raw/icons/macros/svg/trophy-solid.svg create mode 100644 assets-raw/icons/macros/svg/user-friends-solid.svg create mode 100644 assets-raw/icons/macros/svg/user-solid.svg create mode 100644 assets/fonts/almendra-v15-latin-regular.woff create mode 100644 assets/fonts/almendra-v15-latin-regular.woff2 create mode 100644 assets/fonts/audiowide-v9-latin-regular.woff create mode 100644 assets/fonts/audiowide-v9-latin-regular.woff2 create mode 100644 assets/fonts/bilbo-swash-caps-v15-latin-regular.woff create mode 100644 assets/fonts/bilbo-swash-caps-v15-latin-regular.woff2 create mode 100644 assets/fonts/medievalsharp-v14-latin-regular.woff create mode 100644 assets/fonts/medievalsharp-v14-latin-regular.woff2 create mode 100644 assets/fonts/metamorphous-v13-latin-regular.woff create mode 100644 assets/fonts/metamorphous-v13-latin-regular.woff2 create mode 100644 assets/fonts/nova-square-v15-latin-regular.woff create mode 100644 assets/fonts/nova-square-v15-latin-regular.woff2 create mode 100644 assets/icons/macros/DBMigration.png create mode 100644 assets/icons/macros/allowPlayersAcceptOff.png create mode 100644 assets/icons/macros/allowPlayersAcceptOn.png create mode 100644 assets/icons/macros/allowPlayersCreateOff.png create mode 100644 assets/icons/macros/allowPlayersCreateOn.png create mode 100644 assets/icons/macros/allowPlayersDragOff.png create mode 100644 assets/icons/macros/allowPlayersDragOn.png create mode 100644 assets/icons/macros/countHiddenOff.png create mode 100644 assets/icons/macros/countHiddenOn.png create mode 100644 assets/icons/macros/defaultAbstractRewardImage.png create mode 100644 assets/icons/macros/hideFQLFromPlayersOff.png create mode 100644 assets/icons/macros/hideFQLFromPlayersOn.png create mode 100644 assets/icons/macros/notifyRewardDropOff.png create mode 100644 assets/icons/macros/notifyRewardDropOn.png create mode 100644 assets/icons/macros/openQuestLog.png create mode 100644 assets/icons/macros/questTrackerEnableOff.png create mode 100644 assets/icons/macros/questTrackerEnableOn.png create mode 100644 assets/icons/macros/questTrackerResizableOff.png create mode 100644 assets/icons/macros/questTrackerResizableOn.png create mode 100644 assets/icons/macros/trustedPlayerEditOff.png create mode 100644 assets/icons/macros/trustedPlayerEditOn.png create mode 100644 css/init.css create mode 100644 css/init.css.map create mode 100644 database/DBMigration.js create mode 100644 database/schema/dbSchema_1.js create mode 100644 database/schema/dbSchema_2.js create mode 100644 database/schema/dbSchema_3.js create mode 100644 database/schema/index.js create mode 100644 external/DOMPurify.js create mode 100644 external/DOMPurify.js.map create mode 100644 external/collect.js create mode 100644 external/collect.js.map create mode 100644 external/index.js create mode 100644 forien-quest-log.lock create mode 100644 lang/fi-FI.json create mode 100644 lang/it.json delete mode 100644 lang/missing/cn.json delete mode 100644 lang/missing/de.json delete mode 100644 lang/missing/en.json delete mode 100644 lang/missing/es.json delete mode 100644 lang/missing/fr.json delete mode 100644 lang/missing/ja.json delete mode 100644 lang/missing/ko.json delete mode 100644 lang/missing/pl.json delete mode 100644 lang/missing/pt-BR.json create mode 100644 lang/nl.json create mode 100644 lang/ru.json create mode 100644 lang/sv.json create mode 100644 lang/zh-tw.json delete mode 100644 modules/api/hooks.js delete mode 100644 modules/api/quest-api.mjs delete mode 100644 modules/apps/quest-form.mjs delete mode 100644 modules/apps/quest-log.mjs delete mode 100644 modules/apps/quest-preview.mjs delete mode 100644 modules/constants.mjs delete mode 100644 modules/entities/collection/quests-collection.mjs delete mode 100644 modules/entities/quest-folder.mjs delete mode 100644 modules/entities/quest.mjs delete mode 100644 modules/entities/reward.mjs delete mode 100644 modules/entities/task.mjs delete mode 100644 modules/init.mjs delete mode 100644 modules/utility/config.mjs delete mode 100644 modules/utility/socket.mjs delete mode 100644 modules/utility/utils.mjs create mode 100644 package.json create mode 100644 packs/macro-gm/000046.ldb create mode 100644 packs/macro-gm/000050.log create mode 100644 packs/macro-gm/CURRENT create mode 100644 packs/macro-gm/LOCK create mode 100644 packs/macro-gm/LOG create mode 100644 packs/macro-gm/LOG.old create mode 100644 packs/macro-gm/MANIFEST-000049 create mode 100644 packs/macro-player/000046.ldb create mode 100644 packs/macro-player/000050.log create mode 100644 packs/macro-player/CURRENT create mode 100644 packs/macro-player/LOCK create mode 100644 packs/macro-player/LOG create mode 100644 packs/macro-player/LOG.old create mode 100644 packs/macro-player/MANIFEST-000049 create mode 100644 rollup.config.js delete mode 100644 scripts/prompt.js create mode 100644 src/control/FQLHooks.js create mode 100644 src/control/ModuleSettings.js create mode 100644 src/control/Socket.js create mode 100644 src/control/db/Enrich.js create mode 100644 src/control/db/QuestDB.js create mode 100644 src/control/index.js create mode 100644 src/control/public/QuestAPI.js create mode 100644 src/control/public/QuestDBShim.js create mode 100644 src/control/public/index.js create mode 100644 src/control/ui/FoundryUIManager.js create mode 100644 src/control/ui/UINotifications.js create mode 100644 src/control/ui/ViewManager.js create mode 100644 src/control/ui/index.js create mode 100644 src/control/util/FVTTCompat.js create mode 100644 src/control/util/Utils.js create mode 100644 src/control/util/index.js create mode 100644 src/init.js create mode 100644 src/model/Quest.js create mode 100644 src/model/constants.js create mode 100644 src/model/index.js create mode 100644 src/typedefs.js create mode 100644 src/view/index.js create mode 100644 src/view/internal/FQLContextMenu.js create mode 100644 src/view/internal/FQLDialog.js create mode 100644 src/view/internal/FQLDocumentOwnershipConfig.js create mode 100644 src/view/internal/index.js create mode 100644 src/view/log/HandlerLog.js create mode 100644 src/view/log/QuestLog.js create mode 100644 src/view/preview/HandlerAny.js create mode 100644 src/view/preview/HandlerDetails.js create mode 100644 src/view/preview/HandlerManage.js create mode 100644 src/view/preview/QuestPreview.js create mode 100644 src/view/preview/QuestPreviewShim.js create mode 100644 src/view/tracker/HandlerTracker.js create mode 100644 src/view/tracker/QuestTracker.js create mode 100644 styles/basicapp.scss create mode 100644 styles/global-mixin.scss create mode 100644 styles/global-variables.scss delete mode 100644 styles/init.css delete mode 100644 styles/init.css.map delete mode 100644 styles/quest-form.scss create mode 100644 styles/quest-tracker.scss delete mode 100644 templates/partials/quest-form/task.html create mode 100644 templates/partials/quest-preview/playernotes.html delete mode 100644 templates/quest-form.html create mode 100644 templates/quest-tracker.html delete mode 100644 templates/welcome-screen.html diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..cf890289 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,315 @@ +[*] +charset = utf-8 +end_of_line = crlf +indent_size = 3 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 3 +ij_continuation_indent_size = 1 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.css] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = false +ij_css_hex_color_lower_case = false +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = false +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.sass] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scss] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = false +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.cjs,*.js}] +indent_size = 3 +tab_width = 3 +ij_continuation_indent_size = 1 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 0 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 0 +ij_javascript_array_initializer_new_line_after_left_brace = false +ij_javascript_array_initializer_right_brace_on_new_line = false +ij_javascript_array_initializer_wrap = normal +ij_javascript_assignment_wrap = normal +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = off +ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = next_line +ij_javascript_call_parameters_new_line_after_left_paren = false +ij_javascript_call_parameters_right_paren_on_new_line = false +ij_javascript_call_parameters_wrap = off +ij_javascript_catch_on_new_line = true +ij_javascript_chained_call_dot_on_new_line = false +ij_javascript_class_brace_style = next_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = always +ij_javascript_else_on_new_line = true +ij_javascript_enforce_trailing_comma = keep +ij_javascript_extends_keyword_wrap = off +ij_javascript_extends_list_wrap = split_into_lines +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = true +ij_javascript_for_brace_force = always +ij_javascript_for_statement_new_line_after_left_paren = false +ij_javascript_for_statement_right_paren_on_new_line = false +ij_javascript_for_statement_wrap = off +ij_javascript_force_quote_style = false +ij_javascript_force_semicolon_style = false +ij_javascript_function_expression_brace_style = next_line +ij_javascript_if_brace_force = always +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = true +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = false +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = true +ij_javascript_keep_simple_methods_in_one_line = true +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = next_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = false +ij_javascript_method_parameters_right_paren_on_new_line = false +ij_javascript_method_parameters_wrap = off +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = false +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_reformat_c_style_comments = false +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = true +ij_javascript_space_before_generator_mult = false +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = false +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = off +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = true +ij_javascript_use_explicit_js_extension = global +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = true +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = always +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.graphqlconfig,*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = true +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p +ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot +ij_html_enforce_quotes = false +ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span,pre,textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = false +ij_html_text_wrap = normal +ij_html_uniform_ident = false + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..ac9e61df --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +.github/ +docs/ +external/ +lang/ +scripts/ +styles/ +templates/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..613a3c84 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,40 @@ +/** + * Loads https://github.com/typhonjs-node-config/typhonjs-config-eslint/blob/master/3.0/basic/es8/server/node/.eslintrc + * Loads https://github.com/typhonjs-fvtt/eslint-config-foundry.js/blob/main/0.8.0.js + * + * NPM: https://www.npmjs.com/package/typhonjs-config-eslint + * NPM: https://www.npmjs.com/package/@typhonjs-fvtt/eslint-config-foundry.js + */ +{ + // ESLint configs are prone to particular choices, so if the first config below doesn't work for you then replace + // with one that you do prefer. The second config defines globals defined in `foundry.js` for use w/ `no-shadow`. + "extends": [ + "@typhonjs-config/eslint-config/esm/2022/browser", + "@typhonjs-fvtt/eslint-config-foundry.js" + ], + + // Defines / overrides a few more environment parameters not provided in the configs above. + "env": { + "jquery": true + }, + + // Prevents overwriting any built in globals particularly from `@typhonjs-fvtt/eslint-config-foundry.js`, but also + // node & browser environments. `event / window.event` shadowing is allowed due to being a common variable name and + // an uncommonly used browser feature. + // + // Note: if you are using Typescript you must use `@typescript-eslint/no-shadow` + "rules": { + "no-shadow": ["error", { + "builtinGlobals": true, + "hoist": "all", + "allow": [ + "document", + "event", + "name", + "parent", + "status", + "top" + ] + }] + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..4ee706a5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +packs/** binary diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..a7c20698 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,41 @@ +# From https://github.com/League-of-Foundry-Developers/FoundryVTT-Module-Template/blob/master/.github/workflows/main.yml +name: Release Creation + +on: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + # Substitute the Manifest and Download URLs in the module.json + - name: Substitute Manifest and Download Links For Versioned Ones + id: sub_manifest_link_version + uses: microsoft/variable-substitution@v1 + with: + files: 'module.json' + env: + version: ${{github.event.release.tag_name}} + url: https://github.com/${{github.repository}} + manifest: https://github.com/${{github.repository}}/releases/latest/download/module.json + download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/module.zip + + # Create a zip file with all files required by the module to add to the release + - run: zip -r ./module.zip module.json assets/ css/ database/ external/ lang/ packs/ scripts/ src/ styles/ templates/ LICENSE AUTHORS + + # Create a release for this specific version + - name: Update Release with Files + id: create_version_release + uses: ncipollo/release-action@v1 + with: + allowUpdates: true # Set this to false if you want to prevent updating existing releases + name: ${{ github.event.release.name }} + draft: false + prerelease: false + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: './module.json, ./module.zip' + tag: ${{ github.event.release.tag_name }} + body: ${{ github.event.release.body }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml.bak similarity index 100% rename from .github/workflows/release.yml rename to .github/workflows/release.yml.bak diff --git a/.gitignore b/.gitignore index 0dd20ab4..f2a2f972 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ .idea/ -styles/.sass-cache/ -devtool/ +docs/ lang/untranslated.json node_modules/ foundry.js -package.json -/changelog.html +package-lock.json \ No newline at end of file diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..f38e272f --- /dev/null +++ b/AUTHORS @@ -0,0 +1,26 @@ +# This is the official list of foundryvtt-forien-quest-log authors for copyright purposes. +# +# This does not necessarily list everyone who has contributed code, since in +# some cases, their employer may be the copyright holder. To see the full list +# of contributors, see the revision history in source control or +# https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/graphs/contributors. +# +# Authors who wish to be recognized in this file should add themselves (or +# their employer, as appropriate). + +4535992 <5201916+p4535992@users.noreply.github.com> +BrotherSharp <41280723+BrotherSharper@users.noreply.github.com> +Dilomos <49794325+Dilomos@users.noreply.github.com> +Eadorin +eclarke12 <42503461+eclarke12@users.noreply.github.com> +innocenti +JJBocanegra <5797636+JJBocanegra@users.noreply.github.com> +klo +Lyndsey Toft +Michael Leahy +Rughalt <802214+Rughalt@users.noreply.github.com> +Sad <23254376+zeteticl@users.noreply.github.com> +sdenec <8881200+sdenec@users.noreply.github.com> +Wojciech "Forien" Szulc +xdy <246024+xdy@users.noreply.github.com> +Fallayn diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..bf32643b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,46 @@ +## Contribution Etiquette +Open Source projects function most efficiently when everyone communicates well with each other. Here are some suggested practices that will let everyone else work alongside you comfortably: + +### **Did you find a bug? Do you want to suggest an enhancement?** + +* **Ensure your contribution is novel** by searching the [Issues](https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/issues) page. Be sure to look through both open and closed issues, especially for enhancement suggestions as rejected suggestions will be closed. + +* If applicable **use the appropriate issue templates** to automatically apply the relevant tag to the created issue. This allows issues to be quickly differentiated as bug reports, enhancement suggestions, or whatever else without a maintainer manually adding the tag to the issue. The bug report template will specify which information to add that will aid in reproducing the bug. + +* Inconsequential fixes regarding typos, whitespace, etc. may not warrant an issue and can skip straight to the Pull Request. + +### **Do you want to fix a currently existing issue?** + +* Before working on an issue please **honor issue assignments** and ask to be assigned to the issue in a comment on the issue page. This allows everyone else to see that someone is working on the issue preventing any duplicate pull requests down the line. If someone is already assigned to the issue feel free to reach out to the assignee and inquire on the progress of that fix. + +* While working on an issue **document your changes** by providing detailed commit messages and providing an overview of planned / current implementation / changes on the issue page. + +* When you feel your fork adequately fixes an issue, **submit a pull request for review**! [Please indicate which issue is to be closed if the PR is merged](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) as well as giving a detailed overview of your changes. + +* Please **limit the content of your pull requests to its linked issues**. If your pull request does anything additional you must first open an issue that your PR may close (see the below section). + +### **Do you intend to add a new feature or change an existing one?** + +* Please **open an issue** to generate feedback on the change first. The maintainers reserve the right to reject changes / additions that they do not want to maintain, so be sure that the maintainers are on the same page as you to avoid wasted work! + +* Now that an issue covers the changes you wanted to make refer to the above section for implementing the changes. + +### **Do you want to submit/update a translation?** + +* **Submit a pull request** with your new / updated JSON file in the [lang folder](https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/tree/master/lang). + +* Be sure that the JSON file is either completely flat or completely nested. + +* If your localization does not include translations for any strings please indicate as much in the [lang / missing folder](https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/tree/master/lang/missing). + +### **Do you want to contribute documentation?** + +* Please **follow the above guidelines** regarding opening issues and submitting pull requests. Some documentation issues may be broader and ongoing, in which case you may want to contribute to assignee's forks first. Any smaller changes should still open a detailed issue and submit a detailed pull request that [closes that issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue). + +### **Do you have questions about the source code?** + +* **Join the [TyphonJS Discord](https://discord.gg/mnbgN8f)** and direct questions to the appropriate channel (#forien-quest-log). + +* Please **do not directly contact maintainers** with questions; if you have a question other people might as well, so discussions should take place in public forums where others can see and learn from it as well. + +Thank you for your interest in contributing to Forien's Quest Log! :heart: diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b552b2c8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2021 Wojciech "Forien" Szulc, AUTHORS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 0fe83685..77be973f 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,107 @@ # FoundryVTT - Forien's Quest Log -![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/forien/foundryvtt-forien-quest-log?style=for-the-badge) -![GitHub Releases](https://img.shields.io/github/downloads/Forien/foundryvtt-forien-quest-log/latest/total?style=for-the-badge) -![GitHub All Releases](https://img.shields.io/github/downloads/Forien/foundryvtt-forien-quest-log/total?style=for-the-badge&label=Downloads+total) -**[Compatibility]**: *FoundryVTT* 0.6.0+ -**[Systems]**: *any* -**[Languages]**: *Chinese, English, French, German, Japanese, Korean, Polish, Portuguese (Brazil), Spanish* -This module provides comprehensive Quest Log system for players and Game Masters to use with Foundry Virtual Table Top +![FQL Version](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/Forien/foundryvtt-forien-quest-log/master/module.json&label=Forien%27s+Quest+Log+version&query=version&style=flat-square&color=success") +![Foundry Core Compatible Version](https://img.shields.io/badge/dynamic/json.svg?url=https%3A%2F%2Fraw.githubusercontent.com%2FLeague-of-Foundry-Developers%2Ffoundryvtt-forien-quest-log%2Fmaster%2Fmodule.json&label=Foundry%20Version&query=$.compatibility.verified&colorB=orange) +![GitHub release](https://img.shields.io/github/release-date/Forien/foundryvtt-forien-quest-log) +[![GitHub commits](https://img.shields.io/github/commits-since/Forien/foundryvtt-forien-quest-log/latest)](https://github.com/Forien/foundryvtt-forien-quest-log/commits/) +![the latest version zip](https://img.shields.io/github/downloads/Forien/foundryvtt-forien-quest-log/latest/module.zip) +![Forge installs](https://img.shields.io/badge/dynamic/json?label=Forge%20Installs&query=package.installs&suffix=%25&url=https%3A%2F%2Fforge-vtt.com%2Fapi%2Fbazaar%2Fpackage%2Fforien-quest-log) +[![Foundry Hub Endorsements](https://img.shields.io/endpoint?logoColor=white&url=https%3A%2F%2Fwww.foundryvtt-hub.com%2Fwp-json%2Fhubapi%2Fv1%2Fpackage%2Fforien-quest-log%2Fshield%2Fendorsements)](https://www.foundryvtt-hub.com/package/forien-quest-log/) + +[![Weblate Translations](https://weblate.foundryvtt-hub.com/widgets/forien-quest-log/-/287x66-grey.png)](https://weblate.foundryvtt-hub.com/engage/forien-quest-log/) + +This module provides comprehensive Quest Log system for players and Game Masters to use with [Foundry VTT](https://foundryvtt.com/). + +**[Compatibility]**: _FoundryVTT_ `v11` / `v12` as of FQL version `0.8.0`. + +**[Game Systems]**: _any_ + +**[Language Translations]**: _Chinese (simplified / traditional), Dutch, English, Finnish, French, German, Italian, Japanese, Korean, Polish, +Portuguese (Brazil), Russian, Spanish, Swedish_ ## Installation -1. Install Forien's Quest Log using manifest URL: https://raw.githubusercontent.com/Forien/foundryvtt-forien-quest-log/master/module.json -2. While loaded in World, enable **_Forien's Quest Log_** module. +1. (Recommended) Install Forien's Quest Log from the Foundry package manager directly. + - _or_ manually using the manifest URL: `https://github.com/Forien/foundryvtt-forien-quest-log/releases/latest/download/module.json` -## Usage -Button to access Quest Log is situated on the bottom of Journal Directory. -I think module is quite user-friendly with intuitive UI, however if you are confused and lost, you might want to [check out Wiki](https://github.com/Forien/foundryvtt-forien-quest-log/wiki) or most recent [Release Video](https://www.patreon.com/forien/posts?filters[tag]=quest%20log&filters[media_types]=video). +2. While loaded in your World, enable **_Forien's Quest Log_** in the `Module Management` configuration. +## Recent Updates -## Features +The major `0.8.0` update to FQL: -* Quest Log windows that lists all quests divided into `In Progress`, `Completed` and `Failed` tabs -* Quest creator with WYSIWYG editors for description and GM notes -* Quest objectives -* Draggable Item rewards -* Fully editable Quest Details window -* Personal Quests -* Quest Branching in the form of Sub Quests +- Foundry v11 / v12 dual support. +- Actors can now be set as rewards allowing [Item Piles](https://foundryvtt.com/packages/item-piles) and various game + system loot functionality to be utilized in rewards distribution for currency and items. +- Custom rewards may use game system text enrichment where available to distribute XP. For example with the `dnd5e` + system use `[[/award 400xp]]`. +- Player Notes - players can now leave notes on quests in a separate section similar to `GM Notes`. +- Editors switched to ProseMirror. -## Future plans (current ideas) +## Usage -Plans for future include: -* a toggle "hide future tasks from players" -* Chapter/Arc system -* draggable EXP/Money rewards (need to wait for FVTT 0.7.0) +A button to access the Quest Log is situated on the bottom of Journal Directory or in the left hand scene controls icon +toolbar under notes / journal entries where two new icons (scroll and list) opens the Quest Log and Quest Tracker. There +also are two `macro compendiums` available for FQL that provide ready to go macros to drop onto your hotbar that allow +convenient access to FQL for players and several GM related options. -You can **always** check current and up-to-date [planned and requested features here](https://github.com/Forien/foundryvtt-forien-quest-log/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement) +There is a series of useful [in-depth video tutorials on YouTube](https://www.youtube.com/playlist?list=PLHslnNa8QKdD_M29g_Zs0f9zyAUVJ32Ne) +that cover the `0.7 - 0.8` releases. -*If you have **any** suggestion or idea on new contents, hit me up on Discord!* +FQL is quite user-friendly with an intuitive UI, however you might want to [check out the Wiki](https://github.com/Forien/foundryvtt-forien-quest-log/wiki) for more detailed usage including macros and Quest API details for external developers integrations. -## Translations +## Features -If you are interested in translating my module, simply make a new Pull Request with your changes, or contact me on Discord. +- Quest Log windows that lists all quests divided into `In Progress`, `Completed` and `Failed` tabs. +- Quest creator with WYSIWYG editors for description and GM notes. +- Quest objectives. +- Draggable Item rewards. +- Fully editable Quest Details window. +- Personal Quests. +- Quest Branching in the form of Sub Quests. -#### How to translate +## About -I maintain both English and Polish translation of this module, so you check on those two to see how translation file can look like. It can be either expanded (nested) JSON like English, or flat JSON like Polish. +FQL is being updated for stability across core Foundry updates. This stability and long term maintenance of such is +the _main feature_ of FQL presently. You can rest assured that the quest log experience you know and _love_ will +continue to be available now and into the future. -Order of Localization Strings inside a `.json` file is indifferent. +Moving forward FQL is transitioning back to ownership and maintenance by Forien who is active again with Foundry 3rd +party development. -Localization file **must be** either completely flat, or completely expanded (nested). Not partially both. +## Translations -#### What is `missing` Folder? +FQL uses Weblate to coordinate language translation from community translators. Through this interface you are able to +provide language corrections and translations. I am more than willing to support even more language translations for +FQL, so if your language isn't represented yet please visit the [FQL Weblate Portal](https://weblate.foundryvtt-hub.com/engage/forien-quest-log/) +and get in contact. -The `lang/missing/` folder contains files for all languages showing all Localization Strings that are in the Module, but are not covered by that Language. For example, there are 6 strings not covered by Polish language, but since they are simply `API Error` messages, there is no need. +## Future plans (current ideas) +Rock solid stability through future releases of Foundry VTT and even more language / internationalization support. +At this time a few quality of life features may be added in any given release as well. -## Contact +_If you think you have found a bug or usability issue with FQL itself please file an issue in the +[FQL Issue Tracker](https://github.com/Forien/foundryvtt-forien-quest-log/issues)_. -If you wish to contact me for any reason, reach me out on Discord using my tag: `Forien#2130` +## Contact +TBD ## Acknowledgments -* Great thanks to sdenec for his invaluable help with UI overhaul! -* Thanks to Atropos for his relentless work on developing and improving the Foundry VTT -* Thanks to necxelos, TomChristoffer and Kralug for their massive lists of suggestions -* Thanks to Brother Sharp for providing Japanese translation -* Thanks to Acd-Jake for providing German translation -* Thanks to KLO for providing Korean translation -* Thanks to rectulo and Naoki for providing French translation -* Thanks to JJBocanegra for providing Spanish translation -* Thanks to Ztt1996 for providing Chinese translation -* Thanks to Innocenti for providing Brazilian Portuguese translation +See [Authors](https://github.com/Forien/foundryvtt-forien-quest-log/blob/master/AUTHORS) and +[Contributors](https://github.com/Forien/foundryvtt-forien-quest-log/graphs/contributors) -## Support +## Support (Historical) -If you wish to support module development, please consider [becoming Patron](https://www.patreon.com/foundryworkshop) or donating [through Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6P2RRX7HVEMV2&source=url). Thanks! +Between the summer of '21 and '24 FQL was developed and maintained by Michael Leahy aka [TyphonJS](https://github.com/typhonrt) / +[TyphonJS Discord](https://typhonjs.io/discord/). Michael took FQL from MVP to the questing powerhouse that FQL became +and maintained the package through a challenging series of Foundry core update `v0.8` through `v12`. ## License -Forien's Quest Log is a module for Foundry VTT by Forien and is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/). +Forien's Quest Log is a module for Foundry VTT by Forien and is licensed under a [MIT License](https://github.com/Forien/foundryvtt-forien-quest-log/blob/master/LICENSE). -This work is licensed under Foundry Virtual Tabletop [EULA - Limited License Agreement for module development from May 29, 2020](https://foundryvtt.com/article/license/). +This work is licensed under Foundry Virtual Tabletop [EULA - Limited License Agreement for module development from February 17, 2021](https://foundryvtt.com/article/license/). diff --git a/assets-raw/icons/macros/icons-macros.xcf b/assets-raw/icons/macros/icons-macros.xcf new file mode 100644 index 0000000000000000000000000000000000000000..6a3dbd6d2ff3d9cb47deb6bfe572095336d6d072 GIT binary patch literal 1227769 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


Wo$t2 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
_m-j4^OJk$uoBhafpSS;v{_!Ac*kGUquFp()u* z=*0A7Wx1c~l2rO|S#O>r5n6ulCvap;SlQ_b+9Z|Un%$k}K!logW)OTdEAcE#G2?=# zpOw}I>EdM(U~yz+^47{8to%xy1Irc;M?*gptE6Xrm~8ZYDu?5ZIEM~RHU!xv2oYFf zuw20+#)7U8={2#ERV-VDv>306tdVq$o?-SzcC`Uw6v>3l@>As1E^WiFXZUqff?x8d zknXn*Wz|JQwfy(Bs5J&{8umfYRo`88>SAE8dgI; zo97b}mvjIaa*gcftjxoQ_Wd5YX^9mBTjK8hCM^!!m3%PEC`Xokc)tY@s~RRlX8OhK zJDhErV}_q13i-4Bw~_}{xS`{(E|Qth!Jhdpw%(bIEZwLhCk(q7;Go;4sx3)@Bq9UhpYiO!q- z&-(@u!Qg|4tU);%IHrsDfg?nc8hpGn+cQUmRZhze9`Vfa(PHq<;cL<$8_i1hva&YF zXCbo<_^RcQKeqim(N>2) znBnI%XCK}dx%?9wE&d=zh+i4|cY43yTZ1=%(ZH|F{X2f}=qAM1Kr5#uJ2QF1CzhJL zevD2|Yj%3<4}JCdeHp!+wyflpql^XajDAjA_Q9aZW+JrwIg-Os(`-d(@pB}Zv9laB z(9%PS`@xyC@Q`-RaS)+pCtJU>K||gnN0JdWr8gffIQ9+s(1^6yIg&#G!*$Vr?3E+k zzsyy`o-xglCVXwmw}T+b-u}Km&z9+(BTZl7BC=)7a->Pqd-83FkQMTdrVV4BBTZY_ z8)I1zvSQxTv}P=@W{DZkiU^s}?`v3LNakG($+RzwBc3!oFRfU}QzZ2f{l!V>GO>6> z=_4x-fslu%t)&hvwp6V6^_b|w^f@ku;w!Hv2WlqIB<)9$=X)EGq(oYUN1tvyLvlUE z8nPq1od|f2*=E{(Bd-J5PEs+JdMr6u0XQGjuXCuH0_Rw8ew`Va z=IEn6NUAseRu9$*I;hcqsyV@IT{9H~wjmNuaNQ**f=o2%P*0L-j5^N6QAty+$q%`7;!T=rjJZTp(a@tb74}OasZ`(? zC8Z_eTWxNo0?%Yc11A{HDWlh;^HDBMMFaPdRLZy6*39YFJ%24TCR(@tSJ!AN8kR{? zdMw78wNL+xR}fL^TFRGzUdh z$Tf(>(;Jssr$L5Ict&6R*(f4IDg55wooW)2;T3`9+>5|ozJpJi&Eni z;j0d`C;bLiRy4C4)eR*_#%NNZI?RPn1X6Kg}EsX@-X!$BMH$3!^?EhqgF97BGI9HG5^q7%+#0!#C= zStZjR88IY>PkI;A4^ly3zcQN$GL6AIhLTigLekJ29 elTHP`l}{EGgznMVM38BY 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 a5BF}b3{ERaMcgPKl(+h9qWrB5x&IF}Z$2LY literal 0 HcmV?d00001 diff --git a/assets-raw/icons/macros/svg/arrows-alt-h-solid.svg b/assets-raw/icons/macros/svg/arrows-alt-h-solid.svg new file mode 100644 index 00000000..72419ff8 --- /dev/null +++ b/assets-raw/icons/macros/svg/arrows-alt-h-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/arrows-alt-solid.svg b/assets-raw/icons/macros/svg/arrows-alt-solid.svg new file mode 100644 index 00000000..59ca1366 --- /dev/null +++ b/assets-raw/icons/macros/svg/arrows-alt-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/check-solid.svg b/assets-raw/icons/macros/svg/check-solid.svg new file mode 100644 index 00000000..15d7ab5e --- /dev/null +++ b/assets-raw/icons/macros/svg/check-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/check-square-regular.svg b/assets-raw/icons/macros/svg/check-square-regular.svg new file mode 100644 index 00000000..c7699d23 --- /dev/null +++ b/assets-raw/icons/macros/svg/check-square-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/check-square-solid.svg b/assets-raw/icons/macros/svg/check-square-solid.svg new file mode 100644 index 00000000..5638e19b --- /dev/null +++ b/assets-raw/icons/macros/svg/check-square-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/exclamation-solid.svg b/assets-raw/icons/macros/svg/exclamation-solid.svg new file mode 100644 index 00000000..32de166c --- /dev/null +++ b/assets-raw/icons/macros/svg/exclamation-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/eye-slash-solid.svg b/assets-raw/icons/macros/svg/eye-slash-solid.svg new file mode 100644 index 00000000..e19a3c59 --- /dev/null +++ b/assets-raw/icons/macros/svg/eye-slash-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/hashtag-solid.svg b/assets-raw/icons/macros/svg/hashtag-solid.svg new file mode 100644 index 00000000..f63399a7 --- /dev/null +++ b/assets-raw/icons/macros/svg/hashtag-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/pen-nib-solid.svg b/assets-raw/icons/macros/svg/pen-nib-solid.svg new file mode 100644 index 00000000..408b1a4d --- /dev/null +++ b/assets-raw/icons/macros/svg/pen-nib-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/scroll-solid.svg b/assets-raw/icons/macros/svg/scroll-solid.svg new file mode 100644 index 00000000..82f0f2d3 --- /dev/null +++ b/assets-raw/icons/macros/svg/scroll-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/square-regular.svg b/assets-raw/icons/macros/svg/square-regular.svg new file mode 100644 index 00000000..4e73fc5f --- /dev/null +++ b/assets-raw/icons/macros/svg/square-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/star-solid.svg b/assets-raw/icons/macros/svg/star-solid.svg new file mode 100644 index 00000000..ce744164 --- /dev/null +++ b/assets-raw/icons/macros/svg/star-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/tasks-solid.svg b/assets-raw/icons/macros/svg/tasks-solid.svg new file mode 100644 index 00000000..d283aaa5 --- /dev/null +++ b/assets-raw/icons/macros/svg/tasks-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/trophy-solid.svg b/assets-raw/icons/macros/svg/trophy-solid.svg new file mode 100644 index 00000000..543ed227 --- /dev/null +++ b/assets-raw/icons/macros/svg/trophy-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/user-friends-solid.svg b/assets-raw/icons/macros/svg/user-friends-solid.svg new file mode 100644 index 00000000..1add45ec --- /dev/null +++ b/assets-raw/icons/macros/svg/user-friends-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets-raw/icons/macros/svg/user-solid.svg b/assets-raw/icons/macros/svg/user-solid.svg new file mode 100644 index 00000000..23737bfd --- /dev/null +++ b/assets-raw/icons/macros/svg/user-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/fonts/almendra-v15-latin-regular.woff b/assets/fonts/almendra-v15-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..a89343e219acffa6cc0117714da52d8ff93b88d3 GIT binary patch literal 16052 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 z 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 literal 0 HcmV?d00001 diff --git a/assets/fonts/almendra-v15-latin-regular.woff2 b/assets/fonts/almendra-v15-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4921ea525fe2f8859ea16402829d1b2d5f303747 GIT binary patch literal 12236 zcmV;-FEh}0Pew8T0RR91058k{4*&oF0D{y2055L<0RR9100000000000000000000 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 G&VXgE3&|`1 literal 0 HcmV?d00001 diff --git a/assets/fonts/bilbo-swash-caps-v15-latin-regular.woff b/assets/fonts/bilbo-swash-caps-v15-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..9475ceff4a65bcf0b93146ee19239db677a46742 GIT binary patch literal 25040 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

k}$44+!{B3*;Bc>@R&YIEW^EV=H>Ei>WEA8Hx* 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 i$;SUZd7ZNt2e1EK&JI^VeI~5WtQA literal 0 HcmV?d00001 diff --git a/assets/icons/macros/allowPlayersAcceptOn.png b/assets/icons/macros/allowPlayersAcceptOn.png new file mode 100644 index 0000000000000000000000000000000000000000..73c3a2f433483415a9d01909ebaacedc9b48b55f GIT binary patch literal 4231 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 Ugt7|`(VnOPW^7@EHE>J(AC17~7ytkO literal 0 HcmV?d00001 diff --git a/assets/icons/macros/allowPlayersCreateOff.png b/assets/icons/macros/allowPlayersCreateOff.png new file mode 100644 index 0000000000000000000000000000000000000000..27837a006ebf2ca53abfa01ae7223a8cca2d54e2 GIT binary patch literal 4584 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 A^Z)<= literal 0 HcmV?d00001 diff --git a/assets/icons/macros/allowPlayersDragOff.png b/assets/icons/macros/allowPlayersDragOff.png new file mode 100644 index 0000000000000000000000000000000000000000..f993c391e58bac3c0bc4afcefdaa97d3dd3072e7 GIT binary patch literal 4038 zcmV;%4>|COP)EX>4Tx04R}tkv&MmKpe$iQ^g_`1v`j1M5vuCh>AE$6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$B7gx1h+tG=rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjV+`oo1)6o+{yw(t<_X|`2ClTWzuEw1KS{5* zweS(pzYSbmw>5bWxZDATo^;8O9LY~pC=`JAGy0|+Fn9~}uDQLn_Hp_EWT>m<8{ps& zh!iP%-Q(SX&ffk#)9UXBe+Y7{XR^$R00006VoOIv04xA308>6k#;^bY010qNS#tmY z4c7nw4c7reD4Tcy000McNliru

Z283b`q`4RvC4Z}%9K~#9!?VW3I8`pKme|Hzc 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

Z27$&_diMId%4qiz_K~#9!?VW#cT-9~QKli=$ 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∈Xl zGc0FOC7OGfh7ZaC%J&;APd=;%U1v+6*$zR>`(%r-C&{~5MSXFQ z=@{_+W>xi>DY>^x!za%(e$#uQcE;qM2@+{M% zG<^|!aS4gzFBx}K&V6BQ`}4Db8gQhfRoXy${d&5`7lA5&K{IdesKPfzjJH%(;Mram;g@Pf5VNw$iy&9cgL!a!km1L{>-lNSh0E^SIjBB Y?Vm2vrD&d2@IM$pYZ_|Qq8wuW2M|d0@c;k- literal 0 HcmV?d00001 diff --git a/assets/icons/macros/countHiddenOn.png b/assets/icons/macros/countHiddenOn.png new file mode 100644 index 0000000000000000000000000000000000000000..4100b3d20193fc007e8fc6133567626eba811c75 GIT binary patch literal 4477 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 EA7Qi*F#rGn literal 0 HcmV?d00001 diff --git a/assets/icons/macros/hideFQLFromPlayersOff.png b/assets/icons/macros/hideFQLFromPlayersOff.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1f996070a32198a311463e28461cc57c2c908b GIT binary patch literal 3858 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

Z3D;fUetBn8v4Wvm#K~#9!?VWpYT-ANYzrTC$ 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

Z3HZrX=KG6UG3Lr^DK~#9!?VWp!TvZ*%Kfil- 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

Z3HXHATro8|F3aLp%K~#9!?VWjS9Q75)KX1mn zzSeP^HirY4LMVYs^aK?edIi)2RFzhsh^kO11wyDqC7iTT3W$g_t(#V@IFzbf6;(NV zNiAn7P@vEfuA-0#Fad{Pj;z<%dt`TK=k<^IIax2W_Qu|0?95kM?as_^e>1=L{r%qi zUGEKq2oWMg!yv^6s(J{p2{-|0s?t3i;0d5tM0SQEpO}E#fzQ_HUXO~%icsVe6EIN4 zn*Y9*AR;}X$j8GfIc}=qy_!OCPfkFHI%7uGN>#Ohh&jxQh#L~H56=R9z-r)=6$tZ2 z;P7&nfv<>2)}(C*E&xsg4lylwm#W?kTq`2OMfrXoI30LSM1F9f5bz9ewulU=>i>XS zfsan|pF@EoC+jGvY8P-Da7@Yd!+?u{ud3=9A~I;s&o}w*K2Tb~Uf~0XNJ3Q~sephn zTo2sjb3SXnuQI|f05<@CGQUqX1RM_hQdPetB6^^ypmD-CHTD$X{QbxyAtF121?S-cmi$^ zk!MT+p8?J;A;C}WoC;h$#hTv%EH3#pm#9i-g8%2uw>?`3SfQ#PDyn70B$U(nS5HIj zTnl`x%h5Y zi2tko6~2fp_A#Kx0ByhSV%Q8F}oLj3VgU)c~){;;AP-PBJ$(`OMt4j z0uSM>AvXfA1ItAuGZP7@#`g3spu2%(SZtnw1C;=&quL4L{Tog|h>(DpizXkV+5()3 zw-vk+g4!BPqy=1|s_6>Sx_FzsZWWO|f$RmTY9H|JSzhsO5s@DTm4JS{Er7Eb84+0$ zR2wkcg&(LghDJCfAnXNIiXDL8jpD`_Jz(f!Lkb0NqClyhu8(S!)_6F{ng zWk~uFV4ihZng8q#G67r55dbXrIiCmKYG4@#@!!d}obs`cwg#Di`zEj#eX4rYxRIRa zmHv7I%P>&t8Lz5G13#a@#@!!e0{#ZPTPFP?;1*T=RLS}64J^ZpCBi=r&u?sDne^|N zG6s_XWfEQ%&V!SvJ6X7vD7u#&02{0rq2JWDIET3ZR z!dn(>tMl`xfML@rC&R1289{Sjns6ykRgb`P4Gr{YvcggPcSPisnJ^G5wg<1^dB#6A zgN6STup)@UpR@%OwS;y&50`V;7eFKE$O1P5n@lv7{l@0ao7+c5M*fn?WKL35@u{HN z+S>ZyoH=t&Te))Ol|7K>rqHibfgWHL!45*e4S zE(8=2;Q}uKFRALU@xsL{#oHhH4dA#M8r47JMNiod#A_9#&$jImRmF8(EXyJqjUpo0 zwvA<3xUP$;V%v883Gh)*W8uUeSJj8jaDQHvWikX@QW~|Th8R&*bzN6P1Q8i4FCsEV zfQrbJ38;x7H3GVl>dw0tfGg`Ld|cN}vo91{Ipj^c;1FQ&N7D_g7H&3q))S7Z?orip zHUd@M!!#V*Yes;v5my2CR3W>2fUD{qBigd8f~sZ;g#v}b_{KbTPE|9OWfg+h0x*+a zmoUBg_xp|Bulod=ZQBJ^P3QCZy#{xz=DV&-KA%Tb)3$8~lK?|P61WI2j`aT2U>7e| z^eU4_-4TgIR8>=sI3Hn6#@!Bu#_R+uN(E zn#||(6q7I}eA5Dwy}iA`CcuzTz+0)>Q9<%o@ix!~VfVs&6SV-~y=mDQLQFauo}?Ev z5)x437Eo+_eZIpMQ0vjK>$(&Qg>g2Z=y+N!AbhjYHG&uAyvax9RigGRpiNav#|;kNTa)Ux1;)1RWG0g# zkw_4UM2JKpYLU(Tr@t0VDtT$dsXyr!xT0=J7u z&G&e=x3}*|CX>2-`*zv6bLZamfK)0)DwWb$EVd&M1gPp4@m>U44X=5d^4{-@@Lp+h zo~m9dA`jJ)fX>d&2Y^+>!^6kM<8di!85)blwwUWvS8-Jm{xQH^cyGa|Cq{wOMdXDU zYh$XU?{5UY+@Lbt2Yk2Ic46bjjV;-1_7kq_F0d@?o#y7|XV

yC(<)%)#55IJZFr z32&&H*LBxMqtQiUMmU$ty=7U}#KBd(b3WCB9X|-o}L~SE?h`!Yb%*dhPU5-n}LA=^7;Jcj*gC1Q=O0t z#{m-{olbwY}Ns3CD4mKYu>0t*va^w(Y`nI(;wj*G3UA1Uzke zCXK+;_`l<9+Hf3aWp{VC^z`(wV8H@nvDn_-5M!!n_wL;?I5>Dw!w4`zFTOe3YJXo} zpPfu5kLv8~q@$yQmX;PQ%Ns*lmPJcT3mqLDbar+!I5>DzUtga+6`srJG`0?J_Z>eVjrSUetQXlRI3Dn&M%#c>?6*(|A4ilLz);_*1ZVszrRgHm^W`8(P)%hF2~T&5dHoABoc{KG#dRyLr2218SB@tKfO>W z+}zdG)m}EX>4Tx04R}tkv&MmKpe$iQ^g_`1v`j1M5vuCh>AE$6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$B7gx1h+tG=rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjV+`oo1)6o+{yw(t<_X|`2ClTWzuEw1KS{5* zweS(pzYSbmw>5bWxZDATo^;8O9LY~pC=`JAGy0|+Fn9~}uDQLn_Hp_EWT>m<8{ps& zh!iP%-Q(SX&ffk#)9UXBe+Y7{XR^$R00006VoOIv04xA308>6k#;^bY010qNS#tmY z4c7nw4c7reD4Tcy000McNliru

Z48WcoMZrcC=1gA+vK~#9!?VW9iR8<(qf6qEw zndJ*&8X1z+f}v#42PvsOSY)xVLD9>XUW6sGBC+C-gma`;aVr&K8sQ7HGTKPv*x61h@it(cOOm<^h)g?*e~? z0(cPED*>(kyKXk(?mfUep^*JFR5eQ>+sv#~vHMl-{y~+)_L*6q1T-$;3wPfD zY!1y3t5cgxz&SvVyDtNtPi>nItgUj$eQFCz3eZ)+`M@zV8)_hZJ8*3XM{U5*A?|M^ zX(#G4vrR$7k~)VPGP7fdmdfmK_luPiLI@#*5JCtcM65K`7Ub>*tRrc2SxwRwGeFWy zVb@p(DR*B8?52KO%v4eYjsxES{lI5cT212?5HkO1;Bo$YFWE`Dl{}Y{@Bm56WsDpl z=|%B*)?HYd5wH%}LG2s)4m@IJABXhwf&IXoNF|hkSAbWu?Aq8&uZZq((i_knt`tHy z!NU=U-vaOy@K}~7(Tsp=8c5So@rxhKK^eHo-Ph(pKqH}~owM(<6?0G#DFDxe8$D4A zn9i&Ou9tvpxlIDH9+`lj@+9EL3G6eF zdOy3t0(dIfmnQ*xn!F0iz$dBoD}f6l3y=M|5nyJ&Qhj2cT6`4#36HU!xaK515YCnL&y2e!02^O@?)J4{D)Gs&nb1(K1^_W(bn2TpSLPLe52V)>)E1L!fcGr1Pf zprkI~W$HhTIaQQM26gJ4jLeTpfV(du84~SYvY!cQG*mY?o7vZs8lp4I@B+zvk1I*q zRyu*X8D{t?;AqJBeqbQav$P5!gb+dqA%v*Gzm1VdTW*ezT>t<807*qoM6N<$g4luw AGXMYp literal 0 HcmV?d00001 diff --git a/assets/icons/macros/questTrackerEnableOff.png b/assets/icons/macros/questTrackerEnableOff.png new file mode 100644 index 0000000000000000000000000000000000000000..860d4aa9b0deba83736a333d6032f62ac99317b5 GIT binary patch literal 2165 zcmV-*2#WWKP)EX>4Tx04R}tkv&MmKpe$iQ^g_`1v`j1M5vuCh>AE$6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$B7gx1h+tG=rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjV+`oo1)6o+{yw(t<_X|`2ClTWzuEw1KS{5* zweS(pzYSbmw>5bWxZDATo^;8O9LY~pC=`JAGy0|+Fn9~}uDQLn_Hp_EWT>m<8{ps& zh!iP%-Q(SX&ffk#)9UXBe+Y7{XR^$R00006VoOIv04xA308>6k#;^bY010qNS#tmY z4c7nw4c7reD4Tcy000McNliru

Z46)^wRmc;-7269P6K~#9!?VV|;7F8I>f6w)* zEt+Yj<&vaji>;C+rG(#1GMCkXcdD zrlxJSm&^5f|9zNqah&E|yv@5zK0g@d&Ybg}xjg?f&)Ls_<2X*uu=quDbMs)}0pO@) z*ndF4GGKgDQ`1*&@@;8ITt5Je$k6!hB991ZI|&*S*GGl(m%x&Yo-qa(5=+}DB0zi2 zU((dnbaNIDXl`!4JqTcK?$R#Esqq_-3nVoFox|m3Gi!4JI&RGAz~CY^s8h^rQ;54O za2aqGFfhEqYa}fI9x}7vV(DHDoCADdX5(Cd!VCh2mZ~aC>Ipmt9GVE<7q|*&l60<_ zeHZTU8PZ+nZ$NoW1D;B`zbTw22jg!6o&@HFzfTJS3sPQj&bz-++j5z%IbIWr(m?(kP;_h5bS`dS&qY zR}u9SbvLuN(8si(NOEgjfXJvTw$~j2Z-pbyE=gMyGg|Bfq7=OCKm!o>I|GsG>P_QGi!~7?H!DNNXkz)0u$MG zs>tCX{!TT{q^AN+buU0L{siFCaO*%x_nKL2F#Zhwy}Ssb6)+QsW~#-9LWkCY@c|CY ziwn9w7{A?JTnTiN^c2zZqe8}?2s~fM%Ze;70$iN%)eXSqL@O2dOo`tD+ziag)0(cV z$+B>p2DGK5Uk0JC#oeC0)e`+!GNL`bq3xDA+9!uTHnf7O8i@8rh6g@X7-qDit1 z1&n_O@MJkTU(%7l@ETV`7n<2R@`9w!l5UmsZLFocR?eY_!iW$HCm?f#JyPygipQsP$qLgR10whYnVZ|5Op%%or^a>(rBVxPqqM8n%P@1HhjsS`I{ z(NVc9UC@I-&)9V@qWyoC0%sI3{=$&+|K3q6C0X{*tWLStlW336wC5}Wt~Im2*n!DX zfGgO#u~I1(1J{_@pGD&QN`0)Zujme3Sr@|ni1zduRwUXI;EGZ$-_RzwiD(zZT2(_g z679%4KR4}wF!OCDaBxcSQedo^{a$8TMr}9YlbLPFV{3Pyq&E^R-RC9s@Vyu3*1ujWlL zv-?Y=H5z!9+J6sVwV54Lsl>C+SqHG~p3a3hGl*4;y{V6nF$}C^;#mtYi1G$``T)Cn z36Q-28z`?2zm?*jBXI#b$j3wpwuvAy;N6Q^CZBJz?>3sT7bvPSRwN+(Yj&P z@Mr^G%3C$G8_@v$$tmf#08@xYnaWwB)R(Q_38)1dfDco?%2D?Xv96LXkhDP3SCT%H r^o*nve4&QpIF92uj^j9vQ&au{idpfJLqurl00000NkvXXu0mjf@zV$C literal 0 HcmV?d00001 diff --git a/assets/icons/macros/questTrackerEnableOn.png b/assets/icons/macros/questTrackerEnableOn.png new file mode 100644 index 0000000000000000000000000000000000000000..5dcf02dca31ef70fa5d48ab71b33e6907d132ee6 GIT binary patch literal 2328 zcmV+z3Fr2SP)EX>4Tx04R}tkv&MmKpe$iQ^g_`1v`j1M5vuCh>AE$6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$B7gx1h+tG=rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjV+`oo1)6o+{yw(t<_X|`2ClTWzuEw1KS{5* zweS(pzYSbmw>5bWxZDATo^;8O9LY~pC=`JAGy0|+Fn9~}uDQLn_Hp_EWT>m<8{ps& zh!iP%-Q(SX&ffk#)9UXBe+Y7{XR^$R00006VoOIv04xA308>6k#;^bY010qNS#tmY z4c7nw4c7reD4Tcy000McNliru

Z46(S65=ZydW2Ng*~K~#9!?VWp!71bTbKfh&p zSVhF5Ao5UB(Mo-kXti22;SXCOZE2#}XoAr;Dr&7JrD>ERRjWoqO`~FbAS!Apl9Fgt zq%T8_r9Mgpi_ymT;MJ<=R^IGh`1;43b%$Z@LppQso!#FjncST{=bqX9e$Sja?*Yeg zoQ7fX6GvPC@$Uu(Wb}8Q9x_V_n4c2<7_cK0S7-E;YUn3H*jd2T za9%Fwx5vbvyr1Gvlk{rhI6Z`o2%nqM%5*c^2CPlQExZ8_n%T`Vsk z+RvOn5Ez~~`X`FYQibn#hR;4d#egQnY|ZGSd++oSwC>ocnx?P_zG}~q;OvtFruNgDz zlr$4~Bs^rF3sudIApD>Z^*%G}NPPWxNl&CCyV%SY7o{Drj|ue>KW4&mNk0N^4c!nY z$AUY6e!xsgqk)@ZVTS@)+iMABGbORPVr zM|MRtZ5Otg{hNZ(l9IdgqJ&e`fE77jYlX{Q-GJ%9Uo+0FCE$gSw&OUC<2a7vIF92u zj^j8^FGJD@NlPWYBx$@WQh)LPBxz$fR!KUgH)>%G5dTQvVPIS$=mX#!GyAAF8PHm1 z@rM(w0T`DOd=TApL6Kxc)6Ks@Wq8RYQL|NSeTu!u7@vxNm9l#C1 z!XmBd%9<=6Zu5XWDe0FJe-`jq0mN5P4EQy0Z;A;?I)NL31y#iV7qGPn40x$9`awxx{tHxn&?QVr>SooKOlBdejy%xn`yK~i5yzm&8-*3#W5>3vC;hiwL&I+$={ z%!IX)rn&g_H(`dPS3Ku8&IFUxKXfZNj^os`nO&uL>KD2z4h80z*=Dz+j^azYUDAe7 zOIj%DU{|JowWC{O;&&YjB=z?qC};7B`hYG;xpoPdXl8H6;vWDEZD3Kk3;1uId(yS$ zAoAhBo@Dbqh(8m!xQw7r6Rr8}ia&&CAE4tJm_c_Fbu!*oh&w>i1fpF}b^}+M*@~F> zU4u1g4YFr|Ys_qWEUhWPJxx$b>@>46c_rSGq4;MK^@a`!#l{1Y&Xm*&{JetrOMz?S z;s^RQNim)4s9css(4D~G*!iKr{lIeIdu7C57IOZ!-dZWivVSIRXY|2Ddwix{=a0Zo z%xo*Ym@Eyrg6@r#s_|#wYBSqXAx=9vk4DuT0P-27E~L_Pk1T0Qc9h zLgrEX>4Tx04R}tkv&MmKpe$iQ^g_`2Ro>A$WV2$AS&W0RV;#q(pG5I!Q|2}Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOiW=_we!cF3PjK&;2?2l)T9RpGZ8%bi*RvAfDN@ zbk6(4Ay$$U;&bA0gDyz?$aUG}H_ki6e@tQNECM zS>e3JS*_Gq>z@3D!MwJT<~q$V;#figNr;e9Lm3rVh|;Q&Vj@NRF%SQ+<4=-HCRZ7Z z91EyIh2;3b|KNAGW?^d5O$x??&Kfh(=;uQq_$Ptxmc zEpi0(Zvz+CZB5<-E_Z;zCtWfmNAlAY3I*W(jJ_!c4BP^}Yi@6?eVjf38R}~J1~@nb zMvIia?(yzGXK(+WY4!I5hNW_^NU>%}00006VoOIv04xA308>6k#;^bY010qNS#tmY z4c7nw4c7reD4Tcy000McNliru

-AC@9DZg(m<233f?DK~#9!?VW9G6vr9Ie{&oV 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

-ADFKtCED8Vs3I$0-K~#9!?VWvaRMi>AfA6xO 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

Z35FD~RusQ$$4=hPUK~#9!?VWpY9o2ouKWFdN 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 literal 0 HcmV?d00001 diff --git a/assets/icons/macros/trustedPlayerEditOn.png b/assets/icons/macros/trustedPlayerEditOn.png new file mode 100644 index 0000000000000000000000000000000000000000..ea95308b6de8e0fc301f0f8695234803e15fa023 GIT binary patch literal 4545 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 literal 0 HcmV?d00001 diff --git a/changelog.md b/changelog.md index eb9dd50a..056b69fd 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,165 @@ # Changelog +## Release 0.8.0 +This major `0.8.0` update brings to FQL: +- Actors can be set as quest rewards (Item Piles / game system loot support). +- Player Notes - players can now leave notes on quests in a separate section similar to `GM Notes` +- ProseMirror editor support / removed TinyMCE. +- Streamlined codebase updating to ES2022. +- Dual v11 / v12 support. +- This is the last release by Michael Leahy (TyphonJS) before FQL returned to Forien. -### v0.5.1 +## Release 0.7.12 +The minor `0.7.12` update brings to FQL: + +- Foundry v11 support. +- Removed support for v9 / v10 to prevent any compatibility warnings. +- Fixed minor TinyMCE configuration for correct font support. +- Updated Spanish translation. + +## Release 0.7.11 +The minor `0.7.11` update brings to FQL: + +- Corrects a new compatibility warning that came up w/ the 10.285 Foundry release. +- Provides workarounds for various misbehaving game systems (Gurps / L5R). +- Refines the "show quest log to players" feature showing the players the specific quest status tab the GM currently + has selected. +- Adds a Dutch language translation. + +## Release 0.7.10 +This is a major release that brings dual compatibility on Foundry `v9` & `v10`. + +Several quality of life improvements including: + +- Quest document linking is enabled again. +- Show quest log to players link in quest log app header (for GM). +- Show quest tracker to players with icon in quest tracker header (for GM). +- Ability to set quest tracker to transparent via fill icon in app header. +- Expanded language / translation support. + +[Weblate setup](https://weblate.foundryvtt-hub.com/engage/forien-quest-log/) for language / translation community +updates. + +## Release 0.7.9 +- Disable synthetic quest type registration for Foundry `v9+`. As it turns out `CONST` was locked down last +minute in the v9 release cycle. The feature affected is "document linking" for quests. There is a replacement module / +continuing the quest log that will enable this functionality again with a different implementation. You can join the +TyphonJS Discord server to get an announcement when the new module is available: https://discord.gg/mnbgN8f + +## Release 0.7.8 +- A few fixes for external module conflicts. + +## Release 0.7.7 +This release is a major quality of life update. + +- Quest Tracker overhaul + - Removed floating quest log. + - Quest tracker is now dockable / resizable. + - UI management + +- Macro Compendiums + - GM & Player macro compendiums. + - Most common macros to control FQL are pre-made and ready to drop in hotbar. + +- TinyMCE Corrections + - Default font in editor is the same when viewing quest. + - New smaller font sizes. + - Correct implementation for line spacing. + +- Theming + - Support for Whetstone. + - Support for Lib Themer (beta) / not officially released yet. + +## Release 0.7.6 +This release is a major quality of life update. There is deeper integration with Foundry allowing quests to be made into Notes on the canvas and many enhancements to the TinyMCE content editing capabilities. + +- FQL journal entry opens quest details. +- Drag FQL journal entry or quest from quest log to canvas as a Note. +- Quest tracker / floating log can interact w/ objectives. +- Content entity linking in objectives / abstract rewards +- TinyMCE + - New fonts + - oEmbed plugin + - style border + - style drop shadow + - Styles + - Blend mode + - Border + - Filters + - Blur + - Drop Shadow + - Grayscale + - Float + - Fonts + - Neon + - Line height + - Margin + - Opacity + - Source Code Editing + - CSS selector + - background gradient + - background before / after + +## Release 0.7.5 +Small quality of life update. + +Fix for Issue #98. +Esc key now cancels all single line input editing. +For all single line input fields cursor is set to end of input. +The default module setting for countHidden is now false instead of true. +Updated French translation / language file. + +## Release 0.7.4 +Brings substantial finishing aspects to FQL + +Improved user experience +Trusted Player Edit +New quest creation workflow +In-memory QuestDB +and much more! + +## Release 0.7.0-0.7.3 +Total rewrite that fixes most known bugs, courtesy of @typhonrt. +Existing quests will be migrated, except that quest rewards will be removed and need to re-added manually. +Remember to back up your world before installing. + +This is the first release from Michael Leahy (TyphonJS). + +## Release 0.6.0 +* Set compatible with Foundry 0.8.6 (and removes compatibility with lower versions) +* Left sidebar buttons moved from it's own menu (the pen icon) to buttons under the Notes menu (the bookmark icon) + +## Release 0.5.8 +* Set compatible with Foundry 0.7.10 +* Updated Chinese localization courtesy of FuyuEnnju +* Localization fix courtesy of FuyuEnnju + +## Release 0.5.7 +* Buttons to delete and change vertical alignment of quest giver and splash image added courtesy of @Dilomos + +## Release 0.5.6 +* Added the QuestTracker from the 'party-unit-frames' project courtesy of @p4535992 +* Added support for Bug Reporter +* Hopefully fixed the broken release flow... + +## Release 0.5.5 +* Failed release, withdrawn + +## Release 0.5.4 +* A floating quest window, by Rughalt +* Translation to zh-tw, by zeteticl +* Set compatible Foundry version to 0.7.9 (as that is what I tested the above with) + +## Release v0.5.3 +* [BUG] Quest not loading when user removed from world (@xdy) +* Add Svenska (Swedish) translation (@xdy) +* Updated release to point to the League fork instead of the death-save one (@eclarke12) + +## v0.5.2 +* [BUG] Quest Preview not saving +* [BUG] Can't close new Quest Window +* Provide compatibility with Foundry VTT 0.7.7 + +## v0.5.1 * [BUG] "_fql_quests" folder not being created on fresh installs ## v0.5.0 diff --git a/css/init.css b/css/init.css new file mode 100644 index 00000000..8328adb1 --- /dev/null +++ b/css/init.css @@ -0,0 +1,2 @@ +.fql-app{background:url(../../../ui/denim075.png) repeat;border-radius:5px;box-shadow:0 0 20px #000;color:#f0f0e0;margin:3px 0;max-height:100%;position:absolute}.fql-window-app{padding:0;z-index:99}.fql-window-app,.fql-window-app .window-content{display:flex;flex-direction:column;flex-wrap:nowrap;justify-content:flex-start}.fql-window-app .window-content{color:#191813;overflow-x:hidden;overflow-y:auto;padding:8px}.fql-window-app .window-header{border-bottom:1px solid #000;flex:0 0 30px;line-height:30px;overflow:hidden;padding:0 8px;pointer-events:auto}.fql-window-app .window-header a{flex:none;margin:0 0 0 8px}.fql-window-app .window-header h4{font-family:Signika,sans-serif}.fql-window-app .window-header i[class^=fa]{margin-right:3px}.fql-window-app .window-header .window-title{margin:0;word-break:break-all}.fql-window-app .window-resizable-handle{background:#444;border:1px solid #111;border-radius:4px 0 0 0;bottom:-1px;height:20px;padding:2px;position:absolute;right:0;width:20px}.fql-window-app .window-resizable-handle i.fas{transform:rotate(45deg)}.fql-window-app.minimized .window-header{border:1px solid #000}.fql-window-app.minimized .window-resizable-handle{display:none}#forien-quest-log .pad-l-4,#quest-tracker .pad-l-4,.window-app.forien-quest-preview .pad-l-4{padding-left:4px}#forien-quest-log .pad-l-8,#quest-tracker .pad-l-8,.window-app.forien-quest-preview .pad-l-8{padding-left:8px}#forien-quest-log i,#quest-tracker i,.window-app.forien-quest-preview i{flex:none}#forien-quest-log i.fas.fa-star,#quest-tracker i.fas.fa-star,.window-app.forien-quest-preview i.fas.fa-star{color:gold;filter:drop-shadow(0 0 2px #000)}#forien-quest-log i.fas.fa-fill,#quest-tracker i.fas.fa-fill,.window-app.forien-quest-preview i.fas.fa-fill{color:#add8e6;filter:drop-shadow(0 0 2px #000)}#forien-quest-log i.fas.fa-fill.off,#quest-tracker i.fas.fa-fill.off,.window-app.forien-quest-preview i.fas.fa-fill.off{color:#fff;filter:drop-shadow(0 0 2px #000)}#forien-quest-log .window-header,.window-app.forien-quest-preview .window-header{margin:0}#forien-quest-log .window-content,.window-app.forien-quest-preview .window-content{border-radius:0 0 5px 5px;margin:0;padding:0}#forien-quest-log .tab,.window-app.forien-quest-preview .tab{display:none;height:100%}#forien-quest-log .tab.active,.window-app.forien-quest-preview .tab.active{display:block}#forien-quest-log h1,.window-app.forien-quest-preview h1{flex:0 0 1px;font-size:22px;font-weight:700;line-height:1;margin:0 0 8px;padding:0 0 4px}#forien-quest-log h2,.window-app.forien-quest-preview h2{border-width:2px;font-size:18px;font-weight:700;margin:0 0 4px;padding:0 0 2px}#forien-quest-log label,.window-app.forien-quest-preview label{display:block;margin-bottom:3px}#forien-quest-log input[type=text],.window-app.forien-quest-preview input[type=text]{background:#ffffff80;border:none;box-shadow:inset 0 0 3px 1px #0000;height:26px;padding:4px 8px;transition:box-shadow .3s ease}#forien-quest-log input[type=text]:hover,.window-app.forien-quest-preview input[type=text]:hover{box-shadow:0 0 0 1px var(--palette-primary,var(--default-primary-accent,#ff6400)) inset}#forien-quest-log button,.window-app.forien-quest-preview button{border-radius:5px;cursor:pointer;height:30px;margin-bottom:2px;margin-right:4px;margin-top:2px;transition:border-color .3s ease,background .3s ease,box-shadow .3s ease}#forien-quest-log button:first-child,.window-app.forien-quest-preview button:first-child{margin-left:0}#forien-quest-log nav.tabs,.window-app.forien-quest-preview nav.tabs{align-items:center;background:#fff3;flex:0 0 40px;font-size:larger;justify-content:flex-start;padding:0 16px}#forien-quest-log nav.tabs .item,.window-app.forien-quest-preview nav.tabs .item{flex:0 0 1px;margin-left:1rem;text-align:left;transition:color .3s ease;white-space:nowrap}#forien-quest-log nav.tabs .item:hover,.window-app.forien-quest-preview nav.tabs .item:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400));text-shadow:none}#forien-quest-log nav.tabs .item:first-child,.window-app.forien-quest-preview nav.tabs .item:first-child{margin-left:0}#forien-quest-log nav.tabs .item.active,#forien-quest-log nav.tabs .item.active:hover,.window-app.forien-quest-preview nav.tabs .item.active,.window-app.forien-quest-preview nav.tabs .item.active:hover{color:inherit;font-weight:700;text-shadow:none}#forien-quest-log .hidden,.window-app.forien-quest-preview .hidden{display:none}#forien-quest-log .icon-button,.window-app.forien-quest-preview .icon-button{flex:none}#forien-quest-log .editor,.window-app.forien-quest-preview .editor{background:#ffffff80;border-radius:5px;height:100%;padding:8px}#forien-quest-log .editor .editor-content,.window-app.forien-quest-preview .editor .editor-content{height:100%;overflow:auto;padding:0}#forien-quest-log .actions,.window-app.forien-quest-preview .actions{align-items:center;border-left:1px solid #00000026;display:flex;flex:0 0 100px;height:100%;justify-content:center}#forien-quest-log .actions.is-player,.window-app.forien-quest-preview .actions.is-player{flex:0 0 60px}#forien-quest-log .actions span.justify-center,.window-app.forien-quest-preview .actions span.justify-center{flex:1;margin:1px 1px 1px auto;visibility:hidden}#forien-quest-log .actions span.spacer,.window-app.forien-quest-preview .actions span.spacer{flex:0 0 4px}#forien-quest-log .actions i,.window-app.forien-quest-preview .actions i{border:none;color:#000000bf;cursor:pointer;flex:0 0 18px;font-size:16px;padding:0;text-align:center;transition:color .3s ease}#forien-quest-log .actions i.fa-sort,.window-app.forien-quest-preview .actions i.fa-sort{border-right:1px solid #00000026;cursor:move;flex:0 0 18px;width:14px}#forien-quest-log .actions i.fa-eye,.window-app.forien-quest-preview .actions i.fa-eye{flex:0 0 20px;padding-left:1px}#forien-quest-log .actions i.fa-eye-slash,.window-app.forien-quest-preview .actions i.fa-eye-slash{flex:0 0 20px}#forien-quest-log .actions i.fa-check-circle,.window-app.forien-quest-preview .actions i.fa-check-circle{color:#00af00cc}#forien-quest-log .actions i.fa-times-circle,.window-app.forien-quest-preview .actions i.fa-times-circle{color:#c80000cc}#forien-quest-log .actions i.fa-trash,.window-app.forien-quest-preview .actions i.fa-trash{color:#f009}#forien-quest-log .actions i.fa-play,.window-app.forien-quest-preview .actions i.fa-play{font-size:14px;padding-top:2px}#forien-quest-log .actions i:hover,.window-app.forien-quest-preview .actions i:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}#forien-quest-log .actions i:hover.is-player,.window-app.forien-quest-preview .actions i:hover.is-player{color:#000000bf;cursor:default}#forien-quest-log .actions i:first-child,.window-app.forien-quest-preview .actions i:first-child{margin:0}#forien-quest-log .actions-single,.window-app.forien-quest-preview .actions-single{flex:0 0 1px;padding:0 8px}#forien-quest-log .actions-single i,.window-app.forien-quest-preview .actions-single i{cursor:pointer;font-size:18px;transition:color .3s ease}#forien-quest-log .actions-single i:hover,.window-app.forien-quest-preview .actions-single i:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}#forien-quest-log section,.window-app.forien-quest-preview section{display:block;flex-direction:row;justify-content:flex-start}#forien-quest-log ::-webkit-scrollbar-corner,.window-app.forien-quest-preview ::-webkit-scrollbar-corner{background:#0000001a}#forien-quest-log{min-height:640px;min-width:500px}#forien-quest-log.window-app .window-content{overflow:visible}#forien-quest-log .quest-log{display:flex;flex-direction:column;padding:0 0 16px}#forien-quest-log .quest-log.bookmarks nav.log-tabs{align-items:flex-end;background:none;border-block-end:none;flex:0;flex-direction:column;left:0;padding:0;position:absolute;transform:translateX(-97%)}#forien-quest-log .quest-log.bookmarks nav.log-tabs .item{background:var(--palette-app-background-image,url(../../../ui/parchment.jpg)) repeat;border-radius:5px 0 0 5px;box-shadow:0 5px 5px -5px #0000004d,0 -5px 5px -5px #0000004d;margin:0 0 4px;padding:8px 16px;position:relative;text-align:right;transition:padding .3s ease,width .3s ease,color .3s ease;width:150px;z-index:1}#forien-quest-log .quest-log.bookmarks nav.log-tabs .item.active,#forien-quest-log .quest-log.bookmarks nav.log-tabs .item:hover{padding-right:32px;width:166px}#forien-quest-log .quest-log.bookmarks nav.log-tabs .item.active:after{border-radius:5px 0 0 5px;content:"";height:100%;left:0;position:absolute;top:0;width:100%;z-index:-1}#forien-quest-log .quest-log .log-body{flex:1;padding:0 16px}#forien-quest-log .quest-log .log-body header{border-block-end:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));border-bottom:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));display:flex;justify-content:space-between;margin-bottom:4px;margin-top:0;padding-top:0}#forien-quest-log .quest-log .log-body header h1{align-self:flex-end;border:none;margin:0;padding-bottom:4px}#forien-quest-log .quest-log .log-body header button{flex:0 0 fit-content}#forien-quest-log .quest-log .tab{flex-direction:column;padding:4px 0 0}#forien-quest-log .quest-log .tab.active{display:flex}#forien-quest-log .quest-log .tab .table{flex:1;overflow-y:auto;scrollbar-width:thin}#forien-quest-log .quest-log .table ul{list-style:none;margin:0;padding:0}#forien-quest-log .quest-log .table ul li.drag-quest{align-items:center;background:#ffffff4d;border:1px solid #0000;border-radius:5px;display:flex;justify-content:flex-start;margin:0 4px 2px 0;min-height:42px;transition:border-color .3s ease,box-shadow .3s ease}#forien-quest-log .quest-log .table ul li.drag-quest:hover{border-color:var(--palette-primary,var(--default-primary-accent,#ff6400));box-shadow:0 0 2px var(--palette-primary,var(--default-primary-accent,#ff6400)) inset}#forien-quest-log .quest-log .table ul .open-quest{cursor:pointer}#forien-quest-log .quest-log .table ul .img{background-size:cover;border-radius:5px;flex:0 0 40px;height:40px;width:40px}#forien-quest-log .quest-log .table ul .title{display:flex;flex:1;flex-direction:column;justify-content:center;min-height:42px;padding-left:2px;padding-right:8px}#forien-quest-log .quest-log .table ul .title h2{border:none;font-size:16px;font-weight:700;line-height:1;margin:0;padding:0}#forien-quest-log .quest-log .table ul .title p{font-size:12px;font-weight:400;margin:0;padding:0}#forien-quest-log .quest-log .table ul .tasks{align-items:center;border-left:1px solid #00000026;display:flex;flex:0 0 50px;font-size:18px;justify-content:center;min-height:42px}#forien-quest-log .quest-log .table ul .actions{min-height:42px}.window-app.forien-quest-preview{min-height:640px;min-width:1000px}.window-app.forien-quest-preview .tab.active{display:flex;flex-direction:column}.window-app.forien-quest-preview .quest-preview{background:#0000001a;display:flex;flex-direction:column;height:100%;overflow-y:hidden;padding:0}.window-app.forien-quest-preview .quest-body{flex:1;height:100%;overflow-x:hidden;overflow-y:auto;padding:6px 14px 14px}.window-app.forien-quest-preview .quest-body .details-header{display:flex;flex:0 0 1px;margin-bottom:6px}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc{background-color:#0000001a;border-radius:5px;flex:0 0 116px;font-size:12px;font-weight:700;height:116px;line-height:1.2;margin-right:8px;position:relative;text-align:center;width:116px}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .drop-info{align-items:center;border:2px dashed #00000080;border-radius:5px;cursor:pointer;display:flex;height:100%;justify-content:center}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .quest-giver-image{background-size:cover;border-radius:5px;height:100%;width:100%}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage{align-items:center;background:var(--default-secondary-accent,#ffffffbf);border-radius:5px;cursor:pointer;display:flex;height:22px;justify-content:center;left:0;position:absolute;top:0;transition:color .3s ease;width:22px}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage i{border-radius:50%;font-size:16px;line-height:1}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .deleteQuestGiver{align-items:center;background:var(--default-secondary-accent,#ffffffbf);border-radius:5px;cursor:pointer;display:flex;height:22px;justify-content:center;position:absolute;right:0;top:0;transition:color .3s ease;width:22px}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .deleteQuestGiver:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .deleteQuestGiver i{border-radius:50%;font-size:16px;line-height:1}.window-app.forien-quest-preview .quest-body .details-header .quest-setup{display:flex;flex:1;flex-direction:column}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-title{align-items:center;display:flex;justify-content:space-between}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .editable-container{flex:1;padding-left:6px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .editable-container input{height:28px;margin-bottom:8px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link{background-size:cover;cursor:pointer;flex:0 0 100px;position:relative}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link span{align-items:center;background:#0000004d;color:#ffffffa6;display:flex;font-size:28px;height:100%;justify-content:center;left:50%;opacity:1;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .3s ease;width:100%}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link span:hover{opacity:0}.window-app.forien-quest-preview .quest-body .details-header .quest-setup section{background:#ffffff26;border-radius:5px;display:flex;flex:1;margin-right:4px;overflow:hidden}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-details{display:flex;flex:1;flex-direction:column;justify-content:center;padding-right:16px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name{display:inline-flex;flex-direction:row;justify-content:left}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name .editable-container{flex:0 0 auto}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name .editable-container input{height:22px;margin-bottom:2px;padding:0}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name h2{border:none;cursor:pointer;display:inline-block;margin:0;transition:color .3s ease}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name h2:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name .action-single{flex:0 0 1px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status{display:flex;padding-left:6px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p{margin:0 8px 0 0}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p:after{content:"|";margin-left:8px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p:last-child{margin:0}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p:last-child:after{content:none}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name-link{cursor:pointer;transition:color .3s ease}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name-link i{font-size:12px}.window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name-link:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .quest-info{display:flex;flex:1;overflow-y:hidden}.window-app.forien-quest-preview .quest-body .quest-info header{display:flex;justify-content:space-between}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right button{flex:0 0 1px;font-size:15px;height:20px;line-height:1;white-space:nowrap}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right button i{font-size:10px}.window-app.forien-quest-preview .quest-body .quest-info .quest-description{flex:0 0 48%;height:100%;margin-right:8px;overflow-y:hidden}.window-app.forien-quest-preview .quest-body .quest-info .quest-description .description{background:#fff6;border-radius:5px;height:calc(100% - 30px);overflow:auto;padding:8px}.window-app.forien-quest-preview .quest-body .quest-info .quest-description .description .description-content{height:100%;overflow:auto;padding:0 4px 0 0}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right{display:flex;flex:0 0 51%;flex-direction:column}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right h2{border:none;margin:0 auto 0 0}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right header{border-block-end:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));border-bottom:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));display:flex;flex:0 0 1px;margin-bottom:4px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right span.spacer-edit{flex:0 0 18px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks{display:flex;flex:0 0 calc(50% - 8px);flex-direction:column;overflow-y:hidden}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .quest-box,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-box{flex:1;overflow-y:hidden}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards ul,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks ul{display:flex;flex-direction:column;height:100%;list-style:none;margin:0;overflow-y:auto;padding:0}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards ul li,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks ul li{align-items:center;background:#fff6;border-radius:5px;display:flex;margin:0 4px 2px 0}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards ul li:last-of-type,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks ul li:last-of-type{margin-bottom:0}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .is-link,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .is-link{cursor:pointer}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container{flex:1;padding:4px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container p,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container p{margin:0;max-width:290px;word-wrap:break-word}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container p.can-edit,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container p.can-edit{max-width:290px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container p.player-edit,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container p.player-edit{max-width:330px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container p.player,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container p.player{max-width:400px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container input,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container input{height:16px;line-height:14px;padding:0 4px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks{margin-bottom:16px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .toggleState{align-items:center;border-right:1px solid #00000026;cursor:pointer;display:flex;flex:0 0 32px;font-size:18px;height:100%;justify-content:center;transition:color .3s ease}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .toggleState:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container{align-items:center;border-right:1px solid #00000026;display:flex;flex:0 0 32px;font-size:18px;height:100%;justify-content:center}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container .state-display{align-items:center;background:#0000000d;border:1px solid #0000004d;border-radius:2px;display:flex;height:16px;justify-content:center;width:16px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container .state-display i{font-size:11px;line-height:16px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link{cursor:pointer;flex:1;margin:0;padding:4px;transition:color .3s ease;word-wrap:break-word}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link .can-edit{max-width:290px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link .player-edit{max-width:330px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link .player{max-width:390px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name-link i{font-size:12px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .task-hidden{background:#fff3}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .task-hidden .task-name{opacity:.5}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards button.hide-all-rewards,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards button.show-all-rewards{flex:0 0 90px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards button.lock-all-rewards,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards button.unlock-all-rewards{flex:0 0 98px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward{flex:0 0 25px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards span.spacer-edit{flex:0 0 18px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .drop-info{background:#0000;border:2px dashed #00000080;border-radius:5px;flex:1 0 25px;justify-content:center;line-height:20px;margin-right:4px;padding:0 16px;text-align:center}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden{background:#fff3}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden .reward-image,.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden .reward-name{opacity:.5}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-image-container{align-items:center;background-color:#222;border-radius:5px 0 0 5px;display:flex;flex:0 0 25px;height:100%;overflow:hidden}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-image-container.can-edit{cursor:pointer}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-image{background-position:50%;background-size:cover;height:25px;width:25px}.window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-name{flex:1;font-size:14px;font-weight:400;margin:0;padding-right:8px}.window-app.forien-quest-preview .quest-body .gmnotes .quest-gmnotes,.window-app.forien-quest-preview .quest-body .playernotes .quest-playernotes{height:100%;overflow-y:hidden}.window-app.forien-quest-preview .quest-body .management .row{display:flex;flex:0 0 1px}.window-app.forien-quest-preview .quest-body .management .quest-settings{display:flex;flex:1;flex-direction:column;height:226px;margin-right:8px}.window-app.forien-quest-preview .quest-body .management .quest-settings .setting-groups{flex:0 0 1px}.window-app.forien-quest-preview .quest-body .management .quest-settings label{margin:0 0 0 4px;overflow:hidden;text-overflow:ellipsis;width:calc(100% - 20px)}.window-app.forien-quest-preview .quest-body .management .quest-splash{flex:0 0 40%;position:relative}.window-app.forien-quest-preview .quest-body .management .quest-splash .splash-image{background-color:#0000001a;background-size:cover;border-radius:5px;height:200px;width:100%}.window-app.forien-quest-preview .quest-body .management .quest-splash .splash-image:hover{background-color:rgba(0,0,0,.075)}.window-app.forien-quest-preview .quest-body .management .quest-splash .state-container{margin-left:12px;position:relative}.window-app.forien-quest-preview .quest-body .management .quest-splash .state-container input[type=checkbox]{cursor:pointer;display:inline;height:18px;margin:0;position:absolute;top:1px;vertical-align:center;width:18px}.window-app.forien-quest-preview .quest-body .management .quest-splash .state-container label{display:inline;font-weight:lighter;left:22px;position:absolute;width:260px}.window-app.forien-quest-preview .quest-body .management .quest-splash .drop-info{align-items:center;border:2px dashed #00000080;border-radius:5px;cursor:pointer;display:flex;height:100%;justify-content:center}.window-app.forien-quest-preview .quest-body .management .quest-splash .splash-border{border:2px dashed #00000080}.window-app.forien-quest-preview .quest-body .management .quest-splash .delete-splash{align-items:center;background:var(--default-secondary-accent,#ffffffbf);border-radius:5px;cursor:pointer;display:flex;height:22px;justify-content:center;left:calc(100% - 22px);position:relative;top:0;transition:color .3s ease;width:22px}.window-app.forien-quest-preview .quest-body .management .quest-splash .delete-splash:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .management .quest-splash .delete-splash i{border-radius:50%;font-size:16px;line-height:1}.window-app.forien-quest-preview .quest-body .management .quest-splash .change-splash-pos{align-items:center;background:var(--default-secondary-accent,#ffffffbf);border-radius:5px;cursor:pointer;display:flex;height:22px;justify-content:center;left:calc(100% - 22px);position:relative;right:0;top:calc(100% - 44px);transition:color .3s ease;width:22px}.window-app.forien-quest-preview .quest-body .management .quest-splash .change-splash-pos:hover{color:var(--palette-primary,var(--default-primary-accent,#ff6400))}.window-app.forien-quest-preview .quest-body .management .quest-splash .change-splash-pos i{border-radius:50%;font-size:16px;line-height:1}.window-app.forien-quest-preview .quest-body .management .subquests{display:flex;flex:1;flex-direction:column;margin-top:16px;overflow:hidden}.window-app.forien-quest-preview .quest-body .management .subquests header{border-block-end:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));border-bottom:2px solid var(--palette-primary,var(--default-primary-accent,#782e22));display:flex;justify-content:space-between;margin-bottom:4px;margin-top:0;padding-top:0}.window-app.forien-quest-preview .quest-body .management .subquests h2{align-self:flex-end;border:none;margin:0;padding-bottom:0}.window-app.forien-quest-preview .quest-body .management .subquests button{flex:0 0 fit-content}.window-app.forien-quest-preview .quest-body .management .subquests .subquests-box{flex:1;list-style:none;margin:0;overflow-y:auto;padding:0}.window-app.forien-quest-preview .quest-body .management .subquests .subquests-box li{align-items:center;background:#ffffff4d;border:1px solid #0000;border-radius:5px;display:flex;height:30px;margin:0 4px 2px 0;transition:border-color .3s ease,box-shadow .3s ease}.window-app.forien-quest-preview .quest-body .management .subquests .subquests-box li:hover{border-color:var(--palette-primary,var(--default-primary-accent,#ff6400));box-shadow:0 0 2px var(--palette-primary,var(--default-primary-accent,#ff6400)) inset}.window-app.forien-quest-preview .quest-body .management .subquests .subquests-box h2{align-self:center;border:none;cursor:pointer;flex:1;font-size:14px;line-height:30px;margin:0 4px;transition:color .3s ease}.window-app.forien-quest-preview .quest-body .editor{height:calc(100% - 30px)}.window-app.forien-quest-preview .quest-body .gmnotes .editor{height:calc(100% - 36px)}#quest-tracker{max-height:750px;max-width:400px;min-height:72px;min-width:275px;pointer-events:none}@keyframes fql-jiggle{0%{animation-timing-function:ease-in;transform:rotate(-.25deg)}50%{animation-timing-function:ease-out;transform:rotate(.5deg)}}#quest-tracker .window-content{scrollbar-width:thin}#quest-tracker a.content-link{background:var(--palette-fql-qt-color-background-entitylink,#ddd);border:none;color:var(--palette-fql-qt-color-background-entitylink-contrast-text,#000)}#quest-tracker.fql-app{background:var(--palette-fql-qt-image-background,url(../../../ui/denim075.png)) repeat;background-blend-mode:var(--palette-fql-qt-image-background-blend-mode,normal);background-color:var(--palette-fql-qt-color-background,#0000);box-shadow:0 0 12px #000}#quest-tracker.fql-app.no-background{background:none;box-shadow:none;scrollbar-color:#505050b3 #3c3c3c80}#quest-tracker.fql-app.no-background ::-webkit-scrollbar-thumb{background:#3c3c3c80;border:#505050b3}#quest-tracker.fql-app.no-background .window-resizable-handle{opacity:.4}#quest-tracker .window-content{font-family:Open Sans,Lato,Signika,sans-serif;overflow-y:auto;padding:0 8px}#quest-tracker .window-content,#quest-tracker .window-header{color:var(--palette-fql-qt-text-color,var(--default-primary-color,#eee))}#quest-tracker .window-header{pointer-events:auto}#quest-tracker .window-header h4{font-family:Signika,sans-serif}#quest-tracker .window-resizable-handle{pointer-events:auto}#quest-tracker *{box-sizing:border-box}#quest-tracker #hidden{color:var(--palette-fql-qt-text-color-shaded-text,#888)}#quest-tracker .quest:not(:last-child){margin-bottom:16px}#quest-tracker .quests{flex:none;padding:8px 0}#quest-tracker .no-quests{filter:drop-shadow(1px 1px 1px #000);flex:none;padding:12px 0 8px}#quest-tracker .quest{display:flex;flex:1;flex-direction:column;height:auto;overflow-x:hidden;overflow-y:hidden}#quest-tracker .quest .title a,#quest-tracker .quest .title i{filter:drop-shadow(1px 1px 1px #000)}#quest-tracker .quest i{cursor:pointer;pointer-events:auto}#quest-tracker .quest i:last-of-type{flex:0 0 26px;text-align:right}#quest-tracker .quest .title{align-items:center;display:flex;flex-direction:row;font-size:18px;margin:0}#quest-tracker .quest .quest-tracker-header{cursor:pointer;height:auto;pointer-events:auto;width:fit-content}#quest-tracker .quest .quest-tracker-span{flex:1}#quest-tracker .quest .quest-tracker-link{pointer-events:auto}#quest-tracker .quest .tasks{list-style:none;margin:3px 0 0;padding-left:4px}#quest-tracker .quest .tasks i:last-of-type{flex:0 0 21px;text-align:right}#quest-tracker .quest .tasks .subquest{filter:drop-shadow(1px 1px 1px #000)}#quest-tracker .quest .tasks .quest-tracker-task{cursor:pointer;filter:drop-shadow(1px 1px 1px #000);width:fit-content}#quest-tracker .quest .tasks .quest-tracker-task span{cursor:pointer;pointer-events:auto}#quest-tracker .quest .tasks .quest-tracker-task span.check-square,#quest-tracker .quest .tasks .quest-tracker-task span.minus-square{-webkit-text-decoration:line-through;text-decoration:line-through}#quest-tracker .quest .tasks .subquest-separator{background-color:#ffffff80;height:1px;margin-bottom:4px;margin-top:3px;width:50px}#quest-tracker .quest .tasks .task{align-items:center;display:flex;margin:2px 0 0}#quest-tracker .quest .tasks .task span{cursor:pointer}#quest-tracker .quest .tasks .task span.check-square,#quest-tracker .quest .tasks .task span.minus-square{-webkit-text-decoration:line-through;text-decoration:line-through}#quest-tracker .quest .tasks .task:before{align-self:flex-start;content:"\f0c8";display:inline-block;font-family:Font Awesome\ 5 Free;font-weight:400;min-width:14px;padding-right:4px;pointer-events:auto;width:fit-content}#quest-tracker .quest .tasks .task.minus-square:before{content:"\f00d";display:inline-block;font-weight:900;min-width:13px;padding-left:1px;width:fit-content}#quest-tracker .quest .tasks .task.check-square:before{content:"\f00c";display:inline-block;font-weight:900;min-width:14px;width:fit-content} +/*# sourceMappingURL=init.css.map */ \ No newline at end of file diff --git a/css/init.css.map b/css/init.css.map new file mode 100644 index 00000000..8c679dd7 --- /dev/null +++ b/css/init.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../styles/basicapp.scss","init.css","../styles/quest-general.scss","../styles/global-variables.scss","../styles/quest-log.scss","../styles/global-mixin.scss","../styles/quest-preview.scss","../styles/quest-tracker.scss"],"names":[],"mappings":"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","file":"init.css"} \ No newline at end of file diff --git a/database/DBMigration.js b/database/DBMigration.js new file mode 100644 index 00000000..7bfac3ba --- /dev/null +++ b/database/DBMigration.js @@ -0,0 +1,156 @@ +/* eslint-disable */ + +import { + Socket, + Utils } from '../src/control/index.js'; + +import { constants } from '../src/model/constants.js'; + +import { + dbSchema_1, + dbSchema_2, + dbSchema_3 } from './schema/index.js'; + +/** + * Defines the callback functions to execute for each schemaVersion level. + * + * @type {Record} + */ +const migrateImpl = { + 0: () => {}, // Schema level 0 is a noop / assume all data is stored in JE content. + // 1: dbSchema_1, // Migrate to schema 1 transferring any old data to JE flags. + // 2: dbSchema_2, // Schema 2 - store quest giver data in Quest data instead of doing a UUID lookup in Enrich. + // 3: dbSchema_3, // V10 image / name refresh - dnd5e system amongst others have significant image path changes for compendiums. +}; + +/** + * Provides a utility module to manage DB migrations when new versions of FQL are installed / loaded for the first time. + * These updates are organized as schema versions with callback functions defined above. Each schema migration function + * stores the version number in module settings for {@link DBMigration.setting}. On startup {@link DBMigration.migrate} + * is invoked in the `ready` Hook callback from `./src/init.js`. If the current schema version already equals + * {@link DBMigration.version} no migration occurs. Also if there are no journal entries in the `_fql_quests` folder + * no migration occurs which is often the case with a new world and the module setting is set to not run migration + * again. + * + * In the case that a GM needs to manually run migration there is a hook defined in {@link FQLHooks.runDBMigration}. + * This is `ForienQuestLog.Run.DBMigration` which can be executed by a macro with + * `Hooks.call('ForienQuestLog.Run.DBMigration', );`. To run all migration manually substitute + * `` with `0`. + * + * @see registerHooks + */ +export class DBMigration +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + + /** + * Defines the current max schema version. + * + * @returns {number} max schema version. + */ + static get version() { return 0; } + + /** + * Defines the module setting key to store current level DB migration level that already has run for schemaVersion. + * + * @returns {string} module setting for schemaVersion. + */ + static get setting() { return 'dbSchema'; } + + /** + * Runs DB migration. If no `schemaVersion` is set the module setting {@link DBMigration.setting} is used to get the + * current schema value which is stored after any migration occurs. There is a hook available + * `ForienQuestLog.Run.DBMigration`. + * + * @param {number} schemaVersion - A valid schema version from 0 to DBMigration.version - 1 + * + * @returns {Promise} + */ + static async migrate(schemaVersion = void 0) + { + // TODO: Note that the DB migration code is disabled. The last DB migration was between v9 and v10 of Foundry + // September '22. FQL has been v11+ for a while. To provide a clean start for any future DB migration the old + // migration code for previous versions of Foundry is outdated and any migrations moving forward can start fresh. + // This code is kept around to provide a guide / possible solution for future DB migration, but otherwise should + // be freshly evaluated. The previous highest schema value for potential DB migration was `3`; this may still be + // set for the `dbSchema` world setting in the off chance of a world being upgraded. It is recommended when + // DB migration is necessary in the future to use a fresh world setting other than `dbSchema` to provide future + // migration tracking. + + // try + // { + // // Registers the DB Schema world setting. By default this is 0. The `0.7.0` release of FQL has a schema of `1`. + // game.settings.register(constants.moduleName, this.setting, { + // scope: 'world', + // config: false, + // default: 0, + // type: Number + // }); + // + // // If no schemaVersion is defined then pull the value from module settings. + // if (schemaVersion === void 0) + // { + // schemaVersion = game.settings.get(constants.moduleName, this.setting); + // } + // else + // { + // // Otherwise make sure that the schemaVersion supplied to migrate is valid. + // if (!Number.isInteger(schemaVersion) || schemaVersion < 0 || schemaVersion > DBMigration.version - 1) + // { + // const err = `ForienQuestLog - DBMigrate.migrate - schemaVersion must be an integer (0 - ${ + // DBMigration.version - 1})`; + // + // ui.notifications.error(err); + // console.error(err); + // } + // } + // + // // The DB schema matches the current version + // if (schemaVersion === this.version) { return; } + // + // // Increment the schema version to run against the proper callback function. + // schemaVersion++; + // + // // Sanity check to make sure there is a schema migration function for the next schema update. + // if (typeof migrateImpl[schemaVersion] !== 'function') { return; } + // + // const folder = await Utils.initializeQuestFolder(); + // + // // Early out if there are no journal entries / quests in the `_fql-quests` folder. + // const folderContentLength = folder?.contents?.length ?? 0; + // if (folderContentLength === 0) + // { + // await game.settings.set(constants.moduleName, DBMigration.setting, DBMigration.version); + // return; + // } + // + // ui.notifications.info(game.i18n.localize('ForienQuestLog.Migration.Notifications.Start')); + // + // // Start at the schema version and stop when the version exceeds the max version. + // for (let version = schemaVersion; version <= this.version; version++) + // { + // if (version !== 0) + // { + // ui.notifications.info(game.i18n.format('ForienQuestLog.Migration.Notifications.Schema', { version })); + // } + // + // await migrateImpl[version](); + // } + // + // ui.notifications.info(game.i18n.localize('ForienQuestLog.Migration.Notifications.Complete')); + // + // Socket.refreshAll(); + // } + // catch (err) + // { + // console.error(err); + // } + } +} \ No newline at end of file diff --git a/database/schema/dbSchema_1.js b/database/schema/dbSchema_1.js new file mode 100644 index 00000000..fad6ba87 --- /dev/null +++ b/database/schema/dbSchema_1.js @@ -0,0 +1,200 @@ +import { DBMigration } from '../DBMigration.js'; + +import { + FVTTCompat, + Utils } from '../../src/control/index.js'; + +import { Quest } from '../../src/model/index.js'; + +import { + constants, + questStatus } from '../../src/model/constants.js'; + +/** + * Performs DB migration from schema 0 to 1. + * + * Moves serialized quest data from journal entry content field to flags stored by the {@link constants.moduleName} + * and {@link constants.flagDB}. In the process perform any reversal of potential corrupted data which can occur on + * Foundry versions `0.7.10` and `0.8.6` which have improperly configured content sanitation filters that affect the + * journal entry content field. + * + * New data fields: + * - location -> {string}; default: null + * - priority -> {number}; default: 0 + * - type -> {string}; default: null + * - date -> {object} + * - {number} create - Date.now(). + * - {number} active - set if quest is in progress to Date.now(). + * - {number} end - set if quest is completed / failed to Date.now(). + * + * @returns {Promise} + */ +export async function dbSchema_1() +{ + const folder = await Utils.initializeQuestFolder(); + if (!folder) { return; } + + // Iterate through all journal entries from `_fql_quests`. + for (const entry of FVTTCompat.folderContents(folder)) + { + try + { + const flagContent = entry.getFlag(constants.moduleName, constants.flagDB); + + // If there is flag content don't migrate the data otherwise execute `migrateData`. + const content = flagContent ? flagContent : await migrateData(entry); + + if (content !== null) + { + // The new DB schema gets picked up in Quest -> initData. + const quest = new Quest(content, entry); + + // Accept the default permission if defined otherwise set to observer. + const defaultPermission = FVTTCompat.ownership(entry)?.default ?? CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER; + + const data = { + name: quest.name, + content: '', + flags: { + [constants.moduleName]: { json: quest.toJSON() } + } + }; + + data.ownership = { default: defaultPermission }; + + await entry.update(data); + } + else + { + // Must delete any no conforming journal entries. This likely never occurs. + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + await entry.delete(); + } + } + catch (err) + { + // Must delete any journal entries / quests that fail the migration process. + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + await entry.delete(); + } + } + + // Set the DBMigration.setting to `1` indicating that migration to schema version `1` is complete. + await game.settings.set(constants.moduleName, DBMigration.setting, 1); +} + +/** + * Attempts to migrate data from FQL 0.6.0 or prior to new 0.7.0 data format. This function also attempts to reverse any + * damage that the initial server side sanitation filters may have caused to the old data format. + * + * @param {JournalEntry} entry - The source journal entry storing quest data. + * + * @returns {object|null} Loaded Quest data or null if loading fails. + */ +async function migrateData(entry) +{ + let content; + + try + { + // Strip leading / trailing HTML tags in case someone attempted to look at / modify the JE. + let entryContent = FVTTCompat.get(entry, 'content'); + entryContent = entryContent.replace(/^

/, ''); + entryContent = entryContent.replace(/<\/p>$/, ''); + + try + { + // If parsing fails here we are then dealing with damaged data likely from 0.7.10 / 0.8.6 + // server side sanitation filters. + content = JSON.parse(entryContent); + } + catch (e1) + { + try + { + // These regex substitutions will attempt to reverse damage to the stored JSON. + entryContent = entryContent.replace(/("\\"|\\"")/gm, '\\"'); + entryContent = entryContent.replace(/:">/gm, '\\">'); + entryContent = entryContent.replace(/:" /gm, '\\" '); + + // Non-printable characters need to be removed; replace the entire range of non-printable characters. + entryContent = entryContent.replace(/[\x00-\x1F]/gm, ''); // eslint-disable-line no-control-regex + + content = JSON.parse(entryContent); + } + catch (e2) + { + console.error(e2); + return null; + } + } + } + catch (e) + { + console.error(e); + return null; + } + + // Convert title to name; all new Quest use `name` instead of `title` to match Foundry document model + content.name = content.title; + delete content.title; + + // As things go the rewards format for the new FQL only stores UUID and basic info. Can't support old + // rewards format. + content.rewards = []; + + // Old FQL will often store the entire actor data as the giver, so if it is not a string then set to null. + // Verify the quest giver exists; look up UUID. + if (typeof content.giver === 'string') + { + try + { + const doc = await fromUuid(content.giver); + if (!doc) { content.giver = null; } + } + catch (err) { content.giver = null; } + } + else // Handle the situation where the giver could be the complete actor data or is already null. + { + content.giver = null; + } + + // Verify that parent quest is valid. + if (content.parent) + { + try + { + const doc = game.journal.get(content.parent); + if (!doc) { content.parent = null; } + } + catch (err) { content.parent = null; } + } + + // Verify that all subquests refer to active journal entries; if not then remove them. + if (Array.isArray(content.subquests)) + { + const subquests = []; + for (const subquest of content.subquests) + { + try + { + const doc = game.journal.get(subquest); + if (doc) { subquests.push(subquest); } + } + catch (err) { /* */ } + } + + content.subquests = subquests; + } + + // Note: in DB schema v2 update status hidden is renamed to 'inactive'; use bare strings here instead of questStatus. + try + { + if (!questStatus[content.status]) { content.status = 'hidden'; } + } + catch (err) { content.status = 'hidden'; } + + return content; +} diff --git a/database/schema/dbSchema_2.js b/database/schema/dbSchema_2.js new file mode 100644 index 00000000..377f4f22 --- /dev/null +++ b/database/schema/dbSchema_2.js @@ -0,0 +1,75 @@ +import { DBMigration } from '../DBMigration.js'; + +import { + FVTTCompat, + Utils } from '../../src/control/index.js'; + +import { Quest } from '../../src/model/index.js'; + +import { + constants, + questStatus } from '../../src/model/constants.js'; + +/** + * Performs DB migration from schema 1 to 2. + * + * New data field: + * {string} giverData - Stores the quest giver data from {@link Quest.giverFromQuest}. + * + * Convert data: + * {string} status - convert 'hidden' to 'inactive' for code clarity. + * + * The purpose of this update is to store the quest giver data in the new `giverData` field. + * Presently the quest giver if non abstract and a Foundry UUID is looked up in the enrich process via `fromUUID` to + * retrieve this data. This is the only asynchronous action during the enrichment process and to provide QuestDB / + * in-memory caching of Quest and enriched data the process needs to be synchronous to make sure that order of + * operations succeeds atomically and as quick as possible. This update will process all quest data and perform that + * lookup and store the quest giver data in `giverData`. In FQL 0.7.4 and above to update the quest giver data the + * user needs to open QuestPreview and simply save the quest. A macro will also be provided to update all quest giver + * data in bulk. + * + * @returns {Promise} + */ +export async function dbSchema_2() +{ + const folder = await Utils.initializeQuestFolder(); + if (!folder) { return; } + + for (const entry of FVTTCompat.folderContents(folder)) + { + try + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + if (content) + { + const quest = new Quest(content, entry); + + // Load quest giver assets and store as 'giverData'. + if (typeof quest.giver === 'string') + { + const data = await Quest.giverFromQuest(quest); + if (data && typeof data.img === 'string' && data.img.length) { quest.giverData = data; } + } + + // Change any status of 'hidden' to 'inactive'. + if (quest.status === 'hidden') { quest.status = questStatus.inactive; } + + await quest.save(); + } + else + { + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + } + } + catch (err) + { + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + } + } + + // Set the DBMigration.setting to `2` indicating that migration to schema version `2` is complete. + await game.settings.set(constants.moduleName, DBMigration.setting, 2); +} diff --git a/database/schema/dbSchema_3.js b/database/schema/dbSchema_3.js new file mode 100644 index 00000000..74aa4934 --- /dev/null +++ b/database/schema/dbSchema_3.js @@ -0,0 +1,296 @@ +import { DBMigration } from '../DBMigration.js'; + +import { + FVTTCompat, + Utils } from '../../src/control/index.js'; + +import { Quest } from '../../src/model/index.js'; + +import { constants } from '../../src/model/constants.js'; + +/** + * Performs DB migration for v10 and all systems updating cached images / names of quest givers and reward items. + * + * The purpose of this update is that image paths for compendium items have changed for dnd5e system. World items will + * have been migrated and compendium items updated. This update does UUID lookups for all quest givers and item rewards + * changing the image path if it is found and differs from the cached value in the quest flag data. + * + * @returns {Promise} + */ +export async function dbSchema_3() +{ + const folder = await Utils.initializeQuestFolder(); + if (!folder) { return; } + + let dnd5eIconMap = void 0; + + const removedData = []; + + // Retrieve DnD5e system icon migration map if applicable. + if (typeof game?.dnd5e?.migrations?.getMigrationData === 'function') + { + const dndData = await game.dnd5e.migrations.getMigrationData(); + if (dndData && typeof dndData?.iconMap === 'object' && dndData?.iconMap !== null) + { + dnd5eIconMap = dndData.iconMap; + } + } + + for (const entry of FVTTCompat.folderContents(folder)) + { + try + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + if (content) + { + const quest = new Quest(content, entry); + + handleSplashImage(quest, dnd5eIconMap); + const removedDataEntry = {}; + + await handleQuestGiver(quest, removedDataEntry, dnd5eIconMap); + await handleRewards(quest, removedDataEntry, dnd5eIconMap); + + await quest.save(); + + if (Object.keys(removedDataEntry).length > 0) + { + removedDataEntry.questName = quest.name; + removedDataEntry.questId = entry.id; + removedData.push(removedDataEntry); + } + } + else + { + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + } + } + catch (err) + { + console.log(game.i18n.format('ForienQuestLog.Migration.Notifications.CouldNotMigrate', + { name: FVTTCompat.get(entry, 'name') })); + } + } + + // Post informational message to notifications and chat message if unlinked document data exists. + if (removedData.length > 0) + { + ui.notifications.warn(game.i18n.localize('ForienQuestLog.Migration.ChatMessage.Notification')); + + let content = game.i18n.localize('ForienQuestLog.Migration.ChatMessage.Header'); + + for (const entry of removedData) + { + // Shorten to fit in sidebar. + const questName = entry.questName.length > 38 ? `${entry.questName.substring(0, 38)}...` : entry.questName; + + content += `@JournalEntry[${entry.questId}]{${questName}}
`; + + if (typeof entry.giverName === 'string') + { + // Shorten to fit in sidebar. + const giverName = entry.giverName.length > 40 ? `${entry.giverName.substring(0, 40)}...` : entry.giverName; + + content += `${game.i18n.localize('ForienQuestLog.Migration.ChatMessage.QuestGiver')}
- ${ + giverName}
`; + } + + if (Array.isArray(entry.rewards)) + { + content += `${game.i18n.localize('ForienQuestLog.Migration.ChatMessage.QuestRewards')} (${ + entry.rewards.length})
`; + + for (const reward of entry.rewards) + { + // Shorten to fit in sidebar. + const rewardName = reward.length > 40 ? `${reward.substring(0, 40)}...` : reward; + content += `- ${rewardName}
`; + } + } + content += `
`; + } + + content += game.i18n.localize('ForienQuestLog.Migration.ChatMessage.Footer'); + + ChatMessage.create({ + user: game.user.id, + type: CONST.CHAT_MESSAGE_TYPES.OTHER, + content + }); + } + + // Set the DBMigration.setting to `3` indicating that migration to schema version `3` is complete. + await game.settings.set(constants.moduleName, DBMigration.setting, 3); +} + +/** + * @param {string} path - + * + * @param {object} dnd5eIconMap - + * + * @returns {string} Converted path. + */ +function swap5eImage(path, dnd5eIconMap) +{ + if (typeof path !== 'string' || !dnd5eIconMap) { return void 0; } + + if (typeof dnd5eIconMap[path] === 'string') + { + return dnd5eIconMap[path]; + } + else if (path.startsWith('systems/dnd5e')) + { + // Hope for the best and swap extensions to `webp`. + return path.replace(/\.[^/.]+$/, '.webp'); + } + + return path; +} + +/** + * Update quest splash image specifically for remapping dnd5e system images. + * + * @param {Quest} quest - + * + * @param {object} dnd5eIconMap - + */ +function handleSplashImage(quest, dnd5eIconMap) +{ + if (typeof quest.splash === 'string' && dnd5eIconMap) + { + const newPath = swap5eImage(quest.splash, dnd5eIconMap); + if (typeof newPath === 'string') + { + quest.splash = newPath; + } + } +} + +/** + * Update quest giver images w/ special handling for dnd5e system. + * + * @param {Quest} quest - + * + * @param {object} removedDataEntry - + * + * @param {object} dnd5eIconMap - + */ +async function handleQuestGiver(quest, removedDataEntry, dnd5eIconMap) +{ + // Load quest giver assets and store as 'giverData'. + if (typeof quest.giver === 'string') + { + // Handle remapping any dnd5e images used for abstract quest givers. + if (quest.giver === 'abstract' && dnd5eIconMap) + { + const newPath = swap5eImage(quest.image, dnd5eIconMap); + if (typeof newPath === 'string') + { + quest.image = newPath; + if (quest.giverData && typeof quest.giverData?.img === 'string') { quest.giverData.img = newPath; } + } + } + else + { + try + { + // Do a lookup and if it fails then reset giver / giverData below. + const doc = await globalThis.fromUuid(quest.giver); + + if (doc) + { + const data = await Quest.giverFromQuest(quest); + if (data && typeof data.img === 'string' && data.img.length) { quest.giverData = data; } + } + else + { + const giverName = quest?.giverData?.name ?? 'Unknown'; + console.warn(`Forien's Quest Log warning; removed quest giver "${giverName}" from quest: ${quest.name}`); + + // Document is not found, so remove quest giver and giverData. + quest.giver = null; + quest.giverData = null; + + removedDataEntry.giverName = giverName; + } + } + catch (err) + { + const giverName = quest?.giverData?.name ?? 'Unknown'; + console.warn(`Forien's Quest Log warning; removed quest giver "${giverName}" from quest: ${quest.name}`); + + // An error occurred / remove quest giver. + quest.giver = null; + quest.giverData = null; + removedDataEntry.giverName = giverName; + } + } + } +} + +/** + * Update all abstract and item quest rewards. Verify that items still exist otherwise remove them. For dnd5e system + * attempt to remap abstract reward images. For items with valid documents update the name and image otherwise remove + * them. + * + * @param {Quest} quest - + * + * @param {object} removedDataEntry - + * + * @param {object} dnd5eIconMap - + */ +async function handleRewards(quest, removedDataEntry, dnd5eIconMap) +{ + if (!Array.isArray(quest.rewards)) { return; } + + for (let cntr = quest.rewards.length; --cntr >= 0;) + { + const reward = quest.rewards[cntr]; + + if (dnd5eIconMap && reward?.type === 'Abstract' && typeof reward?.data?.img === 'string') + { + const newPath = swap5eImage(reward.data.img, dnd5eIconMap); + if (typeof newPath === 'string') + { + reward.data.img = newPath; + } + } + else if (reward?.type === 'Item' && typeof reward?.data?.uuid === 'string') + { + try + { + const doc = await globalThis.fromUuid(reward.data.uuid); + + // Remove reward as no document found. + if (!doc) + { + const rewardName = reward.data?.name ?? 'Unknown'; + console.warn(`ForienQuestLog warning; removed item reward "${rewardName}" from quest: ${quest.name}`); + + quest.rewards.splice(cntr, 1); + + if (!Array.isArray(removedDataEntry.rewards)) { removedDataEntry.rewards = []; } + removedDataEntry.rewards.push(rewardName); + } + else + { + reward.data.img = doc.img; + reward.data.name = doc.name; + } + } + catch (err) + { + const rewardName = reward.data?.name ?? 'Unknown'; + console.warn(`ForienQuestLog warning; removed item reward "${rewardName}" from quest: ${quest.name}`); + + // Remove reward on any error. + quest.rewards.splice(cntr, 1); + + if (!Array.isArray(removedDataEntry.rewards)) { removedDataEntry.rewards = []; } + removedDataEntry.rewards.push(rewardName); + } + } + } +} \ No newline at end of file diff --git a/database/schema/index.js b/database/schema/index.js new file mode 100644 index 00000000..ada6a6e3 --- /dev/null +++ b/database/schema/index.js @@ -0,0 +1,3 @@ +export * from './dbSchema_1.js'; +export * from './dbSchema_2.js'; +export * from './dbSchema_3.js'; \ No newline at end of file diff --git a/external/DOMPurify.js b/external/DOMPurify.js new file mode 100644 index 00000000..e561869e --- /dev/null +++ b/external/DOMPurify.js @@ -0,0 +1,3 @@ +/*! @license DOMPurify 3.1.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.5/LICENSE */ +const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:a,seal:i,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;a||(a=function(e){return e}),i||(i=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=unapply(Array.prototype.forEach),d=unapply(Array.prototype.pop),p=unapply(Array.prototype.push),m=unapply(String.prototype.toLowerCase),f=unapply(String.prototype.toString),h=unapply(String.prototype.match),T=unapply(String.prototype.replace),g=unapply(String.prototype.indexOf),y=unapply(String.prototype.trim),E=unapply(Object.prototype.hasOwnProperty),S=unapply(RegExp.prototype.test),_=(A=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:m;t&&t(e,null);let a=o.length;for(;a--;){let t=o[a];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[a]=e),t=e)}e[t]=!0}return e}function cleanArray(e){for(let t=0;t/gm),U=i(/\${[\w\W]*}/gm),P=i(/^data-[\-\w.\u00B7-\uFFFF]/),F=i(/^aria-[\-\w]+$/),H=i(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),z=i(/^(?:\w+script|data):/i),G=i(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),B=i(/^html$/i),W=i(/^[a-z][.\w]*(-[.\w]+)+$/i);var Y=Object.freeze({__proto__:null,MUSTACHE_EXPR:M,ERB_EXPR:I,TMPLIT_EXPR:U,DATA_ATTR:P,ARIA_ATTR:F,IS_ALLOWED_URI:H,IS_SCRIPT_OR_DATA:z,ATTR_WHITESPACE:G,DOCTYPE_NAME:B,CUSTOM_ELEMENT:W});const getGlobal=function(){return"undefined"==typeof window?null:window};var j=function createDOMPurify(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:getGlobal();const DOMPurify=e=>createDOMPurify(e);if(DOMPurify.version="3.1.5",DOMPurify.removed=[],!t||!t.document||9!==t.document.nodeType)return DOMPurify.isSupported=!1,DOMPurify;let{document:n}=t;const o=n,r=o.currentScript,{DocumentFragment:i,HTMLTemplateElement:c,Node:s,Element:A,NodeFilter:M,NamedNodeMap:I=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:U,DOMParser:P,trustedTypes:F}=t,z=A.prototype,G=lookupGetter(z,"cloneNode"),W=lookupGetter(z,"nextSibling"),j=lookupGetter(z,"childNodes"),X=lookupGetter(z,"parentNode");if("function"==typeof c){const e=n.createElement("template");e.content&&e.content.ownerDocument&&(n=e.content.ownerDocument)}let q,$="";const{implementation:K,createNodeIterator:V,createDocumentFragment:Z,getElementsByTagName:J}=n,{importNode:Q}=o;let ee={};DOMPurify.isSupported="function"==typeof e&&"function"==typeof X&&K&&void 0!==K.createHTMLDocument;const{MUSTACHE_EXPR:te,ERB_EXPR:ne,TMPLIT_EXPR:oe,DATA_ATTR:re,ARIA_ATTR:ae,IS_SCRIPT_OR_DATA:ie,ATTR_WHITESPACE:le,CUSTOM_ELEMENT:ce}=Y;let{IS_ALLOWED_URI:se}=Y,ue=null;const de=addToSet({},[...N,...b,...R,...D,...L]);let pe=null;const me=addToSet({},[...O,...v,...k,...x]);let fe=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),he=null,Te=null,ge=!0,ye=!0,Ee=!1,Se=!0,_e=!1,Ae=!0,Ne=!1,be=!1,Re=!1,we=!1,De=!1,Ce=!1,Le=!0,Oe=!1,ve=!0,ke=!1,xe={},Me=null;const Ie=addToSet({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Ue=null;const Pe=addToSet({},["audio","video","img","source","image","track"]);let Fe=null;const He=addToSet({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ze="http://www.w3.org/1998/Math/MathML",Ge="http://www.w3.org/2000/svg",Be="http://www.w3.org/1999/xhtml";let We=Be,Ye=!1,je=null;const Xe=addToSet({},[ze,Ge,Be],f);let qe=null;const $e=["application/xhtml+xml","text/html"];let Ke=null,Ve=null;const Ze=n.createElement("form"),isRegexOrFunction=function(e){return e instanceof RegExp||e instanceof Function},_parseConfig=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!Ve||Ve!==e){if(e&&"object"==typeof e||(e={}),e=clone(e),qe=-1===$e.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,Ke="application/xhtml+xml"===qe?f:m,ue=E(e,"ALLOWED_TAGS")?addToSet({},e.ALLOWED_TAGS,Ke):de,pe=E(e,"ALLOWED_ATTR")?addToSet({},e.ALLOWED_ATTR,Ke):me,je=E(e,"ALLOWED_NAMESPACES")?addToSet({},e.ALLOWED_NAMESPACES,f):Xe,Fe=E(e,"ADD_URI_SAFE_ATTR")?addToSet(clone(He),e.ADD_URI_SAFE_ATTR,Ke):He,Ue=E(e,"ADD_DATA_URI_TAGS")?addToSet(clone(Pe),e.ADD_DATA_URI_TAGS,Ke):Pe,Me=E(e,"FORBID_CONTENTS")?addToSet({},e.FORBID_CONTENTS,Ke):Ie,he=E(e,"FORBID_TAGS")?addToSet({},e.FORBID_TAGS,Ke):{},Te=E(e,"FORBID_ATTR")?addToSet({},e.FORBID_ATTR,Ke):{},xe=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,ge=!1!==e.ALLOW_ARIA_ATTR,ye=!1!==e.ALLOW_DATA_ATTR,Ee=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Se=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,_e=e.SAFE_FOR_TEMPLATES||!1,Ae=!1!==e.SAFE_FOR_XML,Ne=e.WHOLE_DOCUMENT||!1,we=e.RETURN_DOM||!1,De=e.RETURN_DOM_FRAGMENT||!1,Ce=e.RETURN_TRUSTED_TYPE||!1,Re=e.FORCE_BODY||!1,Le=!1!==e.SANITIZE_DOM,Oe=e.SANITIZE_NAMED_PROPS||!1,ve=!1!==e.KEEP_CONTENT,ke=e.IN_PLACE||!1,se=e.ALLOWED_URI_REGEXP||H,We=e.NAMESPACE||Be,fe=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&isRegexOrFunction(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(fe.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&isRegexOrFunction(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(fe.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(fe.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),_e&&(ye=!1),De&&(we=!0),xe&&(ue=addToSet({},L),pe=[],!0===xe.html&&(addToSet(ue,N),addToSet(pe,O)),!0===xe.svg&&(addToSet(ue,b),addToSet(pe,v),addToSet(pe,x)),!0===xe.svgFilters&&(addToSet(ue,R),addToSet(pe,v),addToSet(pe,x)),!0===xe.mathMl&&(addToSet(ue,D),addToSet(pe,k),addToSet(pe,x))),e.ADD_TAGS&&(ue===de&&(ue=clone(ue)),addToSet(ue,e.ADD_TAGS,Ke)),e.ADD_ATTR&&(pe===me&&(pe=clone(pe)),addToSet(pe,e.ADD_ATTR,Ke)),e.ADD_URI_SAFE_ATTR&&addToSet(Fe,e.ADD_URI_SAFE_ATTR,Ke),e.FORBID_CONTENTS&&(Me===Ie&&(Me=clone(Me)),addToSet(Me,e.FORBID_CONTENTS,Ke)),ve&&(ue["#text"]=!0),Ne&&addToSet(ue,["html","head","body"]),ue.table&&(addToSet(ue,["tbody"]),delete he.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw _('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw _('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');q=e.TRUSTED_TYPES_POLICY,$=q.createHTML("")}else void 0===q&&(q=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(F,r)),null!==q&&"string"==typeof $&&($=q.createHTML(""));a&&a(e),Ve=e}},Je=addToSet({},["mi","mo","mn","ms","mtext"]),Qe=addToSet({},["foreignobject","annotation-xml"]),et=addToSet({},["title","style","font","a","script"]),tt=addToSet({},[...b,...R,...w]),nt=addToSet({},[...D,...C]),_forceRemove=function(e){p(DOMPurify.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.remove()}},_removeAttribute=function(e,t){try{p(DOMPurify.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(DOMPurify.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!pe[e])if(we||De)try{_forceRemove(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},_initDocument=function(e){let t=null,o=null;if(Re)e=""+e;else{const t=h(e,/^[\r\n\t ]+/);o=t&&t[0]}"application/xhtml+xml"===qe&&We===Be&&(e=''+e+"");const r=q?q.createHTML(e):e;if(We===Be)try{t=(new P).parseFromString(r,qe)}catch(e){}if(!t||!t.documentElement){t=K.createDocument(We,"template",null);try{t.documentElement.innerHTML=Ye?$:r}catch(e){}}const a=t.body||t.documentElement;return e&&o&&a.insertBefore(n.createTextNode(o),a.childNodes[0]||null),We===Be?J.call(t,Ne?"html":"body")[0]:Ne?t.documentElement:a},_createNodeIterator=function(e){return V.call(e.ownerDocument||e,e,M.SHOW_ELEMENT|M.SHOW_COMMENT|M.SHOW_TEXT|M.SHOW_PROCESSING_INSTRUCTION|M.SHOW_CDATA_SECTION,null)},_isClobbered=function(e){return e instanceof U&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof I)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},_isNode=function(e){return"function"==typeof s&&e instanceof s},_executeHook=function(e,t,n){ee[e]&&u(ee[e],(e=>{e.call(DOMPurify,t,n,Ve)}))},_sanitizeElements=function(e){let t=null;if(_executeHook("beforeSanitizeElements",e,null),_isClobbered(e))return _forceRemove(e),!0;const n=Ke(e.nodeName);if(_executeHook("uponSanitizeElement",e,{tagName:n,allowedTags:ue}),e.hasChildNodes()&&!_isNode(e.firstElementChild)&&S(/<[/\w]/g,e.innerHTML)&&S(/<[/\w]/g,e.textContent))return _forceRemove(e),!0;if(7===e.nodeType)return _forceRemove(e),!0;if(Ae&&8===e.nodeType&&S(/<[/\w]/g,e.data))return _forceRemove(e),!0;if(!ue[n]||he[n]){if(!he[n]&&_isBasicCustomElement(n)){if(fe.tagNameCheck instanceof RegExp&&S(fe.tagNameCheck,n))return!1;if(fe.tagNameCheck instanceof Function&&fe.tagNameCheck(n))return!1}if(ve&&!Me[n]){const t=X(e)||e.parentNode,n=j(e)||e.childNodes;if(n&&t)for(let o=n.length-1;o>=0;--o){const r=G(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,W(e))}}return _forceRemove(e),!0}return e instanceof A&&!function(e){let t=X(e);t&&t.tagName||(t={namespaceURI:We,tagName:"template"});const n=m(e.tagName),o=m(t.tagName);return!!je[e.namespaceURI]&&(e.namespaceURI===Ge?t.namespaceURI===Be?"svg"===n:t.namespaceURI===ze?"svg"===n&&("annotation-xml"===o||Je[o]):Boolean(tt[n]):e.namespaceURI===ze?t.namespaceURI===Be?"math"===n:t.namespaceURI===Ge?"math"===n&&Qe[o]:Boolean(nt[n]):e.namespaceURI===Be?!(t.namespaceURI===Ge&&!Qe[o])&&!(t.namespaceURI===ze&&!Je[o])&&!nt[n]&&(et[n]||!tt[n]):!("application/xhtml+xml"!==qe||!je[e.namespaceURI]))}(e)?(_forceRemove(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!S(/<\/no(script|embed|frames)/i,e.innerHTML)?(_e&&3===e.nodeType&&(t=e.textContent,u([te,ne,oe],(e=>{t=T(t,e," ")})),e.textContent!==t&&(p(DOMPurify.removed,{element:e.cloneNode()}),e.textContent=t)),_executeHook("afterSanitizeElements",e,null),!1):(_forceRemove(e),!0)},_isValidAttribute=function(e,t,o){if(Le&&("id"===t||"name"===t)&&(o in n||o in Ze))return!1;if(ye&&!Te[t]&&S(re,t));else if(ge&&S(ae,t));else if(!pe[t]||Te[t]){if(!(_isBasicCustomElement(e)&&(fe.tagNameCheck instanceof RegExp&&S(fe.tagNameCheck,e)||fe.tagNameCheck instanceof Function&&fe.tagNameCheck(e))&&(fe.attributeNameCheck instanceof RegExp&&S(fe.attributeNameCheck,t)||fe.attributeNameCheck instanceof Function&&fe.attributeNameCheck(t))||"is"===t&&fe.allowCustomizedBuiltInElements&&(fe.tagNameCheck instanceof RegExp&&S(fe.tagNameCheck,o)||fe.tagNameCheck instanceof Function&&fe.tagNameCheck(o))))return!1}else if(Fe[t]);else if(S(se,T(o,le,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==g(o,"data:")||!Ue[e])if(Ee&&!S(ie,T(o,le,"")));else if(o)return!1;return!0},_isBasicCustomElement=function(e){return"annotation-xml"!==e&&h(e,ce)},_sanitizeAttributes=function(e){_executeHook("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:pe};let o=t.length;for(;o--;){const r=t[o],{name:a,namespaceURI:i,value:l}=r,c=Ke(a);let s="value"===a?l:y(l);if(n.attrName=c,n.attrValue=s,n.keepAttr=!0,n.forceKeepAttr=void 0,_executeHook("uponSanitizeAttribute",e,n),s=n.attrValue,n.forceKeepAttr)continue;if(_removeAttribute(a,e),!n.keepAttr)continue;if(!Se&&S(/\/>/i,s)){_removeAttribute(a,e);continue}if(Ae&&S(/((--!?|])>)|<\/(style|title)/i,s)){_removeAttribute(a,e);continue}_e&&u([te,ne,oe],(e=>{s=T(s,e," ")}));const p=Ke(e.nodeName);if(_isValidAttribute(p,c,s)){if(!Oe||"id"!==c&&"name"!==c||(_removeAttribute(a,e),s="user-content-"+s),q&&"object"==typeof F&&"function"==typeof F.getAttributeType)if(i);else switch(F.getAttributeType(p,c)){case"TrustedHTML":s=q.createHTML(s);break;case"TrustedScriptURL":s=q.createScriptURL(s)}try{i?e.setAttributeNS(i,a,s):e.setAttribute(a,s),_isClobbered(e)?_forceRemove(e):d(DOMPurify.removed)}catch(e){}}}_executeHook("afterSanitizeAttributes",e,null)},ot=function _sanitizeShadowDOM(e){let t=null;const n=_createNodeIterator(e);for(_executeHook("beforeSanitizeShadowDOM",e,null);t=n.nextNode();)_executeHook("uponSanitizeShadowNode",t,null),_sanitizeElements(t)||(t.content instanceof i&&_sanitizeShadowDOM(t.content),_sanitizeAttributes(t));_executeHook("afterSanitizeShadowDOM",e,null)};return DOMPurify.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,a=null,l=null;if(Ye=!e,Ye&&(e="\x3c!--\x3e"),"string"!=typeof e&&!_isNode(e)){if("function"!=typeof e.toString)throw _("toString is not a function");if("string"!=typeof(e=e.toString()))throw _("dirty is not a string, aborting")}if(!DOMPurify.isSupported)return e;if(be||_parseConfig(t),DOMPurify.removed=[],"string"==typeof e&&(ke=!1),ke){if(e.nodeName){const t=Ke(e.nodeName);if(!ue[t]||he[t])throw _("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof s)n=_initDocument("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),1===r.nodeType&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!we&&!_e&&!Ne&&-1===e.indexOf("<"))return q&&Ce?q.createHTML(e):e;if(n=_initDocument(e),!n)return we?null:Ce?$:""}n&&Re&&_forceRemove(n.firstChild);const c=_createNodeIterator(ke?e:n);for(;a=c.nextNode();)_sanitizeElements(a)||(a.content instanceof i&&ot(a.content),_sanitizeAttributes(a));if(ke)return e;if(we){if(De)for(l=Z.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(pe.shadowroot||pe.shadowrootmode)&&(l=Q.call(o,l,!0)),l}let d=Ne?n.outerHTML:n.innerHTML;return Ne&&ue["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&S(B,n.ownerDocument.doctype.name)&&(d="\n"+d),_e&&u([te,ne,oe],(e=>{d=T(d,e," ")})),q&&Ce?q.createHTML(d):d},DOMPurify.setConfig=function(){_parseConfig(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),be=!0},DOMPurify.clearConfig=function(){Ve=null,be=!1},DOMPurify.isValidAttribute=function(e,t,n){Ve||_parseConfig({});const o=Ke(e),r=Ke(t);return _isValidAttribute(o,r,n)},DOMPurify.addHook=function(e,t){"function"==typeof t&&(ee[e]=ee[e]||[],p(ee[e],t))},DOMPurify.removeHook=function(e){if(ee[e])return d(ee[e])},DOMPurify.removeHooks=function(e){ee[e]&&(ee[e]=[])},DOMPurify.removeAllHooks=function(){ee={}},DOMPurify}();export{j as default}; +//# sourceMappingURL=DOMPurify.js.map diff --git a/external/DOMPurify.js.map b/external/DOMPurify.js.map new file mode 100644 index 00000000..f817c305 --- /dev/null +++ b/external/DOMPurify.js.map @@ -0,0 +1 @@ +{"version":3,"file":"DOMPurify.js","sources":["../node_modules/dompurify/dist/purify.es.mjs"],"sourcesContent":["/*! @license DOMPurify 3.1.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.5/LICENSE */\n\nconst {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor\n} = Object;\nlet {\n freeze,\n seal,\n create\n} = Object; // eslint-disable-line import/no-mutable-exports\nlet {\n apply,\n construct\n} = typeof Reflect !== 'undefined' && Reflect;\nif (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n}\nif (!seal) {\n seal = function seal(x) {\n return x;\n };\n}\nif (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n}\nif (!construct) {\n construct = function construct(Func, args) {\n return new Func(...args);\n };\n}\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\nconst regExpTest = unapply(RegExp.prototype.test);\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n return apply(func, thisArg, args);\n };\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n return construct(func, args);\n };\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\nfunction addToSet(set, array) {\n let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n element = lcElement;\n }\n }\n set[element] = true;\n }\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\nfunction cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\nfunction clone(object) {\n const newObject = create(null);\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n return newObject;\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n object = getPrototypeOf(object);\n }\n function fallbackValue() {\n return null;\n }\n return fallbackValue;\n}\n\nconst html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);\n\n// SVG\nconst svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);\nconst svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nconst svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);\nconst mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nconst mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\nconst text = freeze(['#text']);\n\nconst html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);\nconst svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);\nconst mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);\nconst xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n// eslint-disable-next-line unicorn/better-regex\nconst MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\nconst ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nconst TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\nconst DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\nconst ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nconst IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\n\nconst IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nconst ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\n\nconst DOCTYPE_NAME = seal(/^html$/i);\nconst CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\nvar EXPRESSIONS = /*#__PURE__*/Object.freeze({\n __proto__: null,\n MUSTACHE_EXPR: MUSTACHE_EXPR,\n ERB_EXPR: ERB_EXPR,\n TMPLIT_EXPR: TMPLIT_EXPR,\n DATA_ATTR: DATA_ATTR,\n ARIA_ATTR: ARIA_ATTR,\n IS_ALLOWED_URI: IS_ALLOWED_URI,\n IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE: ATTR_WHITESPACE,\n DOCTYPE_NAME: DOCTYPE_NAME,\n CUSTOM_ELEMENT: CUSTOM_ELEMENT\n});\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5,\n // Deprecated\n entityNode: 6,\n // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12 // Deprecated\n};\n\nconst getGlobal = function getGlobal() {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n }\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n};\nfunction createDOMPurify() {\n let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n const DOMPurify = root => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = '3.1.5';\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n return DOMPurify;\n }\n let {\n document\n } = window;\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes\n } = window;\n const ElementPrototype = Element.prototype;\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n let trustedTypesPolicy;\n let emptyHTML = '';\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName\n } = document;\n const {\n importNode\n } = originalDocument;\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT\n } = EXPRESSIONS;\n let {\n IS_ALLOWED_URI: IS_ALLOWED_URI$1\n } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false\n }\n }));\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n const isRegexOrFunction = function isRegexOrFunction(testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function _parseConfig() {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),\n // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),\n // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html$1);\n addToSet(ALLOWED_ATTR, html);\n }\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg$1);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl$1);\n addToSet(ALLOWED_ATTR, mathMl);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n }\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n CONFIG = cfg;\n };\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);\n const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function _checkValidNamespace(element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template'\n };\n }\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function _forceRemove(node) {\n arrayPush(DOMPurify.removed, {\n element: node\n });\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n node.parentNode.removeChild(node);\n } catch (_) {\n node.remove();\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function _removeAttribute(name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node\n });\n }\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function _initDocument(dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n if (FORCE_BODY) {\n dirty = '' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty = '' + dirty + '';\n }\n const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n const body = doc.body || doc.documentElement;\n if (dirty && leadingWhitespace) {\n body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n }\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function _createNodeIterator(root) {\n return createNodeIterator.call(root.ownerDocument || root, root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function _isClobbered(elm) {\n return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function _isNode(object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function _executeHook(entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n arrayForEach(hooks[entryPoint], hook => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function _sanitizeElements(currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any ocurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\\w]/g, currentNode.data)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {\n return false;\n }\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n content = stringReplace(content, expr, ' ');\n });\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, {\n element: currentNode.cloneNode()\n });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {\n return false;\n } else ;\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function _isBasicCustomElement(tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n const {\n attributes\n } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const {\n name,\n namespaceURI,\n value: attrValue\n } = attr;\n const lcName = transformCaseFunc(name);\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Work around a security issue with comments inside attributes */\n if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\\/(style|title)/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {\n if (namespaceURI) ; else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML':\n {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n case 'TrustedScriptURL':\n {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n while (shadowNode = shadowIterator.nextNode()) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty) {\n let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while (currentNode = nodeIterator.nextNode()) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n return returnNode;\n }\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {\n serializedHTML = '\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function () {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n return DOMPurify;\n}\nvar purify = createDOMPurify();\n\nexport { purify as default };\n//# sourceMappingURL=purify.es.mjs.map\n"],"names":["entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","fun","thisValue","args","Func","arrayForEach","unapply","Array","prototype","forEach","arrayPop","pop","arrayPush","push","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","objectHasOwnProperty","hasOwnProperty","regExpTest","RegExp","test","typeErrorCreate","func","TypeError","_len2","arguments","length","_key2","thisArg","_len","_key","addToSet","set","array","transformCaseFunc","undefined","l","element","lcElement","cleanArray","index","clone","object","newObject","property","value","isArray","constructor","lookupGetter","prop","desc","get","html$1","svg$1","svgFilters","svgDisallowed","mathMl$1","mathMlDisallowed","text","html","svg","mathMl","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","EXPRESSIONS","__proto__","getGlobal","window","purify","createDOMPurify","DOMPurify","root","version","removed","document","nodeType","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","Element","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","createHTMLDocument","IS_ALLOWED_URI$1","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","ALLOWED_URI_REGEXP","ADD_TAGS","ADD_ATTR","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","parentNode","removeChild","remove","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","elm","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHook","entryPoint","currentNode","data","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","i","childClone","__removalCount","parent","parentTagName","Boolean","_checkValidNamespace","expr","_isValidAttribute","lcTag","lcName","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","attr","forceKeepAttr","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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","x_google_ignoreList":[0]} \ No newline at end of file diff --git a/external/collect.js b/external/collect.js new file mode 100644 index 00000000..da1f73cf --- /dev/null +++ b/external/collect.js @@ -0,0 +1,2 @@ +var t={exports:{}},e={isArray:t=>Array.isArray(t),isObject:t=>"object"==typeof t&&!1===Array.isArray(t)&&null!==t,isFunction:t=>"function"==typeof t};const{isFunction:i}=e;var average$1=function(t){return void 0===t?this.sum()/this.items.length:i(t)?new this.constructor(this.items).sum(t)/this.items.length:new this.constructor(this.items).pluck(t).sum()/this.items.length},s=average$1,clone$2=function(t){let e;return Array.isArray(t)?(e=[],e.push(...t)):(e={},Object.keys(t).forEach((i=>{e[i]=t[i]}))),e};const o=clone$2;var values$8=function(t){const e=[];return Array.isArray(t)?e.push(...t):"Collection"===t.constructor.name?e.push(...t.all()):Object.keys(t).forEach((i=>e.push(t[i]))),e};const r=values$8,{isFunction:n}=e;var contains$1=function(t,e){if(void 0!==e)return Array.isArray(this.items)?this.items.filter((i=>void 0!==i[t]&&i[t]===e)).length>0:void 0!==this.items[t]&&this.items[t]===e;if(n(t))return this.items.filter(((e,i)=>t(e,i))).length>0;if(Array.isArray(this.items))return-1!==this.items.indexOf(t);const i=r(this.items);return i.push(...Object.keys(this.items)),-1!==i.indexOf(t)};const c=values$8;var variadic$4=function(t){return Array.isArray(t[0])?t[0]:t};const h=variadic$4;function falsyValue(t){if(Array.isArray(t)){if(t.length)return!1}else if(null!=t&&"object"==typeof t){if(Object.keys(t).length)return!1}else if(t)return!1;return!0}const{isFunction:l}=e,{isFunction:u}=e,{isArray:f,isObject:p}=e,{isFunction:y}=e;var nestedValue$8=function(t,e){try{return e.split(".").reduce(((t,e)=>t[e]),t)}catch(e){return t}};const m=nestedValue$8,{isFunction:a}=e,C=variadic$4,w=nestedValue$8,{isFunction:d}=e,{isFunction:A}=e,O=values$8,b=variadic$4,j=clone$2,{isArray:g,isObject:k}=e,v=nestedValue$8,E=variadic$4;var deleteKeys$2=function(t,...e){E(e).forEach((e=>{delete t[e]}))};const{isArray:x,isObject:F}=e,N=deleteKeys$2,{isFunction:S}=e,M=values$8,{isArray:J,isObject:B,isFunction:I}=e,{isArray:K,isObject:$}=e,P=deleteKeys$2,D=values$8,{isObject:R}=e,{isArray:W,isObject:U,isFunction:V}=e,{isArray:T,isObject:q,isFunction:z}=e,{isFunction:G}=e;var H=contains$1;const L=nestedValue$8,{isFunction:Q}=e,X=values$8,{isFunction:Y}=e,{isArray:Z,isObject:_,isFunction:tt}=e,{isArray:et,isObject:it,isFunction:st}=e;var whenNotEmpty=function(t,e){if(Array.isArray(this.items)&&this.items.length)return t(this);if(Object.keys(this.items).length)return t(this);if(void 0!==e){if(Array.isArray(this.items)&&!this.items.length)return e(this);if(!Object.keys(this.items).length)return e(this)}return this},whenEmpty=function(t,e){if(Array.isArray(this.items)&&!this.items.length)return t(this);if(!Object.keys(this.items).length)return t(this);if(void 0!==e){if(Array.isArray(this.items)&&this.items.length)return e(this);if(Object.keys(this.items).length)return e(this)}return this};const{isFunction:ot}=e,rt=values$8,nt=values$8,ct=nestedValue$8,ht=values$8,lt=nestedValue$8,ut=nestedValue$8,ft=values$8,pt=nestedValue$8;function Collection(t){void 0===t||Array.isArray(t)||"object"==typeof t?t instanceof this.constructor?this.items=t.all():this.items=t||[]:this.items=[t]}"undefined"!=typeof Symbol&&(Collection.prototype[Symbol.iterator]=function(){let t=-1;return{next:()=>(t+=1,{value:this.items[t],done:t>=this.items.length})}}),Collection.prototype.toJSON=function(){return this.items},Collection.prototype.all=function(){return this.items},Collection.prototype.average=average$1,Collection.prototype.avg=s,Collection.prototype.chunk=function(t){const e=[];let i=0;if(Array.isArray(this.items))do{const s=this.items.slice(i,i+t),o=new this.constructor(s);e.push(o),i+=t}while(ir.put(t,this.items[t]))),e.push(r),i+=t}while(i{i[t]=e[s]})):"object"==typeof this.items&&"object"==typeof e?Object.keys(this.items).forEach(((t,s)=>{i[this.items[t]]=e[Object.keys(e)[s]]})):Array.isArray(this.items)?i[this.items[0]]=e:"string"==typeof this.items&&Array.isArray(e)?[i[this.items]]=e:"string"==typeof this.items&&(i[this.items]=e),new this.constructor(i)},Collection.prototype.concat=function(t){let e=t;t instanceof this.constructor?e=t.all():"object"==typeof t&&(e=[],Object.keys(t).forEach((i=>{e.push(t[i])})));const i=o(this.items);return e.forEach((t=>{"object"==typeof t?Object.keys(t).forEach((e=>i.push(t[e]))):i.push(t)})),new this.constructor(i)},Collection.prototype.contains=contains$1,Collection.prototype.containsOneItem=function(){return 1===this.count()},Collection.prototype.count=function(){let t=0;return Array.isArray(this.items)&&(t=this.items.length),Math.max(Object.keys(this.items).length,t)},Collection.prototype.countBy=function(t=(t=>t)){return new this.constructor(this.items).groupBy(t).map((t=>t.count()))},Collection.prototype.crossJoin=function(...t){return new this.constructor(function join(t,e,i){let s=i[0];s instanceof e&&(s=s.all());const o=i.slice(1),r=!o.length;let n=[];for(let i=0;i-1===e.indexOf(t)));return new this.constructor(i)},Collection.prototype.diffAssoc=function(t){let e=t;t instanceof this.constructor&&(e=t.all());const i={};return Object.keys(this.items).forEach((t=>{void 0!==e[t]&&e[t]===this.items[t]||(i[t]=this.items[t])})),new this.constructor(i)},Collection.prototype.diffKeys=function(t){let e;e=t instanceof this.constructor?t.all():t;const i=Object.keys(e),s=Object.keys(this.items).filter((t=>-1===i.indexOf(t)));return new this.constructor(this.items).only(s)},Collection.prototype.diffUsing=function(t,e){const i=this.items.filter((i=>!(t&&t.some((t=>0===e(i,t))))));return new this.constructor(i)},Collection.prototype.doesntContain=function(t,e){return!this.contains(t,e)},Collection.prototype.dump=function(){return console.log(this),this},Collection.prototype.duplicates=function(){const t=[],e={},stringifiedValue=t=>Array.isArray(t)||"object"==typeof t?JSON.stringify(t):t;return Array.isArray(this.items)?this.items.forEach(((i,s)=>{const o=stringifiedValue(i);-1===t.indexOf(o)?t.push(o):e[s]=i})):"object"==typeof this.items&&Object.keys(this.items).forEach((i=>{const s=stringifiedValue(this.items[i]);-1===t.indexOf(s)?t.push(s):e[i]=this.items[i]})),new this.constructor(e)},Collection.prototype.each=function(t){let e=!1;if(Array.isArray(this.items)){const{length:i}=this.items;for(let s=0;s{t(...e,i)})),this},Collection.prototype.every=function(t){return c(this.items).every(t)},Collection.prototype.except=function(...t){const e=h(t);if(Array.isArray(this.items)){const t=this.items.filter((t=>-1===e.indexOf(t)));return new this.constructor(t)}const i={};return Object.keys(this.items).forEach((t=>{-1===e.indexOf(t)&&(i[t]=this.items[t])})),new this.constructor(i)},Collection.prototype.filter=function(t){const e=t||!1;let i=null;return i=Array.isArray(this.items)?function(t,e){if(t)return e.filter(t);const i=[];for(let t=0;t{t?t(e[s],s)&&(i[s]=e[s]):falsyValue(e[s])||(i[s]=e[s])})),i}(e,this.items),new this.constructor(i)},Collection.prototype.first=function(t,e){if(l(t)){const i=Object.keys(this.items);for(let e=0;e{throw new Error("Item not found.")}));const s=this.where(t,e,i);if(s.isEmpty())throw new Error("Item not found.");return s.first()},Collection.prototype.firstWhere=function(t,e,i){return this.where(t,e,i).first()||null},Collection.prototype.flatMap=function(t){return this.map(t).collapse()},Collection.prototype.flatten=function(t){let e=t||1/0,i=!1,s=[];const flat=function(t){s=[],f(t)?t.forEach((t=>{f(t)?s=s.concat(t):p(t)?Object.keys(t).forEach((e=>{s=s.concat(t[e])})):s.push(t)})):Object.keys(t).forEach((e=>{f(t[e])?s=s.concat(t[e]):p(t[e])?Object.keys(t[e]).forEach((i=>{s=s.concat(t[e][i])})):s.push(t[e])})),i=s.filter((t=>p(t))),i=0===i.length,e-=1};for(flat(this.items);!i&&e>0;)flat(s);return new this.constructor(s)},Collection.prototype.flip=function(){const t={};return Array.isArray(this.items)?Object.keys(this.items).forEach((e=>{t[this.items[e]]=Number(e)})):Object.keys(this.items).forEach((e=>{t[this.items[e]]=e})),new this.constructor(t)},Collection.prototype.forPage=function(t,e){let i={};return Array.isArray(this.items)?i=this.items.slice(t*e-e,t*e):Object.keys(this.items).slice(t*e-e,t*e).forEach((t=>{i[t]=this.items[t]})),new this.constructor(i)},Collection.prototype.forget=function(t){return Array.isArray(this.items)?this.items.splice(t,1):delete this.items[t],this},Collection.prototype.get=function(t,e=null){return void 0!==this.items[t]?this.items[t]:y(e)?e():null!==e?e:null},Collection.prototype.groupBy=function(t){const e={};return this.items.forEach(((i,s)=>{let o;o=a(t)?t(i,s):m(i,t)||0===m(i,t)?m(i,t):"",void 0===e[o]&&(e[o]=new this.constructor([])),e[o].push(i)})),new this.constructor(e)},Collection.prototype.has=function(...t){const e=C(t);return e.filter((t=>Object.hasOwnProperty.call(this.items,t))).length===e.length},Collection.prototype.implode=function(t,e){return void 0===e?this.items.join(t):new this.constructor(this.items).pluck(t).all().join(e)},Collection.prototype.intersect=function(t){let e=t;t instanceof this.constructor&&(e=t.all());const i=this.items.filter((t=>-1!==e.indexOf(t)));return new this.constructor(i)},Collection.prototype.intersectByKeys=function(t){let e=Object.keys(t);t instanceof this.constructor&&(e=Object.keys(t.all()));const i={};return Object.keys(this.items).forEach((t=>{-1!==e.indexOf(t)&&(i[t]=this.items[t])})),new this.constructor(i)},Collection.prototype.isEmpty=function(){return Array.isArray(this.items)?!this.items.length:!Object.keys(this.items).length},Collection.prototype.isNotEmpty=function(){return!this.isEmpty()},Collection.prototype.join=function(t,e){const i=this.values();if(void 0===e)return i.implode(t);const s=i.count();if(0===s)return"";if(1===s)return i.last();const o=i.pop();return i.implode(t)+e+o},Collection.prototype.keyBy=function(t){const e={};return d(t)?this.items.forEach((i=>{e[t(i)]=i})):this.items.forEach((i=>{const s=w(i,t);e[s||""]=i})),new this.constructor(e)},Collection.prototype.keys=function(){let t=Object.keys(this.items);return Array.isArray(this.items)&&(t=t.map(Number)),new this.constructor(t)},Collection.prototype.last=function(t,e){let{items:i}=this;if(A(t)&&(i=this.filter(t).all()),Array.isArray(i)&&!i.length||!Object.keys(i).length)return A(e)?e():e;if(Array.isArray(i))return i[i.length-1];const s=Object.keys(i);return i[s[s.length-1]]},Collection.prototype.macro=function(t,e){this.constructor.prototype[t]=e},Collection.prototype.make=function(t=[]){return new this.constructor(t)},Collection.prototype.map=function(t){if(Array.isArray(this.items))return new this.constructor(this.items.map(t));const e={};return Object.keys(this.items).forEach((i=>{e[i]=t(this.items[i],i)})),new this.constructor(e)},Collection.prototype.mapSpread=function(t){return this.map(((e,i)=>t(...e,i)))},Collection.prototype.mapToDictionary=function(t){const e={};return this.items.forEach(((i,s)=>{const[o,r]=t(i,s);void 0===e[o]?e[o]=[r]:e[o].push(r)})),new this.constructor(e)},Collection.prototype.mapInto=function(t){return this.map(((e,i)=>new t(e,i)))},Collection.prototype.mapToGroups=function(t){const e={};return this.items.forEach(((i,s)=>{const[o,r]=t(i,s);void 0===e[o]?e[o]=[r]:e[o].push(r)})),new this.constructor(e)},Collection.prototype.mapWithKeys=function(t){const e={};return Array.isArray(this.items)?this.items.forEach(((i,s)=>{const[o,r]=t(i,s);e[o]=r})):Object.keys(this.items).forEach((i=>{const[s,o]=t(this.items[i],i);e[s]=o})),new this.constructor(e)},Collection.prototype.max=function(t){if("string"==typeof t){const e=this.items.filter((e=>void 0!==e[t]));return Math.max(...e.map((e=>e[t])))}return Math.max(...this.items)},Collection.prototype.median=function(t){const{length:e}=this.items;return void 0===t?e%2==0?(this.items[e/2-1]+this.items[e/2])/2:this.items[Math.floor(e/2)]:e%2==0?(this.items[e/2-1][t]+this.items[e/2][t])/2:this.items[Math.floor(e/2)][t]},Collection.prototype.merge=function(t){let e=t;if("string"==typeof e&&(e=[e]),Array.isArray(this.items)&&Array.isArray(e))return new this.constructor(this.items.concat(e));const i=JSON.parse(JSON.stringify(this.items));return Object.keys(e).forEach((t=>{i[t]=e[t]})),new this.constructor(i)},Collection.prototype.mergeRecursive=function(t){const merge=(t,e)=>{const i={};return Object.keys({...t,...e}).forEach((s=>{void 0===t[s]&&void 0!==e[s]?i[s]=e[s]:void 0!==t[s]&&void 0===e[s]?i[s]=t[s]:void 0!==t[s]&&void 0!==e[s]&&(t[s]===e[s]?i[s]=t[s]:Array.isArray(t[s])||"object"!=typeof t[s]||Array.isArray(e[s])||"object"!=typeof e[s]?i[s]=[].concat(t[s],e[s]):i[s]=merge(t[s],e[s]))})),i};return t?"Collection"===t.constructor.name?new this.constructor(merge(this.items,t.all())):new this.constructor(merge(this.items,t)):this},Collection.prototype.min=function(t){if(void 0!==t){const e=this.items.filter((e=>void 0!==e[t]));return Math.min(...e.map((e=>e[t])))}return Math.min(...this.items)},Collection.prototype.mode=function(t){const e=[];let i=1;return this.items.length?(this.items.forEach((s=>{const o=e.filter((e=>void 0!==t?e.key===s[t]:e.key===s));if(o.length){o[0].count+=1;const{count:t}=o[0];t>i&&(i=t)}else void 0!==t?e.push({key:s[t],count:1}):e.push({key:s,count:1})})),e.filter((t=>t.count===i)).map((t=>t.key))):null},Collection.prototype.nth=function(t,e=0){const i=O(this.items).slice(e).filter(((e,i)=>i%t==0));return new this.constructor(i)},Collection.prototype.only=function(...t){const e=b(t);if(Array.isArray(this.items)){const t=this.items.filter((t=>-1!==e.indexOf(t)));return new this.constructor(t)}const i={};return Object.keys(this.items).forEach((t=>{-1!==e.indexOf(t)&&(i[t]=this.items[t])})),new this.constructor(i)},Collection.prototype.pad=function(t,e){const i=Math.abs(t),s=this.count();if(i<=s)return this;let o=i-s;const r=j(this.items),n=Array.isArray(this.items),c=t<0;for(let t=0;t{!0===t(i)?e[0].push(i):e[1].push(i)}))):(e=[new this.constructor({}),new this.constructor({})],Object.keys(this.items).forEach((i=>{const s=this.items[i];!0===t(s)?e[0].put(i,s):e[1].put(i,s)}))),new this.constructor(e)},Collection.prototype.pipe=function(t){return t(this)},Collection.prototype.pluck=function(t,e){if(-1!==t.indexOf("*")){const i=function(t){const e={};return t.forEach(((t,i)=>{!function buildKeyPath(t,i){k(t)?Object.keys(t).forEach((e=>{buildKeyPath(t[e],`${i}.${e}`)})):g(t)&&t.forEach(((t,e)=>{buildKeyPath(t,`${i}.${e}`)})),e[i]=t}(t,i)})),e}(this.items),s=[];if(void 0!==e){const t=new RegExp(`0.${e}`,"g"),o=`0.${e}`.split(".").length;Object.keys(i).forEach((e=>{const r=e.match(t);if(r){const t=r[0];t.split(".").length===o&&s.push(i[t])}}))}const o=[],r=new RegExp(`0.${t}`,"g"),n=`0.${t}`.split(".").length;if(Object.keys(i).forEach((t=>{const e=t.match(r);if(e){const t=e[0];t.split(".").length===n&&o.push(i[t])}})),void 0!==e){const t={};return this.items.forEach(((e,i)=>{t[s[i]||""]=o})),new this.constructor(t)}return new this.constructor([o])}if(void 0!==e){const i={};return this.items.forEach((s=>{void 0!==v(s,t)?i[s[e]||""]=v(s,t):i[s[e]||""]=null})),new this.constructor(i)}return this.map((e=>void 0!==v(e,t)?v(e,t):null))},Collection.prototype.pop=function(t=1){if(this.isEmpty())return null;if(x(this.items))return 1===t?this.items.pop():new this.constructor(this.items.splice(-t));if(F(this.items)){const e=Object.keys(this.items);if(1===t){const t=e[e.length-1],i=this.items[t];return N(this.items,t),i}const i=e.slice(-t),s=i.reduce(((t,e)=>(t[e]=this.items[e],t)),{});return N(this.items,i),new this.constructor(s)}return null},Collection.prototype.prepend=function(t,e){return void 0!==e?this.put(e,t):(this.items.unshift(t),this)},Collection.prototype.pull=function(t,e){let i=this.items[t]||null;return i||void 0===e||(i=S(e)?e():e),delete this.items[t],i},Collection.prototype.push=function(...t){return this.items.push(...t),this},Collection.prototype.put=function(t,e){return this.items[t]=e,this},Collection.prototype.random=function(t=null){const e=M(this.items),i=new this.constructor(e).shuffle();return t!==parseInt(t,10)?i.first():i.take(t)},Collection.prototype.reduce=function(t,e){let i=null;return void 0!==e&&(i=e),Array.isArray(this.items)?this.items.forEach((e=>{i=t(i,e)})):Object.keys(this.items).forEach((e=>{i=t(i,this.items[e],e)})),i},Collection.prototype.reject=function(t){return new this.constructor(this.items).filter((e=>!t(e)))},Collection.prototype.replace=function(t){if(!t)return this;if(Array.isArray(t)){const e=this.items.map(((e,i)=>t[i]||e));return new this.constructor(e)}if("Collection"===t.constructor.name){const e={...this.items,...t.all()};return new this.constructor(e)}const e={...this.items,...t};return new this.constructor(e)},Collection.prototype.replaceRecursive=function(t){const replace=(t,e)=>{const i={...t};return Object.keys({...t,...e}).forEach((s=>{Array.isArray(e[s])||"object"!=typeof e[s]?void 0===t[s]&&void 0!==e[s]?"object"==typeof t[s]?i[s]={...e[s]}:i[s]=e[s]:void 0!==t[s]&&void 0===e[s]?"object"==typeof t[s]?i[s]={...t[s]}:i[s]=t[s]:void 0!==t[s]&&void 0!==e[s]&&("object"==typeof e[s]?i[s]={...e[s]}:i[s]=e[s]):i[s]=replace(t[s],e[s])})),i};return t?Array.isArray(t)||"object"==typeof t?"Collection"===t.constructor.name?new this.constructor(replace(this.items,t.all())):new this.constructor(replace(this.items,t)):new this.constructor(replace(this.items,[t])):this},Collection.prototype.reverse=function(){const t=[].concat(this.items).reverse();return new this.constructor(t)},Collection.prototype.search=function(t,e){let i;const find=(i,s)=>I(t)?t(this.items[s],s):e?this.items[s]===t:this.items[s]==t;return J(this.items)?i=this.items.findIndex(find):B(this.items)&&(i=Object.keys(this.items).find((t=>find(this.items[t],t)))),!(void 0===i||i<0)&&i},Collection.prototype.shift=function(t=1){if(this.isEmpty())return null;if(K(this.items))return 1===t?this.items.shift():new this.constructor(this.items.splice(0,t));if($(this.items)){if(1===t){const t=Object.keys(this.items)[0],e=this.items[t];return delete this.items[t],e}const e=Object.keys(this.items).slice(0,t),i=e.reduce(((t,e)=>(t[e]=this.items[e],t)),{});return P(this.items,e),new this.constructor(i)}return null},Collection.prototype.shuffle=function(){const t=D(this.items);let e,i,s;for(s=t.length;s;s-=1)e=Math.floor(Math.random()*s),i=t[s-1],t[s-1]=t[e],t[e]=i;return this.items=t,this},Collection.prototype.skip=function(t){return R(this.items)?new this.constructor(Object.keys(this.items).reduce(((e,i,s)=>(s+1>t&&(e[i]=this.items[i]),e)),{})):new this.constructor(this.items.slice(t))},Collection.prototype.skipUntil=function(t){let e,i=null,callback=e=>e===t;return V(t)&&(callback=t),W(this.items)&&(e=this.items.filter((t=>(!0!==i&&(i=callback(t)),i)))),U(this.items)&&(e=Object.keys(this.items).reduce(((t,e)=>(!0!==i&&(i=callback(this.items[e])),!1!==i&&(t[e]=this.items[e]),t)),{})),new this.constructor(e)},Collection.prototype.skipWhile=function(t){let e,i=null,callback=e=>e===t;return z(t)&&(callback=t),T(this.items)&&(e=this.items.filter((t=>(!0!==i&&(i=!callback(t)),i)))),q(this.items)&&(e=Object.keys(this.items).reduce(((t,e)=>(!0!==i&&(i=!callback(this.items[e])),!1!==i&&(t[e]=this.items[e]),t)),{})),new this.constructor(e)},Collection.prototype.slice=function(t,e){let i=this.items.slice(t);return void 0!==e&&(i=i.slice(0,e)),new this.constructor(i)},Collection.prototype.sole=function(t,e,i){let s;if(s=G(t)?this.filter(t):this.where(t,e,i),s.isEmpty())throw new Error("Item not found.");if(s.count()>1)throw new Error("Multiple items found.");return s.first()},Collection.prototype.some=H,Collection.prototype.sort=function(t){const e=[].concat(this.items);return void 0===t?this.every((t=>"number"==typeof t))?e.sort(((t,e)=>t-e)):e.sort():e.sort(t),new this.constructor(e)},Collection.prototype.sortDesc=function(){return this.sort().reverse()},Collection.prototype.sortBy=function(t){const e=[].concat(this.items),getValue=e=>Q(t)?t(e):L(e,t);return e.sort(((t,e)=>{const i=getValue(t),s=getValue(e);return null==i?1:null==s||is?1:0})),new this.constructor(e)},Collection.prototype.sortByDesc=function(t){return this.sortBy(t).reverse()},Collection.prototype.sortKeys=function(){const t={};return Object.keys(this.items).sort().forEach((e=>{t[e]=this.items[e]})),new this.constructor(t)},Collection.prototype.sortKeysDesc=function(){const t={};return Object.keys(this.items).sort().reverse().forEach((e=>{t[e]=this.items[e]})),new this.constructor(t)},Collection.prototype.splice=function(t,e,i){const s=this.slice(t,e);if(this.items=this.diff(s.all()).all(),Array.isArray(i))for(let e=0,{length:s}=i;e{-1!==i.indexOf(t)&&(s[t]=this.items[t])})),new this.constructor(s)}return t<0?new this.constructor(this.items.slice(t)):new this.constructor(this.items.slice(0,t))},Collection.prototype.takeUntil=function(t){let e,i=null,callback=e=>e===t;return tt(t)&&(callback=t),Z(this.items)&&(e=this.items.filter((t=>(!1!==i&&(i=!callback(t)),i)))),_(this.items)&&(e=Object.keys(this.items).reduce(((t,e)=>(!1!==i&&(i=!callback(this.items[e])),!1!==i&&(t[e]=this.items[e]),t)),{})),new this.constructor(e)},Collection.prototype.takeWhile=function(t){let e,i=null,callback=e=>e===t;return st(t)&&(callback=t),et(this.items)&&(e=this.items.filter((t=>(!1!==i&&(i=callback(t)),i)))),it(this.items)&&(e=Object.keys(this.items).reduce(((t,e)=>(!1!==i&&(i=callback(this.items[e])),!1!==i&&(t[e]=this.items[e]),t)),{})),new this.constructor(e)},Collection.prototype.tap=function(t){return t(this),this},Collection.prototype.times=function(t,e){for(let i=1;i<=t;i+=1)this.items.push(e(i));return this},Collection.prototype.toArray=function(){const t=this.constructor;function iterate(e,i){const s=[];e instanceof t?(e.items.forEach((t=>iterate(t,s))),i.push(s)):Array.isArray(e)?(e.forEach((t=>iterate(t,s))),i.push(s)):i.push(e)}if(Array.isArray(this.items)){const t=[];return this.items.forEach((e=>{iterate(e,t)})),t}return this.values().all()},Collection.prototype.toJson=function(){return"object"!=typeof this.items||Array.isArray(this.items)?JSON.stringify(this.toArray()):JSON.stringify(this.all())},Collection.prototype.transform=function(t){if(Array.isArray(this.items))this.items=this.items.map(t);else{const e={};Object.keys(this.items).forEach((i=>{e[i]=t(this.items[i],i)})),this.items=e}return this},Collection.prototype.undot=function(){if(Array.isArray(this.items))return this;let t={};return Object.keys(this.items).forEach((e=>{if(-1!==e.indexOf(".")){const i=t;e.split(".").reduce(((t,i,s,o)=>(t[i]||(t[i]={}),s===o.length-1&&(t[i]=this.items[e]),t[i])),i),t={...t,...i}}else t[e]=this.items[e]})),new this.constructor(t)},Collection.prototype.unless=function(t,e,i){t?i(this):e(this)},Collection.prototype.unlessEmpty=whenNotEmpty,Collection.prototype.unlessNotEmpty=whenEmpty,Collection.prototype.union=function(t){const e=JSON.parse(JSON.stringify(this.items));return Object.keys(t).forEach((i=>{void 0===this.items[i]&&(e[i]=t[i])})),new this.constructor(e)},Collection.prototype.unique=function(t){let e;if(void 0===t)e=this.items.filter(((t,e,i)=>i.indexOf(t)===e));else{e=[];const i=[];for(let s=0,{length:o}=this.items;sct(e,t))));if(!1===e)return new this.constructor(r.filter((e=>!ct(e,t))));void 0===i&&(o=e,s="===");const n=r.filter((e=>{switch(s){case"==":return ct(e,t)===Number(o)||ct(e,t)===o.toString();default:case"===":return ct(e,t)===o;case"!=":case"<>":return ct(e,t)!==Number(o)&&ct(e,t)!==o.toString();case"!==":return ct(e,t)!==o;case"<":return ct(e,t)":return ct(e,t)>o;case">=":return ct(e,t)>=o}}));return new this.constructor(n)},Collection.prototype.whereBetween=function(t,e){return this.where(t,">=",e[0]).where(t,"<=",e[e.length-1])},Collection.prototype.whereIn=function(t,e){const i=ht(e),s=this.items.filter((e=>-1!==i.indexOf(lt(e,t))));return new this.constructor(s)},Collection.prototype.whereInstanceOf=function(t){return this.filter((e=>e instanceof t))},Collection.prototype.whereNotBetween=function(t,e){return this.filter((i=>ut(i,t)e[e.length-1]))},Collection.prototype.whereNotIn=function(t,e){const i=ft(e),s=this.items.filter((e=>-1===i.indexOf(pt(e,t))));return new this.constructor(s)},Collection.prototype.whereNull=function(t=null){return this.where(t,"===",null)},Collection.prototype.whereNotNull=function(t=null){return this.where(t,"!==",null)},Collection.prototype.wrap=function(t){return t instanceof this.constructor?t:"object"==typeof t?new this.constructor(t):new this.constructor([t])},Collection.prototype.zip=function(t){let e=t;e instanceof this.constructor&&(e=e.all());const i=this.items.map(((t,i)=>new this.constructor([t,e[i]])));return new this.constructor(i)};const collect=t=>new Collection(t);t.exports=collect;var yt=t.exports.collect=collect;t.exports.default=collect,t.exports.Collection=Collection;export{yt as default}; +//# sourceMappingURL=collect.js.map diff --git a/external/collect.js.map b/external/collect.js.map new file mode 100644 index 00000000..57628839 --- /dev/null +++ b/external/collect.js.map @@ -0,0 +1 @@ +{"version":3,"file":"collect.js","sources":["../node_modules/collect.js/src/helpers/is.js","../node_modules/collect.js/src/methods/average.js","../node_modules/collect.js/src/methods/avg.js","../node_modules/collect.js/src/helpers/clone.js","../node_modules/collect.js/src/methods/concat.js","../node_modules/collect.js/src/helpers/values.js","../node_modules/collect.js/src/methods/contains.js","../node_modules/collect.js/src/methods/every.js","../node_modules/collect.js/src/helpers/variadic.js","../node_modules/collect.js/src/methods/except.js","../node_modules/collect.js/src/methods/filter.js","../node_modules/collect.js/src/methods/first.js","../node_modules/collect.js/src/methods/firstOrFail.js","../node_modules/collect.js/src/methods/flatten.js","../node_modules/collect.js/src/methods/get.js","../node_modules/collect.js/src/helpers/nestedValue.js","../node_modules/collect.js/src/methods/groupBy.js","../node_modules/collect.js/src/methods/has.js","../node_modules/collect.js/src/methods/keyBy.js","../node_modules/collect.js/src/methods/last.js","../node_modules/collect.js/src/methods/nth.js","../node_modules/collect.js/src/methods/only.js","../node_modules/collect.js/src/methods/pad.js","../node_modules/collect.js/src/methods/pluck.js","../node_modules/collect.js/src/helpers/deleteKeys.js","../node_modules/collect.js/src/methods/pop.js","../node_modules/collect.js/src/methods/pull.js","../node_modules/collect.js/src/methods/random.js","../node_modules/collect.js/src/methods/search.js","../node_modules/collect.js/src/methods/shift.js","../node_modules/collect.js/src/methods/shuffle.js","../node_modules/collect.js/src/methods/skip.js","../node_modules/collect.js/src/methods/skipUntil.js","../node_modules/collect.js/src/methods/skipWhile.js","../node_modules/collect.js/src/methods/sole.js","../node_modules/collect.js/src/methods/some.js","../node_modules/collect.js/src/methods/sortBy.js","../node_modules/collect.js/src/methods/sum.js","../node_modules/collect.js/src/methods/takeUntil.js","../node_modules/collect.js/src/methods/takeWhile.js","../node_modules/collect.js/src/methods/whenNotEmpty.js","../node_modules/collect.js/src/methods/whenEmpty.js","../node_modules/collect.js/src/methods/unique.js","../node_modules/collect.js/src/methods/values.js","../node_modules/collect.js/src/methods/where.js","../node_modules/collect.js/src/methods/whereIn.js","../node_modules/collect.js/src/methods/whereNotBetween.js","../node_modules/collect.js/src/methods/whereNotIn.js","../node_modules/collect.js/src/index.js","../node_modules/collect.js/src/methods/symbol.iterator.js","../node_modules/collect.js/src/methods/all.js","../node_modules/collect.js/src/methods/chunk.js","../node_modules/collect.js/src/methods/collapse.js","../node_modules/collect.js/src/methods/combine.js","../node_modules/collect.js/src/methods/containsOneItem.js","../node_modules/collect.js/src/methods/count.js","../node_modules/collect.js/src/methods/countBy.js","../node_modules/collect.js/src/methods/crossJoin.js","../node_modules/collect.js/src/methods/dd.js","../node_modules/collect.js/src/methods/diff.js","../node_modules/collect.js/src/methods/diffAssoc.js","../node_modules/collect.js/src/methods/diffKeys.js","../node_modules/collect.js/src/methods/diffUsing.js","../node_modules/collect.js/src/methods/doesntContain.js","../node_modules/collect.js/src/methods/dump.js","../node_modules/collect.js/src/methods/duplicates.js","../node_modules/collect.js/src/methods/each.js","../node_modules/collect.js/src/methods/eachSpread.js","../node_modules/collect.js/src/methods/firstWhere.js","../node_modules/collect.js/src/methods/flatMap.js","../node_modules/collect.js/src/methods/flip.js","../node_modules/collect.js/src/methods/forPage.js","../node_modules/collect.js/src/methods/forget.js","../node_modules/collect.js/src/methods/implode.js","../node_modules/collect.js/src/methods/intersect.js","../node_modules/collect.js/src/methods/intersectByKeys.js","../node_modules/collect.js/src/methods/isEmpty.js","../node_modules/collect.js/src/methods/isNotEmpty.js","../node_modules/collect.js/src/methods/join.js","../node_modules/collect.js/src/methods/keys.js","../node_modules/collect.js/src/methods/macro.js","../node_modules/collect.js/src/methods/make.js","../node_modules/collect.js/src/methods/map.js","../node_modules/collect.js/src/methods/mapSpread.js","../node_modules/collect.js/src/methods/mapToDictionary.js","../node_modules/collect.js/src/methods/mapInto.js","../node_modules/collect.js/src/methods/mapToGroups.js","../node_modules/collect.js/src/methods/mapWithKeys.js","../node_modules/collect.js/src/methods/max.js","../node_modules/collect.js/src/methods/median.js","../node_modules/collect.js/src/methods/merge.js","../node_modules/collect.js/src/methods/mergeRecursive.js","../node_modules/collect.js/src/methods/min.js","../node_modules/collect.js/src/methods/mode.js","../node_modules/collect.js/src/methods/partition.js","../node_modules/collect.js/src/methods/pipe.js","../node_modules/collect.js/src/methods/prepend.js","../node_modules/collect.js/src/methods/push.js","../node_modules/collect.js/src/methods/put.js","../node_modules/collect.js/src/methods/reduce.js","../node_modules/collect.js/src/methods/reject.js","../node_modules/collect.js/src/methods/replace.js","../node_modules/collect.js/src/methods/replaceRecursive.js","../node_modules/collect.js/src/methods/reverse.js","../node_modules/collect.js/src/methods/slice.js","../node_modules/collect.js/src/methods/sort.js","../node_modules/collect.js/src/methods/sortDesc.js","../node_modules/collect.js/src/methods/sortByDesc.js","../node_modules/collect.js/src/methods/sortKeys.js","../node_modules/collect.js/src/methods/sortKeysDesc.js","../node_modules/collect.js/src/methods/splice.js","../node_modules/collect.js/src/methods/split.js","../node_modules/collect.js/src/methods/take.js","../node_modules/collect.js/src/methods/tap.js","../node_modules/collect.js/src/methods/times.js","../node_modules/collect.js/src/methods/toArray.js","../node_modules/collect.js/src/methods/toJson.js","../node_modules/collect.js/src/methods/transform.js","../node_modules/collect.js/src/methods/undot.js","../node_modules/collect.js/src/methods/unless.js","../node_modules/collect.js/src/methods/union.js","../node_modules/collect.js/src/methods/unwrap.js","../node_modules/collect.js/src/methods/when.js","../node_modules/collect.js/src/methods/whereBetween.js","../node_modules/collect.js/src/methods/whereInstanceOf.js","../node_modules/collect.js/src/methods/whereNull.js","../node_modules/collect.js/src/methods/whereNotNull.js","../node_modules/collect.js/src/methods/wrap.js","../node_modules/collect.js/src/methods/zip.js"],"sourcesContent":["'use strict';\n\nmodule.exports = {\n /**\n * @returns {boolean}\n */\n isArray: item => Array.isArray(item),\n\n /**\n * @returns {boolean}\n */\n isObject: item => typeof item === 'object' && Array.isArray(item) === false && item !== null,\n\n /**\n * @returns {boolean}\n */\n isFunction: item => typeof item === 'function',\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function average(key) {\n if (key === undefined) {\n return this.sum() / this.items.length;\n }\n\n if (isFunction(key)) {\n return new this.constructor(this.items).sum(key) / this.items.length;\n }\n\n return new this.constructor(this.items).pluck(key).sum() / this.items.length;\n};\n","'use strict';\n\nconst average = require('./average');\n\nmodule.exports = average;\n","'use strict';\n\n/**\n * Clone helper\n *\n * Clone an array or object\n *\n * @param items\n * @returns {*}\n */\nmodule.exports = function clone(items) {\n let cloned;\n\n if (Array.isArray(items)) {\n cloned = [];\n\n cloned.push(...items);\n } else {\n cloned = {};\n\n Object.keys(items).forEach((prop) => {\n cloned[prop] = items[prop];\n });\n }\n\n return cloned;\n};\n","'use strict';\n\nconst clone = require('../helpers/clone');\n\nmodule.exports = function concat(collectionOrArrayOrObject) {\n let list = collectionOrArrayOrObject;\n\n if (collectionOrArrayOrObject instanceof this.constructor) {\n list = collectionOrArrayOrObject.all();\n } else if (typeof collectionOrArrayOrObject === 'object') {\n list = [];\n Object.keys(collectionOrArrayOrObject).forEach((property) => {\n list.push(collectionOrArrayOrObject[property]);\n });\n }\n\n const collection = clone(this.items);\n\n list.forEach((item) => {\n if (typeof item === 'object') {\n Object.keys(item).forEach(key => collection.push(item[key]));\n } else {\n collection.push(item);\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\n/**\n * Values helper\n *\n * Retrieve values from [this.items] when it is an array, object or Collection\n *\n * @param items\n * @returns {*}\n */\nmodule.exports = function values(items) {\n const valuesArray = [];\n\n if (Array.isArray(items)) {\n valuesArray.push(...items);\n } else if (items.constructor.name === 'Collection') {\n valuesArray.push(...items.all());\n } else {\n Object.keys(items).forEach(prop => valuesArray.push(items[prop]));\n }\n\n return valuesArray;\n};\n","'use strict';\n\nconst values = require('../helpers/values');\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function contains(key, value) {\n if (value !== undefined) {\n if (Array.isArray(this.items)) {\n return this.items\n .filter(items => items[key] !== undefined && items[key] === value)\n .length > 0;\n }\n\n return this.items[key] !== undefined && this.items[key] === value;\n }\n\n if (isFunction(key)) {\n return (this.items.filter((item, index) => key(item, index)).length > 0);\n }\n\n if (Array.isArray(this.items)) {\n return this.items.indexOf(key) !== -1;\n }\n\n const keysAndValues = values(this.items);\n keysAndValues.push(...Object.keys(this.items));\n\n return keysAndValues.indexOf(key) !== -1;\n};\n","'use strict';\n\nconst values = require('../helpers/values');\n\nmodule.exports = function every(fn) {\n const items = values(this.items);\n\n return items.every(fn);\n};\n","'use strict';\n\n/**\n * Variadic helper function\n *\n * @param args\n * @returns {Array}\n */\nmodule.exports = function variadic(args) {\n if (Array.isArray(args[0])) {\n return args[0];\n }\n\n return args;\n};\n","'use strict';\n\nconst variadic = require('../helpers/variadic');\n\nmodule.exports = function except(...args) {\n const properties = variadic(args);\n\n if (Array.isArray(this.items)) {\n const collection = this.items\n .filter(item => properties.indexOf(item) === -1);\n\n return new this.constructor(collection);\n }\n\n const collection = {};\n\n Object.keys(this.items).forEach((property) => {\n if (properties.indexOf(property) === -1) {\n collection[property] = this.items[property];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nfunction falsyValue(item) {\n if (Array.isArray(item)) {\n if (item.length) {\n return false;\n }\n } else if (item !== undefined && item !== null\n && typeof item === 'object') {\n if (Object.keys(item).length) {\n return false;\n }\n } else if (item) {\n return false;\n }\n\n return true;\n}\n\nfunction filterObject(func, items) {\n const result = {};\n Object.keys(items).forEach((key) => {\n if (func) {\n if (func(items[key], key)) {\n result[key] = items[key];\n }\n } else if (!falsyValue(items[key])) {\n result[key] = items[key];\n }\n });\n\n return result;\n}\n\nfunction filterArray(func, items) {\n if (func) {\n return items.filter(func);\n }\n const result = [];\n for (let i = 0; i < items.length; i += 1) {\n const item = items[i];\n if (!falsyValue(item)) {\n result.push(item);\n }\n }\n\n return result;\n}\n\nmodule.exports = function filter(fn) {\n const func = fn || false;\n let filteredItems = null;\n if (Array.isArray(this.items)) {\n filteredItems = filterArray(func, this.items);\n } else {\n filteredItems = filterObject(func, this.items);\n }\n\n return new this.constructor(filteredItems);\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function first(fn, defaultValue) {\n if (isFunction(fn)) {\n const keys = Object.keys(this.items);\n\n for (let i = 0; i < keys.length; i += 1) {\n const key = keys[i];\n const item = this.items[key];\n\n if (fn(item, key)) {\n return item;\n }\n }\n\n if (isFunction(defaultValue)) {\n return defaultValue();\n }\n\n return defaultValue;\n }\n\n if ((Array.isArray(this.items) && this.items.length) || (Object.keys(this.items).length)) {\n if (Array.isArray(this.items)) {\n return this.items[0];\n }\n\n const firstKey = Object.keys(this.items)[0];\n\n return this.items[firstKey];\n }\n\n if (isFunction(defaultValue)) {\n return defaultValue();\n }\n\n return defaultValue;\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function firstOrFail(key, operator, value) {\n if (isFunction(key)) {\n return this.first(key, () => {\n throw new Error('Item not found.');\n });\n }\n\n const collection = this.where(key, operator, value);\n\n if (collection.isEmpty()) {\n throw new Error('Item not found.');\n }\n\n return collection.first();\n};\n","'use strict';\n\nconst { isArray, isObject } = require('../helpers/is');\n\nmodule.exports = function flatten(depth) {\n let flattenDepth = depth || Infinity;\n\n let fullyFlattened = false;\n let collection = [];\n\n const flat = function flat(items) {\n collection = [];\n\n if (isArray(items)) {\n items.forEach((item) => {\n if (isArray(item)) {\n collection = collection.concat(item);\n } else if (isObject(item)) {\n Object.keys(item).forEach((property) => {\n collection = collection.concat(item[property]);\n });\n } else {\n collection.push(item);\n }\n });\n } else {\n Object.keys(items).forEach((property) => {\n if (isArray(items[property])) {\n collection = collection.concat(items[property]);\n } else if (isObject(items[property])) {\n Object.keys(items[property]).forEach((prop) => {\n collection = collection.concat(items[property][prop]);\n });\n } else {\n collection.push(items[property]);\n }\n });\n }\n\n fullyFlattened = collection.filter(item => isObject(item));\n fullyFlattened = fullyFlattened.length === 0;\n\n flattenDepth -= 1;\n };\n\n flat(this.items);\n\n while (!fullyFlattened && flattenDepth > 0) {\n flat(collection);\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function get(key, defaultValue = null) {\n if (this.items[key] !== undefined) {\n return this.items[key];\n }\n\n if (isFunction(defaultValue)) {\n return defaultValue();\n }\n\n if (defaultValue !== null) {\n return defaultValue;\n }\n\n return null;\n};\n","'use strict';\n\n/**\n * Get value of a nested property\n *\n * @param mainObject\n * @param key\n * @returns {*}\n */\nmodule.exports = function nestedValue(mainObject, key) {\n try {\n return key.split('.').reduce((obj, property) => obj[property], mainObject);\n } catch (err) {\n // If we end up here, we're not working with an object, and @var mainObject is the value itself\n return mainObject;\n }\n};\n","'use strict';\n\nconst nestedValue = require('../helpers/nestedValue');\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function groupBy(key) {\n const collection = {};\n\n this.items.forEach((item, index) => {\n let resolvedKey;\n\n if (isFunction(key)) {\n resolvedKey = key(item, index);\n } else if (nestedValue(item, key) || nestedValue(item, key) === 0) {\n resolvedKey = nestedValue(item, key);\n } else {\n resolvedKey = '';\n }\n\n if (collection[resolvedKey] === undefined) {\n collection[resolvedKey] = new this.constructor([]);\n }\n\n collection[resolvedKey].push(item);\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst variadic = require('../helpers/variadic');\n\nmodule.exports = function has(...args) {\n const properties = variadic(args);\n\n return properties.filter(key => Object.hasOwnProperty.call(this.items, key)).length\n === properties.length;\n};\n","'use strict';\n\nconst nestedValue = require('../helpers/nestedValue');\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function keyBy(key) {\n const collection = {};\n\n if (isFunction(key)) {\n this.items.forEach((item) => {\n collection[key(item)] = item;\n });\n } else {\n this.items.forEach((item) => {\n const keyValue = nestedValue(item, key);\n\n collection[keyValue || ''] = item;\n });\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function last(fn, defaultValue) {\n let { items } = this;\n\n if (isFunction(fn)) {\n items = this.filter(fn).all();\n }\n\n if ((Array.isArray(items) && !items.length) || (!Object.keys(items).length)) {\n if (isFunction(defaultValue)) {\n return defaultValue();\n }\n\n return defaultValue;\n }\n\n if (Array.isArray(items)) {\n return items[items.length - 1];\n }\n const keys = Object.keys(items);\n\n return items[keys[keys.length - 1]];\n};\n","'use strict';\n\nconst values = require('../helpers/values');\n\nmodule.exports = function nth(n, offset = 0) {\n const items = values(this.items);\n\n const collection = items\n .slice(offset)\n .filter((item, index) => index % n === 0);\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst variadic = require('../helpers/variadic');\n\nmodule.exports = function only(...args) {\n const properties = variadic(args);\n\n if (Array.isArray(this.items)) {\n const collection = this.items\n .filter(item => properties.indexOf(item) !== -1);\n\n return new this.constructor(collection);\n }\n\n const collection = {};\n\n Object.keys(this.items).forEach((prop) => {\n if (properties.indexOf(prop) !== -1) {\n collection[prop] = this.items[prop];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst clone = require('../helpers/clone');\n\nmodule.exports = function pad(size, value) {\n const abs = Math.abs(size);\n const count = this.count();\n\n if (abs <= count) {\n return this;\n }\n\n let diff = abs - count;\n const items = clone(this.items);\n const isArray = Array.isArray(this.items);\n const prepend = size < 0;\n\n for (let iterator = 0; iterator < diff;) {\n if (!isArray) {\n if (items[iterator] !== undefined) {\n diff += 1;\n } else {\n items[iterator] = value;\n }\n } else if (prepend) {\n items.unshift(value);\n } else {\n items.push(value);\n }\n\n iterator += 1;\n }\n\n return new this.constructor(items);\n};\n","'use strict';\n\nconst { isArray, isObject } = require('../helpers/is');\nconst nestedValue = require('../helpers/nestedValue');\n\nconst buildKeyPathMap = function buildKeyPathMap(items) {\n const keyPaths = {};\n\n items.forEach((item, index) => {\n function buildKeyPath(val, keyPath) {\n if (isObject(val)) {\n Object.keys(val).forEach((prop) => {\n buildKeyPath(val[prop], `${keyPath}.${prop}`);\n });\n } else if (isArray(val)) {\n val.forEach((v, i) => {\n buildKeyPath(v, `${keyPath}.${i}`);\n });\n }\n\n keyPaths[keyPath] = val;\n }\n\n buildKeyPath(item, index);\n });\n\n return keyPaths;\n};\n\nmodule.exports = function pluck(value, key) {\n if (value.indexOf('*') !== -1) {\n const keyPathMap = buildKeyPathMap(this.items);\n\n const keyMatches = [];\n\n if (key !== undefined) {\n const keyRegex = new RegExp(`0.${key}`, 'g');\n const keyNumberOfLevels = `0.${key}`.split('.').length;\n\n Object.keys(keyPathMap).forEach((k) => {\n const matchingKey = k.match(keyRegex);\n\n if (matchingKey) {\n const match = matchingKey[0];\n\n if (match.split('.').length === keyNumberOfLevels) {\n keyMatches.push(keyPathMap[match]);\n }\n }\n });\n }\n\n const valueMatches = [];\n const valueRegex = new RegExp(`0.${value}`, 'g');\n const valueNumberOfLevels = `0.${value}`.split('.').length;\n\n\n Object.keys(keyPathMap).forEach((k) => {\n const matchingValue = k.match(valueRegex);\n\n if (matchingValue) {\n const match = matchingValue[0];\n\n if (match.split('.').length === valueNumberOfLevels) {\n valueMatches.push(keyPathMap[match]);\n }\n }\n });\n\n if (key !== undefined) {\n const collection = {};\n\n this.items.forEach((item, index) => {\n collection[keyMatches[index] || ''] = valueMatches;\n });\n\n return new this.constructor(collection);\n }\n\n return new this.constructor([valueMatches]);\n }\n\n if (key !== undefined) {\n const collection = {};\n\n this.items.forEach((item) => {\n if (nestedValue(item, value) !== undefined) {\n collection[item[key] || ''] = nestedValue(item, value);\n } else {\n collection[item[key] || ''] = null;\n }\n });\n\n return new this.constructor(collection);\n }\n\n return this.map((item) => {\n if (nestedValue(item, value) !== undefined) {\n return nestedValue(item, value);\n }\n\n return null;\n });\n};\n","'use strict';\n\nconst variadic = require('./variadic');\n\n/**\n * Delete keys helper\n *\n * Delete one or multiple keys from an object\n *\n * @param obj\n * @param keys\n * @returns {void}\n */\nmodule.exports = function deleteKeys(obj, ...keys) {\n variadic(keys).forEach((key) => {\n // eslint-disable-next-line\n delete obj[key];\n });\n};\n","'use strict';\n\nconst { isArray, isObject } = require('../helpers/is');\nconst deleteKeys = require('../helpers/deleteKeys');\n\nmodule.exports = function pop(count = 1) {\n if (this.isEmpty()) {\n return null;\n }\n\n if (isArray(this.items)) {\n if (count === 1) {\n return this.items.pop();\n }\n\n return new this.constructor(this.items.splice(-count));\n }\n\n if (isObject(this.items)) {\n const keys = Object.keys(this.items);\n\n if (count === 1) {\n const key = keys[keys.length - 1];\n const last = this.items[key];\n\n deleteKeys(this.items, key);\n\n return last;\n }\n\n const poppedKeys = keys.slice(-count);\n\n const newObject = poppedKeys.reduce((acc, current) => {\n acc[current] = this.items[current];\n\n return acc;\n }, {});\n\n deleteKeys(this.items, poppedKeys);\n\n return new this.constructor(newObject);\n }\n\n return null;\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function pull(key, defaultValue) {\n let returnValue = this.items[key] || null;\n\n if (!returnValue && defaultValue !== undefined) {\n if (isFunction(defaultValue)) {\n returnValue = defaultValue();\n } else {\n returnValue = defaultValue;\n }\n }\n\n delete this.items[key];\n\n return returnValue;\n};\n","'use strict';\n\nconst values = require('../helpers/values');\n\nmodule.exports = function random(length = null) {\n const items = values(this.items);\n\n const collection = new this.constructor(items).shuffle();\n\n // If not a length was specified\n if (length !== parseInt(length, 10)) {\n return collection.first();\n }\n\n return collection.take(length);\n};\n","'use strict';\n\n/* eslint-disable eqeqeq */\n\nconst { isArray, isObject, isFunction } = require('../helpers/is');\n\nmodule.exports = function search(valueOrFunction, strict) {\n let result;\n\n const find = (item, key) => {\n if (isFunction(valueOrFunction)) {\n return valueOrFunction(this.items[key], key);\n }\n\n if (strict) {\n return this.items[key] === valueOrFunction;\n }\n\n return this.items[key] == valueOrFunction;\n };\n\n if (isArray(this.items)) {\n result = this.items.findIndex(find);\n } else if (isObject(this.items)) {\n result = Object.keys(this.items).find(key => find(this.items[key], key));\n }\n\n if (result === undefined || result < 0) {\n return false;\n }\n\n return result;\n};\n","'use strict';\n\nconst { isArray, isObject } = require('../helpers/is');\nconst deleteKeys = require('../helpers/deleteKeys');\n\nmodule.exports = function shift(count = 1) {\n if (this.isEmpty()) {\n return null;\n }\n\n if (isArray(this.items)) {\n if (count === 1) {\n return this.items.shift();\n }\n\n return new this.constructor(this.items.splice(0, count));\n }\n\n if (isObject(this.items)) {\n if (count === 1) {\n const key = Object.keys(this.items)[0];\n const value = this.items[key];\n delete this.items[key];\n\n return value;\n }\n\n const keys = Object.keys(this.items);\n const poppedKeys = keys.slice(0, count);\n\n const newObject = poppedKeys.reduce((acc, current) => {\n acc[current] = this.items[current];\n\n return acc;\n }, {});\n\n deleteKeys(this.items, poppedKeys);\n\n return new this.constructor(newObject);\n }\n\n return null;\n};\n","'use strict';\n\nconst values = require('../helpers/values');\n\nmodule.exports = function shuffle() {\n const items = values(this.items);\n\n let j;\n let x;\n let i;\n\n for (i = items.length; i; i -= 1) {\n j = Math.floor(Math.random() * i);\n x = items[i - 1];\n items[i - 1] = items[j];\n items[j] = x;\n }\n\n this.items = items;\n\n return this;\n};\n","'use strict';\n\nconst { isObject } = require('../helpers/is');\n\nmodule.exports = function skip(number) {\n if (isObject(this.items)) {\n return new this.constructor(\n Object.keys(this.items)\n .reduce((accumulator, key, index) => {\n if ((index + 1) > number) {\n accumulator[key] = this.items[key];\n }\n\n return accumulator;\n }, {}),\n );\n }\n\n return new this.constructor(this.items.slice(number));\n};\n","'use strict';\n\nconst { isArray, isObject, isFunction } = require('../helpers/is');\n\nmodule.exports = function skipUntil(valueOrFunction) {\n let previous = null;\n let items;\n\n let callback = value => value === valueOrFunction;\n if (isFunction(valueOrFunction)) {\n callback = valueOrFunction;\n }\n\n if (isArray(this.items)) {\n items = this.items.filter((item) => {\n if (previous !== true) {\n previous = callback(item);\n }\n\n return previous;\n });\n }\n\n if (isObject(this.items)) {\n items = Object.keys(this.items).reduce((acc, key) => {\n if (previous !== true) {\n previous = callback(this.items[key]);\n }\n\n if (previous !== false) {\n acc[key] = this.items[key];\n }\n\n return acc;\n }, {});\n }\n\n return new this.constructor(items);\n};\n","'use strict';\n\nconst { isArray, isObject, isFunction } = require('../helpers/is');\n\nmodule.exports = function skipWhile(valueOrFunction) {\n let previous = null;\n let items;\n\n let callback = value => value === valueOrFunction;\n if (isFunction(valueOrFunction)) {\n callback = valueOrFunction;\n }\n\n if (isArray(this.items)) {\n items = this.items.filter((item) => {\n if (previous !== true) {\n previous = !callback(item);\n }\n\n return previous;\n });\n }\n\n if (isObject(this.items)) {\n items = Object.keys(this.items).reduce((acc, key) => {\n if (previous !== true) {\n previous = !callback(this.items[key]);\n }\n\n if (previous !== false) {\n acc[key] = this.items[key];\n }\n\n return acc;\n }, {});\n }\n\n return new this.constructor(items);\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function sole(key, operator, value) {\n let collection;\n\n if (isFunction(key)) {\n collection = this.filter(key);\n } else {\n collection = this.where(key, operator, value);\n }\n\n if (collection.isEmpty()) {\n throw new Error('Item not found.');\n }\n\n if (collection.count() > 1) {\n throw new Error('Multiple items found.');\n }\n\n return collection.first();\n};\n","'use strict';\n\nconst contains = require('./contains');\n\nmodule.exports = contains;\n","'use strict';\n\nconst nestedValue = require('../helpers/nestedValue');\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function sortBy(valueOrFunction) {\n const collection = [].concat(this.items);\n const getValue = (item) => {\n if (isFunction(valueOrFunction)) {\n return valueOrFunction(item);\n }\n\n return nestedValue(item, valueOrFunction);\n };\n\n collection.sort((a, b) => {\n const valueA = getValue(a);\n const valueB = getValue(b);\n\n if (valueA === null || valueA === undefined) {\n return 1;\n }\n if (valueB === null || valueB === undefined) {\n return -1;\n }\n\n if (valueA < valueB) {\n return -1;\n }\n if (valueA > valueB) {\n return 1;\n }\n\n return 0;\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst values = require('../helpers/values');\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function sum(key) {\n const items = values(this.items);\n\n let total = 0;\n\n if (key === undefined) {\n for (let i = 0, { length } = items; i < length; i += 1) {\n total += parseFloat(items[i]);\n }\n } else if (isFunction(key)) {\n for (let i = 0, { length } = items; i < length; i += 1) {\n total += parseFloat(key(items[i]));\n }\n } else {\n for (let i = 0, { length } = items; i < length; i += 1) {\n total += parseFloat(items[i][key]);\n }\n }\n\n\n return parseFloat(total.toPrecision(12));\n};\n","'use strict';\n\nconst { isArray, isObject, isFunction } = require('../helpers/is');\n\nmodule.exports = function takeUntil(valueOrFunction) {\n let previous = null;\n let items;\n\n let callback = value => value === valueOrFunction;\n if (isFunction(valueOrFunction)) {\n callback = valueOrFunction;\n }\n\n if (isArray(this.items)) {\n items = this.items.filter((item) => {\n if (previous !== false) {\n previous = !callback(item);\n }\n\n return previous;\n });\n }\n\n if (isObject(this.items)) {\n items = Object.keys(this.items).reduce((acc, key) => {\n if (previous !== false) {\n previous = !callback(this.items[key]);\n }\n\n if (previous !== false) {\n acc[key] = this.items[key];\n }\n\n return acc;\n }, {});\n }\n\n return new this.constructor(items);\n};\n","'use strict';\n\nconst { isArray, isObject, isFunction } = require('../helpers/is');\n\nmodule.exports = function takeWhile(valueOrFunction) {\n let previous = null;\n let items;\n\n let callback = value => value === valueOrFunction;\n if (isFunction(valueOrFunction)) {\n callback = valueOrFunction;\n }\n\n if (isArray(this.items)) {\n items = this.items.filter((item) => {\n if (previous !== false) {\n previous = callback(item);\n }\n\n return previous;\n });\n }\n\n if (isObject(this.items)) {\n items = Object.keys(this.items).reduce((acc, key) => {\n if (previous !== false) {\n previous = callback(this.items[key]);\n }\n\n if (previous !== false) {\n acc[key] = this.items[key];\n }\n\n return acc;\n }, {});\n }\n\n return new this.constructor(items);\n};\n","'use strict';\n\nmodule.exports = function whenNotEmpty(fn, defaultFn) {\n if (Array.isArray(this.items) && this.items.length) {\n return fn(this);\n } if (Object.keys(this.items).length) {\n return fn(this);\n }\n\n if (defaultFn !== undefined) {\n if (Array.isArray(this.items) && !this.items.length) {\n return defaultFn(this);\n } if (!Object.keys(this.items).length) {\n return defaultFn(this);\n }\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function whenEmpty(fn, defaultFn) {\n if (Array.isArray(this.items) && !this.items.length) {\n return fn(this);\n } if (!Object.keys(this.items).length) {\n return fn(this);\n }\n\n if (defaultFn !== undefined) {\n if (Array.isArray(this.items) && this.items.length) {\n return defaultFn(this);\n } if (Object.keys(this.items).length) {\n return defaultFn(this);\n }\n }\n\n return this;\n};\n","'use strict';\n\nconst { isFunction } = require('../helpers/is');\n\nmodule.exports = function unique(key) {\n let collection;\n\n if (key === undefined) {\n collection = this.items\n .filter((element, index, self) => self.indexOf(element) === index);\n } else {\n collection = [];\n\n const usedKeys = [];\n\n for (let iterator = 0, { length } = this.items;\n iterator < length; iterator += 1) {\n let uniqueKey;\n if (isFunction(key)) {\n uniqueKey = key(this.items[iterator]);\n } else {\n uniqueKey = this.items[iterator][key];\n }\n\n if (usedKeys.indexOf(uniqueKey) === -1) {\n collection.push(this.items[iterator]);\n usedKeys.push(uniqueKey);\n }\n }\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst getValues = require('../helpers/values');\n\nmodule.exports = function values() {\n return new this.constructor(getValues(this.items));\n};\n","'use strict';\n\nconst values = require('../helpers/values');\nconst nestedValue = require('../helpers/nestedValue');\n\nmodule.exports = function where(key, operator, value) {\n let comparisonOperator = operator;\n let comparisonValue = value;\n\n const items = values(this.items);\n\n if (operator === undefined || operator === true) {\n return new this.constructor(items.filter(item => nestedValue(item, key)));\n }\n\n if (operator === false) {\n return new this.constructor(items.filter(item => !nestedValue(item, key)));\n }\n\n if (value === undefined) {\n comparisonValue = operator;\n comparisonOperator = '===';\n }\n\n const collection = items.filter((item) => {\n switch (comparisonOperator) {\n case '==':\n return nestedValue(item, key) === Number(comparisonValue)\n || nestedValue(item, key) === comparisonValue.toString();\n\n default:\n case '===':\n return nestedValue(item, key) === comparisonValue;\n\n case '!=':\n case '<>':\n return nestedValue(item, key) !== Number(comparisonValue)\n && nestedValue(item, key) !== comparisonValue.toString();\n\n case '!==':\n return nestedValue(item, key) !== comparisonValue;\n\n case '<':\n return nestedValue(item, key) < comparisonValue;\n\n case '<=':\n return nestedValue(item, key) <= comparisonValue;\n\n case '>':\n return nestedValue(item, key) > comparisonValue;\n\n case '>=':\n return nestedValue(item, key) >= comparisonValue;\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst extractValues = require('../helpers/values');\nconst nestedValue = require('../helpers/nestedValue');\n\nmodule.exports = function whereIn(key, values) {\n const items = extractValues(values);\n\n const collection = this.items\n .filter(item => items.indexOf(nestedValue(item, key)) !== -1);\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nconst nestedValue = require('../helpers/nestedValue');\n\nmodule.exports = function whereNotBetween(key, values) {\n return this.filter(item => (\n nestedValue(item, key) < values[0] || nestedValue(item, key) > values[values.length - 1]\n ));\n};\n","'use strict';\n\nconst extractValues = require('../helpers/values');\nconst nestedValue = require('../helpers/nestedValue');\n\nmodule.exports = function whereNotIn(key, values) {\n const items = extractValues(values);\n\n const collection = this.items\n .filter(item => items.indexOf(nestedValue(item, key)) === -1);\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nfunction Collection(collection) {\n if (collection !== undefined && !Array.isArray(collection) && typeof collection !== 'object') {\n this.items = [collection];\n } else if (collection instanceof this.constructor) {\n this.items = collection.all();\n } else {\n this.items = collection || [];\n }\n}\n\n/**\n * Symbol.iterator\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator\n */\nconst SymbolIterator = require('./methods/symbol.iterator');\n\nif (typeof Symbol !== 'undefined') {\n Collection.prototype[Symbol.iterator] = SymbolIterator;\n}\n\n/**\n * Support JSON.stringify\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify\n */\nCollection.prototype.toJSON = function toJSON() {\n return this.items;\n};\n\nCollection.prototype.all = require('./methods/all');\nCollection.prototype.average = require('./methods/average');\nCollection.prototype.avg = require('./methods/avg');\nCollection.prototype.chunk = require('./methods/chunk');\nCollection.prototype.collapse = require('./methods/collapse');\nCollection.prototype.combine = require('./methods/combine');\nCollection.prototype.concat = require('./methods/concat');\nCollection.prototype.contains = require('./methods/contains');\nCollection.prototype.containsOneItem = require('./methods/containsOneItem');\nCollection.prototype.count = require('./methods/count');\nCollection.prototype.countBy = require('./methods/countBy');\nCollection.prototype.crossJoin = require('./methods/crossJoin');\nCollection.prototype.dd = require('./methods/dd');\nCollection.prototype.diff = require('./methods/diff');\nCollection.prototype.diffAssoc = require('./methods/diffAssoc');\nCollection.prototype.diffKeys = require('./methods/diffKeys');\nCollection.prototype.diffUsing = require('./methods/diffUsing');\nCollection.prototype.doesntContain = require('./methods/doesntContain');\nCollection.prototype.dump = require('./methods/dump');\nCollection.prototype.duplicates = require('./methods/duplicates');\nCollection.prototype.each = require('./methods/each');\nCollection.prototype.eachSpread = require('./methods/eachSpread');\nCollection.prototype.every = require('./methods/every');\nCollection.prototype.except = require('./methods/except');\nCollection.prototype.filter = require('./methods/filter');\nCollection.prototype.first = require('./methods/first');\nCollection.prototype.firstOrFail = require('./methods/firstOrFail');\nCollection.prototype.firstWhere = require('./methods/firstWhere');\nCollection.prototype.flatMap = require('./methods/flatMap');\nCollection.prototype.flatten = require('./methods/flatten');\nCollection.prototype.flip = require('./methods/flip');\nCollection.prototype.forPage = require('./methods/forPage');\nCollection.prototype.forget = require('./methods/forget');\nCollection.prototype.get = require('./methods/get');\nCollection.prototype.groupBy = require('./methods/groupBy');\nCollection.prototype.has = require('./methods/has');\nCollection.prototype.implode = require('./methods/implode');\nCollection.prototype.intersect = require('./methods/intersect');\nCollection.prototype.intersectByKeys = require('./methods/intersectByKeys');\nCollection.prototype.isEmpty = require('./methods/isEmpty');\nCollection.prototype.isNotEmpty = require('./methods/isNotEmpty');\nCollection.prototype.join = require('./methods/join');\nCollection.prototype.keyBy = require('./methods/keyBy');\nCollection.prototype.keys = require('./methods/keys');\nCollection.prototype.last = require('./methods/last');\nCollection.prototype.macro = require('./methods/macro');\nCollection.prototype.make = require('./methods/make');\nCollection.prototype.map = require('./methods/map');\nCollection.prototype.mapSpread = require('./methods/mapSpread');\nCollection.prototype.mapToDictionary = require('./methods/mapToDictionary');\nCollection.prototype.mapInto = require('./methods/mapInto');\nCollection.prototype.mapToGroups = require('./methods/mapToGroups');\nCollection.prototype.mapWithKeys = require('./methods/mapWithKeys');\nCollection.prototype.max = require('./methods/max');\nCollection.prototype.median = require('./methods/median');\nCollection.prototype.merge = require('./methods/merge');\nCollection.prototype.mergeRecursive = require('./methods/mergeRecursive');\nCollection.prototype.min = require('./methods/min');\nCollection.prototype.mode = require('./methods/mode');\nCollection.prototype.nth = require('./methods/nth');\nCollection.prototype.only = require('./methods/only');\nCollection.prototype.pad = require('./methods/pad');\nCollection.prototype.partition = require('./methods/partition');\nCollection.prototype.pipe = require('./methods/pipe');\nCollection.prototype.pluck = require('./methods/pluck');\nCollection.prototype.pop = require('./methods/pop');\nCollection.prototype.prepend = require('./methods/prepend');\nCollection.prototype.pull = require('./methods/pull');\nCollection.prototype.push = require('./methods/push');\nCollection.prototype.put = require('./methods/put');\nCollection.prototype.random = require('./methods/random');\nCollection.prototype.reduce = require('./methods/reduce');\nCollection.prototype.reject = require('./methods/reject');\nCollection.prototype.replace = require('./methods/replace');\nCollection.prototype.replaceRecursive = require('./methods/replaceRecursive');\nCollection.prototype.reverse = require('./methods/reverse');\nCollection.prototype.search = require('./methods/search');\nCollection.prototype.shift = require('./methods/shift');\nCollection.prototype.shuffle = require('./methods/shuffle');\nCollection.prototype.skip = require('./methods/skip');\nCollection.prototype.skipUntil = require('./methods/skipUntil');\nCollection.prototype.skipWhile = require('./methods/skipWhile');\nCollection.prototype.slice = require('./methods/slice');\nCollection.prototype.sole = require('./methods/sole');\nCollection.prototype.some = require('./methods/some');\nCollection.prototype.sort = require('./methods/sort');\nCollection.prototype.sortDesc = require('./methods/sortDesc');\nCollection.prototype.sortBy = require('./methods/sortBy');\nCollection.prototype.sortByDesc = require('./methods/sortByDesc');\nCollection.prototype.sortKeys = require('./methods/sortKeys');\nCollection.prototype.sortKeysDesc = require('./methods/sortKeysDesc');\nCollection.prototype.splice = require('./methods/splice');\nCollection.prototype.split = require('./methods/split');\nCollection.prototype.sum = require('./methods/sum');\nCollection.prototype.take = require('./methods/take');\nCollection.prototype.takeUntil = require('./methods/takeUntil');\nCollection.prototype.takeWhile = require('./methods/takeWhile');\nCollection.prototype.tap = require('./methods/tap');\nCollection.prototype.times = require('./methods/times');\nCollection.prototype.toArray = require('./methods/toArray');\nCollection.prototype.toJson = require('./methods/toJson');\nCollection.prototype.transform = require('./methods/transform');\nCollection.prototype.undot = require('./methods/undot');\nCollection.prototype.unless = require('./methods/unless');\nCollection.prototype.unlessEmpty = require('./methods/whenNotEmpty');\nCollection.prototype.unlessNotEmpty = require('./methods/whenEmpty');\nCollection.prototype.union = require('./methods/union');\nCollection.prototype.unique = require('./methods/unique');\nCollection.prototype.unwrap = require('./methods/unwrap');\nCollection.prototype.values = require('./methods/values');\nCollection.prototype.when = require('./methods/when');\nCollection.prototype.whenEmpty = require('./methods/whenEmpty');\nCollection.prototype.whenNotEmpty = require('./methods/whenNotEmpty');\nCollection.prototype.where = require('./methods/where');\nCollection.prototype.whereBetween = require('./methods/whereBetween');\nCollection.prototype.whereIn = require('./methods/whereIn');\nCollection.prototype.whereInstanceOf = require('./methods/whereInstanceOf');\nCollection.prototype.whereNotBetween = require('./methods/whereNotBetween');\nCollection.prototype.whereNotIn = require('./methods/whereNotIn');\nCollection.prototype.whereNull = require('./methods/whereNull');\nCollection.prototype.whereNotNull = require('./methods/whereNotNull');\nCollection.prototype.wrap = require('./methods/wrap');\nCollection.prototype.zip = require('./methods/zip');\n\nconst collect = collection => new Collection(collection);\n\nmodule.exports = collect;\nmodule.exports.collect = collect;\nmodule.exports.default = collect;\nmodule.exports.Collection = Collection;\n","'use strict';\n\nmodule.exports = function SymbolIterator() {\n let index = -1;\n\n return {\n next: () => {\n index += 1;\n\n return {\n value: this.items[index],\n done: index >= this.items.length,\n };\n },\n };\n};\n","'use strict';\n\nmodule.exports = function all() {\n return this.items;\n};\n","'use strict';\n\nmodule.exports = function chunk(size) {\n const chunks = [];\n let index = 0;\n\n if (Array.isArray(this.items)) {\n do {\n const items = this.items.slice(index, index + size);\n const collection = new this.constructor(items);\n\n chunks.push(collection);\n index += size;\n } while (index < this.items.length);\n } else if (typeof this.items === 'object') {\n const keys = Object.keys(this.items);\n\n do {\n const keysOfChunk = keys.slice(index, index + size);\n const collection = new this.constructor({});\n\n keysOfChunk.forEach(key => collection.put(key, this.items[key]));\n\n chunks.push(collection);\n index += size;\n } while (index < keys.length);\n } else {\n chunks.push(new this.constructor([this.items]));\n }\n\n return new this.constructor(chunks);\n};\n","'use strict';\n\nmodule.exports = function collapse() {\n return new this.constructor([].concat(...this.items));\n};\n","'use strict';\n\nmodule.exports = function combine(array) {\n let values = array;\n\n if (values instanceof this.constructor) {\n values = array.all();\n }\n\n const collection = {};\n\n if (Array.isArray(this.items) && Array.isArray(values)) {\n this.items.forEach((key, iterator) => {\n collection[key] = values[iterator];\n });\n } else if (typeof this.items === 'object' && typeof values === 'object') {\n Object.keys(this.items).forEach((key, index) => {\n collection[this.items[key]] = values[Object.keys(values)[index]];\n });\n } else if (Array.isArray(this.items)) {\n collection[this.items[0]] = values;\n } else if (typeof this.items === 'string' && Array.isArray(values)) {\n [collection[this.items]] = values;\n } else if (typeof this.items === 'string') {\n collection[this.items] = values;\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function containsOneItem() {\n return this.count() === 1;\n};\n","'use strict';\n\nmodule.exports = function count() {\n let arrayLength = 0;\n\n if (Array.isArray(this.items)) {\n arrayLength = this.items.length;\n }\n\n return Math.max(Object.keys(this.items).length, arrayLength);\n};\n","'use strict';\n\nmodule.exports = function countBy(fn = value => value) {\n return new this.constructor(this.items)\n .groupBy(fn)\n .map(value => value.count());\n};\n","'use strict';\n\nmodule.exports = function crossJoin(...values) {\n function join(collection, constructor, args) {\n let current = args[0];\n\n if (current instanceof constructor) {\n current = current.all();\n }\n\n const rest = args.slice(1);\n const last = !rest.length;\n let result = [];\n\n for (let i = 0; i < current.length; i += 1) {\n const collectionCopy = collection.slice();\n collectionCopy.push(current[i]);\n\n if (last) {\n result.push(collectionCopy);\n } else {\n result = result.concat(join(collectionCopy, constructor, rest));\n }\n }\n\n return result;\n }\n\n return new this.constructor(join([], this.constructor, [].concat([this.items], values)));\n};\n","'use strict';\n\nmodule.exports = function dd() {\n this.dump();\n\n if (typeof process !== 'undefined') {\n process.exit(1);\n }\n};\n","'use strict';\n\nmodule.exports = function diff(values) {\n let valuesToDiff;\n\n if (values instanceof this.constructor) {\n valuesToDiff = values.all();\n } else {\n valuesToDiff = values;\n }\n\n const collection = this.items.filter(item => valuesToDiff.indexOf(item) === -1);\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function diffAssoc(values) {\n let diffValues = values;\n\n if (values instanceof this.constructor) {\n diffValues = values.all();\n }\n\n const collection = {};\n\n Object.keys(this.items).forEach((key) => {\n if (diffValues[key] === undefined || diffValues[key] !== this.items[key]) {\n collection[key] = this.items[key];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function diffKeys(object) {\n let objectToDiff;\n\n if (object instanceof this.constructor) {\n objectToDiff = object.all();\n } else {\n objectToDiff = object;\n }\n\n const objectKeys = Object.keys(objectToDiff);\n\n const remainingKeys = Object.keys(this.items)\n .filter(item => objectKeys.indexOf(item) === -1);\n\n return new this.constructor(this.items).only(\n remainingKeys,\n );\n};\n","'use strict';\n\nmodule.exports = function diffUsing(values, callback) {\n const collection = this.items.filter(item => (\n !(values && values.some(otherItem => callback(item, otherItem) === 0))\n ));\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function contains(key, value) {\n return !this.contains(key, value);\n};\n","'use strict';\n\nmodule.exports = function dump() {\n // eslint-disable-next-line\n console.log(this);\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function duplicates() {\n const occuredValues = [];\n const duplicateValues = {};\n\n const stringifiedValue = (value) => {\n if (Array.isArray(value) || typeof value === 'object') {\n return JSON.stringify(value);\n }\n\n return value;\n };\n\n if (Array.isArray(this.items)) {\n this.items.forEach((value, index) => {\n const valueAsString = stringifiedValue(value);\n\n if (occuredValues.indexOf(valueAsString) === -1) {\n occuredValues.push(valueAsString);\n } else {\n duplicateValues[index] = value;\n }\n });\n } else if (typeof this.items === 'object') {\n Object.keys(this.items).forEach((key) => {\n const valueAsString = stringifiedValue(this.items[key]);\n\n if (occuredValues.indexOf(valueAsString) === -1) {\n occuredValues.push(valueAsString);\n } else {\n duplicateValues[key] = this.items[key];\n }\n });\n }\n\n return new this.constructor(duplicateValues);\n};\n","'use strict';\n\nmodule.exports = function each(fn) {\n let stop = false;\n\n if (Array.isArray(this.items)) {\n const { length } = this.items;\n\n for (let index = 0; index < length && !stop; index += 1) {\n stop = fn(this.items[index], index, this.items) === false;\n }\n } else {\n const keys = Object.keys(this.items);\n const { length } = keys;\n\n for (let index = 0; index < length && !stop; index += 1) {\n const key = keys[index];\n\n stop = fn(this.items[key], key, this.items) === false;\n }\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function eachSpread(fn) {\n this.each((values, key) => {\n fn(...values, key);\n });\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function firstWhere(key, operator, value) {\n return this.where(key, operator, value).first() || null;\n};\n","'use strict';\n\nmodule.exports = function flatMap(fn) {\n return this.map(fn).collapse();\n};\n","'use strict';\n\nmodule.exports = function flip() {\n const collection = {};\n\n if (Array.isArray(this.items)) {\n Object.keys(this.items).forEach((key) => {\n collection[this.items[key]] = Number(key);\n });\n } else {\n Object.keys(this.items).forEach((key) => {\n collection[this.items[key]] = key;\n });\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function forPage(page, chunk) {\n let collection = {};\n\n if (Array.isArray(this.items)) {\n collection = this.items.slice((page * chunk) - chunk, page * chunk);\n } else {\n Object\n .keys(this.items)\n .slice((page * chunk) - chunk, page * chunk)\n .forEach((key) => {\n collection[key] = this.items[key];\n });\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function forget(key) {\n if (Array.isArray(this.items)) {\n this.items.splice(key, 1);\n } else {\n delete this.items[key];\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function implode(key, glue) {\n if (glue === undefined) {\n return this.items.join(key);\n }\n\n return new this.constructor(this.items).pluck(key).all().join(glue);\n};\n","'use strict';\n\nmodule.exports = function intersect(values) {\n let intersectValues = values;\n\n if (values instanceof this.constructor) {\n intersectValues = values.all();\n }\n\n const collection = this.items\n .filter(item => intersectValues.indexOf(item) !== -1);\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function intersectByKeys(values) {\n let intersectKeys = Object.keys(values);\n\n if (values instanceof this.constructor) {\n intersectKeys = Object.keys(values.all());\n }\n\n const collection = {};\n\n Object.keys(this.items).forEach((key) => {\n if (intersectKeys.indexOf(key) !== -1) {\n collection[key] = this.items[key];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function isEmpty() {\n if (Array.isArray(this.items)) {\n return !this.items.length;\n }\n\n return !Object.keys(this.items).length;\n};\n","'use strict';\n\nmodule.exports = function isNotEmpty() {\n return !this.isEmpty();\n};\n","'use strict';\n\nmodule.exports = function join(glue, finalGlue) {\n const collection = this.values();\n\n if (finalGlue === undefined) {\n return collection.implode(glue);\n }\n\n const count = collection.count();\n\n if (count === 0) {\n return '';\n }\n\n if (count === 1) {\n return collection.last();\n }\n\n const finalItem = collection.pop();\n\n return collection.implode(glue) + finalGlue + finalItem;\n};\n","'use strict';\n\nmodule.exports = function keys() {\n let collection = Object.keys(this.items);\n\n if (Array.isArray(this.items)) {\n collection = collection.map(Number);\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function macro(name, fn) {\n this.constructor.prototype[name] = fn;\n};\n","'use strict';\n\nmodule.exports = function make(items = []) {\n return new this.constructor(items);\n};\n","'use strict';\n\nmodule.exports = function map(fn) {\n if (Array.isArray(this.items)) {\n return new this.constructor(this.items.map(fn));\n }\n\n const collection = {};\n\n Object.keys(this.items).forEach((key) => {\n collection[key] = fn(this.items[key], key);\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function mapSpread(fn) {\n return this.map((values, key) => fn(...values, key));\n};\n","'use strict';\n\nmodule.exports = function mapToDictionary(fn) {\n const collection = {};\n\n this.items.forEach((item, k) => {\n const [key, value] = fn(item, k);\n\n if (collection[key] === undefined) {\n collection[key] = [value];\n } else {\n collection[key].push(value);\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function mapInto(ClassName) {\n return this.map((value, key) => new ClassName(value, key));\n};\n","'use strict';\n\nmodule.exports = function mapToGroups(fn) {\n const collection = {};\n\n this.items.forEach((item, key) => {\n const [keyed, value] = fn(item, key);\n\n if (collection[keyed] === undefined) {\n collection[keyed] = [value];\n } else {\n collection[keyed].push(value);\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function mapWithKeys(fn) {\n const collection = {};\n\n if (Array.isArray(this.items)) {\n this.items.forEach((item, index) => {\n const [keyed, value] = fn(item, index);\n collection[keyed] = value;\n });\n } else {\n Object.keys(this.items).forEach((key) => {\n const [keyed, value] = fn(this.items[key], key);\n collection[keyed] = value;\n });\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function max(key) {\n if (typeof key === 'string') {\n const filtered = this.items.filter(item => item[key] !== undefined);\n\n return Math.max(...filtered.map(item => item[key]));\n }\n\n return Math.max(...this.items);\n};\n","'use strict';\n\nmodule.exports = function median(key) {\n const { length } = this.items;\n\n if (key === undefined) {\n if (length % 2 === 0) {\n return (this.items[(length / 2) - 1] + this.items[length / 2]) / 2;\n }\n\n return this.items[Math.floor(length / 2)];\n }\n\n if (length % 2 === 0) {\n return (this.items[(length / 2) - 1][key]\n + this.items[length / 2][key]) / 2;\n }\n\n return this.items[Math.floor(length / 2)][key];\n};\n","'use strict';\n\nmodule.exports = function merge(value) {\n let arrayOrObject = value;\n\n if (typeof arrayOrObject === 'string') {\n arrayOrObject = [arrayOrObject];\n }\n\n if (Array.isArray(this.items) && Array.isArray(arrayOrObject)) {\n return new this.constructor(this.items.concat(arrayOrObject));\n }\n\n const collection = JSON.parse(JSON.stringify(this.items));\n\n Object.keys(arrayOrObject).forEach((key) => {\n collection[key] = arrayOrObject[key];\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function mergeRecursive(items) {\n const merge = (target, source) => {\n const merged = {};\n\n const mergedKeys = Object.keys({ ...target, ...source });\n\n mergedKeys.forEach((key) => {\n if (target[key] === undefined && source[key] !== undefined) {\n merged[key] = source[key];\n } else if (target[key] !== undefined && source[key] === undefined) {\n merged[key] = target[key];\n } else if (target[key] !== undefined && source[key] !== undefined) {\n if (target[key] === source[key]) {\n merged[key] = target[key];\n } else if (\n (!Array.isArray(target[key]) && typeof target[key] === 'object')\n && (!Array.isArray(source[key]) && typeof source[key] === 'object')\n ) {\n merged[key] = merge(target[key], source[key]);\n } else {\n merged[key] = [].concat(target[key], source[key]);\n }\n }\n });\n\n return merged;\n };\n\n if (!items) {\n return this;\n }\n\n if (items.constructor.name === 'Collection') {\n return new this.constructor(merge(this.items, items.all()));\n }\n\n return new this.constructor(merge(this.items, items));\n};\n","'use strict';\n\nmodule.exports = function min(key) {\n if (key !== undefined) {\n const filtered = this.items.filter(item => item[key] !== undefined);\n\n return Math.min(...filtered.map(item => item[key]));\n }\n\n return Math.min(...this.items);\n};\n","'use strict';\n\nmodule.exports = function mode(key) {\n const values = [];\n let highestCount = 1;\n\n if (!this.items.length) {\n return null;\n }\n\n this.items.forEach((item) => {\n const tempValues = values.filter((value) => {\n if (key !== undefined) {\n return value.key === item[key];\n }\n\n return value.key === item;\n });\n\n if (!tempValues.length) {\n if (key !== undefined) {\n values.push({ key: item[key], count: 1 });\n } else {\n values.push({ key: item, count: 1 });\n }\n } else {\n tempValues[0].count += 1;\n const { count } = tempValues[0];\n\n if (count > highestCount) {\n highestCount = count;\n }\n }\n });\n\n return values\n .filter(value => value.count === highestCount)\n .map(value => value.key);\n};\n","'use strict';\n\nmodule.exports = function partition(fn) {\n let arrays;\n\n if (Array.isArray(this.items)) {\n arrays = [new this.constructor([]), new this.constructor([])];\n\n this.items.forEach((item) => {\n if (fn(item) === true) {\n arrays[0].push(item);\n } else {\n arrays[1].push(item);\n }\n });\n } else {\n arrays = [new this.constructor({}), new this.constructor({})];\n\n Object.keys(this.items).forEach((prop) => {\n const value = this.items[prop];\n\n if (fn(value) === true) {\n arrays[0].put(prop, value);\n } else {\n arrays[1].put(prop, value);\n }\n });\n }\n\n return new this.constructor(arrays);\n};\n","'use strict';\n\nmodule.exports = function pipe(fn) {\n return fn(this);\n};\n","'use strict';\n\nmodule.exports = function prepend(value, key) {\n if (key !== undefined) {\n return this.put(key, value);\n }\n\n this.items.unshift(value);\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function push(...items) {\n this.items.push(...items);\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function put(key, value) {\n this.items[key] = value;\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function reduce(fn, carry) {\n let reduceCarry = null;\n\n if (carry !== undefined) {\n reduceCarry = carry;\n }\n\n if (Array.isArray(this.items)) {\n this.items.forEach((item) => {\n reduceCarry = fn(reduceCarry, item);\n });\n } else {\n Object.keys(this.items).forEach((key) => {\n reduceCarry = fn(reduceCarry, this.items[key], key);\n });\n }\n\n return reduceCarry;\n};\n","'use strict';\n\nmodule.exports = function reject(fn) {\n return new this.constructor(this.items).filter(item => !fn(item));\n};\n","'use strict';\n\nmodule.exports = function replace(items) {\n if (!items) {\n return this;\n }\n\n if (Array.isArray(items)) {\n const replaced = this.items.map((value, index) => items[index] || value);\n\n return new this.constructor(replaced);\n }\n\n if (items.constructor.name === 'Collection') {\n const replaced = { ...this.items, ...items.all() };\n\n return new this.constructor(replaced);\n }\n\n const replaced = { ...this.items, ...items };\n\n return new this.constructor(replaced);\n};\n","'use strict';\n\nmodule.exports = function replaceRecursive(items) {\n const replace = (target, source) => {\n const replaced = { ...target };\n\n const mergedKeys = Object.keys({ ...target, ...source });\n\n mergedKeys.forEach((key) => {\n if (!Array.isArray(source[key]) && typeof source[key] === 'object') {\n replaced[key] = replace(target[key], source[key]);\n } else if (target[key] === undefined && source[key] !== undefined) {\n if (typeof target[key] === 'object') {\n replaced[key] = { ...source[key] };\n } else {\n replaced[key] = source[key];\n }\n } else if (target[key] !== undefined && source[key] === undefined) {\n if (typeof target[key] === 'object') {\n replaced[key] = { ...target[key] };\n } else {\n replaced[key] = target[key];\n }\n } else if (target[key] !== undefined && source[key] !== undefined) {\n if (typeof source[key] === 'object') {\n replaced[key] = { ...source[key] };\n } else {\n replaced[key] = source[key];\n }\n }\n });\n\n return replaced;\n };\n\n if (!items) {\n return this;\n }\n\n if (!Array.isArray(items) && typeof items !== 'object') {\n return new this.constructor(replace(this.items, [items]));\n }\n\n if (items.constructor.name === 'Collection') {\n return new this.constructor(replace(this.items, items.all()));\n }\n\n return new this.constructor(replace(this.items, items));\n};\n","'use strict';\n\nmodule.exports = function reverse() {\n const collection = [].concat(this.items).reverse();\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function slice(remove, limit) {\n let collection = this.items.slice(remove);\n\n if (limit !== undefined) {\n collection = collection.slice(0, limit);\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function sort(fn) {\n const collection = [].concat(this.items);\n\n if (fn === undefined) {\n if (this.every(item => typeof item === 'number')) {\n collection.sort((a, b) => a - b);\n } else {\n collection.sort();\n }\n } else {\n collection.sort(fn);\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function sortDesc() {\n return this.sort().reverse();\n};\n","'use strict';\n\nmodule.exports = function sortByDesc(valueOrFunction) {\n return this.sortBy(valueOrFunction).reverse();\n};\n","'use strict';\n\nmodule.exports = function sortKeys() {\n const ordered = {};\n\n Object.keys(this.items).sort().forEach((key) => {\n ordered[key] = this.items[key];\n });\n\n return new this.constructor(ordered);\n};\n","'use strict';\n\nmodule.exports = function sortKeysDesc() {\n const ordered = {};\n\n Object.keys(this.items).sort().reverse().forEach((key) => {\n ordered[key] = this.items[key];\n });\n\n return new this.constructor(ordered);\n};\n","'use strict';\n\nmodule.exports = function splice(index, limit, replace) {\n const slicedCollection = this.slice(index, limit);\n\n this.items = this.diff(slicedCollection.all()).all();\n\n if (Array.isArray(replace)) {\n for (let iterator = 0, { length } = replace;\n iterator < length; iterator += 1) {\n this.items.splice(index + iterator, 0, replace[iterator]);\n }\n }\n\n return slicedCollection;\n};\n","'use strict';\n\nmodule.exports = function split(numberOfGroups) {\n const itemsPerGroup = Math.round(this.items.length / numberOfGroups);\n\n const items = JSON.parse(JSON.stringify(this.items));\n const collection = [];\n\n for (let iterator = 0; iterator < numberOfGroups; iterator += 1) {\n collection.push(new this.constructor(items.splice(0, itemsPerGroup)));\n }\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function take(length) {\n if (!Array.isArray(this.items) && typeof this.items === 'object') {\n const keys = Object.keys(this.items);\n let slicedKeys;\n\n if (length < 0) {\n slicedKeys = keys.slice(length);\n } else {\n slicedKeys = keys.slice(0, length);\n }\n\n const collection = {};\n\n keys.forEach((prop) => {\n if (slicedKeys.indexOf(prop) !== -1) {\n collection[prop] = this.items[prop];\n }\n });\n\n return new this.constructor(collection);\n }\n\n if (length < 0) {\n return new this.constructor(this.items.slice(length));\n }\n\n return new this.constructor(this.items.slice(0, length));\n};\n","'use strict';\n\nmodule.exports = function tap(fn) {\n fn(this);\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function times(n, fn) {\n for (let iterator = 1; iterator <= n; iterator += 1) {\n this.items.push(fn(iterator));\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function toArray() {\n const collectionInstance = this.constructor;\n\n function iterate(list, collection) {\n const childCollection = [];\n\n if (list instanceof collectionInstance) {\n list.items.forEach(i => iterate(i, childCollection));\n collection.push(childCollection);\n } else if (Array.isArray(list)) {\n list.forEach(i => iterate(i, childCollection));\n collection.push(childCollection);\n } else {\n collection.push(list);\n }\n }\n\n if (Array.isArray(this.items)) {\n const collection = [];\n\n this.items.forEach((items) => {\n iterate(items, collection);\n });\n\n return collection;\n }\n\n return this.values().all();\n};\n","'use strict';\n\nmodule.exports = function toJson() {\n if (typeof this.items === 'object' && !Array.isArray(this.items)) {\n return JSON.stringify(this.all());\n }\n\n return JSON.stringify(this.toArray());\n};\n","'use strict';\n\nmodule.exports = function transform(fn) {\n if (Array.isArray(this.items)) {\n this.items = this.items.map(fn);\n } else {\n const collection = {};\n\n Object.keys(this.items).forEach((key) => {\n collection[key] = fn(this.items[key], key);\n });\n\n this.items = collection;\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function undot() {\n if (Array.isArray(this.items)) {\n return this;\n }\n\n let collection = {};\n\n Object.keys(this.items).forEach((key) => {\n if (key.indexOf('.') !== -1) {\n const obj = collection;\n\n key.split('.').reduce((acc, current, index, array) => {\n if (!acc[current]) {\n acc[current] = {};\n }\n\n if ((index === array.length - 1)) {\n acc[current] = this.items[key];\n }\n\n return acc[current];\n }, obj);\n\n collection = { ...collection, ...obj };\n } else {\n collection[key] = this.items[key];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function when(value, fn, defaultFn) {\n if (!value) {\n fn(this);\n } else {\n defaultFn(this);\n }\n};\n","'use strict';\n\nmodule.exports = function union(object) {\n const collection = JSON.parse(JSON.stringify(this.items));\n\n Object.keys(object).forEach((prop) => {\n if (this.items[prop] === undefined) {\n collection[prop] = object[prop];\n }\n });\n\n return new this.constructor(collection);\n};\n","'use strict';\n\nmodule.exports = function unwrap(value) {\n if (value instanceof this.constructor) {\n return value.all();\n }\n\n return value;\n};\n","'use strict';\n\nmodule.exports = function when(value, fn, defaultFn) {\n if (value) {\n return fn(this, value);\n }\n\n if (defaultFn) {\n return defaultFn(this, value);\n }\n\n return this;\n};\n","'use strict';\n\nmodule.exports = function whereBetween(key, values) {\n return this.where(key, '>=', values[0]).where(key, '<=', values[values.length - 1]);\n};\n","'use strict';\n\nmodule.exports = function whereInstanceOf(type) {\n return this.filter(item => item instanceof type);\n};\n","'use strict';\n\nmodule.exports = function whereNull(key = null) {\n return this.where(key, '===', null);\n};\n","'use strict';\n\nmodule.exports = function whereNotNull(key = null) {\n return this.where(key, '!==', null);\n};\n","'use strict';\n\nmodule.exports = function wrap(value) {\n if (value instanceof this.constructor) {\n return value;\n }\n\n if (typeof value === 'object') {\n return new this.constructor(value);\n }\n\n return new this.constructor([value]);\n};\n","'use strict';\n\nmodule.exports = function zip(array) {\n let values = array;\n\n if (values instanceof this.constructor) {\n values = values.all();\n }\n\n const collection = this.items.map((item, index) => new this.constructor([item, values[index]]));\n\n return new this.constructor(collection);\n};\n"],"names":["is","isArray","item","Array","isObject","isFunction","require$$0","average","key","undefined","this","sum","items","length","constructor","pluck","avg","clone","cloned","push","Object","keys","forEach","prop","values","valuesArray","name","all","require$$1","contains","value","filter","index","indexOf","keysAndValues","variadic","args","falsyValue","nestedValue","mainObject","split","reduce","obj","property","err","deleteKeys","some","whenNotEmpty","fn","defaultFn","whenEmpty","getValues","extractValues","Collection","collection","Symbol","prototype","iterator","next","done","toJSON","require$$2","require$$3","chunk","size","chunks","slice","keysOfChunk","put","collapse","concat","combine","array","collectionOrArrayOrObject","list","require$$8","containsOneItem","count","arrayLength","Math","max","countBy","groupBy","map","crossJoin","join","current","rest","last","result","i","collectionCopy","dd","dump","process","exit","diff","valuesToDiff","diffAssoc","diffValues","diffKeys","object","objectToDiff","objectKeys","remainingKeys","only","diffUsing","callback","otherItem","doesntContain","console","log","duplicates","occuredValues","duplicateValues","stringifiedValue","JSON","stringify","valueAsString","each","stop","eachSpread","every","except","properties","func","filteredItems","filterArray","filterObject","first","defaultValue","firstKey","firstOrFail","operator","Error","where","isEmpty","firstWhere","flatMap","flatten","depth","flattenDepth","Infinity","fullyFlattened","flat","flip","Number","forPage","page","forget","splice","get","resolvedKey","has","hasOwnProperty","call","implode","glue","intersect","intersectValues","intersectByKeys","intersectKeys","isNotEmpty","finalGlue","finalItem","pop","keyBy","keyValue","macro","make","mapSpread","mapToDictionary","k","mapInto","ClassName","mapToGroups","keyed","mapWithKeys","filtered","median","floor","merge","arrayOrObject","parse","mergeRecursive","target","source","merged","min","mode","highestCount","tempValues","nth","n","offset","pad","abs","prepend","unshift","partition","arrays","pipe","keyPathMap","keyPaths","buildKeyPath","val","keyPath","v","buildKeyPathMap","keyMatches","keyRegex","RegExp","keyNumberOfLevels","matchingKey","match","valueMatches","valueRegex","valueNumberOfLevels","matchingValue","poppedKeys","newObject","acc","pull","returnValue","random","shuffle","parseInt","take","carry","reduceCarry","reject","replace","replaced","replaceRecursive","reverse","search","valueOrFunction","strict","find","findIndex","shift","j","x","skip","number","accumulator","skipUntil","previous","skipWhile","remove","limit","sole","require$$85","sort","a","b","sortDesc","sortBy","getValue","valueA","valueB","sortByDesc","sortKeys","ordered","sortKeysDesc","slicedCollection","numberOfGroups","itemsPerGroup","round","total","parseFloat","toPrecision","slicedKeys","takeUntil","takeWhile","tap","times","toArray","collectionInstance","iterate","childCollection","toJson","transform","undot","unless","unlessEmpty","require$$105","unlessNotEmpty","require$$106","union","unique","element","self","usedKeys","uniqueKey","unwrap","when","comparisonOperator","comparisonValue","toString","whereBetween","whereIn","whereInstanceOf","type","whereNotBetween","whereNotIn","whereNull","whereNotNull","wrap","zip","collect","srcModule","exports","collect_1","default"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128]} \ No newline at end of file diff --git a/external/index.js b/external/index.js new file mode 100644 index 00000000..e63634f3 --- /dev/null +++ b/external/index.js @@ -0,0 +1,2 @@ +export { default as collect } from './collect.js'; +export { default as DOMPurify } from './DOMPurify.js'; \ No newline at end of file diff --git a/forien-quest-log.lock b/forien-quest-log.lock new file mode 100644 index 00000000..82ef623b --- /dev/null +++ b/forien-quest-log.lock @@ -0,0 +1 @@ +🔒 \ No newline at end of file diff --git a/lang/cn.json b/lang/cn.json index 08e107aa..be36f05a 100644 --- a/lang/cn.json +++ b/lang/cn.json @@ -1,201 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "新任务", - "QuestLogButton": "任务栏", - "Quests": "{0}任务", - "SampleReward": "例如:300点经验值", - "SampleTask": "例如:消灭鸦阁里所有的不死生物", - - "QuestTypes": { - "InProgress": "进行中", - "Completed": "已完成", - "Failed": "已失败", - "Hidden": "已隐藏", - "Labels": { - "available": "可选", - "active": "进行中", - "completed": "已完成", - "failed": "已失败", - "hidden": "已隐藏" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "打开 ”{name}” 任务" + }, + "Notifications": { + "NoQuest": "API 错误:任务ID无效,无法创建宏。" + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "新任务" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (任务奖励):{userName} 将 '{itemName}' 放到 {actorName} 上。" + } + }, + "Utils": { + "Notifications": { + "NoDocument": "无法加载实体 UUID:'{uuid}'。", + "NoPermission": "您没有足够的权限查看此实体表。" + } } }, - - "Buttons": { - "AddNewQuest": "加入新任务", - "AddNewTask": "加入新目标" + "DeleteDialog": { + "BodyObjective": "该目标及其数据将被永久删除。", + "BodyQuest": "此任务及其数据将被永久删除。", + "BodyReward": "此奖励及其数据将被永久删除。", + "Cancel": "取消", + "Delete": "删除", + "HeaderDel": "你确定你要删除:

'{name}'

", + "TitleDel": "删除 {title}" }, - - "QuestForm": { - "Title": "添加新任务", - "QuestGiver": "委托人", - "QuestGiverPlaceholder": "角色的名字或ID", - "QuestTitle": "任务标题", - "DragDropActor": "将人物拖到这里以将其设定为委托人", - "QuestDescription": "任务描述", - "QuestGMNotes": "GM笔记", - "Submit": "提交", - "SubquestOf": "是 {name} 的支线任务" + "Labels": { + "AppHeader": { + "ShowPlayers": "展示给玩家" + }, + "Quest": "寻求" + }, + "Migration": { + "ChatMessage": { + "Footer": "您必须使用来自纲要或您的世界的有效文档数据手动更新上述任务。
", + "Header": "Forien 的任务日志 - (DB 洄游)
从以下任务中删除了未链接的任务给予者或奖励物品:

", + "Notification": "Forien 的任务日志 - 从一个或多个任务中删除未链接的任务给予者或奖励物品。请查看聊天消息以获取更多信息。", + "QuestGiver": "任务给予者", + "QuestRewards": "任务奖励" + }, + "Notifications": { + "Complete": "Forien 的任务日志 - 迁移数据完成。", + "CouldNotMigrate": "Forien 的任务日志 - 无法迁移任务:'{name}'。", + "Schema": "Forien 的任务日志 - 将数据迁移到架构版本 '{version}'。", + "Start": "Forien 的任务日志 - 正在迁移数据,请不要重新加载。" + } + }, + "Notifications": { + "CannotOpen": "无法查看任务详情。你可能缺少访问权限,或者该任务ID错误,或者该任务已被删除。", + "FinishQuestAdded": "请在添加另一个任务之前完成编辑并关闭当前的新任务。", + "LinkCopied": "该任务的链接已复制到粘贴板中。", + "QuestAdded": "添加了 '{name}' 作为新任务,状态为:'{status}'。", + "QuestIDCopied": "此任务的任务 ID 已复制到剪贴板。", + "QuestMoved": "移动了 '{name}'并将新状态设置为:'{target}'。", + "QuestPrimary": "'{name}' 是新的主要任务。", + "QuestTrackerNoActive": "任务追踪器已启用,但目前没有正在进行的任务。", + "UserCantOpen": "玩家 '{user}' 没有查看该任务的权限。" }, - "QuestLog": { - "Title": "任务栏", - "SubTitle": "part of: {0}", - "Table": { - "QuestGiver": "委托人", - "QuestTitle": "标题", - "Tasks": "目标", - "Actions": "行动" + "Buttons": { + "AddQuest": "加入新任务" }, - "Tabs": { - "Available": "可选", - "InProgress": "进行中", - "Completed": "已完成", - "Failed": "已失败", - "Hidden": "已隐藏" + "ContextMenu": { + "CopyEntityLink": "复制实体内容链接", + "CopyQuestID": "复制任务 ID", + "PrimaryQuest": "设置/取消设置为主要任务" + }, + "Labels": { + "TableHeader": "{0}任务", + "SubTitle": "的子任务 {0}" + }, + "Title": "任务栏", + "Tooltips": { + "Objectives": "目標" } }, - "QuestPreview": { - "Title": "任务详情", - "Objectives": "目标", - "Rewards": "奖励", - "DragDropRewards": "将物品拖拽到此处以将其设为奖励", - "InvalidQuestId": "无法预览任务:无效的任务ID。", - "HeaderButtons": { - "Show": "展示给玩家" - }, - + "Buttons": { + "RewardCustom": "添加用户定义", + "RewardHide": "全部藏起来", + "RewardLock": "锁定所有", + "RewardShow": "显示所有", + "RewardUnlock": "全部解锁" + }, + "Labels": { + "CustomSource": "自定义来源", + "Description": "描述:", + "DragDropActor": "拖放演员、项目或日记条目或左键单击以设置自定义来源。", + "DragDropActorPlayer": "拖放演员、项目或日记条目。", + "DragDropRewards": "将物品拖拽到此处以将其设为奖励。", + "GMNotes": "GM 笔记:", + "Objective": "客观的", + "Objectives": "目标:", + "PlayerNotes": "玩家 笔记:", + "Reward": "报酬", + "Rewards": "奖励:" + }, "Management": { - "IsPersonalQuest": "个人任务?", - "IsPersonalQuestDescription": "勾选以设置任务为个人任务。该任务将仅对以下被标记的玩家显示。反勾选此选项将移除所有任务权限并将该任务移到“隐藏”标签下。", - "SplashArt": "Splash Art", - "QuestBranching": "支线任务", "AddSubquest": "新建支线任务", - "CanPlayerEdit": "允许玩家修改任务详情" + "ConfigurePermissions": "配置权限", + "QuestBranching": "支线任务:", + "QuestSettings": "任务设置:", + "SplashArt": "插画:", + "SplashInfo": "单击以设置图像。", + "SplashQuestIcon": "设置为任务图标" + }, + "Notifications": { + "BadUUID": "无法检索文档 UUID:'{uuid}'。", + "WrongDocType": "Forien 的任务日志仅接受世界/纲要演员、物品和日记条目作为任务提供者。", + "WrongItemType": "Forien 的任务日志只接受世界和纲要物品作为奖励。" }, - "Tabs": { "Details": "详情", - "QuestManagement": "管理任务", - "GMNotes": "GM笔记" + "GMNotes": "GM笔记", + "PlayerNotes": "玩家 笔记", + "QuestManagement": "管理任务" + }, + "Title": "任务详情", + "Tooltips": { + "AddCustom": "添加用户定义", + "AddObjective": "加入新目标", + "ChangeSplashPos": "更改插画对齐。", + "DeleteQuestGiver": "删除发布者。", + "DeleteSplash": "删除插画。", + "HideAll": "全部藏起来", + "LockAll": "锁定所有", + "PrimaryQuestSet": "单击以进行主要任务。", + "PrimaryQuestUnset": "单击以取消设置主要任务。", + "RewardHidden": "奖励已隐藏,点击查看。", + "RewardLocked": "奖励已锁定。点击解锁。", + "RewardLockedPlayer": "奖励已锁定。", + "RewardUnlocked": "奖励已解锁。点击锁定。", + "RewardUnlockedPlayer": "奖励已解锁。", + "RewardVisible": "奖励已可见,点击隐藏。", + "ShowAll": "显示所有", + "TaskHidden": "目标已隐藏,点击查看。", + "TaskVisible": "目标已可见,点击隐藏。", + "ToggleImage": "打开或关闭token/角色图片。", + "UnlockAll": "全部解锁", + "ViewSplashArt": "查看插图。" } - - }, - - "DeleteDialog": { - "Title": "删除 {name}", - "Header": "确定吗?", - "Body": "该任务及其数据将被永久删除。", - "Delete": "删除", - "Cancel": "取消" }, - - "CloseDialog": { - "Title": "Leave Form", - "Header": "确定吗?", - "Body": "确定你要关闭该表格吗?任何未保存的数据将丢失。", - "Discard": "放弃更改", - "Cancel": "取消" + "QuestTracker": { + "NoPrimary": "没有可用的主要任务。", + "Title": "任务追踪器", + "Tooltips": { + "BackgroundShow": "點擊顯示背景。", + "BackgroundUnshow": "單擊以使背景透明。", + "PrimaryQuestShow": "单击以显示主要任务。", + "PrimaryQuestUnshow": "点击显示所有任务。" + } }, - - "Notifications": { - "CannotOpen": "无法查看任务详情。你可能缺少访问权限,或者该任务ID错误,或者该任务已被删除。", - "UserCantOpen": "玩家 {user} 没有查看该任务的权限。", - "LinkCopied": "该任务的链接已复制到粘贴板中", - "QuestMoved": "移动该任务至新文件夹并更改其状态为:{target}" + "QuestTypes": { + "Labels": { + "Active": "进行中", + "active": "进行中", + "Available": "可用的", + "available": "可用的", + "Completed": "已完成", + "completed": "已完成", + "Failed": "已失败", + "failed": "已失败", + "InActive": "不活跃", + "inactive": "不活跃", + "Status": "任务是 {statusLabel}。" + }, + "Tooltips": { + "SetActive": "设定为进行中", + "SetAvailable": "设定为可选", + "SetCompleted": "设定为已完成", + "SetFailed": "设定为已失败", + "SetInactive": "设置为非活动", + "Status": "地位:{statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "玩家可以接受任务", + "EnableHint": "勾选以允许玩家从可选任务中接受任务。" + }, + "allowPlayersCreate": { + "Enable": "玩家可以新建任务", + "EnableHint": "勾选以允许玩家新建任务。玩家新建的任务将出现在可选任务栏中并且可被玩家编辑。需要给予玩家“新建日志”权限。" + }, "allowPlayersDrag": { - "Enable": "允许玩家拖拽任务奖励。", + "Enable": "允许玩家拖拽任务奖励", "EnableHint": "勾选以允许玩家将奖励物品从任务详情中拖拽到自己的角色卡上。" }, - "availableQuests": { - "Enable": "显示可用标签", - "EnableHint": "勾选以展示任务日志中所有的 \"可选\" 标签。玩家们可以在接下任务前查看所有的非隐藏任务。" - }, "countHidden": { "Enable": "包括隐藏任务数量", "EnableHint": "勾选以将隐藏任务的数量算入已完成任务/所有任务数量中。" }, + "defaultPermissionLevel": { + "Enable": "默认任务权限级别", + "EnableHint": "创建新任务时设置默认权限级别。", + "NONE": "没有任何", + "OBSERVER": "观察者", + "OWNER": "所有者" + }, + "dynamicBookmarkBackground": { + "Enable": "动态书签背景", + "EnableHint": "如果选中,书签选项卡背景将动态设置为窗口内容背景。" + }, + "hideFQLFromPlayers": { + "Enable": "对玩家隐藏任务日志", + "EnableHint": "启用此选项后,将对所有玩家隐藏任务日志。只有 GM 级别的用户才能访问任务日志。" + }, "navStyle": { - "Enable": "导航方式", - "EnableHint": "选择如何展示任务日志的导航。", "bookmarks": "书签", - "classic": "经典标签页" + "classic": "经典标签页", + "Enable": "导航方式", + "EnableHint": "选择如何展示任务日志的导航。" + }, + "notifyRewardDrop": { + "Enable": "显示奖励掉落通知", + "EnableHint": "检查以查看任务奖励被放到玩家表上时的通知。" + }, + "questTrackerResizable": { + "Enable": "任务追踪器可调整大小", + "EnableHint": "选中以允许手动调整 Quest Tracker 的大小控制。" }, "showFolder": { "Enable": "显示任务文件夹", "EnableHint": "勾选以在日志栏中显示目标文件夹。仅用于DEBUG。" }, "showTasks": { + "default": "展示目标:已完成/全部", "Enable": "显示任务栏中的目标", "EnableHint": "选择是否或如何在任务日志栏中展示任务的目标数量。", - "default": "展示目标:已完成/全部", - "onlyCurrent": "展示目标:已完成", - "no": "隐藏 \"目标\" 列表" - }, - "titleAlign": { - "Enable": "任务标题对齐", - "EnableHint": "选择任务栏中任务标题的对齐方式。", - "left": "左对齐", - "center": "居中对齐" - }, - "playersWelcomeScreen": { - "Enable": "向玩家们展示欢迎界面", - "EnableHint": "反勾选以停止在玩家们登陆时向他们展示Mod更新后的欢迎界面。他们仍可以点击任务栏中的\"帮助\"图标来查看更新信息。" - }, - "allowPlayersAccept": { - "Enable": "玩家可以接受任务", - "EnableHint": "勾选以允许玩家从可选任务中接受任务。" + "no": "隐藏 \"目标\" 列表", + "onlyCurrent": "展示目标:已完成" }, - "allowPlayersCreate": { - "Enable": "玩家可以新建任务", - "EnableHint": "勾选以允许玩家新建任务。玩家新建的任务将出现在可选任务栏中并且可被玩家编辑。需要给予玩家“新建日志”权限。" + "trustedPlayerEdit": { + "Enable": "允许可信玩家任务编辑", + "EnableHint": "检查以允许受信任的玩家对他们拥有的任务拥有扩展的任务编辑和状态控制功能。" } }, - "Tooltips": { - "SetAvailable": "设定为可选", - "SetActive": "设定为进行中", - "SetCompleted": "设定为已完成", - "SetFailed": "设定为已失败", - "Hide": "隐藏", "Delete": "删除", - "AddAbstractReward": "加入非物质奖励", - "PersonalQuestButNoPlayers": "这是一个个人任务,但是当前没有被分配给任何玩家", - "PersonalQuestVisibleFor": "该个人任务属于", - "RewardHidden": "奖励已隐藏,点击查看。", - "RewardVisible": "奖励已可见,点击隐藏。", - "TaskHidden": "目标已隐藏,点击查看。", - "TaskVisible": "目标已可见,点击隐藏。", - "ToggleImage": "打开或关闭token/角色图片" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "打开 „{name}” Quest", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Edit": "编辑", + "HiddenQuestNoPlayers": "这个任务对所有玩家都是隐藏的。", + "PrimaryQuest": "主要任务" } } -} +} \ No newline at end of file diff --git a/lang/de.json b/lang/de.json index 472f34b6..4795a935 100644 --- a/lang/de.json +++ b/lang/de.json @@ -1,71 +1,256 @@ { - "ForienQuestLog.QuestLog.Tabs.InProgress": "Laufend", - "ForienQuestLog.QuestLog.Tabs.Completed": "Abgeschlossen", - "ForienQuestLog.QuestLog.Tabs.Failed": "Fehlgeschlagen", - "ForienQuestLog.QuestLog.Tabs.Hidden": "Verborgen", - - "ForienQuestLog.QuestPreview.Tabs.Details": "Details", - "ForienQuestLog.QuestPreview.Tabs.GMNotes": "GM Notes", - "ForienQuestLog.NewQuest": "Neue Queste", - - "ForienQuestLog.Notifications.QuestMoved": "Die Queste wurde in einen neuen Ordner verschoben und hat nun den Status: {target}", - - "ForienQuestLog.Buttons.AddNewQuest": "Neue Queste", - "ForienQuestLog.Buttons.AddNewTask": "Hinzufügen", - - "ForienQuestLog.QuestTypes.InProgress": "Laufende", - "ForienQuestLog.QuestTypes.Completed": "Abgeschlossene", - "ForienQuestLog.QuestTypes.Failed": "Fehlgeschlagene", - "ForienQuestLog.QuestTypes.Hidden": "Verborgene", - "ForienQuestLog.Quests": "Questen", - "ForienQuestLog.QuestLog.Table.QuestGiver": "Auftraggeber", - "ForienQuestLog.QuestLog.Table.QuestTitle": "Titel", - "ForienQuestLog.QuestLog.Table.Tasks": "Aufgaben", - "ForienQuestLog.QuestLog.Table.Actions": "Aktionen", - "ForienQuestLog.QuestPreview.Objectives": "Ziele", - "ForienQuestLog.QuestPreview.Rewards": "Belohnungen", - - "ForienQuestLog.Settings.showTasks.Enable": "Zeige Aufgaben im Questenlog", - "ForienQuestLog.Settings.showTasks.EnableHint": "Lege fest ob und wie die Menge von Aufgaben (Zielen) neben dem Titel der Queste im Questenlog angezeigt wird. Dies hat keine Auswirkung auf die Vorschau einer individuellen Queste.", - "ForienQuestLog.Settings.showTasks.default": "Zeige Aufgaben: Beendet/Gesamt", - "ForienQuestLog.Settings.showTasks.onlyCurrent": "Zeige Aufgaben: Beendet", - "ForienQuestLog.Settings.showTasks.no": "Verberge \"Aufgaben\"-Spalte", - - "ForienQuestLog.Settings.navStyle.Enable": "Navigationsstil", - "ForienQuestLog.Settings.navStyle.EnableHint": "Lege fest, wie die Navigation im Questenlog angezeigt werden soll.", - "ForienQuestLog.Settings.navStyle.bookmarks": "Lesezeichen", - "ForienQuestLog.Settings.navStyle.classic": "Klassische Reiter", - - "ForienQuestLog.Settings.titleAlign.Enable": "Titelausrichtung der Queste", - "ForienQuestLog.Settings.titleAlign.EnableHint": "Lege fest, wie die Titel der Questen in der Tabelle im Questenlog positioniert werden sollen.", - "ForienQuestLog.Settings.titleAlign.left": "Linksbündig", - "ForienQuestLog.Settings.titleAlign.center": "Zentriert", - - "ForienQuestLog.QuestLogButton": "Questenlog", - "ForienQuestLog.QuestForm.Title": "Neue Queste anlegen", - "ForienQuestLog.QuestLog.Title": "Questenlog", - "ForienQuestLog.QuestPreview.Title": "Details zur Queste", - - "ForienQuestLog.QuestForm.QuestGiver": "Auftraggeber", - "ForienQuestLog.QuestForm.QuestGiverPlaceholder": "Name oder ID des Actors", - "ForienQuestLog.QuestForm.QuestTitle": "Titel der Queste", - "ForienQuestLog.QuestForm.QuestDescription": "Beschreibung der Queste", - "ForienQuestLog.QuestForm.QuestGMNotes": "GM notes", - "ForienQuestLog.QuestForm.Submit": "Übermitteln", - - "ForienQuestLog.SampleTask": "z.B. Töte alle Ratten in der Schänke „Zum verstauchten Knöchel”", - "ForienQuestLog.QuestPreview.DragDropRewards": "Ziehe Gegenstände hier hinein, um sie als Belohnung hinzuzufügen", - - "ForienQuestLog.DeleteDialog.Title": "Lösche {name}", - "ForienQuestLog.DeleteDialog.Header": "Bist du sicher?", - "ForienQuestLog.DeleteDialog.Body": "Diese Queste und ihre Daten werden permanent gelöscht.", - "ForienQuestLog.DeleteDialog.Delete": "Löschen", - "ForienQuestLog.DeleteDialog.Cancel": "Abbrechen", - - "ForienQuestLog.Tooltips.ToggleImage": "Bild des Token/Actor umschalten", - "ForienQuestLog.Tooltips.SetActive": "Stelle auf Laufend", - "ForienQuestLog.Tooltips.SetCompleted": "Stelle auf Beendet", - "ForienQuestLog.Tooltips.SetFailed": "Stelle auf Fehlgeschlagen", - "ForienQuestLog.Tooltips.Hide": "Verbergen", - "ForienQuestLog.Tooltips.Delete": "Löschen" -} + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Offen ”{name}”" + }, + "Notifications": { + "NoQuest": "API-Fehler: Makro kann mit ungültiger Quest-ID nicht erstellt werden." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Neue Quest" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (Questbelohnung): {userName} hat '{itemName}' auf {actorName} gezogen." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Entität mit UUID '{uuid}' konnte nicht geladen werden.", + "NoPermission": "Du verfügst nicht über die nötigen Berechtigungen, um den Bogen dieser Entität einzusehen." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Dieses Ziel und die zugehörigen Daten werden permanent gelöscht.", + "BodyQuest": "Diese Quest und die zugehörigen Daten werden permanent gelöscht.", + "BodyReward": "Diese Belohnung und die zugehörigen Daten werden permanent gelöscht.", + "Cancel": "Abbrechen", + "Delete": "Löschen", + "HeaderDel": "Bist du sicher, dass du

'{name}'

lĂśschen willst", + "TitleDel": "{title} lĂśschen" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Spielern zeigen" + }, + "Quest": "Quest" + }, + "Migration": { + "ChatMessage": { + "Footer": "Du musst die obigen Quests manuell mit gĂźltigen Dokumentdaten aus Kompendien oder deiner Welt aktualisieren.
", + "Header": "Forien's Questlog (DB-Migration)
Unverlinkte(r) Questgeber oder Questbelohnung von unten stehenden Quests entfernt:

", + "Notification": "Forien's Questlog - Unverlinkte(r) Questgeber oder Questbelohnung von mindestens einer Quest entfernt. Bitte Chatnachrichten für mehr Informationen nachlesen.", + "QuestGiver": "Questgeber", + "QuestRewards": "Questbelohnungen" + }, + "Notifications": { + "Complete": "Foriens Questlog - Migration der Daten abgeschlossen.", + "CouldNotMigrate": "Foriens Questlog - Quest konnte nicht migriert werden: '{name}'.", + "Schema": "Foriens Questlog - Migriere Daten zu Schema-Version '{version}'.", + "Start": "Foriens Questlog - Daten werden migriert, bitte nicht neu laden." + } + }, + "Notifications": { + "CannotOpen": "Questdetails können nicht geöffnet werden. Möglicherweise kann die Quest nicht betrachtet werden oder existiert nicht mehr.", + "FinishQuestAdded": "Bitte schließe das Bearbeiten der Quest ab und schließe sie, bevor du eine neue hinzufügst.", + "LinkCopied": "Entitätslink für diese Quest wurde in die Zwischenablage kopiert.", + "QuestAdded": "'{name}' als neue Quest mit Status '{status}' hinzugefügt.", + "QuestIDCopied": "Quest-ID für diese Quest wurde in die Zwischenablage kopiert.", + "QuestMoved": "'{name}' verschoben und Ziel gesetzt auf: '{target}'.", + "QuestPrimary": "'{name}' ist die neue primäre Quest.", + "QuestTrackerNoActive": "Questtracker ist aktiviert, aber aktuell gibt es keine aktiven Quests.", + "UserCantOpen": "Benutzer '{user}' hat nicht die Berechtigungen, um diese Quest zu öffnen." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Quest hinzufügen" + }, + "ContextMenu": { + "CopyEntityLink": "Entität-Link kopieren", + "CopyQuestID": "Kopieren Sie Quest-ID", + "PrimaryQuest": "Als primäre Quest (de)aktivieren" + }, + "Labels": { + "TableHeader": "{0} Quests", + "SubTitle": "Unterquest von {0}" + }, + "Title": "Questlog", + "Tooltips": { + "Objectives": "Ziele" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Benutzerdefinierten", + "RewardHide": "Verbergen", + "RewardLock": "Sperren", + "RewardShow": "Anzeigen", + "RewardUnlock": "Entsperren" + }, + "Labels": { + "CustomSource": "Eigene Quelle", + "Description": "Beschreibung:", + "DragDropActor": "Akteur, Gegenstand oder Notizbucheintrag hierher ziehen oder linksklicken, um sie als eigene Quelle festzulegen.", + "DragDropActorPlayer": "Akteur, Gegenstand oder Notizbucheintrag hierher ziehen.", + "DragDropRewards": "Gegenstände hierher ziehen, um sie als Belohnung festzulegen.", + "GMNotes": "GM-Notizen:", + "Objective": "Ziel", + "Objectives": "Ziele:", + "PlayerNotes": "Spielernotizen:", + "Reward": "Belohnung", + "Rewards": "Belohnungen:" + }, + "Management": { + "AddSubquest": "Unterquest hinzufügen", + "ConfigurePermissions": "Berechtigungen Konfigurieren", + "QuestBranching": "Unterquests:", + "QuestSettings": "Questeinstellungen:", + "SplashArt": "Titelbild:", + "SplashInfo": "Klicken, um Titelbild zu setzen.", + "SplashQuestIcon": "Als Questicon setzen" + }, + "Notifications": { + "BadUUID": "Konnte Dokument mit UUID {uuid} nicht abrufen.", + "WrongDocType": "Foriens Questlog akzeptnur Welt-/Kompendium-Akteure, -Items und -Notizbucheinträge als Questgeber.", + "WrongItemType": "Foriens Questlog akzeptiert nur Welt- und Kompendium-Items als Belohnungen." + }, + "Tabs": { + "Details": "Details", + "GMNotes": "GM-Notizen", + "PlayerNotes": "Spielernotizen", + "QuestManagement": "Quest verwalten" + }, + "Title": "Questdetails - {name}", + "Tooltips": { + "AddCustom": "Benutzerdefiniert Hinzufügen", + "AddObjective": "Ziel hinzufügen", + "ChangeSplashPos": "Splash-Bildausrichtung ändern.", + "DeleteQuestGiver": "Questgeber löschen.", + "DeleteSplash": "Splash Art löschen.", + "HideAll": "Alle verbergen", + "LockAll": "Alle sperren", + "PrimaryQuestSet": "Anklicken, um als primäre Quest zu setzen.", + "PrimaryQuestUnset": "Anklicken, um primäre Quest aufzuheben.", + "RewardHidden": "Belohnung verborgen. Anklicken zum Anzeigen.", + "RewardLocked": "Belohnung ist gesperrt. Klicken zum Entsperren.", + "RewardLockedPlayer": "Belohnung ist gesperrt.", + "RewardUnlocked": "Belohnung ist entsperrt. Klicken zum Sperren.", + "RewardUnlockedPlayer": "Belohung ist entsperrt.", + "RewardVisible": "Belohnung ist sichtbar. Anklicken zum Verbergen.", + "ShowAll": "Alle anzeigen", + "TaskHidden": "Ziel ist verborgen. Anklicken zum Anzeigen.", + "TaskVisible": "Ziel ist sichtbar. Anklicken zum Verbergen.", + "ToggleImage": "Figur/Akteur-Bild umschalten.", + "UnlockAll": "Alle entsperren", + "ViewSplashArt": "Titelfoto ansehen." + } + }, + "QuestTracker": { + "NoPrimary": "Keine primäre Quest verfügbar.", + "Title": "Questtracker", + "Tooltips": { + "BackgroundShow": "Anklicken, um Hintergrund anzuzeigen.", + "BackgroundUnshow": "Für transparenten Hintergrund klicken.", + "PrimaryQuestShow": "Anklicken, um primäre Quest anzuzeigen.", + "PrimaryQuestUnshow": "Anklicken, um alle Quests anzuzeigen." + } + }, + "QuestTypes": { + "Labels": { + "Active": "Aktive", + "active": "aktiv", + "Available": "Verfügbare", + "available": "verfügbar", + "Completed": "Abgeschlossene", + "completed": "abgeschlossen", + "Failed": "Fehlgeschlagene", + "failed": "fehlgeschlagen", + "InActive": "Inaktive", + "inactive": "inaktiv", + "Status": "Quest ist {statusLabel}." + }, + "Tooltips": { + "SetActive": "Als Aktiv setzen", + "SetAvailable": "Als Verfügbar setzen", + "SetCompleted": "Als abgeschlossen setzen", + "SetFailed": "Als Fehlgeschlagen setzen", + "SetInactive": "Als Inaktiv setzen", + "Status": "Status: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Spieler können Quests annehmen", + "EnableHint": "Aktivieren, um Spielern zu erlauben, Quests aus dem Verfügbar-Reiter anzunehmen." + }, + "allowPlayersCreate": { + "Enable": "Spieler können Quests erstellen", + "EnableHint": "Aktivieren, um Spielern zu erlauben, Quests zu erstellen. Von Spielern erstellte Quests erscheinen im Verfügbar-Reiter mit Bearbeitungsrechten für Spieler. BENÖTIGT Kernberechtigung 'Notizbucheinträge erstellen'." + }, + "allowPlayersDrag": { + "Enable": "Spielern das Ziehen von Belohnungen erlauben", + "EnableHint": "Aktivieren, um Spielern zu erlauben, Belohnungen aus dem Questdetailfenster auf Akteure in ihrem Besitz zu ziehen." + }, + "countHidden": { + "Enable": "Verborgene Ziele mitzählen", + "EnableHint": "Aktivieren, um verborgene Ziele bei abgeschlossenen/gesamten Zielen mitzuzählen." + }, + "defaultPermissionLevel": { + "Enable": "Standard-Berechtigungen für Quests", + "EnableHint": "Setzt das Standard-Berechtigungslevel für neu erstellte Quests.", + "NONE": "Nichts", + "OBSERVER": "Beobachter", + "OWNER": "Besitzer" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynamischer Lesezeichenhintergrund", + "EnableHint": "Aktivieren, um den Fensterinhalt dynamisch als den Hintergrund für den Lesezeichenreiter zu setzen." + }, + "hideFQLFromPlayers": { + "Enable": "Questlog für Spieler verbergen", + "EnableHint": "Aktivieren, um das Questlog für alle Spieler zu verbergen. Nur GM-Benutzer können auf das Questlog zugreifen." + }, + "navStyle": { + "bookmarks": "Lesezeichen", + "classic": "Klassische Reiter", + "Enable": "Navigationsstil", + "EnableHint": "Festlegen, wie die Navigation in Foriens Questlog angezeigt wird." + }, + "notifyRewardDrop": { + "Enable": "Bei Ziehen von Belohnungen benachrichtigen", + "EnableHint": "Aktivieren, um eine UI-Benachrichtigung zu erhalten, wenn Questbelohnungen auf Spielerbögen gezogen werden." + }, + "questTrackerResizable": { + "Enable": "Questtracker skalierbar", + "EnableHint": "Aktivieren, um zu erlauben, dass manuell die Größe des Questtrackers verändert werden kann." + }, + "showFolder": { + "Enable": "Questordner anzeigen", + "EnableHint": "Aktivieren, um den Questdaten-Ordner im Notizbuchreiter anzuzeigen. Nur für DEBUG-Zwecke." + }, + "showTasks": { + "default": "Ziele zeigen: abgeschlossen/gesamt", + "Enable": "Ziele im Questlog anzeigen", + "EnableHint": "Lege fest, ob und wie die Zahl der Ziele neben dem Questtitel im Questlog angezeigt wird. Dies betrifft nicht die Quest-Vorschau.", + "no": "Verberge \"Ziele\" Spalte", + "onlyCurrent": "Ziele zeigen: abgeschlossen" + }, + "trustedPlayerEdit": { + "Enable": "Erlaube Seriösen Spielern das Bearbeiten von Quests", + "EnableHint": "Aktivieren, um Seriösen Spielern (Trusted Players) erweiterte Bearbeitungsmöglichkeiten und Statusänderungen für Quests, die sie kontrollieren einzuräumen." + } + }, + "Tooltips": { + "Delete": "Löschen", + "Edit": "Bearbeiten", + "HiddenQuestNoPlayers": "Diese Quest ist vor allen Spielern verborgen.", + "PrimaryQuest": "Primäre Quest" + } + } +} \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index 0fa3c444..a4d5ef19 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,205 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "New Quest", - "QuestLogButton": "Quest Log", - "Quests": "{0} Quests", - "SampleReward": "e.g. 300 Experience Points", - "SampleTask": "e.g. Kill all rats in „The Twisted Ankle” inn", - - "QuestTypes": { - "InProgress": "Active", - "Completed": "Completed", - "Failed": "Failed", - "Hidden": "Inactive", - "Labels": { - "available": "available", - "active": "in progress", - "completed": "completed", - "failed": "failed", - "hidden": "inactive" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Open ”{name}”" + }, + "Notifications": { + "NoQuest": "API Error: Can't create macro with invalid Quest ID." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "New Quest" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (quest reward): {userName} dropped '{itemName}' onto {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "An entity could not be loaded for UUID: '{uuid}'.", + "NoPermission": "You do not have sufficient permissions to view this entity sheet." + } } }, - - "Buttons": { - "AddNewQuest": "Add new Quest", - "AddNewTask": "Add new Objective", - "AddNewFolder": "Add new Folder" + "DeleteDialog": { + "BodyObjective": "This objective and its data will be permanently deleted.", + "BodyQuest": "This quest and its data will be permanently deleted.", + "BodyReward": "This reward and its data will be permanently deleted.", + "Cancel": "Cancel", + "Delete": "Delete", + "HeaderDel": "Are you sure you want to delete:

'{name}'

", + "TitleDel": "Delete {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Show to Players" + }, + "Quest": "Quest" }, - - "QuestForm": { - "Title": "Add new Quest", - "QuestGiver": "Quest Source", - "QuestGiverPlaceholder": "Enter Actor's name or entity's UUID to set a Quest Source", - "QuestGiverNamePlaceholder": "You selected custom image, please provide name for Quest Source", - "QuestTitle": "Quest Title", - "DragDropActor": "Drag & Drop Actor, Item or Journal Entry here to set a Quest Source", - "QuestDescription": "Quest Description", - "QuestGMNotes": "GM Notes", - "Submit": "Add to Quest Log", - "SubquestOf": "Subquest of {name}" + "Migration": { + "ChatMessage": { + "Footer": "You must manually update the above quests with valid document data from compendiums or your world.
", + "Header": "Forien's Quest Log (DB migration)
Removed unlinked quest giver or reward items from the quests below:

", + "Notification": "Forien's Quest Log - Removed unlinked quest giver or reward items from one or more quests. Please review the chat message for more info.", + "QuestGiver": "Quest Giver", + "QuestRewards": "Quest Rewards" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migrating data complete.", + "CouldNotMigrate": "Forien's Quest Log - Could not migrate quest: '{name}'.", + "Schema": "Forien's Quest Log - Migrating data to schema version '{version}'.", + "Start": "Forien's Quest Log - Migrating data, please do not reload." + } + }, + "Notifications": { + "CannotOpen": "Cannot open Quest Details. This quest may not be observable or may no longer exist.", + "FinishQuestAdded": "Please finish editing and close current new quest before adding another.", + "LinkCopied": "Entity Link for this quest has been copied to clipboard.", + "QuestAdded": "Added '{name}' as a new quest with status: '{status}'.", + "QuestIDCopied": "Quest ID for this quest has been copied to clipboard.", + "QuestMoved": "Moved '{name}' and set new status to: '{target}'.", + "QuestPrimary": "'{name}' is the new primary quest.", + "QuestTrackerNoActive": "Quest Tracker is enabled, but there are currently no in progress quests.", + "UserCantOpen": "User '{user}' doesn't have permission to open this quest." }, - "QuestLog": { - "Title": "Quest Log", - "SubTitle": "Subquest of {0}", - "Table": { - "QuestGiver": "Quest Source", - "QuestTitle": "Title", - "Tasks": "Objectives", - "Actions": "Actions" + "Buttons": { + "AddQuest": "Add Quest" }, - "Tabs": { - "Available": "Available", - "InProgress": "In progress", - "Completed": "Completed", - "Failed": "Failed", - "Hidden": "Inactive" + "ContextMenu": { + "CopyEntityLink": "Copy entity content link", + "CopyQuestID": "Copy quest ID", + "PrimaryQuest": "Set / Unset as primary quest" + }, + "Labels": { + "TableHeader": "{0} Quests", + "SubTitle": "Subquest of {0}" + }, + "Title": "Quest Log", + "Tooltips": { + "Objectives": "Objectives" } }, - "QuestPreview": { - "Title": "Quest Details", - "SubTitle": "Subquest of {0}", - "Objectives": "Objectives", - "Rewards": "Rewards", - "DragDropRewards": "Drag & drop items here to add them as rewards", - "InvalidQuestId": "Cannot open Quest Preview due to invalid Quest ID.", - "HeaderButtons": { - "Show": "Show to Players" - }, - + "Buttons": { + "RewardCustom": "Custom", + "RewardHide": "Hide", + "RewardLock": "Lock", + "RewardShow": "Show", + "RewardUnlock": "Unlock" + }, + "Labels": { + "CustomSource": "Custom Source", + "Description": "Description:", + "DragDropActor": "Drag & Drop Actor, Item or Journal Entry or left click to set a custom source.", + "DragDropActorPlayer": "Drag & Drop Actor, Item or Journal Entry.", + "DragDropRewards": "Drag & drop items here to add them as rewards.", + "GMNotes": "GM Notes:", + "Objective": "Objective", + "Objectives": "Objectives:", + "PlayerNotes": "Player Notes:", + "Reward": "Reward", + "Rewards": "Rewards:" + }, "Management": { - "IsPersonalQuest": "Mark Quest as Personal", - "IsPersonalQuestDescription": "This Quest will only be visible to the selected players. Unchecking this option will remove all permissions and set the quest as inactive.", - "SplashArt": "Splash Art", - "QuestBranching": "Sub Quests", - "AddSubquest": "Create new Sub Quest", - "CanPlayerEdit": "Allow Players to edit Quest Details" - }, - + "AddSubquest": "Add Subquest", + "ConfigurePermissions": "Configure Permissions", + "QuestBranching": "Subquests:", + "QuestSettings": "Quest Settings:", + "SplashArt": "Splash Art:", + "SplashInfo": "Click to set image.", + "SplashQuestIcon": "Set as quest icon" + }, + "Notifications": { + "BadUUID": "Could not retrieve the document for UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log only accepts world / compendium actors, items, and journal entries as quest givers.", + "WrongItemType": "Forien's Quest Log only accepts world and compendium items as rewards." + }, "Tabs": { "Details": "Details", - "QuestManagement": "Manage Quest", - "GMNotes": "GM Notes" + "GMNotes": "GM Notes", + "PlayerNotes": "Player Notes", + "QuestManagement": "Manage Quest" + }, + "Title": "Quest Details - {name}", + "Tooltips": { + "AddCustom": "Add Custom", + "AddObjective": "Add Objective", + "ChangeSplashPos": "Change splash art alignment.", + "DeleteQuestGiver": "Delete quest giver.", + "DeleteSplash": "Delete splash art.", + "HideAll": "Hide All", + "LockAll": "Lock All", + "PrimaryQuestSet": "Click to make primary quest.", + "PrimaryQuestUnset": "Click to unset primary quest.", + "RewardHidden": "Reward is hidden. Click to show.", + "RewardLocked": "Reward is locked. Click to unlock.", + "RewardLockedPlayer": "Reward is locked.", + "RewardUnlocked": "Reward is unlocked. Click to lock.", + "RewardUnlockedPlayer": "Reward is unlocked.", + "RewardVisible": "Reward is visible. Click to hide.", + "ShowAll": "Show All", + "TaskHidden": "Objective is hidden. Click to show.", + "TaskVisible": "Objective is visible. Click to hide.", + "ToggleImage": "Toggle Token/Actor image.", + "UnlockAll": "Unlock All", + "ViewSplashArt": "View splash art." } - - }, - - "DeleteDialog": { - "Title": "Delete {name}", - "Header": "Are you sure?", - "Body": "This quest and its data will be permanently deleted.", - "Delete": "Delete", - "Cancel": "Cancel" }, - - "CloseDialog": { - "Title": "Leave Form", - "Header": "Are you sure?", - "Body": "Are you sure you want to close the form? Unsaved data will be lost.", - "Discard": "Discard changes", - "Cancel": "Cancel" + "QuestTracker": { + "NoPrimary": "No primary quest available.", + "Title": "Quest Tracker", + "Tooltips": { + "BackgroundShow": "Click to show background.", + "BackgroundUnshow": "Click to make background transparent.", + "PrimaryQuestShow": "Click to show primary quest.", + "PrimaryQuestUnshow": "Click to show all quests." + } }, - - "Notifications": { - "CannotOpen": "Cannot open Quest Details. You may lack permissions, Quest might not exist anymore, or provided ID was invalid.", - "UserCantOpen": "User {user} doesn't have permission to open this quest.", - "LinkCopied": "Entity Link for this quest has been copied to clipboard.", - "QuestMoved": "Moved quest to new folder and gave it new status: {target}." + "QuestTypes": { + "Labels": { + "Active": "In Progress", + "active": "in progress", + "Available": "Available", + "available": "available", + "Completed": "Completed", + "completed": "completed", + "Failed": "Failed", + "failed": "failed", + "InActive": "Inactive", + "inactive": "inactive", + "Status": "Quest is {statusLabel}." + }, + "Tooltips": { + "SetActive": "Set as In Progress", + "SetAvailable": "Set as Available", + "SetCompleted": "Set as Completed", + "SetFailed": "Set as Failed", + "SetInactive": "Set as Inactive", + "Status": "Status: {statusI18n}" + } }, - "Settings": { - "allowPlayersDrag": { - "Enable": "Allow Players to drag Rewards to their Inventory", - "EnableHint": "Check to allow Players to drag Rewards from a Quest Details window to their owned Actors." + "allowPlayersAccept": { + "Enable": "Players can accept Quests", + "EnableHint": "Check to allow players to accept Quests from Available tab." }, - "availableQuests": { - "Enable": "Show Available Tab", - "EnableHint": "Check to show the \"Available\" tab in the Quest Log Menu where players can see all non-inactive Quests before they are accepted." + "allowPlayersCreate": { + "Enable": "Players can create Quests", + "EnableHint": "Check to allow players to create Quests. Player created Quests will appear in Available tab with Player Edit permissions. REQUIRES 'create journal' core permission." + }, + "allowPlayersDrag": { + "Enable": "Allow Player Reward Dragging", + "EnableHint": "Check to allow Players to drag Rewards from the Quest Details window to their owned Actors." }, "countHidden": { - "Enable": "Count hidden Tasks", - "EnableHint": "If checked, the number of completed/total tasks will include hidden tasks." + "Enable": "Count hidden objectives", + "EnableHint": "If checked, the number of completed / total objectives will include hidden objectives." + }, + "defaultPermissionLevel": { + "Enable": "Default quest permission level", + "EnableHint": "Sets the default permission level when new quests are created.", + "NONE": "None", + "OBSERVER": "Observer", + "OWNER": "Owner" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynamic Bookmark Background", + "EnableHint": "If checked, the bookmark tab background is dynamically set to the window content background." + }, + "hideFQLFromPlayers": { + "Enable": "Hide Quest Log from players", + "EnableHint": "When enabled this option hides the Quest Log from all players. Only GM level users will be able to access the Quest Log." }, "navStyle": { - "Enable": "Navigation Style", - "EnableHint": "Decide how Quest Log's navigation should be displayed.", "bookmarks": "Bookmarks", - "classic": "Classic tabs" + "classic": "Classic tabs", + "Enable": "Navigation Style", + "EnableHint": "Decide how Quest Log's navigation should be displayed." + }, + "notifyRewardDrop": { + "Enable": "Show Reward Drop Notifications", + "EnableHint": "Check to see UI notifications when quest rewards are dropped onto player sheets." + }, + "questTrackerResizable": { + "Enable": "Quest Tracker Resizable", + "EnableHint": "Check to allow manual resizing control of the Quest Tracker." }, "showFolder": { "Enable": "Show Quest Folder", "EnableHint": "Check to show quest data folder in Journal tab. For DEBUG purposes only." }, "showTasks": { - "Enable": "Show tasks in Quest Log", - "EnableHint": "Decide if or how to show the amount of Objectives next to the Quest Title in Quest Log. This has no effect on the Quest Preview.", "default": "Show Objectives: done/total", - "onlyCurrent": "Show Objectives: done", - "no": "Hide \"Objectives\" column" - }, - "titleAlign": { - "Enable": "Quest Title Alignment", - "EnableHint": "Decide how to position Quest Titles in the Quest Log Table.", - "left": "Aligned to left", - "center": "Centered" - }, - "playersWelcomeScreen": { - "Enable": "Display Welcome Screen to Players", - "EnableHint": "Uncheck to prevent players from seeing Welcome Screen on log in after an update. They might still see it by clicking 'help' icon in Quest Log." - }, - "allowPlayersAccept": { - "Enable": "Players can accept Quests", - "EnableHint": "Check to allow players to accept Quests from Available tab." + "Enable": "Show objectives in Quest Log", + "EnableHint": "Decide if or how to show the amount of Objectives next to the Quest Title in Quest Log. This has no effect on the Quest Preview.", + "no": "Hide \"Objectives\" column", + "onlyCurrent": "Show Objectives: done" }, - "allowPlayersCreate": { - "Enable": "Players can create", - "EnableHint": "Check to allow players to create Quests. Player created Quests will appear in Available tab with Player Edit permissions. REQUIRES 'create journal' core permission." + "trustedPlayerEdit": { + "Enable": "Allow Trusted Player Quest Editing", + "EnableHint": "Check to allow trusted players to have expanded quest editing and status control capabilities over quests they have ownership." } }, - "Tooltips": { - "SetAvailable": "Set as Available", - "SetActive": "Set as In Progress", - "SetCompleted": "Set as Completed", - "SetFailed": "Set as Failed", - "Hide": "Set as Inactive", "Delete": "Delete", "Edit": "Edit", - "AddAbstractReward": "Add Abstract Reward", - "PersonalQuestButNoPlayers": "This is a Personal Quest, but no Players are assigned", - "PersonalQuestVisibleFor": "This is a Personal Quest for", - "RewardHidden": "Reward is hidden. Click to show.", - "RewardVisible": "Reward is visible. Click to hide.", - "TaskHidden": "Objective is hidden. Click to show.", - "TaskVisible": "Objective is visible. Click to hide.", - "ToggleImage": "Toggle Token/Actor image" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "Open „{name}” Quest", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Objective" - } - } + "HiddenQuestNoPlayers": "This Quest is hidden from all players.", + "PrimaryQuest": "Primary Quest" } } -} +} \ No newline at end of file diff --git a/lang/es.json b/lang/es.json index e0407e5d..a7288cd1 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1,195 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "Nueva misión", - "QuestLogButton": "Misiones", - "Quests": "{0} Misiones", - "SampleReward": "p.ej. 300 puntos de experiencia", - "SampleTask": "p.ej. Exterminar las ratas de la posada \"El tobillo torcido\"", - - "QuestTypes": { - "InProgress": "En curso", - "Completed": "Completadas", - "Failed": "Fallidas", - "Hidden": "Ocultas" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Abrir ”{name}”" + }, + "Notifications": { + "NoQuest": "API Error: No se puede crear la macro sin un Quest ID valido." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nueva misión" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (recompensa de misión): {userName} entregó '{itemName}' a {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "No se pudo cargar una entidad para UUID: '{uuid}'.", + "NoPermission": "No tiene suficientes permisos para ver esta hoja de entidad." + } + } }, - - "Buttons": { - "AddNewQuest": "Añadir nueva misión", - "AddNewTask": "Añadir" + "DeleteDialog": { + "BodyObjective": "Este objetivo y sus datos serán eliminados de forma permanente.", + "BodyQuest": "Esta misión y sus datos se eliminarán de forma permanente.", + "BodyReward": "Esta recompensa y sus datos se eliminarán de forma permanente.", + "Cancel": "Cancelar", + "Delete": "Eliminar", + "HeaderDel": "¿Estás seguro de que quieres eliminar?

'{name}'

", + "TitleDel": "Eliminar {title}" }, - - "QuestForm": { - "Title": "AĂąadir nueva misiĂłn", - "QuestGiver": "Dador de la misiĂłn", - "QuestGiverPlaceholder": "Nombre del Actor o UUID de la entidad", - "QuestTitle": "Nombre de la misiĂłn", - "DragDropActor": "Arrastra y suelta el Actor, Objeto o Apunte aquĂ­ para establecerlo como dador de la misiĂłn", - "QuestDescription": "DescripciĂłn de la misiĂłn", - "QuestGMNotes": "Notas del GM", - "Submit": "Crear", - "SubquestOf": "SubmisiĂłn de {name}" + "Labels": { + "AppHeader": { + "ShowPlayers": "Mostrar a jugadores" + }, + "Quest": "MisiĂłn" + }, + "Migration": { + "ChatMessage": { + "Footer": "Debes actualizar manualmente las misiones anteriores con datos de documentos vĂĄlidos de compendios o de tu mundo.
", + "Header": "Forien's Quest Log (DB migraciĂłn)
Se eliminaron los elementos de recompensa o no se encuentra al dador de las misiones a continuaciĂłn:

", + "Notification": "Forien's Quest Log - Se eliminó al dador de misiones o los elementos de recompensa de una o más misiones. Revise el mensaje de chat para obtener más información.", + "QuestGiver": "Dador de Misión", + "QuestRewards": "Recompensas de Misión" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migración de datos completa.", + "CouldNotMigrate": "Forien's Quest Log - No se pudo migrar la misión: '{name}'.", + "Schema": "Forien's Quest Log - Migración de datos a la versión del esquema '{version}'.", + "Start": "Forien's Quest Log - Migrando datos, por favor no recargar." + } + }, + "Notifications": { + "CannotOpen": "No puedes abrir los detalles de la misión. Puede que te falten permisos, que la misión ya no exista o que el ID sea inválido.", + "FinishQuestAdded": "Termina de editar y cierra la nueva misión actual antes de agregar otra.", + "LinkCopied": "El enlace a la entidad de esta misión ha sido copiado al portapapeles.", + "QuestAdded": "Se agregó '{name}' como una nueva misión con estado: '{status}'.", + "QuestIDCopied": "El ID de misión para esta misión se ha copiado al portapapeles.", + "QuestMoved": "Se movió '{name}' y se estableció el nuevo estado en: '{target}'.", + "QuestPrimary": "'{name}' es la nueva misión principal.", + "QuestTrackerNoActive": "Seguimiento de Misiones está habilitado, pero no hay misiones en curso actualmente.", + "UserCantOpen": "El usuario '{user}' no tiene permisos para abrir esta misión." }, - "QuestLog": { - "Title": "Misiones", - "SubTitle": "parte de: {0}", - "Table": { - "QuestGiver": "Dador de la misión", - "QuestTitle": "Nombre", - "Tasks": "Tareas", - "Actions": "Acciones" + "Buttons": { + "AddQuest": "Añadir misión" }, - "Tabs": { - "Available": "Disponibles", - "InProgress": "En curso", - "Completed": "Completadas", - "Failed": "Fallidas", - "Hidden": "Ocultas" + "ContextMenu": { + "CopyEntityLink": "Copiar enlace de contenido de entidad", + "CopyQuestID": "Copiar ID de misión", + "PrimaryQuest": "Establecer / Desestablecer como misión principal" + }, + "Labels": { + "TableHeader": "Misiones {0}", + "SubTitle": "Sub-Misión de: {0}" + }, + "Title": "Registro de Misiones", + "Tooltips": { + "Objectives": "Objetivos" } }, - "QuestPreview": { - "Title": "Detalles de la misión", - "SubTitle": "parte de: {0}", - "Objectives": "Objetivos", - "Rewards": "Recompensas", - "DragDropRewards": "Arrastra y suelta elementos aquí para añadirlos como recompensas", - "InvalidQuestId": "No se puede abrir la vista previa de la misión debido a que el ID de la misión no es válido", - "HeaderButtons": { - "Show": "Mostrar a jugadores" - }, - + "Buttons": { + "RewardCustom": "Personalizado", + "RewardHide": "Ocultar", + "RewardLock": "Bloquear", + "RewardShow": "Mostrar", + "RewardUnlock": "Desbloquear" + }, + "Labels": { + "CustomSource": "Fuente Personalizada", + "Description": "Descripción:", + "DragDropActor": "Arrastre y suelte al actor, elemento o entrada de diario o haga clic con el botón izquierdo para establecer una fuente personalizada.", + "DragDropActorPlayer": "Arrastrar y Soltar actor, elemento o entrada de diario.", + "DragDropRewards": "Arrastra y Suelta elementos aquí para añadirlos como recompensas.", + "GMNotes": "Notas del GM:", + "Objective": "Objetivo", + "Objectives": "Objetivos:", + "PlayerNotes": "Notas del jugador:", + "Reward": "Recompensa", + "Rewards": "Recompensas:" + }, "Management": { - "IsPersonalQuest": "¿Es una misión personal?", - "IsPersonalQuestDescription": "Marcar la misión como personal. Será invisible para todos los jugadores, excepto para los que están marcados específicamente abajo. Desmarcando esta opción se eliminarán todos los permisos y se moverá la misión a la pestaña \"Ocultas\".", - "SplashArt": "Imagen de acompañamiento", - "QuestBranching": "Submisiones", - "AddSubquest": "Crear submisión", - "CanPlayerEdit": "Permitir a los jugadores editar los detalles" - }, - + "AddSubquest": "Crear Sub-Misión", + "ConfigurePermissions": "Configurar Permisos", + "QuestBranching": "Sub-Misiones:", + "QuestSettings": "Configuración de la Misión:", + "SplashArt": "Imagen Portada:", + "SplashInfo": "Haga clic para configurar la imagen.", + "SplashQuestIcon": "Establecer como icono de misión" + }, + "Notifications": { + "BadUUID": "No se pudo recuperar el documento para UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log solo acepta actores del mundo/compendio, elementos y entradas de diario como dador de misiones.", + "WrongItemType": "Forien's Quest Log solo acepta artículos del mundo y del compendio como recompensa." + }, "Tabs": { "Details": "Detalles", - "QuestManagement": "Administrar misión", - "GMNotes": "Notas del GM" + "GMNotes": "Notas del GM", + "PlayerNotes": "Notas del jugador", + "QuestManagement": "Administrar Misión" + }, + "Title": "Detalles de la misión - {name}", + "Tooltips": { + "AddCustom": "Agregar personalizada", + "AddObjective": "Añadir Objetivo", + "ChangeSplashPos": "Cambiar la alineación de la imagen de misión.", + "DeleteQuestGiver": "Eliminar dador de misiones.", + "DeleteSplash": "Eliminar imagen de misión.", + "HideAll": "Ocultar Todo", + "LockAll": "Bloquear Todo", + "PrimaryQuestSet": "Haz clic para seleccionar la misión principal.", + "PrimaryQuestUnset": "Haz clic para anular la misión principal.", + "RewardHidden": "La recompensa está oculta. Haz clic para mostrar.", + "RewardLocked": "La recompensa está bloqueada. Haz clic para desbloquear.", + "RewardLockedPlayer": "La recompensa está bloqueada.", + "RewardUnlocked": "La recompensa está desbloqueada. Haz clic para bloquear.", + "RewardUnlockedPlayer": "La recompensa está desbloqueada.", + "RewardVisible": "La recompensa está visible. Haz clic para ocultar.", + "ShowAll": "Mostrar Todo", + "TaskHidden": "El objetivo está oculto. Haz clic para mostrar.", + "TaskVisible": "La tarea está visible. Haz clic para ocultar.", + "ToggleImage": "Alternar entre imagen de token o actor.", + "UnlockAll": "Desbloquear Todo", + "ViewSplashArt": "Ver imagen de portada." } - - }, - - "DeleteDialog": { - "Title": "Eliminar {name}", - "Header": "¿Estás seguro?", - "Body": "Esta misión y todos sus datos serán permanentemente eliminados.", - "Delete": "Eliminar", - "Cancel": "Cancelar" }, - - "CloseDialog": { - "Title": "Descartar creación de misión", - "Header": "¿Estás seguro?", - "Body": "Los datos no guardados se perderán.", - "Discard": "Descartar cambios", - "Cancel": "Cancelar" + "QuestTracker": { + "NoPrimary": "No hay misión principal disponible.", + "Title": "Seguimiento de Misiones", + "Tooltips": { + "BackgroundShow": "Haz clic para mostrar el fondo.", + "BackgroundUnshow": "Haz clic para hacer que el fondo sea transparente.", + "PrimaryQuestShow": "Haz clic para mostrar la misión principal.", + "PrimaryQuestUnshow": "Haz clic para mostrar todas las misiones." + } }, - - "Notifications": { - "CannotOpen": "No puedes abrir los detalles de la misión. Puede que te falten permisos, que la misión ya no exista o que el ID sea inválido.", - "UserCantOpen": "El usuario {user} no tiene permisos para abrir esta misión.", - "LinkCopied": "El link a la entidad de esta misión ha sido copiado al portapapeles", - "QuestMoved": "Se movió la misión a una nueva carpeta y se le dio el estado: {target}" + "QuestTypes": { + "Labels": { + "Active": "En curso", + "active": "en curso", + "Available": "Disponibles", + "available": "disponible", + "Completed": "Completadas", + "completed": "completada", + "Failed": "Fallidas", + "failed": "fallida", + "InActive": "Inactivas", + "inactive": "inactiva", + "Status": "La Misión está {statusLabel}." + }, + "Tooltips": { + "SetActive": "Establecer como En Curso", + "SetAvailable": "Establecer como Disponible", + "SetCompleted": "Establecer como Completada", + "SetFailed": "Establecer como Fallida", + "SetInactive": "Establecer como Inactiva", + "Status": "Estado: {statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "Los jugadores pueden aceptar misiones", + "EnableHint": "Marcar para permitir a los jugadores aceptar misiones desde la pestaña 'Disponibles'." + }, + "allowPlayersCreate": { + "Enable": "Los jugadores pueden crear misiones", + "EnableHint": "Marcar para permitir a los jugadores crear misiones. Las misiones creadas por ellos aparecerán en la pestaña 'Disponibles'. Requiere tener permisos globales de jugador 'Crear entradas en el Diario'." + }, "allowPlayersDrag": { "Enable": "Permitir a los jugadores arrastrar las recompensas a sus fichas", "EnableHint": "Marcar para permitir a los jugadores arrastrar las recompensas de la ventana de detalles de la misión a su propia ficha de personaje." }, - "availableQuests": { - "Enable": "Mostrar pestaña \"Disponibles\"", - "EnableHint": "Marcar para mostrar la pestaña \"Disponibles\" en el registro de misiones, donde los jugadores podrán ver todas las misiones no ocultas que aún no han sido aceptadas." - }, "countHidden": { "Enable": "Contar las tareas ocultas", "EnableHint": "Marcar para incluir las tareas ocultas en el número de tareas completadas / totales." }, + "defaultPermissionLevel": { + "Enable": "Nivel de permiso de misión predeterminado", + "EnableHint": "Establece el nivel de permiso predeterminado cuando se crean nuevas misiones.", + "NONE": "Ninguno", + "OBSERVER": "Observador", + "OWNER": "Dueño" + }, + "dynamicBookmarkBackground": { + "Enable": "Fondo de Marcador Dinámico", + "EnableHint": "Si está marcado, el fondo de la pestaña de marcadores se establece dinámicamente en el fondo del contenido de la ventana." + }, + "hideFQLFromPlayers": { + "Enable": "Ocultar registro de misiones de los jugadores", + "EnableHint": "Cuando está habilitada, esta opción oculta el registro de misiones de todos los jugadores. Solo los usuarios de nivel GM podrán acceder al registro de misiones." + }, "navStyle": { - "Enable": "Estilo de navegación", - "EnableHint": "Decide como se visualizará el registro de misiones.", "bookmarks": "Marcadores", - "classic": "Pestañas clásicas" + "classic": "Pestañas clásicas", + "Enable": "Estilo de navegación", + "EnableHint": "Decide cómo debe mostrarse la navegación del Registro de Misiones." + }, + "notifyRewardDrop": { + "Enable": "Mostrar notificaciones de entrega de recompensas", + "EnableHint": "Verifique para ver notificaciones cuando las recompensas de misiones se colocan en las hojas de los jugadores." + }, + "questTrackerResizable": { + "Enable": "Seguimiento de misiones redimensionable", + "EnableHint": "Marque para permitir el control de cambio de tamaño manual de la ventana de Seguimiento de Misiones." }, "showFolder": { "Enable": "Mostrar carpeta de misiones", - "EnableHint": "Marcar para mostrar la carpeta de misiones en la pestaña de \"Apuntes\" Solo para modo DEBUG." + "EnableHint": "Marcar para mostrar la carpeta de misiones en la pestaña de \"Diario\" Solo para modo DEBUG." }, "showTasks": { - "Enable": "Mostrar tareas en el registro de misiones", - "EnableHint": "Decide si y como se muestra la cantidad de tareas (objetivos) junto al nombre de la misión en el registro de misiones. Esto no tiene efecto en la visualización de la pantalla de detalle de misión.", "default": "Mostrar tareas: completadas / totales", - "onlyCurrent": "Mostrar tareas: completadas", - "no": "Ocultar columna \"tareas\"" - }, - "titleAlign": { - "Enable": "Alineación del nombre de la misión", - "EnableHint": "Decide como alinear los nombres de misiones en la tabla de registro de misiones.", - "left": "Alineado a la izquierda", - "center": "Centrado" - }, - "playersWelcomeScreen": { - "Enable": "Mostrar mensaje de bienvenida a los jugadores", - "EnableHint": "Desmarcar para prevenir que los jugadores vean la pantalla de bienvenida al entrar a la partida después de una actualización. Aún podrán acceder a ella pulsando en el icono de \"Ayuda\" en la cabecera del registro de misiones." - }, - "allowPlayersAccept": { - "Enable": "Los jugadores pueden aceptar misiones", - "EnableHint": "Marcar para permitir a los jugadores aceptar misiones desde la pestaña \"Disponibles\"." + "Enable": "Mostrar tareas en el registro de misiones", + "EnableHint": "Decide si y cómo se muestra la cantidad de tareas (objetivos) junto al nombre de la misión en el registro de misiones. Esto no tiene efecto en la visualización de la pantalla de detalle de misión.", + "no": "Ocultar columna \"Objetivos\"", + "onlyCurrent": "Mostrar objetivos: completados" }, - "allowPlayersCreate": { - "Enable": "Los jugadores pueden crear misiones", - "EnableHint": "Marcar para permitir a los jugadores crear misiones. Las misiones creadas por ellos aparecerán en la pestaña \"Disponibles\". Requiere tener permisos globales de jugador \"Crear apuntes\"." + "trustedPlayerEdit": { + "Enable": "Permitir la edición de misiones de jugadores de confianza", + "EnableHint": "Marcar para permitir que los jugadores de confianza tengan capacidades ampliadas de edición de misiones y control de estado sobre las misiones de las que son propietarios." } }, - "Tooltips": { - "SetAvailable": "Mover a disponibles", - "SetActive": "Poner en curso", - "SetCompleted": "Completar misión", - "SetFailed": "Mover a fallidas", - "Hide": "Ocultar", "Delete": "Eliminar", - "AddAbstractReward": "Añadir recompensa abstracta", - "PersonalQuestButNoPlayers": "Esta es una misión personal, pero ningún jugador puede verla.", - "PersonalQuestVisibleFor": "Esta es una misión personal para", - "RewardHidden": "La recompensa está oculta. Clic para mostrar.", - "RewardVisible": "La recompensa está visible. Clic para ocultar.", - "TaskHidden": ".La tarea está oculta. Clic para mostrar.", - "TaskVisible": ".La tarea está visible. Clic para ocultar.", - "ToggleImage": "Alternar entre imagen de token o actor" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "Open „{name}” Quest", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Edit": "Editar", + "HiddenQuestNoPlayers": "Esta misión está oculta a todos los jugadores.", + "PrimaryQuest": "Misión Principal" } } } diff --git a/lang/fi-FI.json b/lang/fi-FI.json new file mode 100644 index 00000000..96491bfe --- /dev/null +++ b/lang/fi-FI.json @@ -0,0 +1,256 @@ +{ + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Avaa \"{name}\"" + }, + "Notifications": { + "NoQuest": "API virhe: Makroa ei voi luoda kelvottomalla tehtävän tunnisteella." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Uusi tehtävä" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (palkkio): {userName} raahasi tavaran \"{itemName}\" hahmolle {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Entiteettiä ei voitu ladata UUID:llä \"{uuid}\".", + "NoPermission": "Sinulla ei ole tarvittavia oikeuksia nähdä tämän entiteetin lomaketta." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Tämä tavoite ja sen tiedot poistetaan lopullisesti.", + "BodyQuest": "Tämä tehtävä ja sen tiedot poistetaan lopullisesti.", + "BodyReward": "Tämä palkkio ja sen tiedot poistetaan lopullisesti.", + "Cancel": "Peruuta", + "Delete": "Poista", + "HeaderDel": "Haluatko varmasti poistaa:

\"{name}\"

", + "TitleDel": "Poista {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Näytä pelaajille" + }, + "Quest": "Tehtävä" + }, + "Migration": { + "ChatMessage": { + "Footer": "Sinun täytyy päivittää yllä olevat tehtävät käsin käyttämään kelpaavia dokumenttien tietoja hakemistoista tai maailmastasi.
", + "Header": "Forien's Quest Log (tietokannan siirto)
Alla olevien tehtävien linkittämättÜmät tehtävänantajat ja palkkiotavarat poistettiin:

", + "Notification": "Forien's Quest Log - Linkittämätön tehtävänantaja tai palkkiotavaroita poistettiin yhdestä tai useammasta tehtävästä. Katso lisätietoja keskusteluviestistä.", + "QuestGiver": "Tehtävänantaja", + "QuestRewards": "Tehtävän palkkiot" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Tietojen siirto valmis.", + "CouldNotMigrate": "Forien's Quest Log - Tehtävää \"{name}\" ei voitu siirtää.", + "Schema": "Forien's Quest Log - Tietoja siirretään skeeman versioon \"{version}\".", + "Start": "Forien's Quest Log - Tietoja siirretään, ethän lataa sivua uudelleen." + } + }, + "Notifications": { + "CannotOpen": "Tehtävän yksityiskohtia ei voi avata. Tämä tehtävä ei välttämättä ole havaittavissa tai sitä ei enää ole.", + "FinishQuestAdded": "Teethän muokkauksesi loppuun ja suljet nykyisen tehtävän, ennen kuin lisäät uuden.", + "LinkCopied": "Entiteetin linkki tähän tehtävään kopioitiin leikepöydälle.", + "QuestAdded": "Uusi tehtävä \"{name}\" lisättiin {status}-tilassa.", + "QuestIDCopied": "Tämän tehtävän tunniste kopioitiin leikepöydälle.", + "QuestMoved": "\"{name}\" siirrettiin ja uudeksi tilaksi asetettiin \"{target}\".", + "QuestPrimary": "\"{name}\" on uusi päätehtävä.", + "QuestTrackerNoActive": "Tehtäväseurain on päällä, mutta keskeneräisiä tehtäviä ei tällä hetkellä ole.", + "UserCantOpen": "Käyttäjällä \"{user}\" ei ole oikeuksia avata tätä tehtävää." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Lisää tehtävä" + }, + "ContextMenu": { + "CopyEntityLink": "Kopioi entiteetin sisältölinkki", + "CopyQuestID": "Kopioi tehtävän tunniste", + "PrimaryQuest": "Aseta/poista päätehtäväksi" + }, + "Labels": { + "TableHeader": "{0} tehtävää", + "SubTitle": "Alitehtävä ({0})" + }, + "Title": "Tehtäväloki", + "Tooltips": { + "Objectives": "Tavoitteet" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Käyttäjän Määrittelemä", + "RewardHide": "Piilota", + "RewardLock": "Lukita", + "RewardShow": "Näyttää", + "RewardUnlock": "Avata" + }, + "Labels": { + "CustomSource": "Mukautettu alkuperä", + "Description": "Kuvaus:", + "DragDropActor": "Raahaa & pudota hahmo, tavara tai muistiinpano tai napsauta vasemmalla asettaaksesi mukautetun alkuperän.", + "DragDropActorPlayer": "Raahaa & pudota hahmo, tavara tai muistiinpano.", + "DragDropRewards": "Raahaa & pudota tavaroita tähän asettaaksesi ne palkkioiksi.", + "GMNotes": "PJ:n muistiinpanot:", + "Objective": "Tavoite", + "Objectives": "Tavoitteet:", + "PlayerNotes": "Pelaajan muistiinpanot:", + "Reward": "Palkkio", + "Rewards": "Palkkiot:" + }, + "Management": { + "AddSubquest": "Lisää alitehtävä", + "ConfigurePermissions": "Määritä oikeudet", + "QuestBranching": "Alitehtävät:", + "QuestSettings": "Tehtävän asetukset:", + "SplashArt": "Kansikuva:", + "SplashInfo": "Napsauta asettaaksesi kuvan.", + "SplashQuestIcon": "Aseta tehtävän kuvakkeeksi" + }, + "Notifications": { + "BadUUID": "Dokumenttia ei löytynyt UUID:llä \"{uuid}\".", + "WrongDocType": "Forien's Quest Log hyväksyy vain maailman/hakemiston hahmoja, tavaroita ja muistiinpanoja tehtävänantajiksi.", + "WrongItemType": "Forien's Quest Log hyväksyy vain maailman ja hakemiston tavaroita palkkioiksi." + }, + "Tabs": { + "Details": "Yksityiskohdat", + "GMNotes": "PJ:n muistiinpanot", + "PlayerNotes": "Pelaajan muistiinpanot", + "QuestManagement": "Hallitse tehtävää" + }, + "Title": "Tehtävän yksityiskohdat - {name}", + "Tooltips": { + "AddCustom": "Lisää käyttäjän määrittämä", + "AddObjective": "Lisää tavoite", + "ChangeSplashPos": "Muuta kansikuvan tasausta.", + "DeleteQuestGiver": "Poista tehtävänantaja.", + "DeleteSplash": "Poista kansikuva.", + "HideAll": "Piilota kaikki", + "LockAll": "Lukitse kaikki", + "PrimaryQuestSet": "Napsauta asettaaksesi päätehtäväksi.", + "PrimaryQuestUnset": "Napsauta poistaaksesi päätehtävistä.", + "RewardHidden": "Palkkio on piilotettu. Napsauta näyttääksesi sen.", + "RewardLocked": "Palkkio on lukittu. Napsauta avataksesi sen.", + "RewardLockedPlayer": "Palkkio on lukittu.", + "RewardUnlocked": "Palkkio on lukitsematon. Napsauta lukitaksesi sen.", + "RewardUnlockedPlayer": "Palkkiota ei ole lukittu.", + "RewardVisible": "Palkkio on näkyvillä. Paina piilottaaksesi sen.", + "ShowAll": "Näytä kaikki", + "TaskHidden": "Tavoite on piilotettu. Napsauta näyttääksesi sen.", + "TaskVisible": "Tavoite on näkyvillä. Napsauta piilottaaksesi sen.", + "ToggleImage": "Näytä/piilota pelinappulan/hahmon kuva.", + "UnlockAll": "Avaa lukitus kaikista", + "ViewSplashArt": "Katso kansikuva." + } + }, + "QuestTracker": { + "NoPrimary": "Päätehtävää ei saatavilla.", + "Title": "Tehtäväseurain", + "Tooltips": { + "BackgroundShow": "Napsauta näyttääksesi taustan.", + "BackgroundUnshow": "Napsauta piilottaaksesi taustan.", + "PrimaryQuestShow": "Napsauta näyttääksesi päätehtävän.", + "PrimaryQuestUnshow": "Napsauta näyttääksesi kaikki tehtävät." + } + }, + "QuestTypes": { + "Labels": { + "Active": "Kesken", + "active": "kesken", + "Available": "Saatavilla", + "available": "saatavilla", + "Completed": "Suoritettu", + "completed": "suoritettu", + "Failed": "Epäonnistunut", + "failed": "epäonnistunut", + "InActive": "Ei-aktiivinen", + "inactive": "ei-aktiivinen", + "Status": "Tehtävä on {statusLabel}." + }, + "Tooltips": { + "SetActive": "Aseta kesken-tilaan", + "SetAvailable": "Aseta saatavilla-tilaan", + "SetCompleted": "Aseta suoritettu-tilaan", + "SetFailed": "Aseta epäonnistunut-tilaan", + "SetInactive": "Aseta ei-aktiivinen-tilaan", + "Status": "Tila: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Pelaajat voivat ottaa vastaan tehtäviä", + "EnableHint": "Valitse salliaksesi pelaajien ottaa vastaan tehtäviä Saatavilla-välilehdeltä." + }, + "allowPlayersCreate": { + "Enable": "Pelaajat voivat luoda tehtäviä", + "EnableHint": "Valitse salliaksesi pelaajien luoda tehtäviä. Pelaajien luomat tehtävät ilmestyvät Saatavilla-välilehdelle Pelaajan muokattava -oikeuksilla. VAATII Luoda muistiinpanoja -ydinoikeuden." + }, + "allowPlayersDrag": { + "Enable": "Salli pelaajien raahata palkkioita", + "EnableHint": "Valitse salliaksesi pelaajien raahata palkkioita tehtävän yksityiskohdista omistamilleen hahmoille." + }, + "countHidden": { + "Enable": "Laske piilotetut tavoitteet", + "EnableHint": "Jos valittu, niin myös piilotetut tavoitteet lasketaan mukaan suoritettuihin/kaikkiin tavoitteisiin." + }, + "defaultPermissionLevel": { + "Enable": "Tehtävän oletusoikeudet", + "EnableHint": "Asettaa oletuksena tämän oikeuden uusille tehtäville.", + "NONE": "Ei mitään", + "OBSERVER": "Tarkastelija", + "OWNER": "Omistaja" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynaaminen kirjanmerkin tausta", + "EnableHint": "Jos valittu, kirjanmerkkivälilehden tausta asetetaan dynaamisesti sen ikkunan sisällöstä." + }, + "hideFQLFromPlayers": { + "Enable": "Piilota tehtäväloki pelaajilta", + "EnableHint": "Jos valittu, tehtäväloki piilotetaan kaikilta pelaajilta. Vain pelinjohtajat voivat käyttää sitä." + }, + "navStyle": { + "bookmarks": "Kirjanmerkit", + "classic": "Klassiset välilehdet", + "Enable": "Navigaatiotyyli", + "EnableHint": "Valitse, miltä tehtävälokin navigaatio näyttää." + }, + "notifyRewardDrop": { + "Enable": "Näytä palkkioiden raahausilmoitukset", + "EnableHint": "Valitse nähdäksesi ilmoituksen, kun tehtävien palkkioita raahataan hahmolomakkeille." + }, + "questTrackerResizable": { + "Enable": "Muutettava tehtäväseurain", + "EnableHint": "Valitse salliaksesi tehtäväseuraimen koon muuttamisen käsin." + }, + "showFolder": { + "Enable": "Näytä tehtäväkansio", + "EnableHint": "Valitse näyttääksesi tehtävien tiedot kansiossa Muistiinpanot-välilehdellä. Vain TESTAUSKÄYTTÖÖN." + }, + "showTasks": { + "default": "Näytä tavoitteet: suoritettu/kaikki", + "Enable": "Näytä tavoitteet tehtävälokissa", + "EnableHint": "Valitse kuinka tavoitteiden määrä näytetään tehtävän otsikon vieressä tehtävälokissa. Tämä ei vaikuta tehtävän esikatseluun.", + "no": "Piilota Tavoitteet-sarake", + "onlyCurrent": "Näytä tavoitteet: suoritettu" + }, + "trustedPlayerEdit": { + "Enable": "Salli luotetun pelaajan muokata tehtäviä", + "EnableHint": "Valitse antaaksesi luotetuille pelaajille laajemmat työkalut omistamiensa tehtävien sisällön ja tilan hallintaan." + } + }, + "Tooltips": { + "Delete": "Poista", + "Edit": "Muokkaa", + "HiddenQuestNoPlayers": "Tämä tehtävä on piilotettu kaikilta pelaajilta.", + "PrimaryQuest": "Päätehtävä" + } + } +} diff --git a/lang/fr.json b/lang/fr.json index 92ae697a..3ca80ded 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1,202 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "Nouvelle quête", - "QuestLogButton": "Journal des quêtes", - "Quests": "Quêtes {0}", - "SampleReward": "ex : 300 Points d’Expérience", - "SampleTask": "ex : Tuer tous les rats dans l’Auberge de „La cheville tordue” ", - - "QuestTypes": { - "InProgress": "En cours", - "Completed": "Achevée", - "Failed": "Échouée", - "Hidden": "Cachée", - "Labels": { - "available": "disponibles", - "active": "en cours", - "completed": "complétées", - "failed": "échouées", - "hidden": "cachées" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Ouvrir la Quête ”{name}”" + }, + "Notifications": { + "NoQuest": "Erreur API : impossible de créer une macro avec un ID de quête non valide." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nouvelle quête" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (récompense de quête) : {userName} a donné '{itemName}' à {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Une entité ne pourra pas être chargée pour IDuu : '{uuid}'.", + "NoPermission": "Vous n'avez pas la permission de voir la feuille de cette entité." + } } }, - - "Buttons": { - "AddNewQuest": "Ajouter nouvelle Quête", - "AddNewTask": "Ajouter nouvelle Tâche" + "DeleteDialog": { + "BodyObjective": "Cet objectif et ses données seront effacées définitivement.", + "BodyQuest": "Cette quête et ses données seront effacées définitivement.", + "BodyReward": "Cette récompense et ses données seront effacées définitivement.", + "Cancel": "Annuler", + "Delete": "Effacer", + "HeaderDel": "Êtes vous certain de vouloir effacer :

'{name}'

", + "TitleDel": "Effacer {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Montrer aux joueurs" + }, + "Quest": "QuĂŞte" + }, + "Migration": { + "ChatMessage": { + "Footer": "Vous devez mettre Ă  jour manuellement les quĂŞtes ci-dessus avec des donnĂŠes de document valide des compendiums ou de votre monde.
", + "Header": "Forien's Quest Log (migration de DB)
A retirĂŠ le donneur de quĂŞte sans lien ou les objets rĂŠcompense des quĂŞtes ci-dessous :

", + "Notification": "Forien's Quest Log - A retiré le donneur de quête sans lien ou les objets récompenses de quête d'une ou plusieurs quêtes. Regardez la conversation pour plus d'information.", + "QuestGiver": "Donneur de quête", + "QuestRewards": "Récompenses de quête" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migration des données achevée.", + "CouldNotMigrate": "Forien's Quest Log - ne peut pas migrer la quête : '{name}'.", + "Schema": "Forien's Quest Log - Migration des données sous le schéma de version : '{version}'.", + "Start": "Forien's Quest Log - Migration en cours des données, ne pas recharger." + } }, - - "QuestForm": { - "Title": "Ajouter nouvelle Quête", - "QuestGiver": "Commanditaire", - "QuestGiverPlaceholder": "Nom ou ID du commanditaire(Acteur ou Journal)", - "QuestTitle": "Nom de la Quête", - "DragDropActor": "Glisser/Déposer un acteur ou un journal ici pour en faire un commanditaire", - "QuestDescription": "Description de la quête", - "QuestGMNotes": "Notes du MJ", - "Submit": "Valider", - "SubquestOf": "Quête secondaire de {name}" + "Notifications": { + "CannotOpen": "Ne peut ouvrir les détails de la Quête. Soit vous n’avez pas la permission, soit la quête n’existe plus ou l’ID fournie était invalide.", + "FinishQuestAdded": "Finissez d'éditer et fermez la nouvelle quête actuelle avant d'en ajouter une autre.", + "LinkCopied": "Le lien vers cette quête a été copié dans le presse-papier.", + "QuestAdded": "'{name}' est ajouté comme nouvelle quête avec le statut : '{status}'.", + "QuestIDCopied": "L'ID de cette quête a été copiée vers le presse-papier.", + "QuestMoved": "Quête déplacée avec un nouveau statut : '{target}'.", + "QuestPrimary": "'{name}' est la nouvelle quête primaire.", + "QuestTrackerNoActive": "Le traqueur de quête est activé, mais il n'y a pas pas de quête en cours actuellement.", + "UserCantOpen": "L'utilisateur '{user}' n’a pas la permission d'ouvrir cette quête." }, - "QuestLog": { - "Title": "Journal de Quête", - "SubTitle": "Quête faisant parti de: {0}", - "Table": { - "QuestGiver": "Commanditaire", - "QuestTitle": "Nom de la Quête", - "Tasks": "Tâche(s)", - "Actions": "Actions" + "Buttons": { + "AddQuest": "Ajouter Quête" }, - "Tabs": { - "Available": "Disponible", - "InProgress": "En cours", - "Completed": "Achevée", - "Failed": "Échouée", - "Hidden": "Cachée" + "ContextMenu": { + "CopyEntityLink": "Copier le contenu du lien de l'entité", + "CopyQuestID": "Copier l'ID de la quête", + "PrimaryQuest": "Activer / Désactiver comme quête primaire" + }, + "Labels": { + "TableHeader": "Quêtes {0}", + "SubTitle": "Quête faisant parti de : {0}" + }, + "Title": "Journal de Quête", + "Tooltips": { + "Objectives": "Objectifs" } }, - "QuestPreview": { - "Title": "Détails sur la quête", - "SubTitle": "Quête faisant parti de: {0}", - "Objectives": "Objectifs", - "Rewards": "Récompenses", - "DragDropRewards": "Glisser/Déposer les objets ici pour en faire des récompenses", - "InvalidQuestId": "Impossible d'ouvrir la prévisualisation de la quête en raison d’une ID de Quête invalide.", - "HeaderButtons": { - "Show": "Montrer aux joueurs" - }, - + "Buttons": { + "RewardCustom": "Défini par l'utilisateur", + "RewardHide": "Cacher", + "RewardLock": "Bloquer", + "RewardShow": "Montrer", + "RewardUnlock": "Ouvrir" + }, + "Labels": { + "CustomSource": "Source personnalisée", + "Description": "Description :", + "DragDropActor": "Glisser/déposer un acteur, un objet, une entrée de journal ou clic gauche pour une source personnalisée.", + "DragDropActorPlayer": "Glisser/déposer un acteur, un objet ou une entrée de journal.", + "DragDropRewards": "Glisser/Déposer les objets ici pour en faire des récompenses.", + "GMNotes": "Notes du MJ :", + "Objective": "Objectif", + "Objectives": "Objectifs :", + "PlayerNotes": "Notes des joueurs:", + "Reward": "Récompense", + "Rewards": "Récompenses :" + }, "Management": { - "IsPersonalQuest": "Est-ce une quête personnelle ?", - "IsPersonalQuestDescription": "Cocher pour donner à la quête un personnage. Cela sera invisible pour tous les joueurs sauf ceux spécifiquement marqués ci-dessous. Décocher cette option retirera toutes les permissions et déplacera la quête dans l’onglet Cachée.", - "SplashArt": "Illustration", - "QuestBranching": "Quêtes secondaires", "AddSubquest": "Créer une quête secondaire", - "CanPlayerEdit": "Autoriser les joueurs a modifier les détails de la quête" + "ConfigurePermissions": "Configurer les permissions", + "QuestBranching": "Quêtes secondaires :", + "QuestSettings": "Réglages des quêtes :", + "SplashArt": "Illustration :", + "SplashInfo": "Cliquer pour définir une image.", + "SplashQuestIcon": "Définissez comme icône de quête" + }, + "Notifications": { + "BadUUID": "Ne peut récupérr le document pour IDuu : '{uuid}'.", + "WrongDocType": "Forien's Quest Log accepte seulement les acteurs, les objets et les entrées de journaux du monde /compendium comme commanditaires de quêtes.", + "WrongItemType": "Forien's Quest Log n'accepte que les objets du monde et des compendium items comme récompenses." }, - "Tabs": { "Details": "Détails", - "QuestManagement": "Modifier la Quête", - "GMNotes": "Notes MJ" + "GMNotes": "Notes MJ", + "PlayerNotes": "Notes des joueurs", + "QuestManagement": "Modifier la Quête" + }, + "Title": "Détails sur la quête", + "Tooltips": { + "AddCustom": "Ajouter défini par l'utilisateur", + "AddObjective": "Ajouter Objectif", + "ChangeSplashPos": "Modifier l'alignement de l'image d'illustration.", + "DeleteQuestGiver": "Supprimer le commanditaire.", + "DeleteSplash": "Supprimer l'illustration.", + "HideAll": "Tout cacher", + "LockAll": "Tout verrouiller", + "PrimaryQuestSet": "Ciquer pour activer la quête primaire.", + "PrimaryQuestUnset": "Cliquer pour désactiver la quête primaire.", + "RewardHidden": "Récompense cachée. Cocher pour la montrer.", + "RewardLocked": "Récompense bloquée. Cliquer pour débloquer.", + "RewardLockedPlayer": "Récompense bloquée.", + "RewardUnlocked": "Récompense débloquée. Cliquer pour bloquer.", + "RewardUnlockedPlayer": "Récompense est débloquée.", + "RewardVisible": "Récompense visible. Cocher pour la cacher.", + "ShowAll": "Montrer à tous", + "TaskHidden": "Tache cachée. Cocher pour la montrer.", + "TaskVisible": "Tâche visible. Cocher pour la cacher.", + "ToggleImage": "Activer l’image du token/acteur.", + "UnlockAll": "Tout débloquer", + "ViewSplashArt": "Voir l'illustration." } - }, - - "DeleteDialog": { - "Title": "Effacer {name}", - "Header": "Êtes-vous sûr ?", - "Body": "Cette quête et ces données seront effacées définitivement.", - "Delete": "Effacer", - "Cancel": "Annuler" - }, - - "CloseDialog": { - "Title": "Quitter le Formulaire", - "Header": "Êtes vous sûrs ?", - "Body": "Êtes vous sûrs de vouloir fermer le formulaire ? Toutes données non sauvegardées serons perdus.", - "Discard": "Abandonner les modifications", - "Cancel": "Annuler" + "QuestTracker": { + "NoPrimary": "Pas de quête primaire disponible.", + "Title": "Traqueur de quêtes", + "Tooltips": { + "BackgroundShow": "Cliquez pour afficher l'arrière-plan.", + "BackgroundUnshow": "Cliquer pour un arrière plan transparent.", + "PrimaryQuestShow": "Cliquer pour montrer la quête primaire.", + "PrimaryQuestUnshow": "Cliquer pour cacher toutes les quêtes." + } }, - - "Notifications": { - "CannotOpen": "Ne peut ouvrir les détails de la Quête. Soit vous n’avez pas la permission, soit la quête n’existe plus ou l’ID fournie était invalide.", - "UserCantOpen": "L'utilisateur {user} n’a pas la permission d'ouvrir cette quête.", - "LinkCopied": "Le lien vers cette quête a était copier dans le presse-papier.", - "QuestMoved": "Quête déplacée dans un nouveau dossier avec un nouveau : {target}" + "QuestTypes": { + "Labels": { + "Active": "En cours", + "active": "en cours", + "Available": "Disponible", + "available": "disponibles", + "Completed": "Achevée", + "completed": "complétées", + "Failed": "Échouée", + "failed": "échouées", + "InActive": "Inactif", + "inactive": "inactif", + "Status": "La quête est {statusLabel}." + }, + "Tooltips": { + "SetActive": "Définir comme En cours", + "SetAvailable": "Définir comme Disponible", + "SetCompleted": "Définir comme Achevée", + "SetFailed": "Définir comme Échouée", + "SetInactive": "Définir comme Inactif", + "Status": "Statut : {statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "Joueurs peuvent accepter", + "EnableHint": "Cocher pour permettre aux joueurs d'accepter les quêtes dans l'onglet Disponible." + }, + "allowPlayersCreate": { + "Enable": "Joueurs peuvent créer", + "EnableHint": "Cocher pour permettre aux joueurs de créer des Quêtes. Les quêtes créées par des joueurs atterissent dans l'onglet 'Disponible', NECESSITE l'autorisation 'Créer Journal' dans le core." + }, "allowPlayersDrag": { "Enable": "Permettre aux joueurs de récupérer les récompenses", - "EnableHint": "Cocher pour autoriser les joueurs à récupérer les récompenses de la fenêtre Détails de la quête à leur propres Acteurs." - }, - "availableQuests": { - "Enable": "Montre l’onglet disponible", - "EnableHint": "Cocher pour montrer un nouvelle onglet \"Disponible\" dans le journal des quêtes, où les joueurs pourront voir toutes les quêtes non-cachées avant qu’elles soient acceptées." + "EnableHint": "Cocher pour autoriser les joueurs à récupérer les récompenses de la fenêtre Détails de la quête vers leur propres Acteurs." }, "countHidden": { "Enable": "Montrer le nombre de tâches cachées", "EnableHint": "Cocher pour que le nombre de tâche Completer/Total inclue aussi les tâches cachées." }, + "defaultPermissionLevel": { + "Enable": "Niveau de permission des quêtes nouvelles", + "EnableHint": "Fixer les permissions par défaut lorsque de nouvelles quêtes sont créées.", + "NONE": "Aucun", + "OBSERVER": "Observateur", + "OWNER": "Propriétaire" + }, + "dynamicBookmarkBackground": { + "Enable": "Marques pages dynamiques en arrière plan", + "EnableHint": "Cochez pour que l'onglet marque page soit affichée de manière dynamique sur la fenêtre de contenu de l'arrière plan." + }, + "hideFQLFromPlayers": { + "Enable": "Cacher le journal de quête aux joueurs", + "EnableHint": "Activer cette option cache le journal de quêts à tous les joueurs. Seul less joueurs ayant le nivveau MJ seront capables d'accéder au journal de quêtes." + }, "navStyle": { - "Enable": "Style de navigation ", - "EnableHint": "Décider comment la navigation dans le journal de quête sera affichée.", "bookmarks": "Marque-page", - "classic": "Onglets classiques" + "classic": "Onglets classiques", + "Enable": "Style de navigation", + "EnableHint": "Décider comment la navigation dans le journal de quête sera affichée." + }, + "notifyRewardDrop": { + "Enable": "Montrer les notification de récompenses accordées", + "EnableHint": "Cocher pour voir les notification de l'Interface utilisateur lorsque des récompenses de quêtes sont déposées sur les feuilles des joueurs." + }, + "questTrackerResizable": { + "Enable": "Traqueur de quête redimensionnable", + "EnableHint": "Cocher pour autoriser le contrôle manuel du redimensionnement du Traqueur de quête." }, "showFolder": { "Enable": "Montre le dossier des quêtes", "EnableHint": "Cocher pour montrer le dossier des données de quête dans l’onglet Journal. Seulement pour DÉBUGGER." }, "showTasks": { - "Enable": "Montre les tâches dans le Journal de quête", - "EnableHint": "Décide si ou comment montrer le montant des tâches (objectifs) à côté du titre de la Quête dans le journal de quête. Cela n’a pas d’effet sur la prévisualisation de la Quête individuelle.", "default": "montre les tâches : effectuées/total", - "onlyCurrent": "Montre les tâches : effectuées", - "no": "Cache la colonne \"tâches\"" - }, - "titleAlign": { - "Enable": "Alignement du titre de la quête", - "EnableHint": "Décide comment positionner les titres de quête dans la table de l’onglet du Journal de quête.", - "left": "Alignés à gauche", - "center": "Centrés" - }, - "playersWelcomeScreen": { - "Enable": "Affiche un message bienvenue aux Joueurs.", - "EnableHint": "Décocher pour empécher les joueurs de voir le message de bienvenue qui apparait aprés une mise a jour, ce dernier est toujours accessible en cliquant sur le bouton 'Aide' trouvable dans le journal quête" - }, - "allowPlayersAccept": { - "Enable": "Les joueurs peuvent Accepter", - "EnableHint": "Cocher pour permettre aux joueurs d'accepter les quêtes dans l'onglet Disponible" + "Enable": "Montre les tâches dans le Journal de quête", + "EnableHint": "Décide si ou comment montrer le nombre d'objectifs à côté du Titre de la quête dans le Journal de quête. Cela n’a pas d’effet sur la prévisualisation de la Quête.", + "no": "Cacher la colonne \"objectifs\"", + "onlyCurrent": "Montre les tâches : effectuées" }, - "allowPlayersCreate": { - "Enable": "Les joueurs peuvent créer", - "EnableHint": "Cocher pour permettre aux joueurs de créer des Quêtes. Les quêtes créer par des joueurs atterissent dans l'onglet 'Disponible', NECESSITE 'Créer Journal' Permission" + "trustedPlayerEdit": { + "Enable": "Permettre aux joueurs de confiance d'éditer", + "EnableHint": "Cochez pour permettre aux joueurs de disposer de capacités d'édition et de contrôle du statut des quêtes étendues pour les quêtes dont ils sont propriétaires." } }, - "Tooltips": { - "SetAvailable": "Définir comme Disponible", - "SetActive": "Définir comme En cours", - "SetCompleted": "Définir comme Achevée", - "SetFailed": "Définir comme Échouée", - "Hide": "Cacher", "Delete": "Effacer", - "AddAbstractReward": "Ajouter une récompense abstraite", - "PersonalQuestButNoPlayers": "C’est une quête personnelle, personne ne peut la voir", - "PersonalQuestVisibleFor": "C’est une quête personnelle pour ", - "RewardHidden": "Récompense cachée. Cocher pour la montrer.", - "RewardVisible": "Récompense visible. Cocher pour la cacher.", - "TaskHidden": "Tache cachée. Cocher pour la montrer.", - "TaskVisible": "Tâche visible. Cocher pour la cacher.", - "ToggleImage": "Activer l’image du token/acteur" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "Ouvrir la Quête „{name}”", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Edit": "Éditer", + "HiddenQuestNoPlayers": "Cette quête est cachée à tous les joueurs.", + "PrimaryQuest": "Quête primaire" } } -} +} \ No newline at end of file diff --git a/lang/it.json b/lang/it.json new file mode 100644 index 00000000..a28f6e7e --- /dev/null +++ b/lang/it.json @@ -0,0 +1,256 @@ +{ + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Apri ”{name}”" + }, + "Notifications": { + "NoQuest": "API Error: Impossibile creare macro con un ID missione non valido." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nuova Missione" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (Ricompensa missione): {userName} ha assegnato '{itemName}' a {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "L'entità non può essere caricata per UUID: '{uuid}'.", + "NoPermission": "Non hai sufficienti autorizzazioni per vedere questa scheda entità." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Questo obiettivo e i suoi dati saranno cancellati definitivamente.", + "BodyQuest": "Questa missione e i suoi dati saranno cancellati in modo permanente.", + "BodyReward": "Questa ricompensa e i suoi dati saranno cancellati definitivamente.", + "Cancel": "Annulla", + "Delete": "Rimuovi", + "HeaderDel": "Sei sicuro di voler eliminare:

'{name}'

", + "TitleDel": "Elimina {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Mostra ai Giocatori" + }, + "Quest": "Missione" + }, + "Migration": { + "ChatMessage": { + "Footer": "Devi aggiornare manualmente le missioni qui sopra con dati validi dai compendi o dal tuo mondo.
", + "Header": "Forien's Quest Log (migrazione DB)
Sono stati rimossi Assegnatari Missione o Ricompense non collegati dalla missione sottostante:

", + "Notification": "Forien's Quest Log - Rimosso il donatore di missioni o gli oggetti premio non collegati da una o più missioni. Si prega di rivedere il messaggio di chat per ulteriori informazioni.", + "QuestGiver": "Assegnatario Missione", + "QuestRewards": "Ricompense Missione" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migrazione dei dati completa.", + "CouldNotMigrate": "Forien's Quest Log - Impossibile migrare la missione: '{name}'.", + "Schema": "Forien's Quest Log - Migrazione dei dati alla versione dello schema '{version}'.", + "Start": "Forien's Quest Log - Migrazione dei dati, si prega di non ricaricare." + } + }, + "Notifications": { + "CannotOpen": "Impossibile aprire i dettagli della missione. Potrebbe non essere osservabile o potrebbe non esistere più.", + "FinishQuestAdded": "Si prega di terminare la modifica e chiudere la nuova missione corrente prima di aggiungerne un'altra.", + "LinkCopied": "Entity Link per questa missione è stato copiato negli appunti.", + "QuestAdded": "Aggiunto '{name}' come nuova missione con status: '{status}'.", + "QuestIDCopied": "L'ID missione è stato copiato negli appunti.", + "QuestMoved": "Spostato '{name}' e impostato nuovo stato su: '{target}'.", + "QuestPrimary": "'{name}' è la nuova missione principale.", + "QuestTrackerNoActive": "Quest Tracker è abilitato, ma al momento non ci sono missioni in corso.", + "UserCantOpen": "L'utente '{user}' non ha il permesso di aprire questa missione." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Agg. Missione" + }, + "ContextMenu": { + "CopyEntityLink": "Copia il link al contenuto dell'entità", + "CopyQuestID": "Copia ID Missione", + "PrimaryQuest": "Imposta / Rimuovi come missione primaria" + }, + "Labels": { + "TableHeader": "Missioni {0}", + "SubTitle": "Missione Annidata di {0}" + }, + "Title": "Log Missioni", + "Tooltips": { + "Objectives": "Obiettivi" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Definito dall'utente", + "RewardHide": "Nascondi", + "RewardLock": "Blocca", + "RewardShow": "Mostra", + "RewardUnlock": "Sblocca" + }, + "Labels": { + "CustomSource": "Fonte Personalizzata", + "Description": "Descrizione:", + "DragDropActor": "Trascina qui il personaggio, voce o nota o clic con il pulsante sinistro del mouse per impostare un'origine personalizzata.", + "DragDropActorPlayer": "Trascina qui il personaggio, l'oggetto o la voce del diario.", + "DragDropRewards": "Trascina e rilascia gli oggetti qui per aggiungerli come ricompense.", + "GMNotes": "Note GM:", + "Objective": "Obiettivo", + "Objectives": "Obiettivi:", + "PlayerNotes": "Note del giocatore:", + "Reward": "Ricompensa", + "Rewards": "Ricompense:" + }, + "Management": { + "AddSubquest": "Agg. Missione", + "ConfigurePermissions": "Configura Autorizzazioni", + "QuestBranching": "Missioni Annidate:", + "QuestSettings": "Impostazioni Missione:", + "SplashArt": "Foto Copertina:", + "SplashInfo": "Click per impostare l'immagine.", + "SplashQuestIcon": "Imposta come icona missione" + }, + "Notifications": { + "BadUUID": "Impossibile recuperare il documento per l'UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log Accetta solo attori, oggetti e voci di diario dal mondo / compendi, come assegnatari di missioni.", + "WrongItemType": "Forien's Quest Log Accetta solo oggetti del mondo e dal compendio come ricompensa." + }, + "Tabs": { + "Details": "Dettaglio", + "GMNotes": "Note GM", + "PlayerNotes": "Note del giocatore", + "QuestManagement": "Gestisci Missione" + }, + "Title": "Dettaglio Missione - {name}", + "Tooltips": { + "AddCustom": "Aggiungi definito dall'utente", + "AddObjective": "Aggiungi Obiettivo", + "ChangeSplashPos": "Modifica Allineamento Copertina.", + "DeleteQuestGiver": "Elimina Assegnatario Missione.", + "DeleteSplash": "Elimina copertina.", + "HideAll": "Nascondi Tutto", + "LockAll": "Blocca Tutto", + "PrimaryQuestSet": "Clic per rendere la missione principale.", + "PrimaryQuestUnset": "Fai clic per rimuovere da missione principale.", + "RewardHidden": "La ricompensa è nascosta. Clicca per mostrare.", + "RewardLocked": "La ricompensa è bloccata. Cliacca per sbloccare.", + "RewardLockedPlayer": "La ricompensa è bloccata.", + "RewardUnlocked": "La ricompensa è sbloccata. Cliacca per bloccare.", + "RewardUnlockedPlayer": "La ricompensa è sbloccata.", + "RewardVisible": "La ricompensa è visibile. Clicca per nascondere.", + "ShowAll": "Mostra Tutte", + "TaskHidden": "L'obiettivo è nascosto. Clicca per mostrare.", + "TaskVisible": "L'obiettivo è visibile. Cliicca per nascondere.", + "ToggleImage": "Attiva/Disattiva immagine Token/Personaggio.", + "UnlockAll": "Sblocca Tutte", + "ViewSplashArt": "Visualizza la foto di copertina." + } + }, + "QuestTracker": { + "NoPrimary": "Nessuna missione principale disponibile.", + "Title": "Tracker Missione", + "Tooltips": { + "BackgroundShow": "Clic per mostrare lo sfondo.", + "BackgroundUnshow": "Clic per rendere lo sfondo trasparente.", + "PrimaryQuestShow": "Clic per mostrare la missione principale.", + "PrimaryQuestUnshow": "Clic per mostrare tutte le missioni." + } + }, + "QuestTypes": { + "Labels": { + "Active": "In Corso", + "active": "in corso", + "Available": "Disponibile", + "available": "disponibile", + "Completed": "Completata", + "completed": "completata", + "Failed": "Fallita", + "failed": "fallita", + "InActive": "Non Attiva", + "inactive": "non attiva", + "Status": "La Missione è {statusLabel}." + }, + "Tooltips": { + "SetActive": "Imposta come In Corso", + "SetAvailable": "Imposta come Disponibile", + "SetCompleted": "Imposta come Completata", + "SetFailed": "Imposta come Fallita", + "SetInactive": "Imposta come Non Attiva", + "Status": "Stato: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "I giocatori possono accettare missioni", + "EnableHint": "Abilita per consentire ai giocatori di accettare le missioni tra quelle disponibili." + }, + "allowPlayersCreate": { + "Enable": "I giocatori possono creare missioni", + "EnableHint": "Abilita per consentire ai giocatori di creare missioni. Le missioni create dal giocatore appariranno nella scheda Disponibili con le autorizzazioni di modifica del giocatore. RICHIEDE l'autorizzazione di base di 'crea diario'." + }, + "allowPlayersDrag": { + "Enable": "Consenti il trascinamento della ricompensa del giocatore", + "EnableHint": "Abilita per consentire ai giocatori di trascinare le ricompense dalla finestra Dettagli missione ai propri personaggi." + }, + "countHidden": { + "Enable": "Conta le attività nascoste", + "EnableHint": "Se selezionato, il numero di attività completate/totali includerà le attività nascoste." + }, + "defaultPermissionLevel": { + "Enable": "Livello autorizzazione missione predefinito", + "EnableHint": "Imposta il livello di autorizzazione predefinito per quando vengono create nuove missioni.", + "NONE": "Nessuno", + "OBSERVER": "Osservatore", + "OWNER": "Proprietario" + }, + "dynamicBookmarkBackground": { + "Enable": "Sfondo di segnalibro dinamico", + "EnableHint": "Se selezionato, lo sfondo della scheda segnalibro è impostato dinamicamente sullo sfondo del contenuto della finestra." + }, + "hideFQLFromPlayers": { + "Enable": "Nascondi il registro missioni ai giocatori", + "EnableHint": "Quando abilitato, questa opzione nasconde il registro delle missioni a tutti i giocatori. Solo gli utenti di livello GM saranno in grado di accedere al registro delle missioni." + }, + "navStyle": { + "bookmarks": "Segnalibri", + "classic": "Schede Classiche", + "Enable": "Stile Navigazione", + "EnableHint": "Decidi come visualizzare la navigazione di Log Missioni." + }, + "notifyRewardDrop": { + "Enable": "Mostra Notifiche Trascinamento Ricompensa", + "EnableHint": "Abilita se vedere le notifiche dell'interfaccia utente quando le ricompense delle missioni vengono trascinate nelle schede dei giocatori." + }, + "questTrackerResizable": { + "Enable": "Tracker Missione Ridimensionabile", + "EnableHint": "Abilita per consentire il ridimensionamento manuale del Tracker Missione." + }, + "showFolder": { + "Enable": "Mostra Cartella Missione", + "EnableHint": "Abilita per mostrare la cartella dei dati delle missioni nella scheda Journal. Solo per scopi di DEBUG." + }, + "showTasks": { + "default": "Mostra Obiettivi: fatto/totale", + "Enable": "Mostra le attività nel registro delle missioni", + "EnableHint": "Decidi se o come mostrare la quantità di obiettivi accanto al titolo della missione nel registro delle missioni. Questo non ha alcun effetto sull'anteprima della missione.", + "no": "Nascondi colonna \"Obiettivi\"", + "onlyCurrent": "Mostra obiettivi: fatti" + }, + "trustedPlayerEdit": { + "Enable": "Consenti l'editing delle missioni dei giocatori fidati", + "EnableHint": "Abilita per consentire ai giocatori fidati di aver funzionalità di modifica delle missioni e controllo dello stato oltre alle missioni di loro proprietà." + } + }, + "Tooltips": { + "Delete": "Rimuovi", + "Edit": "Modifica", + "HiddenQuestNoPlayers": "Questa Missione è nascosta a tutti i giocatori.", + "PrimaryQuest": "Missione Primaria" + } + } +} \ No newline at end of file diff --git a/lang/ja.json b/lang/ja.json index 9e721ced..cd68160a 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -1,202 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "クエストを追加", - "QuestLogButton": "クエストログ", - "Quests": "{0}個のクエスト", - "SampleReward": "例:300の経験点", - "SampleTask": "例:魔王を討伐する", - - "QuestTypes": { - "InProgress": "進行中", - "Completed": "完了", - "Failed": "失敗", - "Hidden": "秘匿", - "Labels": { - "available": "受注可能", - "active": "進行中", - "completed": "完了", - "failed": "失敗", - "hidden": "秘匿" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "{name} - 開く" + }, + "Notifications": { + "NoQuest": "API エラー: 無効なクエスト ID でマクロを作成できません。" + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "クエストを追加" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (quest reward):{userName}が'{itemName}'を{actorName}に移動しました。" + } + }, + "Utils": { + "Notifications": { + "NoDocument": "UUID:{uuid}のデータを読み込めませんでした。", + "NoPermission": "このデータを閲覧する権限を持っていません。" + } } }, - - "Buttons": { - "AddNewQuest": "新しいクエストを追加", - "AddNewTask": "追加" + "DeleteDialog": { + "BodyObjective": "この目標とその内容はすべて削除されます。", + "BodyQuest": "このクエストとその内容はすべて削除されます。", + "BodyReward": "この報酬とその内容はすべて削除されます。", + "Cancel": "取り消す", + "Delete": "削除", + "HeaderDel": "消去してもよろしいですか:

'{name}'

", + "TitleDel": "{title} デリート" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "プレイヤーに表示" + }, + "Quest": "クエスト" }, - - "QuestForm": { - "Title": "新しいクエストを追加", - "QuestGiver": "クエスト依頼主", - "QuestGiverPlaceholder": "Actor's name or entity's UUID", - "QuestTitle": "クエスト名", - "DragDropActor": "キャラクター、アイテムまたは資料をここにドラッグ&ドロップするとクエストの依頼主として設定できます。", - "QuestDescription": "クエスト内容", - "QuestGMNotes": "GMノート", - "Submit": "保存", - "SubquestOf": "{name}のサブクエストです" + "Migration": { + "ChatMessage": { + "Footer": "大要またはあなたの世界からの有効な文書データを使用して、上記のクエストを手動で更新する必要があります。
", + "Header": "Forien's Quest Log (DB 移動)
以下のクエストから、リンクされていないクエスト提供者または報酬アイテムを削除しました:

", + "Notification": "Forien's Quest Log - 1 つまたは複数のクエストから、リンクされていないクエスト提供者または報酬アイテムを削除しました。詳細については、チャット メッセージを確認してください。", + "QuestGiver": "クエストギバー", + "QuestRewards": "クエスト報酬" + }, + "Notifications": { + "Complete": "Forien's Quest Log - マイグレーション完了。", + "CouldNotMigrate": "Forien's Quest Log - クエスト'{name}'をマイグレーションできませんでした。", + "Schema": "Forien's Quest Log - データを最新スキーマバージョン'{version}'にマイグレーションしてます。", + "Start": "Forien's Quest Log - データマイグレーション中です、リロードしないでください。" + } + }, + "Notifications": { + "CannotOpen": "クエストの内容を開けませんでした。権限が無いかクエストが存在しないかもしれません。", + "FinishQuestAdded": "他のクエストを追加する前に現在のクエスト記入を完了してください。", + "LinkCopied": "このクエストのエンティティリンクをコピーしました。", + "QuestAdded": "「{name}」を新規追加し、状態を「{status}」に設定しました。", + "QuestIDCopied": "クエストIDがコピーされました。", + "QuestMoved": "「{name}」を移動し、状態を「{target}」に変更しました。", + "QuestPrimary": "「{name}」がメインクエストになりました。", + "QuestTrackerNoActive": "クエスト一覧が有効になっていますが、進行中のクエストがありません。", + "UserCantOpen": "ユーザー「{user}」はこのクエストを開く権限を持っていません。" }, - "QuestLog": { - "Title": "クエストログ", - "SubTitle": "{0}に含まれています", - "Table": { - "QuestGiver": "クエスト依頼主", - "QuestTitle": "クエスト名", - "Tasks": "内容", - "Actions": "行動" + "Buttons": { + "AddQuest": "クエスト追加" }, - "Tabs": { - "Available": "受注可能", - "InProgress": "進行中", - "Completed": "完了", - "Failed": "失敗", - "Hidden": "秘匿" + "ContextMenu": { + "CopyEntityLink": "データへのリンクをコピー", + "CopyQuestID": "クエストIDをコピー", + "PrimaryQuest": "メインクエスト指定切り替え" + }, + "Labels": { + "TableHeader": "{0}クエスト", + "SubTitle": "{0}に含まれています" + }, + "Title": "クエストログ", + "Tooltips": { + "Objectives": "目標" } }, - "QuestPreview": { - "Title": "クエスト詳細", - "SubTitle": "{0}に含まれています", - "Objectives": "目標", - "Rewards": "報酬", - "DragDropRewards": "アイテムをここにドラッグ&ドロップすると報酬として設定できます。", - "InvalidQuestId": "クエストIDが存在しないため開けません。", - "HeaderButtons": { - "Show": "プレイヤーに表示" - }, - + "Buttons": { + "RewardCustom": "ユーザー定義の", + "RewardHide": "隠す", + "RewardLock": "閉ざす", + "RewardShow": "示す", + "RewardUnlock": "ロック解除" + }, + "Labels": { + "CustomSource": "カスタムソース", + "Description": "詳細:", + "DragDropActor": "キャラ、アイテム、資料をドラッグ&ドロップすることでソースを手動で変更できます。", + "DragDropActorPlayer": "キャラ、アイテム、資料をドラッグ&ドロップしてください。", + "DragDropRewards": "アイテムをここにドラッグ&ドロップすると報酬として設定できます。", + "GMNotes": "GMノート:", + "Objective": "目標", + "Objectives": "目標:", + "PlayerNotes": "プレイヤーのメモ:", + "Reward": "報酬", + "Rewards": "報酬:" + }, "Management": { - "IsPersonalQuest": "個人クエスト?", - "IsPersonalQuestDescription": "個人クエストとして指定すると、そのプレイヤーにしか視認できなくなります。チェックをすべて外すとクエストが秘匿タブに表示されるようになります。", - "SplashArt": "画像", - "QuestBranching": "サブクエスト", - "AddSubquest": "サブクエストを作成する", - "CanPlayerEdit": "プレイヤーに編集権限を与える" - }, - + "AddSubquest": "サブクエスト追加", + "ConfigurePermissions": "権限設定", + "QuestBranching": "サブクエスト:", + "QuestSettings": "クエスト設定:", + "SplashArt": "表紙画像:", + "SplashInfo": "クリックしてカバー画像を設定します。", + "SplashQuestIcon": "クエストアイコンとして設定" + }, + "Notifications": { + "BadUUID": "{uuid}のオブジェクトを取得できませんでした。", + "WrongDocType": "Forien's Quest Logはワールドや辞典に指定されたキャラ、アイテム、資料のみをクエスト提供者として受け付けます。", + "WrongItemType": "Forien's Quest Logはワールドや辞典に指定された報酬のみを受け付けます。" + }, "Tabs": { "Details": "内容", - "QuestManagement": "クエスト管理", - "GMNotes": "GMノート" + "GMNotes": "GMノート", + "PlayerNotes": "プレイヤーのメモ", + "QuestManagement": "クエスト管理" + }, + "Title": "クエスト詳細", + "Tooltips": { + "AddCustom": "ユーザー定義を追加", + "AddObjective": "目標を追加", + "ChangeSplashPos": "画像の位置を調整。", + "DeleteQuestGiver": "クエスト依頼主削除。", + "DeleteSplash": "カバー画像を削除します。", + "HideAll": "全非表示", + "LockAll": "全ロック", + "PrimaryQuestSet": "メインクエストに設定。", + "PrimaryQuestUnset": "メインクエストから削除。", + "RewardHidden": "報酬は非表示になっています。クリックで表示できます。", + "RewardLocked": "報酬はロックされています。クリックでアンロックできます。", + "RewardLockedPlayer": "報酬はロックされています。", + "RewardUnlocked": "報酬はアンロックされています。", + "RewardUnlockedPlayer": "報酬はアンロックされています。", + "RewardVisible": "報酬は表示されています。クリックで非表示できます。", + "ShowAll": "全表示", + "TaskHidden": "目標は非表示になっています。クリックで表示できます。", + "TaskVisible": "目標表示されています。クリックで非表示できます。", + "ToggleImage": "キャラ・コマ画像切替。", + "UnlockAll": "全アンロック", + "ViewSplashArt": "表紙画像を見る。" } - }, - - "DeleteDialog": { - "Title": "{name}を削除します", - "Header": "本当によろしいですか?", - "Body": "このクエストとその内容はすべて削除されます。", - "Delete": "削除", - "Cancel": "取り消す" - }, - - "CloseDialog": { - "Title": "記入をやめようとしています", - "Header": "本当によろしいですか?", - "Body": "保存されていない内容は失われます。", - "Discard": "保存を破棄する", - "Cancel": "戻る" + "QuestTracker": { + "NoPrimary": "メインクエスト無し。", + "Title": "クエスト一覧", + "Tooltips": { + "BackgroundShow": "クリックすると背景が表示されます。", + "BackgroundUnshow": "クリックすると背景が透明になります。", + "PrimaryQuestShow": "クリックでメインクエストを表示。", + "PrimaryQuestUnshow": "クリックですべてのクエスト表示。" + } }, - - "Notifications": { - "CannotOpen": "クエストの内容を開けませんでした。権限が無いかクエストが存在しないかもしれません。", - "UserCantOpen": "{user}はこのクエストを開く権限を持っていません。", - "LinkCopied": "このクエストのエンティティリンクをコピーしました。", - "QuestMoved": "クエストを新たなフォルダに移動し状態を{target}に変更しました。" + "QuestTypes": { + "Labels": { + "Active": "進行中", + "active": "進行中", + "Available": "受注可能", + "available": "受注可能", + "Completed": "完了", + "completed": "完了", + "Failed": "失敗", + "failed": "失敗", + "InActive": "無効", + "inactive": "無効", + "Status": "クエスト状態{statusLabel}。" + }, + "Tooltips": { + "SetActive": "進行中として設定", + "SetAvailable": "利用可能に設定", + "SetCompleted": "完了として設定", + "SetFailed": "失敗として設定", + "SetInactive": "非アクティブに設定", + "Status": "状態:{statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "プレイヤー受注可", + "EnableHint": "プレイヤーたちは受注可能タブからクエストを受注することが可能になります。" + }, + "allowPlayersCreate": { + "Enable": "プレイヤー作成可", + "EnableHint": "チェックをいれることでプレイヤーが独自にクエストを作成できるようになります。プレイヤーが作成したクエストは受注可能タブに表示されます。この機能を使うにはプレイヤーの権限に「資料の作成」を付与している必要があります。" + }, "allowPlayersDrag": { "Enable": "報酬のドラッグを許可", "EnableHint": "プレイヤーはクエスト報酬にあるアイテム等を自分のキャラシにドラッグできるようになります。" }, - "availableQuests": { - "Enable": "受注可能タブを表示する", - "EnableHint": "許可するとプレイヤーは新たな「受注可能」タブを閲覧できるようになり、受注・秘匿されていないクエストの閲覧が可能となります。" - }, "countHidden": { "Enable": "隠しタスクをカウントする", "EnableHint": "オンにすることでクエストの合計目標数に隠し目標も含まれるようになります。" }, + "defaultPermissionLevel": { + "Enable": "デフォルト", + "EnableHint": "新規クエスト作成時の権限レベルを設定します。", + "NONE": "なし", + "OBSERVER": "監視者(Observer)", + "OWNER": "所有者(Owner)" + }, + "dynamicBookmarkBackground": { + "Enable": "動的しおり背景", + "EnableHint": "有効化時、しおりタブは自動的に現在のウィンドウの背景に置かれます。" + }, + "hideFQLFromPlayers": { + "Enable": "PLからクエスト一覧を隠す", + "EnableHint": "有効化のとき、PLはクエスト一覧を閲覧できなくなります。GM権限を持っているユーザは依然として閲覧できます。" + }, "navStyle": { - "Enable": "タブのスタイル", - "EnableHint": "クエストログのタブをどのように表示するのかを設定します", "bookmarks": "しおり風", - "classic": "クラシック風" + "classic": "クラシック風", + "Enable": "タブのスタイル", + "EnableHint": "クエストログのタブをどのように表示するのかを設定します。" + }, + "notifyRewardDrop": { + "Enable": "報酬ドロップ通知", + "EnableHint": "プレイヤーのキャラクターに報酬が移動されたことを通知します。" + }, + "questTrackerResizable": { + "Enable": "クエスト一覧リサイズ可能", + "EnableHint": "クエスト一覧の大きさを手動で変更できるようにします。" }, "showFolder": { "Enable": "クエストフォルダーを表示する", "EnableHint": "クエストデータが含まれているフォルダを表示する。デバッグ用。" }, "showTasks": { + "default": "完了/合計", "Enable": "クエストログにクエスト内容を表示する", "EnableHint": "クエストの名前の隣にそのクエストに付随する内容の表示の仕方を設定します。クエストの詳細画面には効果ありません。", - "default": "完了/合計", - "onlyCurrent": "完了のみ", - "no": "内容の列を隠す" - }, - "titleAlign": { - "Enable": "クエスト名位置合わせ", - "EnableHint": "クエストログのクエスト名の位置を調整するための設定です", - "left": "左寄せ", - "center": "中央" - }, - "playersWelcomeScreen": { - "Enable": "プレイヤーにウェルカム画面を表示する", - "EnableHint": "チェックを外すとプレイヤーたちがアップデート後にログインしたときに表示されるウェルカム画面を見えなくなります。クエストログのヘルプボタンを押すことで再び表示できます。" + "no": "内容の列を隠す", + "onlyCurrent": "完了のみ" }, - "allowPlayersAccept": { - "Enable": "プレイヤー受注可", - "EnableHint": "プレイヤーたちは受注可能タブからクエストを受注することが可能になります。" - }, - "allowPlayersCreate": { - "Enable": "プレイヤー作成可", - "EnableHint": "チェックをいれることでプレイヤーが独自にクエストを作成できるようになります。プレイヤーが作成したクエストは受注可能タブに表示されます。この機能を使うにはプレイヤーの権限に「資料の作成」を付与している必要があります。" + "trustedPlayerEdit": { + "Enable": "優良プレイヤークエスト編集権限", + "EnableHint": "優良プレイヤーとして指定されているPLに所持しているクエストを編集するための上位の権限を付与します。" } }, - "Tooltips": { - "SetAvailable": "受注可能にする", - "SetActive": "進行中にする", - "SetCompleted": "完了にする", - "SetFailed": "失敗にする", - "Hide": "秘匿", "Delete": "削除", - "AddAbstractReward": "抽象報酬を設定する", - "PersonalQuestButNoPlayers": "これは個人クエストですが誰も見ることができません。", - "PersonalQuestVisibleFor": "これは個人クエストです", - "RewardHidden": "報酬は秘匿されています。クリックして表示します。", - "RewardVisible": "報酬は表示されています。クリックして秘匿します。", - "TaskHidden": "内容が秘匿されています。クリックして表示します。", - "TaskVisible": "内容が表示されています。クリックして秘匿します。", - "ToggleImage": "コマ/キャラの画像切替" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "「{name}」クエストを開くt", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Edit": "編集", + "HiddenQuestNoPlayers": "このクエストはPLに表示されていません。", + "PrimaryQuest": "メインクエスト" } } -} +} \ No newline at end of file diff --git a/lang/ko.json b/lang/ko.json index 6a23e54e..8139b55c 100644 --- a/lang/ko.json +++ b/lang/ko.json @@ -1,202 +1,256 @@ { "ForienQuestLog": { - "NewQuest": "새 퀘스트", - "QuestLogButton": "퀘스트 로그", - "Quests": "{0} 퀘스트", - "SampleReward": "예시. 300 경험치", - "SampleTask": "예시. 꼬인 발목 여관에 있는 모든 쥐를 처리해주세요", - - "QuestTypes": { - "InProgress": "진행 중", - "Completed": "성공", - "Failed": "실패", - "Hidden": "비공개", - "Labels": { - "available": "활성화", - "active": "진행 중", - "completed": "성공", - "failed": "실패", - "hidden": "비공개" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "열려 있는 ”{name}”" + }, + "Notifications": { + "NoQuest": "API 오류: 잘못된 퀘스트 ID로 매크로를 생성할 수 없습니다." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "새 퀘스트" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (quest reward): {userName} 유저가 '{itemName}' 아이템을 {actorName} 액터에 가져갔습니다." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "UUID: {uuid}에 대해 엔티티를 불러올 수 없습니다.", + "NoPermission": "사용 권한이 부족하여 이 엔티티 시트를 볼 수 없습니다." + } } }, - - "Buttons": { - "AddNewQuest": "새 퀘스트 추가", - "AddNewTask": "새 목표 추가" + "DeleteDialog": { + "BodyObjective": "이 목표와 데이터가 영구적으로 삭제됩니다.", + "BodyQuest": "이 퀘스트와 데이터가 영구적으로 삭제됩니다.", + "BodyReward": "이 보상과 데이터가 영구적으로 삭제됩니다.", + "Cancel": "취소", + "Delete": "삭제", + "HeaderDel": "정말로 삭제하시겠습니까? :

'{name}'

", + "TitleDel": "{name} 삭제" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "플레이어에게 표시" + }, + "Quest": "퀘스트" + }, + "Migration": { + "ChatMessage": { + "Footer": "위 퀘스트를 컴펜디움 또는 월드의 유효 문서 데이터로 수동으로 업데이트 해야 합니다.
", + "Header": "Forien's Quest Log (DB 마이그레이션)
아래 퀘스트에서 연결되지 않은 퀘스트 제공자 또는 보상 아이템을 제거했습니다.

", + "Notification": "Forien's Quest Log - 하나 이상의 연결되지 않은 퀘스트 제공자 또는 보상 아이템이 제거되었습니다. 자세한 내용은 채팅 메시지를 확인하십시오.", + "QuestGiver": "퀘스트 제공자", + "QuestRewards": "퀘스트 보상" + }, + "Notifications": { + "Complete": "Forien's Quest Log - 데이터 마이그레이션 완료.", + "CouldNotMigrate": "Forien's Quest Log - 마이그레이션 할 수 없었음. 퀘스트: '{name}'.", + "Schema": "Forien's Quest Log - 스키마 버전 '{version}' 데이터 마이그레이션 중.", + "Start": "Forien's Quest Log - 데이터 마이그레이션 중, 리로드하지 마십시오." + } }, - - "QuestForm": { - "Title": "새 퀘스트 추가", - "QuestGiver": "퀘스트 의뢰인", - "QuestGiverPlaceholder": "액터의 이름 혹은 엔티티의 UUID", - "QuestTitle": "퀘스트 제목", - "DragDropActor": "액터, 아이템, 저널을 여기로 끌어다 놓아 퀘스트 의뢰인을 추가합니다", - "QuestDescription": "퀘스트 설명", - "QuestGMNotes": "GM 노트", - "Submit": "완료", - "SubquestOf": "{name}의 서브 퀘스트" + "Notifications": { + "CannotOpen": "퀘스트 세부 정보를 열 수 없습니다. 권한이 없거나 퀘스트가 더 이상 존재하지 않거나 제공된 ID가 유효하지 않을 수 있습니다.", + "FinishQuestAdded": "다른 퀘스트를 추가하기 전 현재 새 퀘스트를 편집 완료하여 닫으십시오.", + "LinkCopied": "이 퀘스트에 대한 엔티티 링크가 클립보드에 복사 되었습니다.", + "QuestAdded": "'{status}' 상태로 '{name}' 새 퀘스트가 추가되었습니다.", + "QuestIDCopied": "이 퀘스트의 퀘스트 ID가 클립보드에 복사되었습니다.", + "QuestMoved": "퀘스트를 새 폴더로 이동하고 새 상태를 부여했습니다: '{target}'.", + "QuestPrimary": "'{name}' 퀘스트는 새로운 중요 퀘스트입니다..", + "QuestTrackerNoActive": "퀘스트 트래커가 활성화 되었지만 진행 중인 퀘스트가 없습니다.", + "UserCantOpen": "'{user}' 플레이어는 이 퀘스트를 열람할 권한을 가지고 있지 않습니다." }, - "QuestLog": { - "Title": "퀘스트 로그", - "SubTitle": "연관 : {0}", - "Table": { - "QuestGiver": "퀘스트 의뢰인", - "QuestTitle": "제목", - "Tasks": "목표", - "Actions": "액션" + "Buttons": { + "AddQuest": "퀘스트 추가" }, - "Tabs": { - "Available": "활성화", - "InProgress": "진행 중", - "Completed": "완료", - "Failed": "실패", - "Hidden": "비공개" + "ContextMenu": { + "CopyEntityLink": "엔티티 내용 링크 복사", + "CopyQuestID": "퀘스트 ID 복사", + "PrimaryQuest": "중요 퀘스트로 설정/해제" + }, + "Labels": { + "TableHeader": "{0} 퀘스트", + "SubTitle": "서브 퀘스트 : {0}" + }, + "Title": "퀘스트 로그", + "Tooltips": { + "Objectives": "목표" } }, - "QuestPreview": { - "Title": "퀘스트 세부 정보", - "SubTitle": "연관 : {0}", - "Objectives": "목표", - "Rewards": "보상", - "DragDropRewards": "보상으로 추가할 아이템을 여기로 끌어다 놓으십시오", - "InvalidQuestId": "퀘스트 ID가 잘못되어 미리보기를 열 수 없음.", - "HeaderButtons": { - "Show": "플레이어들에게 보이기" - }, - + "Buttons": { + "RewardCustom": "사용자 정의", + "RewardHide": "모두 숨기기", + "RewardLock": "모두 잠그다", + "RewardShow": "모두 보기", + "RewardUnlock": "모두 잠금 해제" + }, + "Labels": { + "CustomSource": "사용자 지정 공급자", + "Description": "설명:", + "DragDropActor": "액터, 아이템, 저널 엔트리를 끌어다 놓아 퀘스트 제공자로 지정합니다.", + "DragDropActorPlayer": "액터, 아이템, 저널 엔트리를 드래그&드롭 하십시오.", + "DragDropRewards": "보상으로 추가할 아이템을 여기로 끌어다 놓으십시오.", + "GMNotes": "GM 메모:", + "Objective": "목표", + "Objectives": "목표:", + "PlayerNotes": "플레이어 노트:", + "Reward": "보상", + "Rewards": "보상:" + }, "Management": { - "IsPersonalQuest": "개인적 퀘스트입니까?", - "IsPersonalQuestDescription": "퀘스트를 개인적으로 표시하려면 체크한다. 체크된 플레이어를 제외한 모든 플레이어들이 볼 수 없으며 이 옵션을 선택 해제하면 모든 권한이 제거되고 퀘스트가 비공개 탭으로 이동한다.", - "SplashArt": "스플래시 아트", - "QuestBranching": "서브 퀘스트", - "AddSubquest": "서브 퀘스트 생성", - "CanPlayerEdit": "플레이어의 세부 정보 수정 허용" - }, - + "AddSubquest": "새 서브 퀘스트 생성", + "ConfigurePermissions": "권한 설정", + "QuestBranching": "서브 퀘스트:", + "QuestSettings": "퀘스트 설정:", + "SplashArt": "스플래시 아트:", + "SplashInfo": "클릭하여 이미지 설정.", + "SplashQuestIcon": "퀘스트 아이콘으로 설정" + }, + "Notifications": { + "BadUUID": "UUID: {uuid}에 대한 문서를 검색할 수 없습니다.", + "WrongDocType": "Forien's Quest Log는 월드/컴펜디움 액터, 아이템, 저널 항목만을 퀘스트 제공자로 받을 수 있습니다.", + "WrongItemType": "Forien's Quest Log는 월드 아이템과 컴펜디움 아이템만을 보상으로 할 수 있습니다." + }, "Tabs": { "Details": "세부 정보", - "QuestManagement": "퀘스트 관리", - "GMNotes": "GM 노트" + "GMNotes": "GM 노트", + "PlayerNotes": "플레이어 노트", + "QuestManagement": "퀘스트 관리" + }, + "Title": "퀘스트 세부 정보 - {name}", + "Tooltips": { + "AddCustom": "사용자 정의 추가", + "AddObjective": "목표 추가", + "ChangeSplashPos": "스플래시 아트 정렬 변경.", + "DeleteQuestGiver": "퀘스트 제공자 제거.", + "DeleteSplash": "스플래시 아트 제거.", + "HideAll": "모두 숨기기", + "LockAll": "모두 잠그다", + "PrimaryQuestSet": "중요 퀘스트를 만들려면 클릭한다.", + "PrimaryQuestUnset": "중요 퀘스트를 해제하려면 클릭한다.", + "RewardHidden": "보상이 비공개 상태입니다. 공개하려면 클릭하십시오.", + "RewardLocked": "보상이 잠금 상태입니다. 해제하려면 클릭하십시오.", + "RewardLockedPlayer": "보상이 잠겼습니다.", + "RewardUnlocked": "보상이 잠금 해제 상태입니다. 잠그려면 클릭하십시오.", + "RewardUnlockedPlayer": "보상이 잠금 해제 되었습니다.", + "RewardVisible": "보상이 공개 상태입니다. 비공개하려면 클릭하십시오.", + "ShowAll": "모두 보기", + "TaskHidden": "목표가 비공개 상태입니다. 공개하려면 클릭하십시오.", + "TaskVisible": "목표가 공개 상태입니다. 비공개하려면 클릭하십시오.", + "ToggleImage": "토큰/액터 이미지 전환.", + "UnlockAll": "모두 잠금 해제", + "ViewSplashArt": "스플래시 아트를 봅니다." } - - }, - - "DeleteDialog": { - "Title": "{name} 삭제", - "Header": "확실합니까?", - "Body": "이 퀘스트와 데이터가 영구적으로 삭제됩니다.", - "Delete": "삭제", - "Cancel": "취소" }, - - "CloseDialog": { - "Title": "삭제", - "Header": "확실합니까??", - "Body": "작성 화면을 닫으시겠습니까? 저장되지 않은 데이터가 손실됩니다.", - "Discard": "폐기", - "Cancel": "취소" + "QuestTracker": { + "NoPrimary": "가능한 중요 퀘스트가 없습니다.", + "Title": "퀘스트 트래커", + "Tooltips": { + "BackgroundShow": "클릭하여 배경을 표시.", + "BackgroundUnshow": "클릭하여 배경을 투명화.", + "PrimaryQuestShow": "중요 퀘스트를 표시하려면 클릭한다.", + "PrimaryQuestUnshow": "모든 퀘스트를 표시하려면 클릭한다." + } }, - - "Notifications": { - "CannotOpen": "퀘스트 세부 정보를 열 수 없습니다. 권한이 없거나 퀘스트가 더 이상 존재하지 않거나 제공된 ID가 유효하지 않을 수 있습니다.", - "UserCantOpen": "{user} 플레이어는 이 퀘스트를 열람할 권한을 가지고 있지 않습니다.", - "LinkCopied": "이 퀘스트에 대한 엔티티 링크가 클립보드에 복사 되었습니다.", - "QuestMoved": "퀘스트를 새 폴더로 이동하고 새 상태를 부여했습니다 : {target}" + "QuestTypes": { + "Labels": { + "Active": "진행 중", + "active": "진행 중", + "Available": "활성화", + "available": "활성화", + "Completed": "성공", + "completed": "완료된", + "Failed": "실패", + "failed": "실패한", + "InActive": "비활성화", + "inactive": "비공개", + "Status": "{statusLabel} 상태인 퀘스트입니다." + }, + "Tooltips": { + "SetActive": "진행 중으로 설정", + "SetAvailable": "활성화로 설정", + "SetCompleted": "완료로 설정", + "SetFailed": "실패로 설정", + "SetInactive": "비활성으로 설정", + "Status": "상태: {statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "플레이어가 수락 가능", + "EnableHint": "플레이어가 활성화 탭에서 퀘스트를 수락할 수 있도록 하려면 선택한다." + }, + "allowPlayersCreate": { + "Enable": "플레이어가 생성 가능", + "EnableHint": "플레이어가 퀘스트를 만들 수 있게 하려면 선택한다. 플레이어가 만든 퀘스트는 플레이어 편집 권한으로 활성화 탭으로 이동된다. 코어 욥션의 '저널 생성' 권한 필요." + }, "allowPlayersDrag": { - "Enable": "플레이어에게 보상 드래그 허용", + "Enable": "플레이어에게 보상을 인벤토리로 드래그 허용", "EnableHint": "플레이어들이 퀘스트 세부 정보 창에서 자신의 소유 액터로 보상을 드래그 할 수 있도록 하려면 선택한다." }, - "availableQuests": { - "Enable": "활성화 탭 표시", - "EnableHint": "퀘스트 로그에 \"활성화\" 탭을 표시하려면 선택한다. 비공개 상태가 아닌 모든 퀘스트들을 수락하기 전에 볼 수 있다." - }, "countHidden": { "Enable": "비공개 목표 세기", "EnableHint": "선택될 경우 완료/전체 목표의 수에 비공개된 목표가 포함된다." }, + "defaultPermissionLevel": { + "Enable": "퀘스트 권한 레벨 기본값", + "EnableHint": "새 퀘스트를 생성할 때 기본 권한 레벨을 설정한다.", + "NONE": "없음", + "OBSERVER": "관찰자", + "OWNER": "소유자" + }, + "dynamicBookmarkBackground": { + "Enable": "동적 북마크 배경", + "EnableHint": "이 옵션을 활성화하면 북마크 탭 배경이 퀘스트 창 컨텐츠 배경으로 설정된다." + }, + "hideFQLFromPlayers": { + "Enable": "퀘스트 로그를 플레이어에게 숨기기", + "EnableHint": "활성화할 경우 퀘스트 로그가 모든 플레이어에게 숨겨진다. GM 레벨 유저만 퀘스트 로그에 액세스 할 수 있다." + }, "navStyle": { - "Enable": "내비게이션 스타일", - "EnableHint": "퀘스트 로그의 내비게이션 표시 방법을 정한다.", "bookmarks": "북마크", - "classic": "고전적 탭" + "classic": "고전적 탭", + "Enable": "내비게이션 스타일", + "EnableHint": "퀘스트 로그의 내비게이션 표시 방법을 정한다." + }, + "notifyRewardDrop": { + "Enable": "보상 드롭 알림 표시", + "EnableHint": "퀘스트 보상을 플레이어 시트에 놓을 때 UI 알림을 확인한다." + }, + "questTrackerResizable": { + "Enable": "퀘스트 트래커 크기 조절 기능", + "EnableHint": "활성화시 퀘스트 트래커의 크기를 수동으로 조절할 수 있다." }, "showFolder": { "Enable": "퀘스트 폴더 보이기", "EnableHint": "저널 탭에 퀘스트 데이터 폴더를 표시하려면 선택한다. 디버그만을 위한 것이다." }, "showTasks": { + "default": "목표 보기: 완료/전체", "Enable": "퀘스트 로그에 목표 표시", "EnableHint": "퀘스트 로그에서 퀘스트 제목 옆에 목표를 표시할 것인지, 또는 어떻게 표시할 지를 결정한다. 이는 퀘스트 개별 미리보기에는 영향을 미치지 않는다.", - "default": "목표 보기: 완료/전체", - "onlyCurrent": "목표 보기: 완료", - "no": "\"목표\" 열 숨김" - }, - "titleAlign": { - "Enable": "퀘스트 제목 정렬", - "EnableHint": "퀘스트 기록에 퀘스트 제목을 배치하는 방법을 정한다.", - "left": "좌측 정렬", - "center": "중앙 정렬" - }, - "playersWelcomeScreen": { - "Enable": "플레이어에게 환영 화면 표시", - "EnableHint": "업데이트 후 로그인 시 플레이어가 시작 화면을 볼 수 없도록 하려면 선택을 취소할 것. 시작 화면은 Quest Log의 Help 아이콘을 클릭하여 볼 수 있다." - }, - "allowPlayersAccept": { - "Enable": "플레이어가 수락 가능", - "EnableHint": "플레이어가 활성화 탭에서 퀘스트를 수락할 수 있도록 하려면 선택한다." + "no": "\"목표\" 열 숨김", + "onlyCurrent": "목표 보기: 완료" }, - "allowPlayersCreate": { - "Enable": "플레이어가 생성 가능", - "EnableHint": "플레이어가 퀘스트를 만들 수 있게 하려면 선택한다. 플레이어가 만든 퀘스트는 플레이어 편집 권한으로 활성화 탭으로 이동된다. 코어 욥션의 '저널 생성' 권한 필요." + "trustedPlayerEdit": { + "Enable": "신뢰할 수 있는 플레이어의 퀘스트 편집 허용", + "EnableHint": "신뢰할 수 있는 플레이어가 퀘스트 소유를 넘어 퀘스트 편집 권한 확장과 상태 제어 권한을 허용하도록 하려면 선택하십시오." } }, - "Tooltips": { - "SetAvailable": "활성화로 설정", - "SetActive": "진행 중으로 설정", - "SetCompleted": "완료로 설정", - "SetFailed": "실패로 설정", - "Hide": "비공개", "Delete": "삭제", - "AddAbstractReward": "추상적 보상 추가", - "PersonalQuestButNoPlayers": "이 퀘스트는 개인적인 것이며 누구도 볼 수 없습니다.", - "PersonalQuestVisibleFor": "다음 플레이어를 위한 개인적인 퀘스트입니다 ", - "RewardHidden": "보상이 비공개 상태입니다. 공개하려면 클릭하십시오.", - "RewardVisible": "보상이 공개 상태입니다. 비공개하려면 클릭하십시오.", - "TaskHidden": "목표가 비공개 상태입니다. 공개하려면 클릭하십시오.", - "TaskVisible": "목표가 공개 상태입니다. 비공개하려면 클릭하십시오.", - "ToggleImage": "토큰/액터 이미지 토글" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "„{name}” 퀘스트 열기", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Edit": "편집", + "HiddenQuestNoPlayers": "이 퀘스트는 모든 플레이어에게 숨겨져 있습니다.", + "PrimaryQuest": "중요 퀘스트" } } -} +} \ No newline at end of file diff --git a/lang/missing/cn.json b/lang/missing/cn.json deleted file mode 100644 index 55b389fe..00000000 --- a/lang/missing/cn.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ForienQuestLog.QuestPreview.SubTitle": "", - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/de.json b/lang/missing/de.json deleted file mode 100644 index 9143a11a..00000000 --- a/lang/missing/de.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "ForienQuestLog.Api.hooks.createOpenQuestMacro.error.noQuest": "", - "ForienQuestLog.Api.hooks.createOpenQuestMacro.name": "", - "ForienQuestLog.Notifications.CannotOpen": "", - "ForienQuestLog.Api.create.title": "", - "ForienQuestLog.QuestForm.SubquestOf": "", - "ForienQuestLog.CloseDialog.Title": "", - "ForienQuestLog.CloseDialog.Header": "", - "ForienQuestLog.CloseDialog.Body": "", - "ForienQuestLog.CloseDialog.Cancel": "", - "ForienQuestLog.CloseDialog.Discard": "", - "ForienQuestLog.QuestPreview.InvalidQuestId": "", - "ForienQuestLog.QuestPreview.HeaderButtons.Show": "", - "ForienQuestLog.Notifications.LinkCopied": "", - "ForienQuestLog.SampleReward": "", - "ForienQuestLog.Tooltips.PersonalQuestVisibleFor": "", - "ForienQuestLog.Tooltips.PersonalQuestButNoPlayers": "", - "ForienQuestLog.Api.reward.create.type": "", - "ForienQuestLog.Api.reward.create.data": "", - "ForienQuestLog.Api.task.create.name": "", - "ForienQuestLog.Settings.availableQuests.Enable": "", - "ForienQuestLog.Settings.availableQuests.EnableHint": "", - "ForienQuestLog.Settings.allowPlayersDrag.Enable": "", - "ForienQuestLog.Settings.allowPlayersDrag.EnableHint": "", - "ForienQuestLog.Settings.allowPlayersCreate.Enable": "", - "ForienQuestLog.Settings.allowPlayersCreate.EnableHint": "", - "ForienQuestLog.Settings.allowPlayersAccept.Enable": "", - "ForienQuestLog.Settings.allowPlayersAccept.EnableHint": "", - "ForienQuestLog.Settings.countHidden.Enable": "", - "ForienQuestLog.Settings.countHidden.EnableHint": "", - "ForienQuestLog.Settings.playersWelcomeScreen.Enable": "", - "ForienQuestLog.Settings.playersWelcomeScreen.EnableHint": "", - "ForienQuestLog.Settings.showFolder.Enable": "", - "ForienQuestLog.Settings.showFolder.EnableHint": "", - "ForienQuestLog.Notifications.UserCantOpen": "", - "ForienQuestLog.QuestPreview.SubTitle": "", - "ForienQuestLog.Tooltips.SetAvailable": "", - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.Tooltips.TaskHidden": "", - "ForienQuestLog.Tooltips.TaskVisible": "", - "ForienQuestLog.Tooltips.AddAbstractReward": "", - "ForienQuestLog.Tooltips.RewardHidden": "", - "ForienQuestLog.Tooltips.RewardVisible": "", - "ForienQuestLog.QuestPreview.Management.CanPlayerEdit": "", - "ForienQuestLog.QuestPreview.Management.IsPersonalQuest": "", - "ForienQuestLog.QuestPreview.Management.IsPersonalQuestDescription": "", - "ForienQuestLog.QuestPreview.Management.SplashArt": "", - "ForienQuestLog.QuestPreview.Management.QuestBranching": "", - "ForienQuestLog.QuestPreview.Management.AddSubquest": "", - "ForienQuestLog.QuestForm.DragDropActor": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.QuestLog.Tabs.Available": "", - "ForienQuestLog.Buttons.AddNewFolder": "", - "ForienQuestLog.QuestPreview.Tabs.QuestManagement": "" -} \ No newline at end of file diff --git a/lang/missing/en.json b/lang/missing/en.json deleted file mode 100644 index 9e26dfee..00000000 --- a/lang/missing/en.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/lang/missing/es.json b/lang/missing/es.json deleted file mode 100644 index 7eaddf9c..00000000 --- a/lang/missing/es.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/fr.json b/lang/missing/fr.json deleted file mode 100644 index 7eaddf9c..00000000 --- a/lang/missing/fr.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/ja.json b/lang/missing/ja.json deleted file mode 100644 index 7eaddf9c..00000000 --- a/lang/missing/ja.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/ko.json b/lang/missing/ko.json deleted file mode 100644 index 7eaddf9c..00000000 --- a/lang/missing/ko.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/pl.json b/lang/missing/pl.json deleted file mode 100644 index db914e22..00000000 --- a/lang/missing/pl.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "ForienQuestLog.Api.hooks.createOpenQuestMacro.error.noQuest": "", - "ForienQuestLog.Api.create.title": "", - "ForienQuestLog.QuestForm.SubquestOf": "", - "ForienQuestLog.QuestPreview.InvalidQuestId": "", - "ForienQuestLog.Notifications.LinkCopied": "", - "ForienQuestLog.Api.reward.create.type": "", - "ForienQuestLog.Api.reward.create.data": "", - "ForienQuestLog.Api.task.create.name": "", - "ForienQuestLog.Settings.allowPlayersCreate.Enable": "", - "ForienQuestLog.Settings.allowPlayersCreate.EnableHint": "", - "ForienQuestLog.Settings.allowPlayersAccept.Enable": "", - "ForienQuestLog.Settings.allowPlayersAccept.EnableHint": "", - "ForienQuestLog.Settings.countHidden.Enable": "", - "ForienQuestLog.Settings.countHidden.EnableHint": "", - "ForienQuestLog.QuestPreview.SubTitle": "", - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestPreview.Management.CanPlayerEdit": "", - "ForienQuestLog.QuestPreview.Management.SplashArt": "", - "ForienQuestLog.QuestPreview.Management.QuestBranching": "", - "ForienQuestLog.QuestPreview.Management.AddSubquest": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/missing/pt-BR.json b/lang/missing/pt-BR.json deleted file mode 100644 index 55b389fe..00000000 --- a/lang/missing/pt-BR.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ForienQuestLog.QuestPreview.SubTitle": "", - "ForienQuestLog.Tooltips.Edit": "", - "ForienQuestLog.QuestForm.QuestGiverNamePlaceholder": "", - "ForienQuestLog.Buttons.AddNewFolder": "" -} \ No newline at end of file diff --git a/lang/nl.json b/lang/nl.json new file mode 100644 index 00000000..9fff87ec --- /dev/null +++ b/lang/nl.json @@ -0,0 +1,256 @@ +{ + "ForienQuestLog": { + "API": { + "QuestDB": { + "Labels": { + "NewQuest": "Nieuwe Missie" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (missiebeloning): {userName} heeft '{itemName}' op {actorName} neergezet." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Entiteit met UUID '{uuid}' kan niet geladen worden.", + "NoPermission": "Je hebt niet de juiste machtigingen om het blad van deze entiteit te bekijken." + } + }, + "Hooks": { + "Labels": { + "OpenMacro": "Open ”{name}”" + }, + "Notifications": { + "NoQuest": "API-fout: Macro met invalide Quest-ID kan niet aangemaakt worden." + } + } + }, + "DeleteDialog": { + "Delete": "Verwijderen", + "Cancel": "Annuleren", + "TitleDel": "Verwijder {title}", + "BodyObjective": "Dit doel en de bijbehorende data zullen permanent verwijderd worden.", + "BodyQuest": "Deze missie en de bijbehorende data zullen permanent verwijderd worden.", + "BodyReward": "Deze beloning en de bijbehorende data zullen permanent verwijderd worden.", + "HeaderDel": "Weet je zeker dat je

'{name}'

wil verwijderen" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Aan Spelers tonen" + }, + "Quest": "Missie" + }, + "Migration": { + "ChatMessage": { + "Notification": "Forien's Quest Log - Onverbonden missiegever of beloningen verwijderd uit een of verscheidene missies verwijderd. Lees het chatbericht voor meer informatie.", + "QuestGiver": "Missiegever", + "QuestRewards": "Missiebeloningen", + "Footer": "Je moet handmatig de bovenstaande missies updaten met valide documentdata uit compendiums of je wereld.
", + "Header": "Forien's Quest Log (DB-migratie)
Onverbonden missiegever of beloningen verwijderd uit onderstaande missies:

" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Datamigratie afgerond.", + "CouldNotMigrate": "Forien's Quest Log - Missie kan niet gemigreerd worden: '{name}'.", + "Schema": "Forien's Quest Log - Data wordt naar schemaversie '{version}' gemigreerd.", + "Start": "Forien's Quest Log - Data wordt gemigreerd, herlaad de pagina niet." + } + }, + "Notifications": { + "CannotOpen": "Kan missiedetails niet openen. Mogelijk is de missie niet meer te bekijken of bestaat de missie niet meer.", + "FinishQuestAdded": "Rond het wijzigen af en sluit de missie voordat je een nieuwe missie toevoegt.", + "QuestMoved": "'{name}' verplaatst en nieuwe status op '{target}' gezet.", + "UserCantOpen": "Gebruiker '{user}' heeft niet de juiste machtigingen om deze missie te openen.", + "LinkCopied": "Entiteitslink voor deze missie is naar het klembord gekopieerd.", + "QuestAdded": "'{name}' als nieuwe missie met status '{status}' toegevoegd.", + "QuestIDCopied": "Missie-ID voor deze missie is naar het klembord gekopieerd.", + "QuestPrimary": "'{name}' is de nieuwe primaire missie.", + "QuestTrackerNoActive": "Missietracker is geactiveerd maar er zijn momenteel geen actieve missies." + }, + "QuestLog": { + "ContextMenu": { + "CopyEntityLink": "Kopieer entiteitslink", + "CopyQuestID": "Kopieer missie-ID", + "PrimaryQuest": "Instellen/uitschakelen als primaire missie" + }, + "Labels": { + "TableHeader": "{0} Missies", + "SubTitle": "Sub-missie van {0}" + }, + "Title": "Missielogboek", + "Tooltips": { + "Objectives": "Doelen" + }, + "Buttons": { + "AddQuest": "Voeg missie toe" + } + }, + "QuestPreview": { + "Buttons": { + "RewardHide": "Verbergen", + "RewardLock": "Op slot doen", + "RewardCustom": "Gebruikergedefinieerd", + "RewardShow": "Weergeven", + "RewardUnlock": "Ontgrendelen" + }, + "Labels": { + "CustomSource": "Gebruikergedefinieerde Bron", + "Description": "Beschrijving:", + "DragDropActorPlayer": "Acteur, Voorwerp of Journaalboeking hiernaartoe slepen.", + "DragDropRewards": "Sleep voorwerpen hiernaartoe om als beloning toe te voegen.", + "GMNotes": "GM-Notities:", + "Objective": "Doel", + "Objectives": "Doelen:", + "PlayerNotes": "Speler-Notities:", + "Reward": "Beloning", + "Rewards": "Beloningen:", + "DragDropActor": "Acteur, object of journaalboeking hiernaartoe slepen of (links) klikken om als gebruikergedefinieerde bron vast te leggen." + }, + "Management": { + "AddSubquest": "Sub-missie toevoegen", + "QuestBranching": "Sub-missies:", + "ConfigurePermissions": "Machtigingen Configureren", + "SplashArt": "Omslagfoto:", + "SplashInfo": "Klik om afbeelding in te stellen.", + "SplashQuestIcon": "Als missieicoon instellen", + "QuestSettings": "Missieinstellingen:" + }, + "Tabs": { + "Details": "Details", + "GMNotes": "GM-Notities", + "PlayerNotes": "Speler-Notities", + "QuestManagement": "Missie beheren" + }, + "Title": "Missiedetails - {name}", + "Tooltips": { + "AddCustom": "Gebruikergedefinieerd Toevoegen", + "AddObjective": "Doel toevoegen", + "ChangeSplashPos": "Omslagfoto-uitlijning wijzigen.", + "DeleteQuestGiver": "Missiegever verwijderen.", + "DeleteSplash": "Omslagfoto verwijderen.", + "HideAll": "Alles verbergen", + "LockAll": "Alles vergrendelen", + "PrimaryQuestSet": "Klik om in te stellen als primaire missie.", + "RewardLocked": "Belong is vergrendeld. Klik om te ontgrendelen.", + "RewardLockedPlayer": "Beloning is vergrendeld.", + "RewardUnlocked": "Beloning is ontgrendeld. Klik om te vergrendelen.", + "RewardUnlockedPlayer": "Beloning is ontgrendeld.", + "RewardVisible": "Beloning is zichtbaar. Klik om te verbergen.", + "ShowAll": "Toon aan allen", + "TaskVisible": "Doel is zichtbaar. Klik om te verbergen.", + "ToggleImage": "Token/Acteurafbeelding omschakelen.", + "UnlockAll": "Alles ontgrendelen", + "ViewSplashArt": "Omslagfoto bekijken.", + "PrimaryQuestUnset": "Klik om uit te schakelen als primaire missie.", + "RewardHidden": "Beloning is verborgen. Klik om weer te geven.", + "TaskHidden": "Doel is verborgen. Klik om te tonen." + }, + "Notifications": { + "BadUUID": "Kon document met UUID {uuid} niet vinden.", + "WrongItemType": "Foriens Questlog accepteert allen wereld- en compendiumvoorwerpen als beloningen.", + "WrongDocType": "Foriens Questlog accepteert alleen wereld-/compendiumacteurs, -voorwerpen en -journaalboekingen als missiegever." + } + }, + "QuestTracker": { + "NoPrimary": "Geen primaire missie beschikbaar.", + "Title": "Missietracker", + "Tooltips": { + "BackgroundUnshow": "Klik om achtergrond transparent te maken.", + "PrimaryQuestShow": "Klik om primaire missie te tonen.", + "PrimaryQuestUnshow": "Klik om alle missies te tonen.", + "BackgroundShow": "Klik om achtergrond te tonen." + } + }, + "QuestTypes": { + "Labels": { + "Active": "Actief", + "active": "actief", + "Available": "Beschikbaar", + "available": "beschikbaar", + "Completed": "Voltooid", + "completed": "voltooid", + "InActive": "Inactief", + "inactive": "inactief", + "Status": "Missie is {statusLabel}.", + "Failed": "Gefaald", + "failed": "gefaald" + }, + "Tooltips": { + "SetActive": "Instellen als Actief", + "SetCompleted": "Instellen als Voltooid", + "SetFailed": "Instellen als Gefaald", + "SetInactive": "Instellen als Inactief", + "Status": "Status: {statusI18n}", + "SetAvailable": "Instellen als Beschikbaar" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Spelers kunnen missies accepteren", + "EnableHint": "Schakel deze optie in om spelers toe te staan missies uit het Beschikbaar-tabblad te accepteren." + }, + "allowPlayersCreate": { + "Enable": "Spelers kunnen missies aanmaken", + "EnableHint": "Schakel deze optie in om spelers toe te staan missies aan te maken. Door spelers gemaakte missies zullen in het Beschikbaar-tabblad verschijnen met Wijzigingsmachtigingen voor Spelers. VEREIST kernrecht 'maak journaal aan'." + }, + "allowPlayersDrag": { + "Enable": "Sta spelers toe beloningen te verslepen", + "EnableHint": "Schakel deze optie in om spelers toe te staan beloningen uit het missiedetailvenster naar hun eigen Acteurs te verslepen." + }, + "countHidden": { + "Enable": "Tel verborgen doelen", + "EnableHint": "Indien aangevinkt bevat het aantal voltooide/totale doelen ook verborgen doelen." + }, + "defaultPermissionLevel": { + "EnableHint": "Stelt het standaard machtigingsniveau in voor nieuw aangemaakte missies.", + "NONE": "Geen", + "OBSERVER": "Waarnemer", + "OWNER": "Eigenaar", + "Enable": "Standaard machtigingsniveau voor missies" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynamische bladwijzerachtergrond", + "EnableHint": "Indien aangevinkt wordt de vensterinhoud dynamisch ingesteld als achtergrond voor het bladwijzertabblad." + }, + "hideFQLFromPlayers": { + "Enable": "Verberg Missielogboek voor spelers", + "EnableHint": "Indien aangevinkt verbergt deze optie het missielogboek voor alle spelers. Alleen GM-gebruikers zullen toegang hebben tot het missielogboek." + }, + "navStyle": { + "bookmarks": "Bladwijzers", + "classic": "Klassieke tabbladen", + "Enable": "Navigatiestijl", + "EnableHint": "Stel in hoe de navigatie van het missielogboek wordt weergegeven." + }, + "notifyRewardDrop": { + "EnableHint": "Indien aangevinkt worden in de UI meldingen getoond als missiebeloningen op spelerbladen worden neergezet.", + "Enable": "Beloningsmeldingen tonen" + }, + "questTrackerResizable": { + "Enable": "Missietracker schaalbaar", + "EnableHint": "Indien aangevinkt kan de missietracker handmatig herschaald worden." + }, + "showFolder": { + "Enable": "Missiemap tonen", + "EnableHint": "Indien aangevinkt wordt de missiedatamap in het Journaal-tabblad getoond. Alleen voor DEBUG-doeleinden." + }, + "showTasks": { + "default": "Toon doelen: voltooid/totaal", + "Enable": "Doelen in missielogboek tonen", + "EnableHint": "Stel in of en hoe het aantal doelen naast de missietitel in het missielogboek wordt getoond. Dit heeft geen effect op het missievoorbeeld.", + "no": "Verberg \"doel\"-kolom", + "onlyCurrent": "Toon doelen: voltooid" + }, + "trustedPlayerEdit": { + "Enable": "Sta Vertrouwde Spelers toe om missies te wijzigen", + "EnableHint": "Indien aangevinkt hebben vertrouwde spelers uitgebreide wijzigings- en statusbeheermogelijkheden voor missies die ze in eigendom hebben." + } + }, + "Tooltips": { + "Delete": "Verwijderen", + "Edit": "Wijzigen", + "HiddenQuestNoPlayers": "Deze missie is verborgen voor alle spelers.", + "PrimaryQuest": "Primaire Missie" + } + } +} diff --git a/lang/pl.json b/lang/pl.json index 423df43d..95758501 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -1,109 +1,256 @@ { - "ForienQuestLog.QuestLog.Title": "Dziennik Misji", - "ForienQuestLog.QuestLog.Tabs.Available": "Dostępne", - "ForienQuestLog.QuestLog.Tabs.InProgress": "W trakcie", - "ForienQuestLog.QuestLog.Tabs.Completed": "Zakończone", - "ForienQuestLog.QuestLog.Tabs.Failed": "Nieudane", - "ForienQuestLog.QuestLog.Tabs.Hidden": "Ukryte", - - "ForienQuestLog.NewQuest": "Nowa misja", - "ForienQuestLog.QuestLogButton": "Dziennik", - "ForienQuestLog.Quests": "Misje", - - "ForienQuestLog.Notifications.QuestMoved": "Przeniesiono misję do nowego folderu, a jej nowy status to: {target}", - "ForienQuestLog.Notifications.CannotOpen": "Nie można otworzyć okna Misji, gdyż ona nie istnieje, podane ID jest niepoprawne, lub najzwyczajniej nie masz uprawnień do jej wyświetlenia", - "ForienQuestLog.Notifications.UserCantOpen": "Użytkownik {user} nie posiada uprawnień do otwarcia tej Misji.", - - "ForienQuestLog.Buttons.AddNewQuest": "Dodaj nową misję", - "ForienQuestLog.Buttons.AddNewTask": "dodaj", - - "ForienQuestLog.QuestTypes.InProgress": "Aktywne", - "ForienQuestLog.QuestTypes.Completed": "Zakończone", - "ForienQuestLog.QuestTypes.Failed": "Nieudane", - "ForienQuestLog.QuestTypes.Hidden": "Ukryte", - - "ForienQuestLog.QuestLog.Table.QuestGiver": "Zleceniodawca", - "ForienQuestLog.QuestLog.Table.QuestTitle": "Tytuł", - "ForienQuestLog.QuestLog.Table.Tasks": "Zadania", - "ForienQuestLog.QuestLog.Table.Actions": "Akcje", - - "ForienQuestLog.Settings.showFolder.Enable": "Pokaż Folder", - "ForienQuestLog.Settings.showFolder.EnableHint": "Kliknij, aby pokazać Folder z danymi Misji. Tylko w celach developerskich.", - - "ForienQuestLog.Settings.availableQuests.Enable": "Dostępne Misje", - "ForienQuestLog.Settings.availableQuests.EnableHint": "Kliknij, aby włączyć widoczność Dostępnych Misji. Doda to nową zakładkę w Dzienniku, która wyświetli wszystkie dostępne (nie ukryte) misje, które nie są Aktywne, Zakońćzone lub Nieudane.", - - "ForienQuestLog.Settings.allowPlayersDrag.Enable": "Pozwól graczom przeciągać nagrody", - "ForienQuestLog.Settings.allowPlayersDrag.EnableHint": "Domyślnie gracze nie mogą przeciągać nagród z Misji na swoich Aktorów. Aby na to pozwolić, zaznacż tę opcję.", - - "ForienQuestLog.Settings.showTasks.Enable": "Pokaż zadania w Dzienniku", - "ForienQuestLog.Settings.showTasks.EnableHint": "Zdecyduj czy, i w jaki sposób wyświetlać ilość Zadań obok tytułu Misji w Dzienniku Misji. Nie wpływa na widoczność Zadań na ekranie podglądu Misji.", - "ForienQuestLog.Settings.showTasks.default": "Pokaż zadania: wykonane/wszystkie", - "ForienQuestLog.Settings.showTasks.onlyCurrent": "Pokaż zadania: wykonane", - "ForienQuestLog.Settings.showTasks.no": "Ukryj kolumnę zadań", - - "ForienQuestLog.Settings.navStyle.Enable": "Styl nawigacji", - "ForienQuestLog.Settings.navStyle.EnableHint": "Zdecyduj jak chcesz przełączać się między rodzajami Misji.", - "ForienQuestLog.Settings.navStyle.bookmarks": "Zakładki", - "ForienQuestLog.Settings.navStyle.classic": "Klasyczne karty", - - "ForienQuestLog.Settings.titleAlign.Enable": "Wyrównanie tytułów Misji", - "ForienQuestLog.Settings.titleAlign.EnableHint": "Zdecyduj jak wyrównać tytuły Misji w Dzienniku Misji.", - "ForienQuestLog.Settings.titleAlign.left": "Wyrównaj do lewej", - "ForienQuestLog.Settings.titleAlign.center": "Wyśrodkuj", - - "ForienQuestLog.Settings.playersWelcomeScreen.Enable": "Pokazuj graczom Ekran Powitalny", - "ForienQuestLog.Settings.playersWelcomeScreen.EnableHint": "Odznacz, aby graczom nie wyświetlać po zalogowaniu Ekranu Powitalnego z każdą nową wersją. Gracze wciąż mogą go wyświetlić klikając na ikonę \"pomocy\" w Dzienniku Misji.", - - "ForienQuestLog.QuestForm.Title": "Stwórz nową Misję", - "ForienQuestLog.QuestForm.QuestGiver": "Zleceniodawca", - "ForienQuestLog.QuestForm.QuestGiverPlaceholder": "Imię Aktora lub UUID obiektu", - "ForienQuestLog.QuestForm.QuestTitle": "Tytuł misji", - "ForienQuestLog.QuestForm.QuestDescription": "Opis misji", - "ForienQuestLog.QuestForm.QuestGMNotes": "Notatki MG", - "ForienQuestLog.QuestForm.Submit": "Zapisz", - "ForienQuestLog.QuestForm.DragDropActor": "Przeciągnij Aktora, Przedmiot lub Notatkę w to miejsce, aby ustawić jako zleceniodawcę", - - "ForienQuestLog.SampleTask": "np. Zabij wszystkie szczury w karczmie „Pod Skręconą Kostką”", - "ForienQuestLog.SampleReward": "np. „100 Punktów Doświadczenia”", - - "ForienQuestLog.QuestPreview.Title": "Podgląd Misji", - "ForienQuestLog.QuestPreview.Objectives": "Zadania", - "ForienQuestLog.QuestPreview.Rewards": "Nagrody", - "ForienQuestLog.QuestPreview.Tabs.Details": "Szczegóły", - "ForienQuestLog.QuestPreview.Tabs.QuestManagement": "Zarządzaj Misją", - "ForienQuestLog.QuestPreview.Tabs.GMNotes": "Notatki MG", - "ForienQuestLog.QuestPreview.DragDropRewards": "Kliknij i Przeciągnij przedmioty w to miejsce, aby dodać je jako nagrody", - "ForienQuestLog.QuestPreview.Management.IsPersonalQuest": "Misja Prywatna", - "ForienQuestLog.QuestPreview.Management.IsPersonalQuestDescription": "Zaznacz, aby utworzyć misję prywatną. Będzie ona niewidoczna dla wszystkich graczy z wyjątkiem tych oznaczonych poniżej. Wyłączenie tej opcji usunie wszystkie uprawnienia i przeniesie tę misję do Ukrytych.", - "ForienQuestLog.QuestPreview.HeaderButtons.Show": "Pokaż Graczom", - - "ForienQuestLog.DeleteDialog.Title": "Usuń {name}", - "ForienQuestLog.DeleteDialog.Header": "Na pewno?", - "ForienQuestLog.DeleteDialog.Body": "Ta misja i związane z nią dane zostaną utracone na stałe.", - "ForienQuestLog.DeleteDialog.Delete": "Usuń", - "ForienQuestLog.DeleteDialog.Cancel": "Anuluj", - - "ForienQuestLog.CloseDialog.Title": "Opuszczasz formularz", - "ForienQuestLog.CloseDialog.Header": "Czy na pewno?", - "ForienQuestLog.CloseDialog.Body": "Opuszczasz formularz bez zapisania go. Jeśli to zrobisz, utracisz niezapisane zmiany.", - "ForienQuestLog.CloseDialog.Cancel": "Anuluj", - "ForienQuestLog.CloseDialog.Discard": "Odrzuć zmiany", - - "ForienQuestLog.Tooltips.ToggleImage": "Przełącz obraz Aktora/Tokenu", - "ForienQuestLog.Tooltips.SetActive": "Ustaw na Aktywną", - "ForienQuestLog.Tooltips.SetCompleted": "Ustaw jako Zakończoną", - "ForienQuestLog.Tooltips.SetFailed": "Ustaw jako Nieudaną", - "ForienQuestLog.Tooltips.Hide": "Ukryj", - "ForienQuestLog.Tooltips.Delete": "Usuń", - "ForienQuestLog.Tooltips.SetAvailable": "Ustaw jako Dostępną", - "ForienQuestLog.Tooltips.TaskHidden": "Zadanie ukryte. Kliknij aby pokazać.", - "ForienQuestLog.Tooltips.TaskVisible": "Zadanie widoczne. Kliknij aby ukryć.", - "ForienQuestLog.Tooltips.AddAbstractReward": "Dodaj sztuczną nagrodę", - "ForienQuestLog.Tooltips.RewardHidden": "Nagroda ukryta. Kliknij aby pokazać.", - "ForienQuestLog.Tooltips.RewardVisible": "Nagroda widoczna. Kliknij aby ukryć.", - "ForienQuestLog.Tooltips.PersonalQuestVisibleFor": "Misja prywatna dla:", - "ForienQuestLog.Tooltips.PersonalQuestButNoPlayers": "Misja prywatna, ale nikt jej nie widzi.", - - "ForienQuestLog.Api.hooks.createOpenQuestMacro.name": "Otwórz „{name}”" -} + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Otwórz ”{name}”" + }, + "Notifications": { + "NoQuest": "Błąd interfejsu API: nie można utworzyć makra z nieprawidłowym identyfikatorem Misja." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nowa Misja" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (nagroda za misję): {userName} umieszczony '{itemName}' na {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Nie można załadować dokumentu dla UUID: '{uuid}'.", + "NoPermission": "Nie masz wystarczających uprawnień, aby wyświetlić ten arkusz encji." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Cel ten i jego dane zostaną trwale usunięte.", + "BodyQuest": "Ta misja i jej dane zostaną trwale usunięte.", + "BodyReward": "Ta nagroda i jej dane zostaną trwale usunięte.", + "Cancel": "Anuluj", + "Delete": "Usuń", + "HeaderDel": "Czy na pewno chcesz usunąć:

'{name}'

", + "TitleDel": "Usuń {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Pokaż do Graczom" + }, + "Quest": "Misja" + }, + "Migration": { + "ChatMessage": { + "Footer": "Musisz ręcznie zaktualizować powyższe misje prawidłowymi danymi dokumentów z kompendiów lub twojego świata.
", + "Header": "Forien's Quest Log (DB migracja)
Usunięto nie połączone zleceniodawcy lub nagrody z poniższych zadań:

", + "Notification": "Forien's Quest Log - Usunięto nie połączone zleceniodawcy lub nagrody z jednego lub więcej zadań. Przejrzyj wiadomość na czacie, aby uzyskać więcej informacji.", + "QuestGiver": "Zleceniodawca Zadań", + "QuestRewards": "Nagrody za Zadania" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migracja danych zakończona.", + "CouldNotMigrate": "Forien's Quest Log - Nie udało się przenieść misji: '{name}'.", + "Schema": "Forien's Quest Log - Migracja danych do wersji schematu '{version}'.", + "Start": "Forien's Quest Log - Migracja danych, nie ładuj przeładować." + } + }, + "Notifications": { + "CannotOpen": "Nie można otworzyć szczegółów misji. Ta misja może nie być obserwowalna lub może już nie istnieć.", + "FinishQuestAdded": "Zakończ edycję i zamknij bieżącą misję przed dodaniem kolejnej.", + "LinkCopied": "Link do dokumentu dla tej misji został skopiowany do schowka.", + "QuestAdded": "Dodany '{name}' jako nowa misja ze statusem: '{status}'.", + "QuestIDCopied": "Identyfikator dokumentu tej misji został skopiowany do schowka.", + "QuestMoved": "Wzruszony '{name}' i ustaw nowy status na: '{target}'.", + "QuestPrimary": "'{name}' to nowa główna misja.", + "QuestTrackerNoActive": "Śledzenie misji jest włączone, ale obecnie nie ma żadnych misji w toku.", + "UserCantOpen": "Użytkownik '{user}' nie posiada uprawnień do otwarcia tej Misji." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Dodaj misję" + }, + "ContextMenu": { + "CopyEntityLink": "Skopiuj link treści encji", + "CopyQuestID": "Skopiuj identyfikator misji", + "PrimaryQuest": "Ustaw / wyłącz jako misję główną" + }, + "Labels": { + "TableHeader": "{0} Misje", + "SubTitle": "Zadanie podrzędne z {0}" + }, + "Title": "Dziennik Misji", + "Tooltips": { + "Objectives": "Cele" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Określony przez użytkownika", + "RewardHide": "Schowaj", + "RewardLock": "Zablokuj", + "RewardShow": "Pokazać", + "RewardUnlock": "Odemknąć" + }, + "Labels": { + "CustomSource": "Niestandardowe źródło", + "Description": "Opis:", + "DragDropActor": "Przeciągnij i upuść aktora, przedmiot lub wpis do dziennika lub kliknij lewym przyciskiem myszy, aby ustawić niestandardowe źródło.", + "DragDropActorPlayer": "Przeciągnij i upuść aktora, przedmiot lub wpis do dziennika.", + "DragDropRewards": "Przeciągnij i upuść elementy tutaj, aby dodać je jako nagrody.", + "GMNotes": "Notatki GM:", + "Objective": "Cel", + "Objectives": "Cele:", + "PlayerNotes": "Notatki Gracza:", + "Reward": "Nagroda", + "Rewards": "Nagrody:" + }, + "Management": { + "AddSubquest": "Dodaj misję podrzędną", + "ConfigurePermissions": "Konfiguruj Uprawnienia", + "QuestBranching": "Zadania podrzędne:", + "QuestSettings": "Ustawienia Misji:", + "SplashArt": "Sztuka Rozchlapania:", + "SplashInfo": "Kliknij, aby ustawić obraz.", + "SplashQuestIcon": "Ustaw jako ikonę misji" + }, + "Notifications": { + "BadUUID": "Nie można pobrać dokumentu dla UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log akceptuje tylko aktorów świata / kompendium, przedmioty i wpisy do dziennika jako zleceniodawców zadań.", + "WrongItemType": "Forien's Quest Log akceptuje tylko przedmioty ze świata i kompendium jako nagrody." + }, + "Tabs": { + "Details": "Szczegóły", + "GMNotes": "Notatki GM", + "PlayerNotes": "Notatki Gracza", + "QuestManagement": "Zarządzaj Misją" + }, + "Title": "Szczegóły Misji - {name}", + "Tooltips": { + "AddCustom": "Dodaj zdefiniowane przez użytkownika", + "AddObjective": "Dodaj Cel", + "ChangeSplashPos": "Zmień pozycję obrazu powitalnego.", + "DeleteQuestGiver": "Usuń zleceniodawcę misji.", + "DeleteSplash": "Usuń grafikę pluśnięcie.", + "HideAll": "Schowaj wszystko", + "LockAll": "Zablokuj wszystko", + "PrimaryQuestSet": "Kliknij, aby ustawić misję główną.", + "PrimaryQuestUnset": "Kliknij, aby rozbroić misję główną.", + "RewardHidden": "Nagroda jest ukryta. Kliknij, aby pokazać.", + "RewardLocked": "Nagroda jest zablokowana. Kliknij, aby odblokować.", + "RewardLockedPlayer": "Nagroda jest zablokowana.", + "RewardUnlocked": "Nagroda jest odblokowana. Kliknij, aby zablokować.", + "RewardUnlockedPlayer": "Nagroda jest odblokowana.", + "RewardVisible": "Nagroda jest widoczna. Kliknij, aby ukryć.", + "ShowAll": "Pokazać wszystko", + "TaskHidden": "Zadanie jest ukryte. Kliknij, aby pokazać.", + "TaskVisible": "Zadanie jest widoczne. Kliknij, aby ukryć.", + "ToggleImage": "Przełącz obraz Aktora/Tokenu.", + "UnlockAll": "Odblokuj wszystkie", + "ViewSplashArt": "Obejrzeć sztuka rozchlapania." + } + }, + "QuestTracker": { + "NoPrimary": "Brak dostępnych głównych zadań.", + "Title": "Śledzenie Misji", + "Tooltips": { + "BackgroundShow": "Kliknij, aby pokazać tło.", + "BackgroundUnshow": "Kliknij, aby tło było przezroczyste.", + "PrimaryQuestShow": "Kliknij, aby wyświetlić główne zadanie.", + "PrimaryQuestUnshow": "Kliknij, aby wyświetlić wszystkie misje." + } + }, + "QuestTypes": { + "Labels": { + "Active": "W trakcie", + "active": "w trakcie", + "Available": "Dostępne", + "available": "dostępne", + "Completed": "Zakończone", + "completed": "zakończone", + "Failed": "Nieudane", + "failed": "nieudane", + "InActive": "Nieaktywny", + "inactive": "nieaktywny", + "Status": "Misja to {statusLabel}." + }, + "Tooltips": { + "SetActive": "Ustaw na Aktywną", + "SetAvailable": "Ustaw jako Dostępną", + "SetCompleted": "Ustaw jako Zakończoną", + "SetFailed": "Ustaw jako Nieudaną", + "SetInactive": "Ustaw jako Nieaktywne", + "Status": "Status: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Gracze mogą przyjmować Zadania", + "EnableHint": "Zaznacz, aby umożliwić graczom przyjmowanie Zadań z zakładki Dostępne." + }, + "allowPlayersCreate": { + "Enable": "Gracze mogą tworzyć Questy", + "EnableHint": "Zaznacz, aby umożliwić graczom tworzenie zadań. Zadania stworzone przez graczy pojawią się w zakładce Dostępne z uprawnieniami do edycji gracza. WYMAGA uprawnienia rdzenia do tworzenia dziennika." + }, + "allowPlayersDrag": { + "Enable": "Zezwalaj na przeciąganie nagród gracza", + "EnableHint": "Zaznacz, aby umożliwić graczom przeciąganie nagród z okna szczegółów misji do posiadanych aktorów." + }, + "countHidden": { + "Enable": "Policz ukryte zadania", + "EnableHint": "Jeśli zaznaczone, liczba ukończonych/ogółem zadań będzie obejmować zadania ukryte." + }, + "defaultPermissionLevel": { + "Enable": "Domyślny poziom uprawnień do misji", + "EnableHint": "Ustawia domyślny poziom uprawnień podczas tworzenia nowych misji.", + "NONE": "Żaden", + "OBSERVER": "Obserwator", + "OWNER": "Właściciel" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynamiczne Tło Zakładki", + "EnableHint": "Jeśli zaznaczone, tło zakładki jest dynamicznie ustawiane na tło zawartości okna." + }, + "hideFQLFromPlayers": { + "Enable": "Ukryj dziennik zadań przed graczami", + "EnableHint": "Po włączeniu ta opcja ukrywa dziennik zadań przed wszystkimi graczami. Tylko użytkownicy na poziomie GM będą mieli dostęp do dziennika zadań." + }, + "navStyle": { + "bookmarks": "Zakładki", + "classic": "Klasyczne zakładki", + "Enable": "Styl Nawigacji", + "EnableHint": "Zdecyduj, jak powinna być wyświetlana nawigacja w dzienniku misji." + }, + "notifyRewardDrop": { + "Enable": "Pokaż powiadomienia o zrzuceniu nagrody", + "EnableHint": "Zaznacz, aby zobaczyć powiadomienia interfejsu użytkownika, gdy nagrody za misje zostaną upuszczone na arkusze graczy." + }, + "questTrackerResizable": { + "Enable": "Zmiana Rozmiaru śledzenia misji", + "EnableHint": "Zaznacz, aby umożliwić ręczną zmianę rozmiaru z Śledzenie misji." + }, + "showFolder": { + "Enable": "Pokaż Folder Misji", + "EnableHint": "Zaznacz, aby wyświetlić folder danych misji w zakładce Dziennik. Wyłącznie do celów DEBUGOWANIA." + }, + "showTasks": { + "default": "Pokaż Zadania: gotowe/ogółem", + "Enable": "Pokaż zadania w Dzienniku Misji", + "EnableHint": "Zdecyduj, czy lub jak wyświetlać liczbę celów obok tytułu zadania w dzienniku zadań. Nie ma to wpływu na podgląd zadania.", + "no": "Ukryj kolumnę „Cele”", + "onlyCurrent": "Pokaż cele: gotowe" + }, + "trustedPlayerEdit": { + "Enable": "Zezwalaj na edycję misji zaufanych graczy", + "EnableHint": "Zaznacz, aby zaufani gracze mogli mieć rozszerzone możliwości edycji misji i kontroli statusu nad misjami, których są właścicielami." + } + }, + "Tooltips": { + "Delete": "Usuń", + "Edit": "Edytować", + "HiddenQuestNoPlayers": "To zadanie jest ukryte przed wszystkimi graczami.", + "PrimaryQuest": "Główny Misja" + } + } +} \ No newline at end of file diff --git a/lang/pt-BR.json b/lang/pt-BR.json index e6b8e570..f7576b5e 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1,130 +1,235 @@ { "ForienQuestLog": { - "NewQuest": "Nova Missão", - "QuestLogButton": "Registro De Missões", - "Quests": "Missões", - "SampleReward": "ex. 300 pontos de Experiências", - "SampleTask": "ex. Matar todos os ratos da pousada „Trornozelo Torcido”", - - "QuestTypes": { - "InProgress": "Ativas", - "Completed": "Completas", - "Failed": "Perdidas", - "Hidden": "Ocultas", - "Labels": { - "available": "disponivel", - "active": "em progresso", - "completed": "completa", - "failed": "perdida", - "hidden": "oculta" + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Abrir a Missão ”{name}”" + }, + "Notifications": { + "NoQuest": "Erro de API: não é possível criar macro com ID de Quest inválido." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nova Missão" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (recompensa de missão) : {userName} deu '{itemName}' para {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Uma entidade não pôde ser carregada para IDuu: '{uuid}'.", + "NoPermission": "Você não tem permissão para visualizar o documento desta entidade." + } } }, - - "Buttons": { - "AddNewQuest": "Adicionar Nova Missão", - "AddNewTask": "adicionar nova" + "DeleteDialog": { + "BodyObjective": "Este objetivo e seus dados serão apagados permanentemente.", + "BodyQuest": "Esta missão e seus dados serão apagados permanentemente.", + "BodyReward": "Esta recompensa e seus dados serão apagados permanentemente.", + "Cancel": "Cancelar", + "Delete": "Remover", + "HeaderDel": "Tem certeza de que deseja excluir:

'{name}'

", + "TitleDel": "Excluir {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Exibir aos Jogadores" + }, + "Quest": "Missão" + }, + "Migration": { + "ChatMessage": { + "Footer": "Você deve manualmente atualizar as missþes acima com o dado valido de documentação de um dos compendiums de seu mundo.
", + "Header": "Forien's Quest Log (DB migração)
Removido entregador de missĂŁo ou items de recompensa das quests abaixo:

", + "Notification": "Forien's Quest Log - Removido entregador de missão ou items de recompensa de uma ou mais missões. Por favor revise a mensagem no chat para mais informação.", + "QuestGiver": "Entregador de Missão", + "QuestRewards": "Recompensa de Missão" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migração de dados completa.", + "CouldNotMigrate": "Forien's Quest Log - Não é possível migrar: '{name}'.", + "Schema": "Forien's Quest Log - Migrando dados sob a versão: '{version}'.", + "Start": "Forien's Quest Log - Migrando dados, não recarregue." + } }, - - "QuestForm": { - "Title": "Adicionar nova Missão", - "QuestGiver": "Missão Entregue por", - "QuestGiverPlaceholder": "nome do Ator ou ID", - "QuestTitle": "Titulo da Missão", - "DragDropActor": "Arraste e solte ator que entregará a missão aqui", - "QuestDescription": "Descritivo da Missão", - "QuestGMNotes": "Notas do Mestre de Jogo", - "Submit": "Enviar", - "SubquestOf": "Desdobramento de {name}" + "Notifications": { + "CannotOpen": "Não é possível abrir os detalhes da missão. Você não tem permissão, a missão não existe mais ou o ID fornecido é inválido.", + "FinishQuestAdded": "Termine a edição e feche a nova missão atual antes de adicionar outra.", + "LinkCopied": "O link para esta missão foi copiado para a área de transferência.", + "QuestAdded": "'{name}' foi adicionado como uma nova missão com a condição: '{status}'.", + "QuestIDCopied": "Este ID de missão foi copiado para a área de transferência.", + "QuestMoved": "Missão movida com nova condição: '{target}'.", + "QuestPrimary": "'{name}' é a nova missão principal.", + "QuestTrackerNoActive": "O rastreador de missões está ativado, mas não há missões ativas no momento.", + "UserCantOpen": "O usuário '{user}' não tem permissão para abrir esta missão." }, - "QuestLog": { - "Title": "Registro de Missão", - "SubTitle": "parte de: {0}", - "Table": { - "QuestGiver": "Missão Entregue por", - "QuestTitle": "Titulo", - "Tasks": "Tarefas", - "Actions": "Ações" + "Buttons": { + "AddQuest": "Adicionar Missão" }, - "Tabs": { - "Available": "Disponivel", - "InProgress": "em Progresso", - "Completed": "Completas", - "Failed": "Perdidas", - "Hidden": "Ocultas" + "ContextMenu": { + "CopyEntityLink": "Copiar conteúdo do link da entidade", + "CopyQuestID": "Copiar ID da missão", + "PrimaryQuest": "Ativar / Desativar como missão principal" + }, + "Labels": { + "TableHeader": "Missões {0}", + "SubTitle": "Parte da missão de: {0}" + }, + "Title": "Registro de Missões", + "Tooltips": { + "Objectives": "Objetivos" } }, - "QuestPreview": { - "Title": "Detalhes das Missões", - "SubTitle": "part of: {0}", - "Objectives": "Objetivos", - "Rewards": "Recompensas", - "DragDropRewards": "Arraste e Solte um item aqui apra recompensas", - "InvalidQuestId": "Não pode abrir a Visualização da missão, ID da Missão inválido.", - "HeaderButtons": { - "Show": "Exibir aos Jogadores" - }, - + "Buttons": { + "RewardCustom": "Usuário Definido", + "RewardHide": "Esconder", + "RewardLock": "Trancar", + "RewardShow": "Mostrar", + "RewardUnlock": "Desbloquear" + }, + "Labels": { + "CustomSource": "Fonte personalizada", + "Description": "Descrição:", + "DragDropActor": "Arraste e solte o ator, item, journal ou clique com o botão esquerdo para definir uma fonte customizada.", + "DragDropActorPlayer": "Arraste e solte o ator, um objeto ou uma entrada do journal.", + "DragDropRewards": "Arraste e solte itens aqui para torná-los recompensas.", + "GMNotes": "Notas do Mestre :", + "Objective": "Objetivos", + "Objectives": "Objetivos:", + "PlayerNotes": "Notas do Jogador:", + "Reward": "Recompensa", + "Rewards": "Recompensas:" + }, "Management": { - "IsPersonalQuest": "É uma Missão Pessoal?", - "IsPersonalQuestDescription": "Marque a missão como pessoalCheck to mark quest as Personal. Será invisível para todos os jogadores, exceto aqueles especificamente marcados abaixo. Desmarcar esta opção removerá todas as permissões e moverá a missão para a guia Ocultas.", - "SplashArt": "Arte de Exibição", - "QuestBranching": "Desdobramento da Missão", - "AddSubquest": "Criar um desdobramento", - "CanPlayerEdit": "Permitir aos jogadores editar os Detalhes." - }, - + "AddSubquest": "Criar uma Missão Secundária", + "ConfigurePermissions": "Configurar as permissões", + "QuestBranching": "Missões Secundárias:", + "QuestSettings": "Configurações da missão:", + "SplashArt": "Ilustração:", + "SplashInfo": "Clique para definir uma imagem.", + "SplashQuestIcon": "Definir como ícone de Missão" + }, + "Notifications": { + "BadUUID": "Não é possível recuperar documento para IDuu: '{uuid}'.", + "WrongDocType": "Forien's Quest Log só aceita atores, itens e entradas de log de mundo/compêndio como entregadores de missões.", + "WrongItemType": "O Registro de Missões de Forien só aceita itens de mundo e itens de compêndio como recompensas." + }, "Tabs": { "Details": "Detalhes", - "QuestManagement": "Controle de Missões", - "GMNotes": "Notas do Mestre" + "GMNotes": "Notas do Mestre", + "PlayerNotes": "Notas do Jogador", + "QuestManagement": "Controle de Missões" + }, + "Title": "Detalhes da Missão", + "Tooltips": { + "AddCustom": "Adicionar definido pelo usuário", + "AddObjective": "Adicionar Objetivo", + "ChangeSplashPos": "Modificar o alinhamento da imagem de ilustração.", + "DeleteQuestGiver": "Excluir entragor da missão.", + "DeleteSplash": "Excluir a ilustração.", + "HideAll": "Esconder Tudo", + "LockAll": "Bloquear Tudo", + "PrimaryQuestSet": "Clique para ativar a missão principal.", + "PrimaryQuestUnset": "Clique para desativar a missão principal.", + "RewardHidden": "Recompensa escondida. Clique para mostrar.", + "RewardLocked": "Recompensa bloqueada. Clique para desbloquear.", + "RewardLockedPlayer": "Recompensa bloqueada.", + "RewardUnlocked": "Recompensa desbloqueada. Clique para bloquear.", + "RewardUnlockedPlayer": "A recompensa é desbloqueada.", + "RewardVisible": "Recompensa visível. Marque para ocultá-la.", + "ShowAll": "Mostrar Todo", + "TaskHidden": "Tarefa oculta. Marque para mostrar.", + "TaskVisible": "Tarefa visível. Marque para ocultá-la.", + "ToggleImage": "Ativar a imagem do token/ator.", + "UnlockAll": "Destrancar Tudo", + "ViewSplashArt": "Ver ilustração." } - }, - - "DeleteDialog": { - "Title": "Removida {name}", - "Header": "Você tem certeza?", - "Body": "Esta missão e todos os seus arquivos serão removidos permanentemente.", - "Delete": "Remover", - "Cancel": "Cancelar" - }, - - "CloseDialog": { - "Title": "Sair Do Formulário", - "Header": "Você tem certeza?", - "Body": "Você tem certeza que quer fechar o formulário? Informações não salvas serão perdidas.", - "Discard": "Descartar Alterações", - "Cancel": "Cancelar" + "QuestTracker": { + "Title": "Registro de Missões", + "NoPrimary": "Nenhuma missão principal disponível.", + "Tooltips": { + "BackgroundShow": "Clique para mostrar o plano de fundo.", + "BackgroundUnshow": "Clique para tornar o fundo transparente.", + "PrimaryQuestShow": "Clique para mostrar a missão principal.", + "PrimaryQuestUnshow": "Clique para ocultar todas as missões." + } }, - - "Notifications": { - "CannotOpen": "Não é possível abrir os detalhes da missão. Você pode não ter permissões, a Missão pode não existir mais ou o ID é inválido.", - "UserCantOpen": "o usuário {user} Não tem permissão apra abrir esta missão.", - "LinkCopied": "Um link da Entidade para esta missão foi copiada na área de transferência", - "QuestMoved": "A missão foi movida para a nova pasta e deu um novo status: {target}" + "QuestTypes": { + "Labels": { + "Active": "Em Progresso", + "active": "em progresso", + "Available": "Disponíveis", + "available": "disponível", + "Completed": "Completas", + "completed": "completa", + "Failed": "Perdidas", + "failed": "perdida", + "InActive": "Inativas", + "inactive": "inativa", + "Status": "A missão está {statusLabel}." + }, + "Tooltips": { + "SetActive": "Definir como Em Progresso", + "SetAvailable": "Definir como Disponível", + "SetCompleted": "Definir como Completa", + "SetFailed": "Definir como Perdida", + "SetInactive": "Definir como Inativo", + "Status": "Condição : {statusI18n}" + } }, - "Settings": { + "allowPlayersAccept": { + "Enable": "Os jogadores podem aceitar", + "EnableHint": "Marque para permitir que os jogadores aceitem missões na guia Disponível." + }, + "allowPlayersCreate": { + "Enable": "Jogadores podem Criar", + "EnableHint": "Ative para permitir que os jogadores possam criar Missões. Jogadores criam Missões diretamente na aba Disponivel com permissão de edição. REQUER a Permissão de núcleo 'criar diário'." + }, "allowPlayersDrag": { "Enable": "Permitir que os jogadores arrastem recompensas", "EnableHint": "Marque para permitir que os jogadores arrastem recompensas da janela Detalhes da missão para seus proprios atores." }, - "availableQuests": { - "Enable": "Exibir Guia de Disponiveis", - "EnableHint": "Marque para mostrar a nova guia \"Disponível\" no Registro de Missões, onde os jogadores podem ver todas as Missões não ocultas antes de serem aceitas" - }, "countHidden": { "Enable": "Contar as tarefas ocultas", "EnableHint": "Se ativo, o numero total de tarefas completas/total incluirá as tarefas ocultas." }, + "defaultPermissionLevel": { + "Enable": "Novo nível de permissão de missões", + "EnableHint": "Definir permissões como padrão quando novas missões forem criadas.", + "NONE": "Nenhum", + "OBSERVER": "Observador", + "OWNER": "Proprietário" + }, + "dynamicBookmarkBackground": { + "Enable": "Marcadores dinâmicos em segundo plano", + "EnableHint": "Marque para que a guia de favoritos seja exibida dinamicamente na janela de conteúdo em segundo plano." + }, + "hideFQLFromPlayers": { + "Enable": "Ocultar registro de missões dos jogadores", + "EnableHint": "Ativar esta opção oculta o registro de missões de todos os jogadores. Somente jogadores com nível GM poderão acessar o registro de missões." + }, "navStyle": { "Enable": "Estilo de Navegação", - "EnableHint": "Decide como a navegação do Registro de Missões deve ser exibida.", - "bookmarks": "marcador de livros", + "EnableHint": "Decida como a navegação do registro de missões será exibida.", + "bookmarks": "Marcador de página", "classic": "Guias Clássicas" }, + "notifyRewardDrop": { + "Enable": "Mostrar notificações de recompensas concedidas", + "EnableHint": "Verifique para ver as notificações quando as recompensas das missões forem para a fichas dos jogadores." + }, + "questTrackerResizable": { + "Enable": "Registro de Missões redimensionável", + "EnableHint": "Marque para permitir o controle manual do redimensionamento do Registro de Missões." + }, "showFolder": { "Enable": "Exibir a Pasta de Missões", "EnableHint": "Marque para mostrar a pasta de dados da missão na guia Diário. Apenas para fins de DEBUG." @@ -133,70 +238,19 @@ "Enable": "Exibir tarefas no Registro de Missões", "EnableHint": "Decida se ou como mostrar a quantidade de tarefas (objetivos) ao lado do título da Missão no Registro de Missões. Isso não afeta a visualização individual da missão.", "default": "Exibir tarefas: feitas/total", - "onlyCurrent": "Exibir tarefas: feitas", - "no": "Esconder a coluna \"Tarefas\"." - }, - "titleAlign": { - "Enable": "Alinhamento do Titulo da Missão", - "EnableHint": "Decide como a posição do titulo é exibida no Registro de Missões.", - "left": "Alinhada a Esquerda", - "center": "Centralizada" + "no": "Esconder a coluna \"Tarefas\"", + "onlyCurrent": "Exibir tarefas: feitas" }, - "playersWelcomeScreen": { - "Enable": "Exibir a Tela de Boas vindas aos Jogadores", - "EnableHint": "Desmarque para impedir que os jogadores vejam a tela de boas-vindas no login após uma atualização. Eles ainda podem vê-lo clicando no ícone 'ajuda' no Registro de missões." - }, - "allowPlayersAccept": { - "Enable": "Jogadores podem Aceitar", - "EnableHint": "Ative para permitir que os jogadores possam aceitar Missões na ana Disponiveis." - }, - "allowPlayersCreate": { - "Enable": "Jogadores podem Criar", - "EnableHint": "Ative para permitir que os jogadores possam criar Missões. Jogadores criam Missões diretamente na aba Disponivel com permissão de edição. REQUER a Permissão de núcleo 'criar diário'." + "trustedPlayerEdit": { + "Enable": "Permitir que jogadores confiáveis editem", + "EnableHint": "Marque para permitir que os jogadores tenham recursos expandidos de edição e verificação de status de missões para as missões que possuem." } }, - "Tooltips": { - "SetAvailable": "Defina como Disponivel", - "SetActive": "Defina como Em Progresso", - "SetCompleted": "Defina como Completa", - "SetFailed": "Defina como Perdida", - "Hide": "Esconda", - "Delete": "Remova", - "AddAbstractReward": "Adicionar Recompensa abstrata", - "PersonalQuestButNoPlayers": "Esta é uma Missão Pessoal, mas ningu[em a vê", - "PersonalQuestVisibleFor": "Esta é uma missão pessoal para", - "RewardHidden": "Recompensas estão Ocultas. Clique para exibi-las.", - "RewardVisible": "Recompensas estão Visíveis. Clique para Oculta-las.", - "TaskHidden": "Tarefas estão Ocultas. Clique para exibir.", - "TaskVisible": "Tarefas estão visíveis. Clique para Ocultar.", - "ToggleImage": "Alternar entre imagem de token/actor" - }, - - "Api": { - "__COMMENT__": "No need for translating lines starting with 'API ERROR', they show in console for developers only.", - "create": { - "title": "API Error: Title property is required to create new Quest" - }, - "hooks": { - "createOpenQuestMacro": { - "name": "Open „{name}” Quest", - "error": { - "noQuest": "API Error: Can't create macro with invalid Quest ID" - } - } - }, - "reward": { - "create": { - "data": "API Error: Data property with at least {name, img} is required to create new Reward", - "type": "API Error: Type property is required to create new Reward" - } - }, - "task": { - "create": { - "name": "API Error: Name property is required to create new Task" - } - } + "Delete": "Excluir", + "Edit": "Editar", + "HiddenQuestNoPlayers": "Esta missão está escondida de todos os jogadores.", + "PrimaryQuest": "Missão Principal" } } } diff --git a/lang/ru.json b/lang/ru.json new file mode 100644 index 00000000..ed1e7d09 --- /dev/null +++ b/lang/ru.json @@ -0,0 +1,256 @@ +{ + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Открыть ”{name}”" + }, + "Notifications": { + "NoQuest": "Ошибка API: невозможно создать макрос с недопустимым идентификатором квеста." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Новое задание" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (награда): {userName} передал '{itemName}' к {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "Не удаётся загрузить элемент для UUID: '{uuid}'.", + "NoPermission": "У вас нет прав доступа к листу этого документа." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Задача и все её данные будут навсегда удалены.", + "BodyQuest": "Задание и все его данные будут навсегда удалены.", + "BodyReward": "Награда и все её данные будут навсегда удалены.", + "Cancel": "Отмена", + "Delete": "Удаление", + "HeaderDel": "Вы уверены, что хотите удалить:

'{name}'

", + "TitleDel": "Удаление {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Показать игрокам" + }, + "Quest": "Задание" + }, + "Migration": { + "ChatMessage": { + "Footer": "Вы должны вручную обновить эти задания с корректным типом документов из вашей библиотеки или мира.
", + "Header": "Forien's Quest Log (миграция базы)
Удалены несвязанные выдающие задания или награды из заданий:

", + "Notification": "Forien's Quest Log - Удалён несвязанный выдающий задание или награда из одного или нескольких заданий. Подробности в чате.", + "QuestGiver": "Выдающий задание", + "QuestRewards": "Награды задания" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Перенос данных завершён.", + "CouldNotMigrate": "Forien's Quest Log - Не удалось перенести задание: '{name}'.", + "Schema": "Forien's Quest Log - Обновление данных до версии '{version}'.", + "Start": "Forien's Quest Log - Перенос данных, подождите." + } + }, + "Notifications": { + "CannotOpen": "Не удаётся открыть подробности задания. Это задания может быть не доступно вам или больше не существует.", + "FinishQuestAdded": "Завершите редактирование и закройте текущее задание перед добавлением нового.", + "LinkCopied": "Ссылка на документ этого задания была скопирована в буфер.", + "QuestAdded": "Добавлено новое задание '{name}' со статусом '{status}'.", + "QuestIDCopied": "ID этого задания был скопирована в буфер.", + "QuestMoved": "'{name}' перемещено в новую папку со статусом: '{target}'.", + "QuestPrimary": "'{name}' теперь основное задание.", + "QuestTrackerNoActive": "Трекер включён, но нет активных заданий.", + "UserCantOpen": "Участник '{user}' не имеет разрешения для просмотра этого задания." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Добавить квест" + }, + "ContextMenu": { + "CopyEntityLink": "Копирование ссылки на документ", + "CopyQuestID": "Копирование ID задания", + "PrimaryQuest": "Переключение главного задания" + }, + "Labels": { + "TableHeader": "{0} задания", + "SubTitle": "Подзадание у {0}" + }, + "Title": "Журнал заданий", + "Tooltips": { + "Objectives": "Задачи" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Уникальный", + "RewardHide": "Скрывать", + "RewardLock": "Запирать", + "RewardShow": "Показывать", + "RewardUnlock": "Разблокировать" + }, + "Labels": { + "CustomSource": "Свой источник", + "Description": "Описание:", + "DragDropActor": "Перенесите актёра, предмет или запись журнала или ЛКМ для выбора своего источника.", + "DragDropActorPlayer": "Перенесите актёра, предмет или запись журнала.", + "DragDropRewards": "Перенесите предмет, чтобы сделать его наградой.", + "GMNotes": "Заметки GM:", + "Objective": "Задача", + "Objectives": "Задачи:", + "PlayerNotes": "Примечания игрока:", + "Reward": "Награда", + "Rewards": "Награда:" + }, + "Management": { + "AddSubquest": "Добавить подзадание", + "ConfigurePermissions": "Настройка прав", + "QuestBranching": "Подзадания:", + "QuestSettings": "Настройки задания:", + "SplashArt": "Обложка:", + "SplashInfo": "Выбор изображения.", + "SplashQuestIcon": "Выбор иконки задания" + }, + "Notifications": { + "BadUUID": "Не удаётся получить документ для UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log принимает только актёров, предметы и записи журнала в качестве выдающего задание.", + "WrongItemType": "Forien's Quest Log принимает только предметы из мира и библиотеки в качестве наград." + }, + "Tabs": { + "Details": "Подробности", + "GMNotes": "Примечания GM", + "PlayerNotes": "Примечания игрока", + "QuestManagement": "Управление заданием" + }, + "Title": "Подробности задания - {name}", + "Tooltips": { + "AddCustom": "Добавить уникальный", + "AddObjective": "Добавить цель", + "ChangeSplashPos": "Изменить расположение обложки.", + "DeleteQuestGiver": "Удалить выдающего задание.", + "DeleteSplash": "Удалить обложку.", + "HideAll": "Скрыть все", + "LockAll": "Заблокировать все", + "PrimaryQuestSet": "Сделать основным заданием.", + "PrimaryQuestUnset": "Сделать неосновным заданием.", + "RewardHidden": "Награда скрыта. Нажмите, чтобы показать.", + "RewardLocked": "Награда заблокирована. Нажмите для разблокирования.", + "RewardLockedPlayer": "Награда заблокирована.", + "RewardUnlocked": "Награда разблокирована. Нажмите для блокировки.", + "RewardUnlockedPlayer": "Награда разблокирована.", + "RewardVisible": "Награда видима. Нажмите, чтобы скрыть.", + "ShowAll": "Показывать все", + "TaskHidden": "Задача скрыта. Нажмите, чтобы показать.", + "TaskVisible": "Задача видима. Нажмите, чтобы скрыть.", + "ToggleImage": "Переключение портрета/токена.", + "UnlockAll": "Разблокировать все", + "ViewSplashArt": "Посмотреть обложку." + } + }, + "QuestTracker": { + "NoPrimary": "Нет основного задания.", + "Title": "Трекер заданий", + "Tooltips": { + "BackgroundShow": "Сделать фон видимым.", + "BackgroundUnshow": "Сделать фон прозрачным.", + "PrimaryQuestShow": "Показать основное задание.", + "PrimaryQuestUnshow": "Показать все задания." + } + }, + "QuestTypes": { + "Labels": { + "Active": "В процессе", + "active": "в процессе", + "Available": "Доступные", + "available": "доступные", + "Completed": "Завершённые", + "completed": "завершённые", + "Failed": "Проваленные", + "failed": "проваленные", + "InActive": "Неактивные", + "inactive": "неактивные", + "Status": "Задание {statusLabel}." + }, + "Tooltips": { + "SetActive": "Сделать текущим", + "SetAvailable": "Сделать доступным", + "SetCompleted": "Сделать завершённым", + "SetFailed": "Сделать проваленным", + "SetInactive": "Сделать неактивным", + "Status": "Состояние: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Игроки могут принимают задания", + "EnableHint": "Если включено, игроки смогут сами принимать задания из вкладки Доступных." + }, + "allowPlayersCreate": { + "Enable": "Игроки могут создавать задания", + "EnableHint": "Если включено, игроки смогут сами создавать задания. Созданные игроками задания отображаются во вкладке Доступные. ТРЕБУЮТСЯ права на 'Создание журналов' в Foundry." + }, + "allowPlayersDrag": { + "Enable": "Разрешить игрокам перемещать награды", + "EnableHint": "Если включено, игроки смогут перемещать награды из окна задания в свой инвентарь." + }, + "countHidden": { + "Enable": "Считать скрытые задачи", + "EnableHint": "Если включено, число завершено/всего задач будет включать скрытые." + }, + "defaultPermissionLevel": { + "Enable": "Доступ к заданиям по умолчанию", + "EnableHint": "Настройте права доступа по умолчанию к новым заданиям.", + "NONE": "Нет", + "OBSERVER": "Наблюдатель", + "OWNER": "Владелец" + }, + "dynamicBookmarkBackground": { + "Enable": "Динамический фон закладки", + "EnableHint": "Если включено, цвет закладки будет соответствовать фону содержимого." + }, + "hideFQLFromPlayers": { + "Enable": "Скрывать список заданий от игроков", + "EnableHint": "Если включено, список заданий будет скрыт для всех игроков. Только участники с правами GM могут просматривать список заданий." + }, + "navStyle": { + "bookmarks": "Закладки", + "classic": "Вкладки", + "Enable": "Способ навигации", + "EnableHint": "Вид отображение заданий в журнале." + }, + "notifyRewardDrop": { + "Enable": "Отображение уведомления передачи награды", + "EnableHint": "Включение уведомлений при перемещении награды на листы актёров." + }, + "questTrackerResizable": { + "Enable": "Изменяемый размер трекера", + "EnableHint": "Включение ручного изменения размера Трекера заданий." + }, + "showFolder": { + "Enable": "Отображение папки заданий", + "EnableHint": "Если включено, папка заданий будет отображаться в журналах. ТОЛЬКО ДЛЯ РАЗРАБОТЧИКОВ." + }, + "showTasks": { + "default": "Показывать задачи: завершено/всего", + "Enable": "Отображение задач в журнале заданий", + "EnableHint": "Если включено, число задач будет отображаться около названия задания.", + "no": "Скрыть колонку \"задачи\"", + "onlyCurrent": "Показывать задачи: завершено" + }, + "trustedPlayerEdit": { + "Enable": "Разрешить доверенным игрокам изменять задания", + "EnableHint": "Если включено, доверенные игроки будут видеть расширенное управление заданиями, включая управление статусом тех заданий, к которым у них есть доступ." + } + }, + "Tooltips": { + "Delete": "Удаление", + "Edit": "Изменение", + "HiddenQuestNoPlayers": "Это задание скрыто от всех игроков.", + "PrimaryQuest": "Основное задание" + } + } +} \ No newline at end of file diff --git a/lang/sv.json b/lang/sv.json new file mode 100644 index 00000000..09f9061b --- /dev/null +++ b/lang/sv.json @@ -0,0 +1,256 @@ +{ + "ForienQuestLog": { + "API": { + "Hooks": { + "Labels": { + "OpenMacro": "Öppna ”{name}”" + }, + "Notifications": { + "NoQuest": "API-fel: Kan inte skapa makro med ogiltigt uppdrags-ID." + } + }, + "QuestDB": { + "Labels": { + "NewQuest": "Nytt uppdrag" + } + }, + "Socket": { + "Notifications": { + "RewardDrop": "FQL (uppdragsbelöning): {userName} släppte '{itemName}' på {actorName}." + } + }, + "Utils": { + "Notifications": { + "NoDocument": "En entitet kunde inte laddas med UUID: '{uuid}'.", + "NoPermission": "Du har inte tillräckliga behörigheter för att visa detta entitetsblad." + } + } + }, + "DeleteDialog": { + "BodyObjective": "Detta mål och dess data kommer att raderas permanent.", + "BodyQuest": "Detta uppdrag och dess data kommer att raderas permanent.", + "BodyReward": "Denna belöning och dess data kommer att raderas permanent.", + "Cancel": "Avbryt", + "Delete": "Radera", + "HeaderDel": "Är du säker att du vill radera:

'{name}'

", + "TitleDel": "Radera {title}" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "Visa fÜr spelare" + }, + "Quest": "Uppdrag" + }, + "Migration": { + "ChatMessage": { + "Footer": "Du müste manuellt uppdatera ovanstüende uppdrag med giltiga dokumentdata frün kompendier eller din värld.
", + "Header": "Forien's Quest Log (DB flyttning)
Tog bort olänkade uppdragsgivare eller belÜningsobjekt frün uppdragen nedan:

", + "Notification": "Forien's Quest Log - Tog bort olänkade uppdragsgivare eller belöningsobjekt från ett eller flera uppdrag. Läs chattmeddelandet för mer information.", + "QuestGiver": "Uppdrag Givare", + "QuestRewards": "Uppdrag Belöningar" + }, + "Notifications": { + "Complete": "Forien's Quest Log - Migrering av data klar.", + "CouldNotMigrate": "Forien's Quest Log - Det gick inte att migrera uppdraget: '{name}'.", + "Schema": "Forien's Quest Log - Migrerar data till schemaversion '{version}'.", + "Start": "Forien's Quest Log - Migrerar data, vänligen ladda inte om." + } + }, + "Notifications": { + "CannotOpen": "Kan inte öppna Uppdragsdetaljer. Detta uppdrag kanske inte går att observera eller kanske inte längre existerar.", + "FinishQuestAdded": "Slutför redigeringen och stäng aktuellt nytt uppdrag innan du lägger till ett nytt.", + "LinkCopied": "Entitetslänk för detta uppdrag har kopierats till urklipp.", + "QuestAdded": "Lagt till '{name}' som ett nytt uppdrag med status: '{status}'.", + "QuestIDCopied": "Uppdrags-ID för detta uppdrag har kopierats till urklipp.", + "QuestMoved": "Flyttat '{name}' och satt dess status till: '{target}'.", + "QuestPrimary": "'{name}' är det nya primära uppdraget.", + "QuestTrackerNoActive": "Uppdragsspårare är aktiverad, men det finns inga pågående uppdrag för närvarande.", + "UserCantOpen": "Användare '{user}' har inte behörighet att öppna det här uppdraget." + }, + "QuestLog": { + "Buttons": { + "AddQuest": "Lägg till uppdrag" + }, + "ContextMenu": { + "CopyEntityLink": "Kopiera entitetsinnehållslänk", + "CopyQuestID": "Kopiera uppdrags-ID", + "PrimaryQuest": "Välj / välj bort som primärt uppdrag" + }, + "Labels": { + "TableHeader": "{0} Uppdrag", + "SubTitle": "Deluppdrag till {0}" + }, + "Title": "Uppdragslogg", + "Tooltips": { + "Objectives": "Mål" + } + }, + "QuestPreview": { + "Buttons": { + "RewardCustom": "Användardefinierad", + "RewardHide": "Dölja", + "RewardLock": "Låsa", + "RewardShow": "Visa", + "RewardUnlock": "Låsa Upp" + }, + "Labels": { + "CustomSource": "Anpassad källa", + "Description": "Beskrivning:", + "DragDropActor": "Dra och släpp aktörer, saker eller journalanteckningar eller vänsterklicka för att ställa in en anpassad källa.", + "DragDropActorPlayer": "Dra och släpp aktörer, saker eller journalanteckningar.", + "DragDropRewards": "Dra och släpp objekt här för att lägga till dem som belöningar.", + "GMNotes": "SL-anteckningar:", + "Objective": "Mål", + "Objectives": "Mål:", + "PlayerNotes": "Spelare-anteckningar:", + "Reward": "Belöning", + "Rewards": "Belöningar:" + }, + "Management": { + "AddSubquest": "Skapa underuppdrag", + "ConfigurePermissions": "Konfigurera Behörigheter", + "QuestBranching": "Underuppdrag:", + "QuestSettings": "Uppdragsinställningar:", + "SplashArt": "Skvätt Konst:", + "SplashInfo": "Klicka för att ställa in bild.", + "SplashQuestIcon": "Ställ in som uppdragsikon" + }, + "Notifications": { + "BadUUID": "Det gick inte att hämta dokumentet för UUID: '{uuid}'.", + "WrongDocType": "Forien's Quest Log accepterar endast världs-/kompendieaktörer, saker och journalanteckningar som uppdragsgivare.", + "WrongItemType": "Forien's Quest Log accepterar endast världs- och kompendiumobjekt som belöningar." + }, + "Tabs": { + "Details": "Detaljer", + "GMNotes": "SL-anteckningar", + "PlayerNotes": "Spelare-anteckningar", + "QuestManagement": "Hantera uppdrag" + }, + "Title": "Uppdragsdetaljer", + "Tooltips": { + "AddCustom": "Lägg till användardefinierad", + "AddObjective": "Lägg till Mål", + "ChangeSplashPos": "Ändra blänkarbild-justering.", + "DeleteQuestGiver": "Ta bort uppdragsgivare.", + "DeleteSplash": "Ta bort blänkar-bild.", + "HideAll": "Dölj Alla", + "LockAll": "Lås allt", + "PrimaryQuestSet": "Klicka för att göra primärt uppdrag.", + "PrimaryQuestUnset": "Klicka för att avaktivera primärt uppdrag.", + "RewardHidden": "Belöningen är dold. Klicka för att visa.", + "RewardLocked": "Belöningen är låst. Klicka för att låsa upp.", + "RewardLockedPlayer": "Belöningen är låst.", + "RewardUnlocked": "Belöningen är upplåst. Klicka för att låsa.", + "RewardUnlockedPlayer": "Belöningen är upplåst.", + "RewardVisible": "Belöningen är synlig. Klicka för att dölja.", + "ShowAll": "Visa Allt", + "TaskHidden": "Mål är dolt. Klicka för att visa.", + "TaskVisible": "Mål är synligt. Klicka för att dölja.", + "ToggleImage": "Toggla Spelfigursbild / Aktörsbild.", + "UnlockAll": "Lås upp Alla", + "ViewSplashArt": "Se blänkarbild." + } + }, + "QuestTracker": { + "NoPrimary": "Inget primärt uppdrag tillgängligt.", + "Title": "Uppdragsspårare", + "Tooltips": { + "BackgroundShow": "Klicka för att visa bakgrund.", + "BackgroundUnshow": "Klicka för att göra bakgrunden genomskinlig.", + "PrimaryQuestShow": "Klicka för att visa primärt uppdrag.", + "PrimaryQuestUnshow": "Klicka för att visa alla uppdrag." + } + }, + "QuestTypes": { + "Labels": { + "Active": "Aktiv", + "active": "aktiv", + "Available": "Tillgängliga", + "available": "tillgängliga", + "Completed": "Avklarade", + "completed": "avklarade", + "Failed": "Misslyckade", + "failed": "misslyckade", + "InActive": "Inaktiva", + "inactive": "inaktiva", + "Status": "Uppdrag är {statusLabel}." + }, + "Tooltips": { + "SetActive": "Ställ in som Pågående", + "SetAvailable": "Ställ in som tillgänglig", + "SetCompleted": "Ställ in som slutfört", + "SetFailed": "Ställ in som misslyckad", + "SetInactive": "Ställ in som inaktiv", + "Status": "Status: {statusI18n}" + } + }, + "Settings": { + "allowPlayersAccept": { + "Enable": "Spelare kan acceptera uppdrag", + "EnableHint": "Markera för att tillåta spelare att acceptera uppdrag från fliken Tillgänglig." + }, + "allowPlayersCreate": { + "Enable": "Spelare kan skapa", + "EnableHint": "Markera för att tillåta spelare att skapa uppdrag. Spelare skapade uppdrag kommer att visas på fliken Tillgänglig med spelarredigeringsbehörigheter. KRÄVER skapa journal tillstånd i själva Foundry." + }, + "allowPlayersDrag": { + "Enable": "Tillåt spelare att dra belöningar till deras utrustningslista", + "EnableHint": "Markera för att tillåta spelare att dra belöningar från ett Uppdragsdetaljsfönster till sina ägda aktör." + }, + "countHidden": { + "Enable": "Räkna dolda uppgifter", + "EnableHint": "Om detta väljs kommer antalet slutförda / totala uppgifter att inkludera dolda uppgifter." + }, + "defaultPermissionLevel": { + "Enable": "Standardbehörighetsnivå för uppdrag", + "EnableHint": "Ställer in standardbehörighetsnivån när nya uppdrag skapas.", + "NONE": "Ingen", + "OBSERVER": "Observatör", + "OWNER": "Ägare" + }, + "dynamicBookmarkBackground": { + "Enable": "Dynamisk bokmärkebakgrund", + "EnableHint": "Om markerad, ställs bokmärkesflikens bakgrund dynamiskt in på fönstrets innehållsbakgrund." + }, + "hideFQLFromPlayers": { + "Enable": "Dölj Uppdragslogg från spelare", + "EnableHint": "När det här alternativet är aktiverat döljer Uppdragsloggen för alla spelare. Endast användare på SL-nivå kommer att kunna komma åt Uppdragsloggen." + }, + "navStyle": { + "bookmarks": "Bokmärken", + "classic": "Klassiska flikar", + "Enable": "Navigationsstil", + "EnableHint": "Bestäm hur Uppdragsloggens navigering ska visas." + }, + "notifyRewardDrop": { + "Enable": "Visa belöningsaviseringar", + "EnableHint": "Markera för att se UI-aviseringar när uppdragsbelöningar släpps på spelarark." + }, + "questTrackerResizable": { + "Enable": "Uppdragsspåraren kan ändra storlek", + "EnableHint": "Markera för att tillåta manuell storleksändringskontroll av Quest Tracker." + }, + "showFolder": { + "Enable": "Visa Uppdragsmapp", + "EnableHint": "Markera för att visa sökdatamappen på fliken Journal. Endast för DEBUG-syften." + }, + "showTasks": { + "default": "Visa mål: gjort / totalt", + "Enable": "Visa uppgifter i Uppdragslogg", + "EnableHint": "Bestäm om eller hur man ska visa mängden uppgifter bredvid Uppdragstiteln i Uppdragsloggen. Detta har ingen effekt på Quest Preview.", + "no": "Dölj Målkolumn", + "onlyCurrent": "Visa mål: klar" + }, + "trustedPlayerEdit": { + "Enable": "Tillåt pålitlig spelare uppdrag-redigering", + "EnableHint": "Markera kryssrutan för att tillåta betrodda spelare att ha utökade uppdragsredigerings- och statuskontrollmöjligheter över uppdrag som de äger." + } + }, + "Tooltips": { + "Delete": "Radera", + "Edit": "Redigera", + "HiddenQuestNoPlayers": "Detta uppdrag är dolt för alla spelare.", + "PrimaryQuest": "Primärt Uppdrag" + } + } +} diff --git a/lang/zh-tw.json b/lang/zh-tw.json new file mode 100644 index 00000000..4236320a --- /dev/null +++ b/lang/zh-tw.json @@ -0,0 +1,259 @@ +{ + "ForienQuestLog" : { + "API" : { + "Hooks": { + "Labels": { + "OpenMacro": "打開任務 „{name}”" + }, + "Notifications": { + "NoQuest": "API Error: Can't create macro with invalid Quest ID。" + } + }, + "QuestDB": { + "Labels": { + "NewQuest" : "新任務" + } + }, + "Socket": { + "Notifications": { + "RewardDrop" : "FQL(任務獎勵):{userName} 將 '{itemName}' 放到 {actorName} 上。" + } + }, + "Utils": { + "Notifications": { + "NoDocument" : "無法加載 UUID:'{uuid}'。", + "NoPermission" : "您沒有足夠的權限查看此entity表格。" + } + } + }, + "DeleteDialog" : { + "BodyObjective" : "該目標及其資料將被永久刪除。", + "BodyQuest" : "此任務及其資料將被永久刪除。", + "BodyReward" : "此獎勵及其資料將被永久刪除。", + "Cancel" : "取消", + "Delete" : "刪除", + "HeaderDel" : "你確定要刪除:

'{name}'

", + "TitleDel" : "刪除 {title}" + }, + "HeaderLabels": { + "Show": "展示給玩家" + }, + "Labels": { + "AppHeader": { + "ShowPlayers": "展示給玩家" + }, + "Quest" : "任務" + }, + "Migration" : { + "ChatMessage" : { + "Footer" : "您必須使用來自Compendiums或你的World中的有效文檔資料,來手動更新上述任務。
", + "Header" : "Forien's Quest Log (DB migration)
從以下任務中移除了未連結的任務給予者或獎勵物品:

", + "Notification" : "Forien's Quest Log - 從一個或多個任務中刪除未連結的任務給予者或獎勵物品。請查看聊天消息以獲取更多信息。", + "QuestGiver" : "任務給予者", + "QuestRewards" : "任務獎勵" + }, + "Notifications": { + "Complete" : "Forien's Quest Log - 遷移資料完成。", + "CouldNotMigrate" : "Forien's Quest Log - 無法遷移任務:'{name}'。", + "Schema" : "Forien's Quest Log - 將資料遷移到版本 '{version}'。", + "Start" : "Forien's Quest Log - 遷移資料中,請不要重新加載。" + } + }, + "Notifications" : { + "CannotOpen" : "無法查看任務詳情。你可能缺少訪問權限,或者該任務ID錯誤,或者該任務已被刪除。", + "FinishQuestAdded" : "請先完成編輯並關閉當前的新任務,然後再添加另一個任務。", + "LinkCopied" : "該任務的連結已複製到剪貼板中。", + "QuestAdded" : "添加了 '{name}' 作為新任務,狀態為:'{status}'。", + "QuestIDCopied" : "此任務的任務 ID 已複製到剪貼板。", + "QuestMoved" : "移動該任務至新文件夾並更改其狀態為:'{target}'。", + "QuestPrimary" : "'{name}' 是新的主要任務。", + "QuestTrackerNoActive" : "任務追踪器已啟用,但目前沒有正在進行的任務。", + "UserCantOpen" : "玩家 '{user}' 沒有查看該任務的權限。" + }, + "QuestLog" : { + "Buttons": { + "AddQuest": "添加任務" + }, + "ContextMenu" : { + "CopyEntityLink" : "複製內容連結", + "CopyQuestID" : "複製任務 ID", + "PrimaryQuest" : "設定/取消設定為主要任務" + }, + "Labels": { + "TableHeader": "{0}任務", + "SubTitle": "的子任務 {0}" + }, + "Title" : "任務欄", + "Tooltips" : { + "Objectives" : "目標" + } + }, + "QuestPreview" : { + "Buttons": { + "RewardCustom": "添加用戶定義", + "RewardHide": "隱藏所有", + "RewardLock": "鎖定所有", + "RewardShow": "顯示全部", + "RewardUnlock": "全部解鎖" + }, + "Labels": { + "CustomSource" : "自定義來源", + "Description" : "描述:", + "DragDropActor" : "拖放Actor、物品、日誌條目或左鍵單擊以設定自定義來源。", + "DragDropActorPlayer" : "拖放Actor、物品或日誌條目。", + "DragDropRewards" : "將物品拖拽到此處以將其設為獎勵。", + "GMNotes" : "GM 筆記:", + "Objective" : "目標", + "Objectives" : "目標:", + "PlayerNotes": "玩家 筆記:", + "Reward" : "獎勵", + "Rewards" : "獎勵:" + }, + "Management" : { + "AddSubquest" : "新建支線任務", + "ConfigurePermissions" : "配置權限", + "QuestBranching" : "支線任務:", + "QuestSettings" : "任務設定:", + "SplashArt" : "插畫:", + "SplashInfo" : "點擊設定圖片.", + "SplashQuestIcon" : "設定為任務圖示" + }, + "Notifications" : { + "BadUUID" : "無法搜索到 UUID 文檔:'{uuid}'。", + "WrongDocType" : "Forien 的任務日誌只接受World/Compendium Actor、物品和日誌條目作為任務提供者。", + "WrongItemType" : "Forien 的任務日誌只接受World和Compendium items作為獎勵。" + }, + "Tabs" : { + "Details" : "詳情", + "GMNotes" : "GM筆記", + "PlayerNotes": "玩家 筆記", + "QuestManagement" : "管理任務" + }, + "Title" : "任務詳情", + "Tooltips" : { + "AddCustom" : "添加用戶定義", + "AddObjective": "添加目標", + "ChangeSplashPos" : "改變插畫對齊方式。", + "DeleteQuestGiver" : "刪除任務給予者。", + "DeleteSplash" : "刪除插畫。", + "HideAll" : "隱藏所有", + "LockAll" : "鎖定所有", + "PrimaryQuestSet" : "點擊進行主要任務。", + "PrimaryQuestUnset" : "點擊取消設定主要任務。", + "RewardHidden" : "獎勵已隱藏,點擊查看。", + "RewardLocked" : "獎勵已鎖定,點擊解鎖。", + "RewardLockedPlayer" : "獎勵已鎖定。", + "RewardUnlocked" : "獎勵已解鎖,點擊鎖定。", + "RewardUnlockedPlayer" : "獎勵已解鎖。", + "RewardVisible" : "獎勵已可見,點擊隱藏。", + "ShowAll" : "顯示全部", + "TaskHidden" : "目標已隱藏,點擊查看。", + "TaskVisible" : "目標已可見,點擊隱藏。", + "ToggleImage" : "打開或關閉token/角色圖片。", + "UnlockAll" : "全部解鎖", + "ViewSplashArt": "查看插圖。" + } + }, + "QuestTracker" : { + "NoPrimary" : "沒有可用的主要任務。", + "Title" : "任務追踪器", + "Tooltips" : { + "BackgroundShow" : "點擊顯示背景。", + "BackgroundUnshow" : "點擊使背景透明。", + "PrimaryQuestShow" : "點擊顯示主要任務。", + "PrimaryQuestUnshow" : "點擊顯示所有任務。" + } + }, + "QuestTypes" : { + "Labels" : { + "Active" : "進行中", + "active" : "進行中", + "Available" : "可選", + "available" : "可選", + "Completed" : "已完成", + "completed" : "已完成", + "Failed" : "已失敗", + "failed" : "已失敗", + "InActive" : "未啓動", + "inactive" : "未啓動", + "Status" : "任務是 {statusLabel}。" + }, + "Tooltips": { + "SetActive" : "設定為進行中", + "SetAvailable" : "設定為可選", + "SetCompleted" : "設定為已完成", + "SetFailed" : "設定為已失敗", + "SetInactive" : "設置為非活動", + "Status" : "狀態:{statusI18n}" + } + }, + "Settings" : { + "allowPlayersAccept" : { + "Enable" : "玩家可以接受任務", + "EnableHint" : "勾選以允許玩家從可選任務中接受任務。" + }, + "allowPlayersCreate" : { + "Enable" : "玩家可以新建任務", + "EnableHint" : "勾選以允許玩家新建任務。玩家新建的任務將出現在可選任務欄中並且可被玩家編輯。需要給予玩家“新建日誌”權限。" + }, + "allowPlayersDrag" : { + "Enable" : "允許玩家拖拽任務獎勵", + "EnableHint" : "勾選以允許玩家將獎勵物品從任務詳情中拖拽到自己的角色卡上。" + }, + "countHidden" : { + "Enable" : "包括隱藏任務數量", + "EnableHint" : "勾選以將隱藏任務的數量算入已完成任務/所有任務數量中。" + }, + "defaultPermissionLevel" : { + "Enable" : "預設任務權限等級", + "EnableHint" : "新增任務時,任務所默認的權限級別.", + "NONE" : "無", + "OBSERVER" : "查看者", + "OWNER" : "所有者" + }, + "dynamicBookmarkBackground" : { + "Enable" : "動態書籤背景", + "EnableHint" : "啟用此選項後,書籤標籤背景將動態設定為視窗內容背景。" + }, + "hideFQLFromPlayers" : { + "Enable" : "對玩家隱藏任務日誌", + "EnableHint" : "啟用此選項後,所有玩家都無法看到任務日誌。只有 GM 級別的用戶才能訪問任務日誌。" + }, + "navStyle" : { + "bookmarks" : "書籤", + "classic" : "經典標籤頁", + "Enable" : "導航方式", + "EnableHint" : "選擇如何展示任務日誌的導航。" + }, + "notifyRewardDrop" : { + "Enable" : "顯示獎勵掉落通知", + "EnableHint" : "當任務獎勵被放到玩家表上時,將彈出 UI 通知。" + }, + "questTrackerResizable" : { + "Enable" : "任務跟踪器可調整大小", + "EnableHint" : "啟用此選項後,將允許對 任務跟踪器 進行手動調整大小控制。" + }, + "showFolder" : { + "Enable" : "顯示任務文件夾", + "EnableHint" : "勾選以在日誌欄中顯示目標文件夾。僅用於DEBUG。" + }, + "showTasks" : { + "default" : "展示目標:已完成/全部", + "Enable" : "顯示任務欄中的目標", + "EnableHint" : "選擇是否或如何在任務日誌欄中展示任務的目標數量。", + "no" : "隱藏 \"目標\" 列表", + "onlyCurrent" : "展示目標:已完成" + }, + "trustedPlayerEdit" : { + "Enable" : "允許受信任的玩家編輯任務", + "EnableHint" : "啟用此選項後,將允許受信任的玩家對他們擁有的擴展任務,進行編輯和狀態控制。" + } + }, + "Tooltips" : { + "Delete" : "刪除", + "Edit" : "編輯", + "HiddenQuestNoPlayers" : "這個任務對所有玩家都是隱藏的。", + "PrimaryQuest" : "主要任務" + } + } +} \ No newline at end of file diff --git a/module.json b/module.json index af25ff4c..06504d8e 100644 --- a/module.json +++ b/module.json @@ -1,35 +1,44 @@ { - "name": "forien-quest-log", + "id": "forien-quest-log", "title": "Forien's Quest Log", "description": "Provides comprehensive Quest Log system for players and Game Masters", - "author": "Forien — Forien#2130", "authors": [ { "name": "Forien", "url": "https://www.patreon.com/forien" + }, + { + "name": "Michael Leahy (TyphonJS)", + "url": "https://www.typhonjs.io" } ], - "version": "0.5.1", - "minimumCoreVersion": "0.6.0", - "compatibleCoreVersion": "0.7.1", - "url": "https://github.com/Forien/foundryvtt-forien-quest-log", - "manifest": "https://raw.githubusercontent.com/Forien/foundryvtt-forien-quest-log/master/module.json", - "download": "https://github.com/Forien/foundryvtt-forien-quest-log/releases/download/v0.5.1/v0.5.1.zip", - "readme": "https://github.com/Forien/foundryvtt-forien-quest-log/blob/v0.5.1/README.md", - "changelog": "https://github.com/Forien/foundryvtt-forien-quest-log/blob/v0.5.1/changelog.md", - "bugs": "https://github.com/Forien/foundryvtt-forien-quest-log/issues", - "wiki": "https://github.com/Forien/foundryvtt-forien-quest-log/wiki", + "url": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log", + "readme": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/blob/master/README.md", + "bugs": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/issues", + "changelog": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/releases/latest/", + "version": "0.8.0", + "compatibility": { + "minimum": "11", + "verified": "12", + "maximum": "12" + }, + "esmodules": [ + "./src/init.js" + ], + "styles": [ + "./css/init.css" + ], "languages": [ - { - "lang": "de", - "name": "Deutsch", - "path": "lang/de.json" - }, { "lang": "cn", "name": "中文(简体", "path": "lang/cn.json" }, + { + "lang": "de", + "name": "Deutsch", + "path": "lang/de.json" + }, { "lang": "en", "name": "English", @@ -40,11 +49,21 @@ "name": "Español", "path": "lang/es.json" }, + { + "lang": "fi-Fl", + "name": "Finnish", + "path": "lang/fi-FI.json" + }, { "lang": "fr", "name": "Français", "path": "lang/fr.json" }, + { + "lang": "it", + "name": "Italiano", + "path": "lang/it.json" + }, { "lang": "ja", "name": "日本語", @@ -55,6 +74,11 @@ "name": "한국어", "path": "lang/ko.json" }, + { + "lang": "nl", + "name": "Nederlands", + "path": "lang/nl.json" + }, { "lang": "pl", "name": "Polski", @@ -64,16 +88,47 @@ "lang": "pt-BR", "name": "Português (Brasil)", "path": "lang/pt-BR.json" + }, + { + "lang": "ru", + "name": "Russian", + "path": "lang/ru.json" + }, + { + "lang": "sv", + "name": "Svenska", + "path": "lang/sv.json" + }, + { + "lang": "zh-tw", + "name": "正體中文", + "path": "lang/zh-tw.json" } ], - "scripts": [ - "./scripts/prompt.mjs" - ], - "esmodules": [ - "./modules/init.mjs" - ], - "styles": [ - "./styles/init.css" + "packs": [ + { + "name": "macros-gm", + "label": "FQL Macros (GM)", + "module": "forien-quest-log", + "path": "./packs/macro-gm.db", + "type": "Macro", + "ownership": { + "PLAYER": "NONE", + "ASSISTANT": "OWNER" + } + }, + { + "name": "macros-player", + "label": "FQL Macros (Player)", + "module": "forien-quest-log", + "path": "./packs/macro-player.db", + "type": "Macro" + } ], - "socket": true -} + "socket": true, + "manifest": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/releases/latest/download/module.json", + "download": "https://github.com/League-of-Foundry-Developers/foundryvtt-forien-quest-log/releases/download/0.8.0/module.zip", + "protected": false, + "coreTranslation": false, + "library": false +} \ No newline at end of file diff --git a/modules/api/hooks.js b/modules/api/hooks.js deleted file mode 100644 index 478fefcf..00000000 --- a/modules/api/hooks.js +++ /dev/null @@ -1,57 +0,0 @@ -import Quest from "../entities/quest.mjs"; -import Utils from "../utility/utils.mjs"; - -/** - * Function for registering API-related Hooks. - */ -export default function registerApiHooks() { - // Create "open quest" Macro when Quest is dropped onto Hotbar. - Hooks.on("hotbarDrop", async (bar, data, slot) => { - if (data.type === "Quest") { - let questId = data.id; - - let quest = Quest.get(questId); - if (!quest) - throw new Error(game.i18n.localize("ForienQuestLog.Api.hooks.createOpenQuestMacro.error.noQuest")); - - let command = `Quests.open("${questId}");`; - let macroData = { - name: game.i18n.format("ForienQuestLog.Api.hooks.createOpenQuestMacro.name", {name: quest.title}), - type: "script", - command: command - }; - - let actor = Utils.findActor(quest.giver); - if (actor) { - if (quest.image === 'actor') - macroData.img = actor.img; - else - macroData.img = actor.data.token.img; - } else { - if (quest.giver) { - let entity = await fromUuid(quest.giver); - macroData.img = entity.img; - } - } - - let macro = game.macros.entities.find(m => (m.data.command === command)); - if (!macro) { - macro = await Macro.create(macroData, {displaySheet: false}) - } - - game.user.assignHotbarMacro(macro, slot); - } - return false; - }); - - // open quest details on link click - $('body').on("click", "a.entity-link[data-entity='Quest']", function (event) { - event.preventDefault(); - event.stopImmediatePropagation(); - const a = event.currentTarget; - - Quests.open(a.dataset.id); - - return false; - }); -} diff --git a/modules/api/quest-api.mjs b/modules/api/quest-api.mjs deleted file mode 100644 index 13eb9978..00000000 --- a/modules/api/quest-api.mjs +++ /dev/null @@ -1,70 +0,0 @@ -import QuestPreview from "../apps/quest-preview.mjs"; -import Quest from "../entities/quest.mjs"; -import Reward from "../entities/reward.mjs"; -import Task from "../entities/task.mjs"; -import Socket from "../utility/socket.mjs"; - -/** - * Quest public Api available under `Quests.` - */ -export default class QuestApi { - /** - * Retrieves Quest instance for given quest ID - * - * @param questId - * @returns {Quest} - */ - static get(questId) { - return Quest.get(questId); - } - - /** - * Opens Quest Details for given quest ID - * - * @param questId - * @param notif - */ - static open(questId, notif = true) { - try { - let questPreview = new QuestPreview(questId); - questPreview.render(true); - } catch (error) { - if (notif) - ui.notifications.error(game.i18n.localize("ForienQuestLog.Notifications.CannotOpen"), {}); - else - Socket.userCantOpenQuest(); - } - } - - /** - * Creates new Quest programmatically through API - * - * @param data - * @returns {Quest} - */ - static create(data = {}) { - if (data.title === undefined) { - throw new Error(game.i18n.localize("ForienQuestLog.Api.create.title")); - } - - return new Quest({}); - } - - /** - * Tunnel to `game.quests.reward.create()`. Creates new Reward programmatically through API. - * - * @returns {Reward} - */ - static get reward() { - return Reward; - } - - /** - * Tunnel to `game.quests.task.create()`. Creates new Task programmatically through API. - * - * @returns {Task} - */ - static get task() { - return Task; - } -} diff --git a/modules/apps/quest-form.mjs b/modules/apps/quest-form.mjs deleted file mode 100644 index ffb56451..00000000 --- a/modules/apps/quest-form.mjs +++ /dev/null @@ -1,280 +0,0 @@ -import QuestFolder from "../entities/quest-folder.mjs"; -import Utils from "../utility/utils.mjs"; -import Task from "../entities/task.mjs"; -import Quest from "../entities/quest.mjs"; -import Socket from "../utility/socket.mjs"; - -export default class QuestForm extends FormApplication { - submitted = false; - - /** - * Default Application options - * - * @returns {Object} - */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - id: "forien-quest-log-form", - template: "modules/forien-quest-log/templates/quest-form.html", - title: game.i18n.localize("ForienQuestLog.QuestForm.Title"), - width: 940, - height: 640, - closeOnSubmit: true - }); - } - - /** - * Retrieves Data to be used in rendering template. - * - * @param options - * @returns {Promise} - */ - async getData(options = {}) { - this.subquest = (this.object._id !== undefined); - const parent = this.subquest ? this.object : null; - - if (this.subquest) - this.options.title += ` – ${game.i18n.format('ForienQuestLog.QuestForm.SubquestOf', {name: parent.name})}`; - - return { - isGM: game.user.isGM, - subquest: this.subquest, - parent: parent, - options: mergeObject(this.options, options) - }; - } - - /** - * Proxy for QuestFolder.get('hidden'). - * Needed? probably not... - * - * @returns {*} - */ - getHiddenFolder() { - return QuestFolder.get('hidden'); - } - - /** - * Called "on submit". Handles saving Form's data - * - * @param event - * @param formData - * @private - */ - async _updateObject(event, formData) { - const actor = Utils.findActor(formData.giver); - let giver = null; - let permission = 0; - - if (actor !== false) { - giver = actor.uuid; - } else { - try { - let entity = await fromUuid(formData.giver); - giver = entity.uuid; - } catch (e) { - giver = null; - } - } - - let title = formData.title; - if (title.length === 0) - title = game.i18n.localize("ForienQuestLog.NewQuest"); - - let tasks = []; - if (formData.tasks !== undefined) { - if (!Array.isArray(formData.tasks)) { - formData.tasks = [formData.tasks]; - } - tasks = formData.tasks.filter(t => t.length > 0).map(t => { - return new Task({name: t}); - }); - } - - let description = (formData.description !== undefined && formData.description.length) ? formData.description : this.description; - let gmnotes = (formData.gmnotes !== undefined && formData.gmnotes.length) ? formData.gmnotes : this.gmnotes; - - let data = { - giver: giver, - title: title, - description: description, - gmnotes: gmnotes, - tasks: tasks - }; - - if (!game.user.isGM) { - data.status = 'available'; - permission = 3; - } - - if (formData.giver === 'abstract') { - data.giver = formData.giver; - data.image = formData.sourceImage; - data.giverName = formData.giverName; - } - - if (this.subquest) { - data.parent = this.object._id; - } - - data = new Quest(data); - - let folder = this.getHiddenFolder(); - - return JournalEntry.create({ - name: title, - content: JSON.stringify(data), - folder: folder._id, - permission: {default: permission} - }).then((entry) => { - if (this.subquest) { - this.object.addSubquest(entry._id); - this.object.save().then(() => { - Socket.refreshQuestPreview(this.object._id); - }); - } - // players don't see Hidden tab, but assistant GM can, so emit anyway - Socket.refreshQuestLog(); - this.submitted = true; - - return entry; - }); - } - - - async close() { - if (this.submitted) { - return super.close(); - } - - new Dialog({ - title: game.i18n.localize("ForienQuestLog.CloseDialog.Title"), - content: `

${game.i18n.localize("ForienQuestLog.CloseDialog.Header")}

-

${game.i18n.localize("ForienQuestLog.CloseDialog.Body")}

`, - buttons: { - no: { - icon: ``, - label: game.i18n.localize("ForienQuestLog.CloseDialog.Cancel") - }, - yes: { - icon: ``, - label: game.i18n.localize("ForienQuestLog.CloseDialog.Discard"), - callback: () => { - this.submitted = true; - this.close(); - } - } - }, - default: "no" - }).render(true); - - - } - - /** - * Need to override because of earlier bad design caused bug with text editors inheriting parent's data - * - * @param div - * @private - */ - _activateEditor(div) { - const temp = this.object; - this.object = undefined; - super._activateEditor(div); - this.object = temp; - } - - /** - * Fired whenever any of TinyMCE editors is saved. - * Just pass data to object's property, we handle save in one go after submit - * - * @see _updateObject() - * - * @param target - * @param element - * @param content - * @returns {Promise} - * @private - */ - async _onEditorSave(target, element, content) { - this[target] = content; - - // keep function to override parent function - // we don't need to submit form on editor save - } - - /** - * Defines all event listeners like click, drag, drop etc. - * - * @param html - */ - activateListeners(html) { - super.activateListeners(html); - - html.on("change", "#giver", async (event) => { - const giverId = $(event.currentTarget).val(); - let giver; - - try { - giver = Utils.findActor(giverId); - - if (giver === false) { - giver = await fromUuid(giverId); - } - } catch (e) { - giver = false; - } - - if (giver) { - if (giver.data.img.length) { - html.find('.giver-portrait').attr({ - 'style': 'background-image:url(' + giver.data.img + ')', - 'title': giver.name - }).removeClass('hidden'); - } else { - html.find('.giver-portrait').attr('style', '').addClass('hidden'); - } - html.find('.drop-info').addClass('hidden'); - } else { - html.find('.giver-portrait').addClass('hidden'); - html.find('.drop-info').removeClass('hidden'); - } - }); - - html.on("drop", ".giver-data-fieldset", async (event) => { - event.preventDefault(); - let data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); - if (['Actor', 'Item', 'JournalEntry'].includes(data.type)) { - let uuid = `${data.type}.${data.id}`; - html.find('#giver').val(uuid).prop('readonly', false).change(); - html.find('.quest-giver-name').slideUp(); - } - }); - - html.on("click", ".add-new-task", () => { - renderTemplate('modules/forien-quest-log/templates/partials/quest-form/task.html', {}).then(el => { - - html.find('.list').append(el); - html.find('.del-btn').unbind(); - html.on("click", ".del-btn", (event) => { - $(event.target).parent().remove(); - }); - }); - }); - - html.on("click", ".source-image", () => { - let currentPath = html.find('.quest-giver-name').val(); - new FilePicker({ - type: "image", - current: currentPath, - callback: path => { - html.find('#giver').val('abstract').prop('readonly', true); - html.find('#sourceImage').val(path); - html.find('.quest-giver-name').slideDown(); - html.find('.giver-portrait').css('background-image', `url(${path})`).removeClass('hidden'); - html.find('.drop-info').addClass('hidden'); - }, - }).browse(currentPath); - }); - } -}; diff --git a/modules/apps/quest-log.mjs b/modules/apps/quest-log.mjs deleted file mode 100644 index 742712a5..00000000 --- a/modules/apps/quest-log.mjs +++ /dev/null @@ -1,138 +0,0 @@ -import Quest from "../entities/quest.mjs"; -import QuestPreview from "./quest-preview.mjs"; -import QuestForm from "./quest-form.mjs"; -import Socket from "../utility/socket.mjs"; - -export default class QuestLog extends Application { - sortBy = null; - sortDirection = 'asc'; - - /** - * Default Application options - * - * @returns {Object} - */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - id: "forien-quest-log", - classes: ["forien-quest-log"], - template: "modules/forien-quest-log/templates/quest-log.html", - width: 700, - height: 480, - minimizable: true, - resizable: true, - title: game.i18n.localize("ForienQuestLog.QuestLog.Title"), - tabs: [{navSelector: ".log-tabs", contentSelector: ".log-body", initial: "progress"}] - }); - } - - /** - * Retrieves Data to be used in rendering template. - * - * @param options - * @returns {Promise} - */ - getData(options = {}) { - let available = game.settings.get("forien-quest-log", "availableQuests"); - return mergeObject(super.getData(), { - options: options, - isGM: game.user.isGM, - availableTab: available, - canAccept: game.settings.get("forien-quest-log", "allowPlayersAccept"), - canCreate: game.settings.get("forien-quest-log", "allowPlayersCreate"), - showTasks: game.settings.get("forien-quest-log", "showTasks"), - style: game.settings.get("forien-quest-log", "navStyle"), - // titleAlign: game.settings.get("forien-quest-log", "titleAlign"), - questTypes: Quest.getQuestTypes(), - quests: Quest.getQuests(this.sortBy, this.sortDirection, available, true) - }); - } - - /** - * Set sort target and toggle direction. Refresh window - * - * @param target - */ - toggleSort(target, direction = undefined) { - if (this.sortBy === target) { - this.sortDirection = (this.sortDirection === 'desc') ? 'asc' : 'desc'; - } else { - this.sortBy = target; - this.sortDirection = 'asc'; - } - if (direction !== undefined && (direction === 'asc' || direction === 'desc')) - this.sortDirection = direction; - - this.render(true); - } - - /** - * Defines all event listeners like click, drag, drop etc. - * - * @param html - */ - activateListeners(html) { - super.activateListeners(html); - - html.on("click", ".new-quest-btn", () => { - new QuestForm({}).render(true); - }); - - html.on("click", ".actions i", event => { - const canPlayerAccept = game.settings.get("forien-quest-log", "allowPlayersAccept"); - const target = $(event.target).data('target'); - const questId = $(event.target).data('quest-id'); - - if (target === 'active' && canPlayerAccept) Socket.acceptQuest(questId); - if (!game.user.isGM) return; - - const classList = $(event.target).attr('class'); - if (classList.includes('move')) { - Quest.move(questId, target); - } else if (classList.includes('delete')) { - Quest.delete(questId); - } - }); - - html.on("click", ".title", event => { - let questId = $(event.target).closest('.title').data('quest-id'); - let questPreview = new QuestPreview(questId); - questPreview.render(true); - }); - - html.on("click", ".sortable", event => { - let el = $(event.target); - this.toggleSort(el.data('sort')); - }); - - html.on("dragstart", ".drag-quest", event => { - let dataTransfer = { - type: "Quest", - id: $(event.target).data('quest-id') - }; - event.originalEvent.dataTransfer.setData("text/plain", JSON.stringify(dataTransfer)); - - }); - - html.on("drop", ".tab", event => { - const dt = event.target.closest('.drag-quest') || null; - if (!dt) return; - - const data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); - const id = data.id; - const journal = game.journal.get(id); - if (!journal) return; - - const quest = Quest.get(id); - if (!quest) return; - - const sortData = {sortKey: "sort", sortBefore: true}; - const targetId = dt.dataset.questId; - sortData.target = game.journal.get(targetId); - const ids = Quest.getQuests()[quest.status].map(q => q.id); - sortData.siblings = game.journal.filter(e => (e._id !== data.id && ids.includes(e._id))); - - journal.sortRelative(sortData).then(() => this.render()); - }); - } -}; diff --git a/modules/apps/quest-preview.mjs b/modules/apps/quest-preview.mjs deleted file mode 100644 index 2e3b0d0e..00000000 --- a/modules/apps/quest-preview.mjs +++ /dev/null @@ -1,525 +0,0 @@ -import Quest from "../entities/quest.mjs"; -import Socket from "../utility/socket.mjs"; -import QuestForm from "./quest-form.mjs"; - -export default class QuestPreview extends FormApplication { - /** - * Since Quest Preview shows data for single Quest, it needs a Quest instance or - * there is no point in rendering it. - * - * @param questId - * @param options - */ - constructor(questId, options = {}) { - super(options); - this.quest = Quest.get(questId); - if (!this.quest) throw new Error(game.i18n.localize("ForienQuestLog.QuestPreview.InvalidQuestId")); - } - - set object(value) {} - - get object() { - return this.quest; - } - - /** - * Default Application options - * - * @returns {Object} - */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - classes: ["forien-quest-preview"], - template: "modules/forien-quest-log/templates/quest-preview.html", - width: 700, - height: 540, - minimizable: true, - resizable: true, - title: game.i18n.localize("ForienQuestLog.QuestPreview.Title"), - tabs: [{navSelector: ".quest-tabs", contentSelector: ".quest-body", initial: "details"}] - }); - } - - /** @override */ - get id() { - return `quest-${this.quest.id}`; - } - - /** - * Retrieves Data to be used in rendering template. - * - * @param options - * @returns {Promise} - */ - async getData(options = {}) { - let quest = duplicate(this.quest); - let content = Quest.populate(quest, this.quest.entry); - this.canEdit = (content.playerEdit || game.user.isGM); - this.playerEdit = content.playerEdit; - - let data = { - id: this.quest.id, - isGM: game.user.isGM, - canEdit: this.canEdit - }; - - if (game.user.isGM) { - let entry = game.journal.get(this.quest.id); - data.users = game.users; - data.observerLevel = CONST.ENTITY_PERMISSIONS.OBSERVER; - - data.users = game.users.map(u => { - if (u.isGM) return; - return { - user: u, - level: entry.data.permission[u._id], - hidden: u.isGM - }; - }).filter(u => u !== undefined); - } - - return mergeObject(content, data); - } - - /** @override */ - _getHeaderButtons() { - let buttons = super._getHeaderButtons(); - - // Share Entry - if (game.user.isGM) { - buttons.unshift({ - label: game.i18n.localize("ForienQuestLog.QuestPreview.HeaderButtons.Show"), - class: "share-quest", - icon: "fas fa-eye", - onclick: () => Socket.showQuestPreview(this.quest.id) - }); - } - - if (this.quest.splash.length) { - buttons.unshift({ - label: '', - class: "splash-image", - icon: "far fa-image", - onclick: () => { - (new ImagePopout(this.quest.splash, {shareable: true})).render(true) - } - }); - } - - buttons.unshift({ - label: '', - class: "copy-link", - icon: "fas fa-link", - onclick: (event) => { - const el = document.createElement('textarea'); - el.value = `@Quest[${this.quest.id}]{${this.quest.title}}`; - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); - ui.notifications.info(game.i18n.localize("ForienQuestLog.Notifications.LinkCopied"), {}); - } - }); - - return buttons; - } - - getQuestName () { - return this.quest.name; - } - - /** - * This might be a FormApplication, but we don't want Submit event to fire. - * @param event - * @param formData - * @returns {Promise} - * @private - */ - async _onSubmit(event, {updateData = null, preventClose = false, preventRender = false} = {}) { - event.preventDefault(); - - return false; - } - - /** - * This might be a FormApplication, but we don't want to update anything on submit. - * @param event - * @param formData - * @returns {Promise} - * @private - */ - async _updateObject(event, formData) { - event.preventDefault(); - - return false; - } - - /** - * When editor is saved, we want to update and save quest. - * - * @param target - * @param element - * @param content - * @returns {Promise} - * @private - */ - async _onEditorSave(target, element, content) { - this.quest[target] = content; - this.saveQuest(); - } - - /** - * Save associated quest and refresh window - * - * @returns {Promise} - */ - async saveQuest() { - this.quest.save().then(() => { - this.refresh(); - }); - } - - /** - * Refreshes the Quest Details window and emits Socket so other players get updated view as well - * - * @returns {Promise} - */ - async refresh() { - this.render(true); - Socket.refreshQuestLog(); - Socket.refreshQuestPreview(this.quest.id); - if (this.quest.parent) { - Socket.refreshQuestPreview(this.quest.parent); - } - } - - /** - * When rendering window, add reference to global variable. - * - * @see close() - * @returns {Promise} - */ - render(force = false, options = {}) { - game.questPreview[this.quest.id] = this; - if (force) this.quest.refresh(); - return super.render(force, options); - } - - /** - * When closing window, remove reference from global variable. - * - * @see render() - * @returns {Promise} - */ - async close() { - delete game.questPreview[this.quest.id]; - await super.close(); - } - - /** - * Retrieves Item from Compendium - * - * @param packId - * @param itemId - */ - async getItemFromPack(packId, itemId) { - const pack = game.packs.get(packId); - if (pack.metadata.entity !== "Item") - return; - return await pack.getEntity(itemId).then(ent => { - delete ent._id; - return ent; - }); - } - - /** - * Defines all event listeners like click, drag, drop etc. - * - * @param html - */ - activateListeners(html) { - super.activateListeners(html); - - html.on('click', '.splash-image-link', (event) => { - (new ImagePopout(this.quest.splash, {shareable: true})).render(true) - }); - - html.on('dragstart', '.fa-sort', (event) => { - event.stopPropagation(); - const li = event.target.closest('li') || null; - if (!li) return; - let dataTransfer = { - mode: "Sort", - index: $(li).data('index') - }; - event.originalEvent.dataTransfer.setData("text/plain", JSON.stringify(dataTransfer)); - }); - - html.on('dragstart', '.item-reward', (event) => { - let dataTransfer = { - type: "Item", - data: $(event.target).data('transfer') - }; - event.originalEvent.dataTransfer.setData("text/plain", JSON.stringify(dataTransfer)); - }); - - html.on("click", ".item-reward", (event) => { - let data = $(event.currentTarget).data('transfer'); - delete data._id; - delete data.permission; - let item = new CONFIG.Item.entityClass(data); - item.sheet.render(true); - }); - - html.on("click", ".quest-name", (event) => { - let id = $(event.currentTarget).data('id'); - Quests.open(id); - }); - - html.on("click", ".open-actor-sheet", (event) => { - let actorId = $(event.target).data('actor-id'); - let actor = game.actors.get(actorId); - if (actor?.permission > 0) - actor.sheet.render(true); - }); - - if (this.canEdit) { - html.on("click", ".actions i", async (event) => { - const target = $(event.target).data('target'); - const questId = $(event.target).data('id'); - const classList = $(event.target).attr('class'); - - if (classList.includes('move')) { - Quest.move(questId, target).then(() => this.refresh()); - } else if (classList.includes('delete')) { - Quest.delete(questId, this.quest.id).then(() => this.refresh()); - } - }); - - html.on("drop", ".rewards-box", async (event) => { - event.preventDefault(); - let item; - let data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); - if (data.mode === 'Sort') { - this.quest.sortRewards(event, data); - } else if (data.type === 'Item') { - if (data.pack) { - item = await this.getItemFromPack(data.pack, data.id); - } else if (data.data) { - item = data.data; - } else { - let witem = game.items.get(data.id); - if (!witem) - return; - item = duplicate(witem); - } - if (item) { - this.quest.addReward({type: "Item", data: item}); - this.saveQuest(); - } - } - }); - - html.on("drop", ".tasks-box", async (event) => { - event.preventDefault(); - let data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); - if (data.mode === 'Sort') { - this.quest.sortTasks(event, data); - } - }); - - html.on("drop", ".quest-giver-gc", (event) => { - event.preventDefault(); - let data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); - if (['Actor', 'Item', 'JournalEntry'].includes(data.type)) { - this.quest.giver = `${data.type}.${data.id}`; - this.saveQuest(); - } - }); - - html.on("click", '.editable', (event) => { - let target = $(event.target).data('target'); - if (target === undefined) return; - - let value = this.quest[target]; - let index = undefined; - if (target === 'task.name') { - index = $(event.target).data('index'); - value = this.quest.tasks[index].name; - } - if (target === 'reward.name') { - index = $(event.target).data('index'); - value = this.quest.rewards[index].data.name; - } - - value = value.replace(/"/g, '"'); - let input = $(``); - let parent = $(event.target).closest('.actions').prev('.editable-container'); - - parent.html(''); - parent.append(input); - input.focus(); - - input.focusout((event) => { - let target = $(event.target).data('target'); - let value = $(event.target).val(); - let index; - - switch (target) { - case 'task.name': - index = $(event.target).data('index'); - this.quest.tasks[index].name = value; - break; - case 'reward.name': - index = $(event.target).data('index'); - this.quest.rewards[index].data.name = value; - break; - default: - if (this.quest[target] !== undefined) - this.quest[target] = value; - } - this.saveQuest(); - }); - }); - - html.on("click", '.del-btn', (event) => { - let index = $(event.target).data('index'); - let target = $(event.target).data('target'); - - if (target === 'tasks') { - this.quest.removeTask(index); - } else if (target === 'rewards') { - this.quest.removeReward(index); - } - this.saveQuest(); - }); - - html.on("click", '.task .toggleState', (event) => { - let index = $(event.target).data('task-index'); - this.quest.tasks[index].toggle(); - this.saveQuest(); - }); - - html.on("click", ".toggleImage", (event) => { - this.quest.toggleImage().then(() => { - this.saveQuest(); - }); - }); - - html.on("click", ".add-new-task", (event) => { - event.preventDefault(); - let li = $('
  • '); - let placeholder = $(''); - let input = $(``); - let box = $(event.target).closest('.quest-tasks').find('.tasks-box ul'); - - li.append(placeholder); - li.append(input); - box.append(li); - - input.focus(); - - input.focusout((event) => { - let value = $(event.target).val(); - if (value !== undefined && value.length) { - this.quest.addTask({ - name: value - }) - } - this.saveQuest(); - }); - }); - - html.on("click", ".toggleHidden", (event) => { - let target = $(event.target).data('target'); - let index = $(event.target).data('index'); - - if (target === 'task') { - this.quest.toggleTask(index).then(() => this.saveQuest()); - } else if (target === 'reward') { - this.quest.toggleReward(index).then(() => this.saveQuest()); - } - }); - - html.on("click", ".add-abstract", (event) => { - let li = $('
  • '); - let input = $(``); - let box = $(event.target).closest('.quest-rewards').find('.rewards-box ul'); - - // $(box).children('.drop-info').each(function () { - // $(this).remove(); - // }); - - li.append(input); - box.append(li); - - input.focus(); - - input.focusout((event) => { - let value = $(event.target).val(); - if (value !== undefined && value.length) { - this.quest.addReward({ - data: { - name: value, - img: 'icons/svg/mystery-man.svg' - }, - type: 'Abstract' - }) - } - this.saveQuest(); - }); - }); - - html.on("click", ".abstract-reward .reward-image", (event) => { - let index = $(event.target).data('index'); - let currentPath = this.quest.rewards[index].data.img; - new FilePicker({ - type: "image", - current: currentPath, - callback: path => { - this.quest.rewards[index].data.img = path; - this.saveQuest(); - }, - }).browse(currentPath); - }); - } - - if (game.user.isGM) { - html.on("click", "#personal-quest", (event) => { - this.quest.togglePersonal().then(() => { - this.saveQuest(); - }); - }); - - html.on("click", ".personal-user", (event) => { - let userId = $(event.target).data('user-id'); - let value = $(event.target).data('value'); - let permission = value ? 0 : (this.playerEdit ? 3 : 2); - - this.quest.savePermission(userId, permission).then(() => this.saveQuest()); - }); - - html.on("click", ".quest-splash", (event) => { - let currentPath = this.quest.splash; - new FilePicker({ - type: "image", - current: currentPath, - callback: path => { - this.quest.splash = path; - this.saveQuest(); - }, - }).browse(currentPath); - }); - - html.on("click", ".add-subquest-btn", (event) => { - new QuestForm(this.quest, {subquest:true}).render(true); - }); - - html.on("click", "#player-edit", event => { - let checked = $(event.target).prop('checked'); - let permission = checked ? 3 : 2; - this.quest.savePermission('*', permission).then(() => this.saveQuest()); - }); - } - } -}; diff --git a/modules/constants.mjs b/modules/constants.mjs deleted file mode 100644 index bd9a9b63..00000000 --- a/modules/constants.mjs +++ /dev/null @@ -1,5 +0,0 @@ -let constants = { - moduleName: "forien-quest-log", - moduleLabel: "Forien's Quest Log" -}; -export default constants; diff --git a/modules/entities/collection/quests-collection.mjs b/modules/entities/collection/quests-collection.mjs deleted file mode 100644 index 77e486b0..00000000 --- a/modules/entities/collection/quests-collection.mjs +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Class that acts "kind of" like Entity, to help Manage everything Quest Related - * in a more structured way, than to call JournalEntry every time. - */ -import Quest from "../quest.mjs"; - -export default class QuestsCollection { - static _entities = undefined; - static get entities() { - if (this._entities === undefined) { - let quests = Quest.getQuests(); - let entities = [...quests.active, ...quests.completed, ...quests.failed, ...quests.hidden]; - - this._entities = entities.map(e => { - let data = e; - data.name = data.title; - - return { - _id: e.id, - id: e.id, - name: e.title, - data: data - } - }) - } - - return this._entities; - } - - static get(questId) { - return Quest.get(questId); - } - - static getName(name) { - return this.entities.find(e => e.name === name); - } - - static get instance() { - return this; - } -} diff --git a/modules/entities/quest-folder.mjs b/modules/entities/quest-folder.mjs deleted file mode 100644 index 9dd81ab5..00000000 --- a/modules/entities/quest-folder.mjs +++ /dev/null @@ -1,41 +0,0 @@ -export default class QuestFolder { - static questDirName = '_fql_quests'; - static _questDirId = null; - - /** - * Returns true if quest directory has been created - * - * @param folder - * @returns {boolean} - */ - static folderExists(folder = 'root') { - let result = game.journal.directory.folders.find(f => f.name === this.questDirName); - - return result !== undefined; - } - - /** - * Initializes the creation of quest folders - * - * @returns {Promise} - */ - static async initializeJournals() { - let dirExists = this.folderExists(); - - if (!dirExists) { - await Folder.create({name: this.questDirName, type: "JournalEntry", parent: null}); - } - - let folder = await game.journal.directory.folders.find(f => f.name === this.questDirName); - this._questDirId = folder._id; - } - - /** - * Retrieves instance of Quest folder - * - * @returns {*} - */ - static get() { - return game.journal.directory.folders.find(f => f.name === this.questDirName); - } -} diff --git a/modules/entities/quest.mjs b/modules/entities/quest.mjs deleted file mode 100644 index aac1cda5..00000000 --- a/modules/entities/quest.mjs +++ /dev/null @@ -1,722 +0,0 @@ -import Socket from "../utility/socket.mjs"; -import QuestFolder from "./quest-folder.mjs"; -import Reward from "./reward.mjs"; -import Task from "./task.mjs"; -import QuestsCollection from "./collection/quests-collection.mjs"; -import constants from "../constants.mjs"; - -/** - * Class that acts "kind of" like Entity, to help Manage everything Quest Related - * in a more structured way, than to call JournalEntry every time. - */ -export default class Quest { - constructor(data = {}, entry = null) { - this._id = data.id || null; - this.initData(data); - this.entry = entry; - this._data = data; - } - - /** - * Normally would be in constructor(), but is extracted for usage in different methods as well - * - * @see refresh() - * @param data - */ - initData(data) { - this._giver = data.giver || null; - this._title = data.title || game.i18n.localize("ForienQuestLog.NewQuest"); - this._status = data.status || 'hidden'; - this._description = data.description || ''; - this._gmnotes = data.gmnotes || ''; - this._image = data.image || 'actor'; - this._giverName = data.giverName || 'actor'; - this._splash = data.splash || ''; - this._personal = data.personal || false; - this._parent = data.parent || null; - this._permission = data.permission || 0; - this._subquests = data.subquests || []; - this._tasks = []; - this._rewards = []; - this._populated = false; - - if (data.tasks !== undefined && Array.isArray(data.tasks)) - this._tasks = data.tasks.map((task) => { - return new Task(task); - }); - if (data.rewards !== undefined && Array.isArray(data.rewards)) - this._rewards = data.rewards.map((reward) => { - return new Reward(reward); - }); - } - - /** - * Creates new and adds Quest to task array of quest. - * - * @param questId - */ - addSubquest(questId) { - this._subquests.push(questId); - } - - /** - * Creates new and adds Task to task array of quest. - * - * @param data - */ - addTask(data = {}) { - let task = new Task(data); - if (task.isValid) - this._tasks.push(task); - } - - /** - * Creates new and adds Reward to reward array of quest. - * - * @param data - */ - addReward(data = {}) { - let reward = new Reward(data); - if (reward.isValid) - this._rewards.push(reward); - } - - /** - * Deletes Task from Quest - * - * @param questId - */ - removeSubquest(questId) { - this._subquests = this._subquests.filter(id => id !== questId); - } - - /** - * Deletes Task from Quest - * - * @param index - */ - removeTask(index) { - if (this._tasks[index] !== undefined) - this._tasks.splice(index, 1); - } - - /** - * Deletes Reward from Quest - * - * @param index - */ - removeReward(index) { - if (this._rewards[index] !== undefined) - this._rewards.splice(index, 1); - } - - /** - * Toggles visibility of Reward - * - * @param index - * @returns {Promise} - */ - async toggleReward(index) { - if (this._rewards[index] !== undefined) - return await this._rewards[index].toggleVisible(); - } - - /** - * Toggles visibility of Task - * - * @param index - * @returns {Promise} - */ - async toggleTask(index) { - if (this._tasks[index] !== undefined) - return await this._tasks[index].toggleVisible(); - } - - /** - * Toggles Actor image between sheet's and token's images - */ - async toggleImage() { - if (this._image === 'actor') { - this._image = 'token'; - } else { - this._image = 'actor'; - } - } - - /** - * Refreshes data without need of destroying and reinstantiating Quest object - */ - refresh() { - let entry = game.journal.get(this._id); - let content = Quest.getContent(entry); - - this.initData(content); - } - - /** - * Toggles quest between Public and Personal. In both cases, it hides the quest from everyone. - * If new status is public, then hide it. - * - * @returns {Promise} - */ - async togglePersonal() { - this._personal = !this._personal; - this.entryPermission = {default: 0}; - if (this._personal === false) { - this.status = 'hidden'; - } - } - - /** - * Saves new permissions for users. Used by Personal Quests feature. - * - * @param userId - * @param permission - * @returns {Promise} - */ - async savePermission(userId, permission) { - if ([ - CONST.ENTITY_PERMISSIONS.OWNER, - CONST.ENTITY_PERMISSIONS.OBSERVER, - CONST.ENTITY_PERMISSIONS.NONE - ].includes(permission) === false) return; - - let entryData = duplicate(game.journal.get(this._id)); - let permissionData; - - if (userId === '*') { - permissionData = entryData.permission - } else { - permissionData = {[userId]: userId}; - } - - for (let p in permissionData) { - if (this.personal && p === 'default') continue; - if (p !== 'default') { - let user = game.users.get(p); - if (user === null) { - delete entryData.permission[p]; - continue; - } - } - - if (permission === CONST.ENTITY_PERMISSIONS.NONE && p !== 'default') { - delete entryData.permission[p]; - } else { - entryData.permission[p] = permission; - } - } - - this.entryPermission = entryData.permission; - } - - sortRewards(event, data) { - const dt = event.target.closest('li.reward') || null; - const index = data.index; - let targetIdx = dt?.dataset.index; - - this.sortParts(index, targetIdx, this.rewards) - } - - sortTasks(event, data) { - const dt = event.target.closest('li.task') || null; - const index = data.index; - let targetIdx = dt?.dataset.index; - this.sortParts(index, targetIdx, this.tasks) - } - - sortParts(index, targetIdx, array) { - const entry = array.splice(index, 1)[0]; - if (targetIdx) { - if (index < targetIdx) targetIdx--; - array.splice(targetIdx, 0, entry); - } else { - array.push(entry); - } - this.save().then(() => Socket.refreshQuestPreview(this.id)); - } - - /** - * Saves Quest to JournalEntry's content, and if needed, moves JournalEntry to different folder. - * Can also update JournalEntry's permissions. - * - * @returns {Promise} - */ - async save() { - if (this._populated) { - throw new Error(`Can't save populated Quest (${this._id})`); - } - - let update = { - content: JSON.stringify(this) - }; - if (this.entryPermission !== undefined) { - update.permission = this.entryPermission; - } - - let entry = game.journal.get(this._id); - await entry.update(update, {diff: false}); - } - - static get(questId) { - let entry = game.journal.get(questId); - if (!entry) return undefined; - let content = this.getContent(entry); - content.permission = entry.permission; - - if (entry.permission < 2) return undefined; - - return new Quest(content, entry); - } - - /** - * Populates content with a lot of additional data, that doesn't necessarily have to be saved - * with Quest itself, such as Actor's data. - * - * This method also performs content manipulation, for example enriching HTML or calculating amount - * of done/total tasks etc. - * - * Be advised, that even if `content` parameter is Quest object, after populating it cannot be saved. - * If you need to keep Quest instance to be edited and saved, duplicate() it and populate copy. - * - * @param content - * @param entry - * @returns {*} - */ - static populate(content, entry = undefined) { - // let actor = Utils.findActor(content.actor); - let isGM = game.user.isGM; - let canPlayerDrag = game.settings.get("forien-quest-log", "allowPlayersDrag"); - let countHidden = game.settings.get("forien-quest-log", "countHidden"); - - if (content.giver) { - if (content.giver === 'abstract') { - content.giver = { - name: content.giverName, - img: content.image - }; - content.image = undefined; - } else { - fromUuid(content.giver).then((entity) => { - if (entity === null) { - content.giver = false; - return; - } - content.giver = duplicate(entity); - - switch (entity.entity) { - case Actor.entity: - if (content.image === 'token') - content.giver.img = entity.data.token.img; - break; - case Item.entity: - case JournalEntry.entity: - break; - default: - content.giver = false; - } - }); - } - } - - content.isSubquest = false; - if (content.parent !== null) { - content.isSubquest = true; - content.parent = Quest.get(content.parent); - } - content.statusLabel = game.i18n.localize(`ForienQuestLog.QuestTypes.Labels.${content.status}`); - - if (countHidden) { - content.checkedTasks = content.tasks.filter(t => t.completed).length; - content.totalTasks = content.tasks.length; - } else { - content.checkedTasks = content.tasks.filter(t => t.hidden === false && t.completed).length; - content.totalTasks = content.tasks.filter(t => t.hidden === false).length; - } - - if (content.rewards === undefined) { - content.rewards = []; - } - - content.tasks = content.tasks.map((t) => { - let task = new Task(t); - task.name = TextEditor.enrichHTML(task.name); - return task; - }); - - content.noRewards = (content.rewards.length === 0); - content.rewards.forEach((item) => { - item.transfer = JSON.stringify(item.data); - item.type = item.type.toLowerCase(); - item.draggable = ((isGM || canPlayerDrag) && item.type !== 'abstract'); - }); - content.subquests = (content.subquests !== undefined) - ? content.subquests.map(questId => Quest.get(questId)) - : []; - - if (entry) - content.playerEdit = Object.values(entry.data.permission).some(p => p === 3); - - - if (!(isGM || content.playerEdit)) { - content.description = TextEditor.enrichHTML(content.description); - content.tasks = content.tasks.filter(t => t.hidden === false); - content.rewards = content.rewards.filter(r => r.hidden === false); - } - - if (entry) { - if (isGM && content.personal) { - let users = [`${game.i18n.localize('ForienQuestLog.Tooltips.PersonalQuestVisibleFor')}:`]; - - for (let perm in entry.data.permission) { - if (perm === 'default') continue; - if (entry.data.permission[perm] >= 2) { - let user = game.users.get(perm); - users.push(user.name); - } - } - - if (users.length > 1) { - content.users = users.join('\r'); - } else { - content.users = game.i18n.localize('ForienQuestLog.Tooltips.PersonalQuestButNoPlayers'); - } - } - } - - return content; - } - - - /** - * Retrieves JournalEntry's content (which is Quest's data) and optionally populates it. - * - * @see populate() - * - * @param entry - * @param populate - * @returns {*} - */ - static getContent(entry, populate = false) { - let content = entry.data.content; - - try { - content = JSON.parse(content); - content.id = entry._id; - } catch (e) { - console.log(`${constants.moduleLabel} | Quest Folder contains invalid entry. The "${entry.data.name}" is either corrupted Quest Entry, or non-Quest Journal Entry.`); - console.error(e); - return null; - } - - if (populate) - content = this.populate(content, entry); - - return content; - } - - /** - * Retrieves all Quests, grouped by folders. - * - * @param sortTarget sort by - * @param sortDirection sort direction - * @param availableTab true if Available tab is visible - * @param populate - * @returns {{}} - */ - static getQuests(sortTarget = undefined, sortDirection = 'asc', availableTab = false, populate = false) { - let folder = QuestFolder.get(); - let entries = []; - - folder.content.forEach(entry => { - let content = this.getContent(entry, populate); - if (content) entries.push(content); - }); - - if (sortTarget !== undefined) { - entries = this.sort(entries, sortTarget, sortDirection) - } - - const quests = { - available: entries.filter(e => e.status === 'available' && e.parent == null), - active: entries.filter(e => e.status === 'active'), - completed: entries.filter(e => e.status === 'completed' && e.parent == null), - failed: entries.filter(e => e.status === 'failed' && e.parent == null), - hidden: entries.filter(e => e.status === 'hidden' && e.parent == null) - }; - - if (!availableTab) { - quests.hidden = [...quests.available, ...quests.hidden]; - quests.hidden = this.sort(quests.hidden, sortTarget, sortDirection) - } - - return quests; - } - - /** - * Returns localization strings for quest types (statuses) - * - * @returns {{hidden: string, available: string, active: string, completed: string, failed: string}} - */ - static getQuestTypes() { - return { - active: "ForienQuestLog.QuestTypes.InProgress", - completed: "ForienQuestLog.QuestTypes.Completed", - failed: "ForienQuestLog.QuestTypes.Failed", - hidden: "ForienQuestLog.QuestTypes.Hidden", - available: "ForienQuestLog.QuestLog.Tabs.Available" - } - } - - /** - * Sort function to sort quests. - * - * @see getQuests() - * - * @param entries - * @param sortTarget - * @param sortDirection - * @returns -1 | 0 | 1 - */ - static sort(entries, sortTarget, sortDirection) { - return entries.sort((a, b) => { - let targetA; - let targetB; - - if (sortTarget === 'actor') { - targetA = (a.actor) ? (a.actor.name || 'ZZZZZ') : 'ZZZZZ'; - targetB = (b.actor) ? (b.actor.name || 'ZZZZZ') : 'ZZZZZ'; - } else { - targetA = a[sortTarget]; - targetB = b[sortTarget]; - } - - if (sortDirection === 'asc') - return (targetA < targetB) ? -1 : (targetA > targetB) ? 1 : 0; - - return (targetA > targetB) ? -1 : (targetA < targetB) ? 1 : 0; - }); - } - - /** - * Moves Quest (and Journal Entry) to different Folder and updates permissions if needed. - * - * @param questId - * @param target - * @param permission - * @returns {Promise} - */ - static async move(questId, target, permission = undefined) { - let journal = game.journal.get(questId); - let quest = this.getContent(journal); - if (permission === undefined) { - permission = journal.data.permission; - } - - if (!quest.personal) { - if (permission.default < CONST.ENTITY_PERMISSIONS.OWNER) { - if (target === 'hidden') - permission = {default: CONST.ENTITY_PERMISSIONS.NONE}; - else - permission = {default: CONST.ENTITY_PERMISSIONS.OBSERVER}; - } - } - - let content = Quest.getContent(journal); - content.status = target; - content = JSON.stringify(content); - - return journal.update({content: content, "permission": permission}).then(() => { - Socket.refreshQuestLog(); - Socket.refreshQuestPreview(questId); - let dirname = game.i18n.localize(this.getQuestTypes()[target]); - ui.notifications.info(game.i18n.format("ForienQuestLog.Notifications.QuestMoved", {target: dirname}), {}); - }); - } - - /** - * Calls a delete quest dialog. - * - * @param questId - * @param parentId - * @returns {Promise} - */ - static async delete(questId, parentId = null) { - let entry = this.get(questId); - - new Dialog({ - title: game.i18n.format("ForienQuestLog.DeleteDialog.Title", entry.name), - content: `

    ${game.i18n.localize("ForienQuestLog.DeleteDialog.Header")}

    ` + - `

    ${game.i18n.localize("ForienQuestLog.DeleteDialog.Body")}

    `, - buttons: { - yes: { - icon: '', - label: game.i18n.localize("ForienQuestLog.DeleteDialog.Delete"), - callback: () => this.deleteConfirm(questId, parentId) - }, - no: { - icon: '', - label: game.i18n.localize("ForienQuestLog.DeleteDialog.Cancel") - } - }, - default: 'yes' - }).render(true); - } - - /** - * Called when user confirms the delete. - * Deletes the Quest by deleting related JournalEntry. - * - * @param questId - * @param parentId - * @returns {Promise} - */ - static async deleteConfirm(questId, parentId = null) { - let entry = game.journal.get(questId); - - if (parentId !== null) { - let quest = Quests.get(parentId); - quest.removeSubquest(questId); - await quest.save(); - Socket.refreshQuestPreview(parentId); - } - - entry.delete().then(() => { - Socket.refreshQuestLog(); - Socket.closeQuest(questId); - }); - } - - get id() { - return this._id; - } - - set id(value) { - this._id = value; - } - - get giver() { - return this._giver; - } - - set giver(value) { - this._giver = value; - } - - get title() { - return this._title; - } - - set title(value) { - this._title = value; - } - - get description() { - return this._description; - } - - set description(value) { - this._description = value; - } - - get gmnotes() { - return this._gmnotes; - } - - set gmnotes(value) { - this._gmnotes = value; - } - - get subquests() { - return this._subquests; - } - - get tasks() { - return this._tasks; - } - - get rewards() { - return this._rewards; - } - - set image(image) { - if (image === 'actor' || image === 'token') - this._image = image; - } - - get image() { - return this._image; - } - - set splash(splash) { - this._splash = splash; - } - - get splash() { - return this._splash; - } - - get personal() { - return this._personal; - } - - set personal(value) { - this._personal = (value === true); - } - - get status() { - return this._status; - } - - set status(value) { - this._status = value; - } - - get parent() { - return this._parent; - } - - set parent(value) { - this._parent = value; - } - - static get collection() { - return QuestsCollection; - } - - get giverName() { - return this._giverName; - } - - set giverName(value) { - this._giverName = value; - } - - get name() { - return this._title; - } - - get permission() { - return this._permission; - } - - toJSON() { - return { - giver: this._giver, - title: this._title, - status: this._status, - description: this._description, - gmnotes: this._gmnotes, - personal: this._personal, - image: this._image, - giverName: this._giverName, - splash: this._splash, - parent: this._parent, - subquests: this._subquests, - tasks: this._tasks, - rewards: this._rewards - } - } -} - -window.Quest = Quest; \ No newline at end of file diff --git a/modules/entities/reward.mjs b/modules/entities/reward.mjs deleted file mode 100644 index 15014024..00000000 --- a/modules/entities/reward.mjs +++ /dev/null @@ -1,60 +0,0 @@ -export default class Reward { - constructor(data = {}) { - this._type = data.type || null; - this._data = data.data || {}; - this._hidden = data.hidden || false; - } - - get type() { - return this._type; - } - - set type(type) { - this._type = type; - } - - get data() { - return this._data; - } - - set data(data) { - this._data = data; - } - - get isValid() { - return (this._type !== null) - } - - get hidden() { - return this._hidden; - } - - set hidden(value) { - this._hidden = value; - } - - async toggleVisible() { - this._hidden = !this._hidden; - - return this._hidden; - } - - static create(data = {}) { - if (data.type === undefined) { - throw new Error(game.i18n.localize("ForienQuestLog.Api.reward.create.type")); - } - if (data.data === undefined || data.data.name === undefined || data.data.img === undefined) { - throw new Error(game.i18n.localize("ForienQuestLog.Api.reward.create.data")); - } - - return new Reward(data); - } - - toJSON() { - return { - type: this._type, - data: this._data, - hidden: this._hidden - } - } -} diff --git a/modules/entities/task.mjs b/modules/entities/task.mjs deleted file mode 100644 index c77a6d67..00000000 --- a/modules/entities/task.mjs +++ /dev/null @@ -1,87 +0,0 @@ -export default class Task { - constructor(data = {}) { - this._name = data.name || null; - this._completed = data.completed || false; - this._failed = data.failed || false; - this._hidden = data.hidden || false; - } - - toggle() { - if (this._completed === false && this._failed === false) { - this._completed = true; - } else if (this._completed === true) { - this._failed = true; - this._completed = false; - } else { - this._failed = false; - } - } - - get state() { - if (this._completed) { - return 'check-square'; - } else if (this._failed) { - return 'minus-square'; - } - return 'square'; - } - - get name() { - return this._name; - } - - set name(name) { - this._name = name; - } - - get completed() { - return this._completed; - } - - set completed(completed) { - this._completed = (completed === true); - } - - get failed() { - return this._failed; - } - - set failed(failed) { - this._failed = (failed === true); - } - - get hidden() { - return this._hidden; - } - - set hidden(hidden) { - this._hidden = (hidden === true); - } - - async toggleVisible() { - this._hidden = !this._hidden; - - return this._hidden; - } - - get isValid() { - return (this._name.length) - } - - static create(data = {}) { - if (data.name === undefined) { - throw new Error(game.i18n.localize("ForienQuestLog.Api.task.create.name")); - } - - return new Task(data); - } - - toJSON() { - return { - name: this._name, - completed: this._completed, - failed: this._failed, - hidden: this._hidden - } - } -} diff --git a/modules/init.mjs b/modules/init.mjs deleted file mode 100644 index 1d5a9ba9..00000000 --- a/modules/init.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import registerApiHooks from "./api/hooks.js"; -import QuestApi from "./api/quest-api.mjs"; -import QuestLogClass from "./apps/quest-log.mjs"; -import QuestFolder from "./entities/quest-folder.mjs"; -import ModuleSettings from "./utility/config.mjs"; -import Socket from "./utility/socket.mjs"; -import Utils from "./utility/utils.mjs"; -import Quest from "./entities/quest.mjs"; -import QuestsCollection from "./entities/collection/quests-collection.mjs"; - - -Hooks.once('init', () => { - ModuleSettings.register(); - - CONST.ENTITY_TYPES?.push("Quest"); - CONST.ENTITY_LINK_TYPES?.push("Quest"); - CONFIG["Quest"] = { - entityClass: Quest, - collection: QuestsCollection, - sidebarIcon: 'far fa-question-circle', - }; - - Utils.preloadTemplates(); - Utils.registerHandlebarsHelpers(); - - Hooks.callAll("ForienQuestLog.afterInit"); -}); - -Hooks.once('setup', () => { - window.Quests = QuestApi; - window.QuestLog = new QuestLogClass(); - game.questPreview = {}; - - Hooks.callAll("ForienQuestLog.afterSetup"); -}); - -Hooks.once("ready", () => { - QuestFolder.initializeJournals(); - registerApiHooks(); - - // Allow and process incoming socket data - Socket.listen(); - - Hooks.callAll("ForienQuestLog.afterReady"); -}); - -Hooks.on("renderJournalDirectory", (app, html, data) => { - const button = $(``); - let footer = html.find(".directory-footer"); - if (footer.length === 0) { - footer = $(`
    `); - html.append(footer); - } - footer.append(button); - - button.click(ev => { - QuestLog.render(true) - }); - - if (!(game.user.isGM && game.settings.get('forien-quest-log', 'showFolder'))) { - let folderId = QuestFolder.get('root')._id; - let folder = html.find(`.folder[data-folder-id="${folderId}"]`); - - folder.remove(); - } -}); diff --git a/modules/utility/config.mjs b/modules/utility/config.mjs deleted file mode 100644 index 9c91d2ad..00000000 --- a/modules/utility/config.mjs +++ /dev/null @@ -1,134 +0,0 @@ -export default class ModuleSettings { - /** - * Registers various configuration settings for Module - */ - static register() { - game.settings.register("forien-quest-log", "availableQuests", { - name: "ForienQuestLog.Settings.availableQuests.Enable", - hint: "ForienQuestLog.Settings.availableQuests.EnableHint", - scope: "world", - config: true, - default: false, - type: Boolean, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "allowPlayersDrag", { - name: "ForienQuestLog.Settings.allowPlayersDrag.Enable", - hint: "ForienQuestLog.Settings.allowPlayersDrag.EnableHint", - scope: "world", - config: true, - default: false, - type: Boolean, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "allowPlayersCreate", { - name: "ForienQuestLog.Settings.allowPlayersCreate.Enable", - hint: "ForienQuestLog.Settings.allowPlayersCreate.EnableHint", - scope: "world", - config: true, - default: false, - type: Boolean, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "allowPlayersAccept", { - name: "ForienQuestLog.Settings.allowPlayersAccept.Enable", - hint: "ForienQuestLog.Settings.allowPlayersAccept.EnableHint", - scope: "world", - config: true, - default: false, - type: Boolean, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "countHidden", { - name: "ForienQuestLog.Settings.countHidden.Enable", - hint: "ForienQuestLog.Settings.countHidden.EnableHint", - scope: "world", - config: true, - default: true, - type: Boolean, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "showTasks", { - name: "ForienQuestLog.Settings.showTasks.Enable", - hint: "ForienQuestLog.Settings.showTasks.EnableHint", - scope: "world", - config: true, - default: "default", - type: String, - choices: { - "default": "ForienQuestLog.Settings.showTasks.default", - "onlyCurrent": "ForienQuestLog.Settings.showTasks.onlyCurrent", - "no": "ForienQuestLog.Settings.showTasks.no" - }, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - - game.settings.register("forien-quest-log", "navStyle", { - name: "ForienQuestLog.Settings.navStyle.Enable", - hint: "ForienQuestLog.Settings.navStyle.EnableHint", - scope: "client", - config: true, - default: "bookmarks", - type: String, - choices: { - "bookmarks": "ForienQuestLog.Settings.navStyle.bookmarks", - "classic": "ForienQuestLog.Settings.navStyle.classic" - }, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); - -/* - game.settings.register("forien-quest-log", "titleAlign", { - name: "ForienQuestLog.Settings.titleAlign.Enable", - hint: "ForienQuestLog.Settings.titleAlign.EnableHint", - scope: "client", - config: true, - default: "left", - type: String, - choices: { - "left": "ForienQuestLog.Settings.titleAlign.left", - "center": "ForienQuestLog.Settings.titleAlign.center" - }, - onChange: value => { - if (QuestLog && QuestLog.rendered) - QuestLog.render(); - } - }); -*/ - game.settings.register("forien-quest-log", "showFolder", { - name: "ForienQuestLog.Settings.showFolder.Enable", - hint: "ForienQuestLog.Settings.showFolder.EnableHint", - scope: "world", - config: true, - default: false, - type: Boolean, - onChange: value => game.journal.render() - }); - } -} diff --git a/modules/utility/socket.mjs b/modules/utility/socket.mjs deleted file mode 100644 index 8032fd4c..00000000 --- a/modules/utility/socket.mjs +++ /dev/null @@ -1,106 +0,0 @@ -import QuestApi from "../api/quest-api.mjs"; -import Quest from "../entities/quest.mjs"; - -export default class Socket { - static refreshQuestLog() { - if (QuestLog.rendered) - QuestLog.render(true); - game.socket.emit("module.forien-quest-log", { - type: "questLogRefresh" - }) - } - - static refreshQuestPreview(questId) { - if (game.questPreview[questId] !== undefined) - game.questPreview[questId].render(true); - game.socket.emit("module.forien-quest-log", { - type: "questPreviewRefresh", - payload: { - questId: questId - } - }) - } - - static showQuestPreview(questId) { - game.socket.emit("module.forien-quest-log", { - type: "showQuestPreview", - payload: { - questId: questId - } - }) - } - - static userCantOpenQuest() { - game.socket.emit("module.forien-quest-log", { - type: "userCantOpenQuest", - payload: { - user: game.user.name - } - }) - } - - static acceptQuest(questId) { - game.socket.emit("module.forien-quest-log", { - type: "acceptQuest", - payload: { - questId: questId - } - }) - } - - static closeQuest(questId) { - if (game.questPreview[questId] !== undefined) - game.questPreview[questId].close(); - game.socket.emit("module.forien-quest-log", { - type: "closeQuest", - payload: { - questId: questId - } - }) - } - - static listen() { - game.socket.on("module.forien-quest-log", data => { - if (data.type === "questLogRefresh") { - if (QuestLog.rendered) - QuestLog.render(true); - return; - } - - if (data.type === "questPreviewRefresh") { - if (game.questPreview[data.payload.questId] !== undefined) - game.questPreview[data.payload.questId].render(true); - - if (QuestLog.rendered) - QuestLog.render(true); - - return; - } - - if (data.type === "showQuestPreview") { - QuestApi.open(data.payload.questId, false); - - return; - } - - if (data.type === "userCantOpenQuest") { - if (game.user.isGM) { - ui.notifications.warn(game.i18n.format("ForienQuestLog.Notifications.UserCantOpen", {user: data.payload.user}), {}); - } - - return; - } - - if (data.type === "acceptQuest") { - if (game.user.isGM) { - Quest.move(data.payload.questId, 'active'); - } - } - - if (data.type === "closeQuest") { - if (game.questPreview[data.payload.questId] !== undefined) - game.questPreview[data.payload.questId].close(); - } - }); - } -}; diff --git a/modules/utility/utils.mjs b/modules/utility/utils.mjs deleted file mode 100644 index 7cfc0671..00000000 --- a/modules/utility/utils.mjs +++ /dev/null @@ -1,41 +0,0 @@ -export default class Utils { - static findActor(actorId) { - let actor = game.actors.get(actorId); - if (actor === undefined || actor === null) { - actor = game.actors.find(a => a.name === actorId); - } - - if (actor === undefined || actor === null) { - return false; - } - - return actor; - } - - /** - * Preloads templates for partials - */ - static preloadTemplates() { - let templates = [ - "templates/partials/quest-log/tab.html", - "templates/partials/quest-preview/gmnotes.html", - "templates/partials/quest-preview/details.html", - "templates/partials/quest-preview/management.html" - ]; - - templates = templates.map(t => `modules/forien-quest-log/${t}`); - loadTemplates(templates); - } - - static registerHandlebarsHelpers() { - Handlebars.registerHelper('format', function(stringId, ...arrData) { - let objData; - if (typeof arrData[0] === 'object') - objData = arrData[0]; - else - objData = {...arrData}; - - return game.i18n.format(stringId, objData); - }); - } -}; diff --git a/package.json b/package.json new file mode 100644 index 00000000..6ebff92f --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "forien-quest-log", + "description": "This package.json just provides a PostCSS build script for Sass to CSS", + "license": "MIT", + "private": true, + "type": "module", + "author": "Michael Leahy (https://github.com/typhonrt)", + "contributors": [ + "Michael Leahy (https://github.com/typhonrt)" + ], + "dependencies": { + "collect.js": "^4.36.0", + "dompurify": "^3.1.5" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^26.0.0", + "@rollup/plugin-node-resolve": "^15.2.0", + "@rollup/plugin-virtual": "^3.0.0", + "@rollup/plugin-terser": "^0.4.0", + "@types/jquery": "^3.5.29", + "@typhonjs-config/eslint-config": "^0.6.0", + "@typhonjs-fvtt/eslint-config-foundry.js": "^0.8.0", + "autoprefixer": "^10.4.19", + "cssnano": "^7.0.4", + "eslint": "^8.42.0", + "postcss": "^8.4.39", + "postcss-cli": "^11.0.0", + "postcss-preset-env": "^9.6.0", + "rollup": "^4.18.0", + "sass": "^1.77.0" + }, + "browserslist": [">5%", "not IE 11"], + "scripts": { + "build-css": "sass ./styles/init.scss ./css/init.css && postcss ./css/init.css -p sass -u autoprefixer postcss-preset-env cssnano -m -o ./css/init.css", + "eslint": "eslint .", + "rollup-external": "rollup --config" + } +} diff --git a/packs/macro-gm/000046.ldb b/packs/macro-gm/000046.ldb new file mode 100644 index 0000000000000000000000000000000000000000..4dd04cb7a40edfc81ab02970282b73ca8fc75a6a GIT binary patch literal 2034 zcmcJQZD<@t7{_O(yEbQ&n6#-zY-Ms(lfdP2=F+6Swg-2~UA;7El1tL0rL~>go!hM0 z-MQ}0CAo`f6F*c6VRi1()Jlu^ zL5JCcXP$jtW_JF+Tf~z9|0>m)M6sDu7t9-4U+<>T@&4HMNt?#uy+DRDQ(lXh)En}4 zu&l-Lu;9Gm>SmPE^BFzkyiv3tw!w?NHn|nh6v1|~{@rI_nVHv`j zM~+ENj^{o3s+6^wq+0Lvw9mU=hu??ah3iC){f=l#9`06{O?Oe-(U~P$eyqhGY-z6x z)#e;d&4jx4m|V5C(eoNsY%2Dk4(fHkc-GX2Z5TMei(h{Jm-YNcqdI=NMBJwq*3 z&zb`)Yb&(67OUBep(`TP{{Zlb4%mbxijC?S_}jB8O_Qu4dJj%dm(`w@TlI-V@5ruP zvTJ)F5gghKSAn({QH}Vx6!%9WTX8qjaN1@j&KM*|ZTB>qJB@s!!XNMNjtfVhhr4Hx zeFnuDxcDaO>ICjQ>Y7LKG}yNo{v5iCXlX_lQTNMocQ%#kQG)G8Ykym;Evdlr*x7T5 znuuYr3EZ=>9CLkLRd-FbVP<(`?8Jb7yfEcj& zWQH%}?<$4ZkIKtpCmVZ5###a+T|=z3eTV%dtP*0sapacT2Pns#OSc9`QVzF?!k1f0 zm_(!EVhiyX!SH{G|5d43^&GA~M{Rh~Oybu+Avy}tX6Kr(CL&M5BDHJfnw zgXHtNCsF<+k~*VnP2hj}837T-#vFg-Kv_e5JoadyzX*7N6Tb-cukS9NUtqz7;fJ8> z-kebvcAu1uNzF(lhArJ5GShA85x6?!!t#MpHu1uV4V^a2;GK-?=}5X<0Mv2I(UEcl zEXY9axl?ck^v+JW!V zz`G)?8=TsHgN{=}P5Gl)Ve3}ZV9XTPRJd9SmG>8;isA$>4ZU6f)hm{Txd;BSG{E(h sz$1B=%^z2OTB`Jb2tmcT-+zAN)YZzs+6I_Ft;Q#;t literal 0 HcmV?d00001 diff --git a/packs/macro-gm/000050.log b/packs/macro-gm/000050.log new file mode 100644 index 00000000..e69de29b diff --git a/packs/macro-gm/CURRENT b/packs/macro-gm/CURRENT new file mode 100644 index 00000000..a980eefb --- /dev/null +++ b/packs/macro-gm/CURRENT @@ -0,0 +1 @@ +MANIFEST-000049 diff --git a/packs/macro-gm/LOCK b/packs/macro-gm/LOCK new file mode 100644 index 00000000..e69de29b diff --git a/packs/macro-gm/LOG b/packs/macro-gm/LOG new file mode 100644 index 00000000..077484b5 --- /dev/null +++ b/packs/macro-gm/LOG @@ -0,0 +1,3 @@ +2024/07/04-12:43:50.350 597c Recovering log #48 +2024/07/04-12:43:50.355 597c Delete type=0 #48 +2024/07/04-12:43:50.355 597c Delete type=3 #47 diff --git a/packs/macro-gm/LOG.old b/packs/macro-gm/LOG.old new file mode 100644 index 00000000..9468d2b7 --- /dev/null +++ b/packs/macro-gm/LOG.old @@ -0,0 +1,3 @@ +2024/07/02-19:31:19.293 10f8 Recovering log #44 +2024/07/02-19:31:19.306 10f8 Delete type=0 #44 +2024/07/02-19:31:19.306 10f8 Delete type=3 #42 diff --git a/packs/macro-gm/MANIFEST-000049 b/packs/macro-gm/MANIFEST-000049 new file mode 100644 index 0000000000000000000000000000000000000000..5ad5a31241473461d1146ef9411b2d07bce74c4d GIT binary patch literal 156 zcmexq@DS84A>d*mv!4=>#hUMGm Q{TvL8Oh%jx%*HH202u!)kN^Mx literal 0 HcmV?d00001 diff --git a/packs/macro-player/000046.ldb b/packs/macro-player/000046.ldb new file mode 100644 index 0000000000000000000000000000000000000000..a222a2f0e7438898f48a550edccceaabb2361306 GIT binary patch literal 849 zcmaJ--Afcv6u-01NJ}c3E^SaTJ0z>L&aSTcvDT8CsfA`{Ru7Tfow+-E^Ul4ybMK_P zB3KXveNYgIz4h@B8d4xd5D2{oz2_egJx2+_*4>OAJDhvreEfdrcg~N7d7wYkA}+K% z#v_R&?wq{Z2gOu(xp+FCP*k8Pw-yWvU1X$;lN4qN(kFeyg?`?H)-3Xjm?269<=_`? zdAJ~C2z`-fo^0>Og-i2^a&pRQK7pyjO$Uj#XnG0MMPqt&n1Qxv`@m%i=O7k(&kz87RerJ1o%`(rk~YVPEmuoX zpAb2edBR8~WST&S8>s~&{TL`Mt&O0g{=+Ugdw3Oujm5>7F@qx@{ZZL3DQ377qFouY zn1?PPk7Gt->p2;d2=y?^Wn~*^RAOjK3_<<&qPlNofNZj3qRji-U` zQO0JuX+c8TG+$aXrURJQ+mW?LD1rk$O3^Sz^|#_9N(;)%TI zR%%;+th{JVJ$TZhpF96l=jOTsX<4b|sYBng}ZqVO)R|7^(4ikYqlb~ye*jY2<%NWxP zVay%=Q|fxB?Wv-wTwvwVw@nbNF_d3B1~#;RwZmRYe9{s(Yxh=D|F?@jmu?^OM?U`s D&{zX} literal 0 HcmV?d00001 diff --git a/packs/macro-player/000050.log b/packs/macro-player/000050.log new file mode 100644 index 00000000..e69de29b diff --git a/packs/macro-player/CURRENT b/packs/macro-player/CURRENT new file mode 100644 index 00000000..a980eefb --- /dev/null +++ b/packs/macro-player/CURRENT @@ -0,0 +1 @@ +MANIFEST-000049 diff --git a/packs/macro-player/LOCK b/packs/macro-player/LOCK new file mode 100644 index 00000000..e69de29b diff --git a/packs/macro-player/LOG b/packs/macro-player/LOG new file mode 100644 index 00000000..ecf9b019 --- /dev/null +++ b/packs/macro-player/LOG @@ -0,0 +1,3 @@ +2024/07/04-12:43:50.357 1eac Recovering log #48 +2024/07/04-12:43:50.364 1eac Delete type=0 #48 +2024/07/04-12:43:50.364 1eac Delete type=3 #47 diff --git a/packs/macro-player/LOG.old b/packs/macro-player/LOG.old new file mode 100644 index 00000000..214c2bc1 --- /dev/null +++ b/packs/macro-player/LOG.old @@ -0,0 +1,3 @@ +2024/07/02-19:31:19.309 4958 Recovering log #44 +2024/07/02-19:31:19.321 4958 Delete type=0 #44 +2024/07/02-19:31:19.321 4958 Delete type=3 #42 diff --git a/packs/macro-player/MANIFEST-000049 b/packs/macro-player/MANIFEST-000049 new file mode 100644 index 0000000000000000000000000000000000000000..25cd56bbee0ca409e2d201d98c166be1b2aacffc GIT binary patch literal 156 zcmX@N$g{tVfss)vC$%g!CnZVGsj?)sJhM2}IX|}`u_&=5zlfDVK`}QmxhTI_F(5QI z!`#EuH_z9v&^e>TgprK_4A>d#rlwyw QfrEjO$%vDI*_ee50B?6G3IG5A literal 0 HcmV?d00001 diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..6c491688 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,68 @@ +import path from 'node:path'; + +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; // Terser is used for minification / mangling +import virtual from '@rollup/plugin-virtual'; + +// Terser config; refer to respective documentation for more information. +const terserConfig = { + compress: { passes: 3 }, + mangle: { toplevel: true, keep_classnames: true, keep_fnames: true }, + ecma: 2021, + module: true +}; + +// The deploy path for the server bundle which includes the common code. +const s_DEPLOY_PATH = './external'; + +const s_DEPLOY_MINIFY = true; + +// Produce sourcemaps or not +const s_SOURCEMAP = true; + +// Defines potential output plugins to use conditionally if the .env file indicates the bundles should be +// minified / mangled. +const outputPlugins = []; +if (s_DEPLOY_MINIFY) +{ + outputPlugins.push(terser(terserConfig)); +} + +export default () => +{ + return [ + { + input: 'pack', + output: [{ + file: `${s_DEPLOY_PATH}${path.sep}collect.js`, + format: 'es', + plugins: outputPlugins, + generatedCode: { constBindings: true }, + sourcemap: s_SOURCEMAP, + }], + plugins: [ + virtual({ + pack: `export { collect as default } from './node_modules/collect.js/src/index.js';` + }), + resolve({ browser: true }), + commonjs() + ] + }, + { + input: 'pack', + output: [{ + file: `${s_DEPLOY_PATH}${path.sep}DOMPurify.js`, + format: 'es', + plugins: outputPlugins, + generatedCode: { constBindings: true }, + sourcemap: s_SOURCEMAP, + }], + plugins: [ + virtual({ + pack: `export { default } from './node_modules/dompurify/dist/purify.es.mjs';` + }) + ] + } + ]; +}; diff --git a/scripts/prompt.js b/scripts/prompt.js deleted file mode 100644 index ec6b8152..00000000 --- a/scripts/prompt.js +++ /dev/null @@ -1,154 +0,0 @@ -(() => { - const module = "Forien's Quest Log"; - const author = "Forien"; - const message = "

    Thank you for downloading our modules! We are implementing a new, unified Welcome Screen to contain information for any/all of our Foundry Workshop modules.

    We strongly recommend you install it so that you are updated and notified about new versions. The new Welcome Screen is highly customizable and offers several different display options.

    "; - const messageEnable = "You have installed Foundry Workshop Welcome Screen. Do you want to enable it now?"; - const disclaimer = "Clicking 'Install' will download the 'Foundry Workshop Welcome Screen' module and install it into your Foundry instance. It will also send you back to the setup screen where you will need to re-launch your world."; - const ending = "Sincerely,"; - const manifest = 'https://raw.githubusercontent.com/Foundry-Workshop/welcome-screen/master/module.json'; - const wsID = 'workshop-welcome-screen'; - - let testSetup = async () => { - let response = {}; - try { - response = await fetch(SetupConfiguration.setupURL, { - method: "POST", - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({}) - }); - } catch (e) { - return false; - } - - return response.status !== 403; - }; - - let tryInstall = async () => { - let test = await testSetup(); - - if (test === true) { - ui.notifications.active = []; - ui.notifications.info("Preparing to download module…", {permanent: true}); - const notif = ui.notifications.active[0]; - game.socket.on("progress", data => { - notif.html(data.msg); - }); - await SetupConfiguration.installPackage({type: "module", manifest: manifest}); - await game.shutDown(); - } else { - new Dialog({ - title: `Foundry is protected`, - content: `

    Your Foundry VTT instance's setup is password protected (which is good!). Because of it, you need to 'back to setup' and install the module manually, or come back after you login as an administrator.

    Click on the link below to copy it:

    `, - buttons: { - shutdown: { - label: "Back to Setup", - callback: () => { - game.shutDown(); - } - }, - close: { - label: "Close", - } - } - })._render(true).then(() => { - document.getElementById("workshop-welcome-screen-manifest").onclick = function () { - this.select(); - document.execCommand('copy'); - ui.notifications.info("Manifest URL copied!", {}); - } - }); - } - }; - - let installPrompt = () => { - if (window.workshopWS.app) return; - game.settings.register(wsID, 'showPrompt', {scope: "client", config: false, default: true}); - if (!game.settings.get(wsID, 'showPrompt')) return; - - let authors = Object.keys(window.workshopWS.authors).join(' and '); - let modules = window.workshopWS.modules.map(m => `
  • ${m}
  • `).join(''); - - window.workshopWS.app = new Dialog({ - title: `Install Welcome Screen for Foundry Workshop's modules?`, - content: `${message}
    Installed modules:
      ${modules}

    ${ending}
    ${authors}

    ${disclaimer}

    `, - buttons: { - cancel: { - label: "No" - }, - never: { - label: "Never show again", - callback: () => { - game.settings.set(wsID, 'showPrompt', false) - } - }, - install: { - label: "Install", - callback: () => { - tryInstall() - } - } - }, - default: 'install' - }, - {id: `${wsID}-install-prompt`, width: 420, height: 540}); - window.workshopWS.app.render(true); - }; - - let enablePrompt = () => { - if (window.workshopWS.app) return; - game.settings.register(wsID, 'showPrompt', {scope: "client", config: false, default: true}); - if (!game.settings.get(wsID, 'showPrompt')) return; - - window.workshopWS.app = new Dialog({ - title: `Enable Welcome Screen?`, - content: `

    ${messageEnable}

    `, - buttons: { - cancel: { - label: "No" - }, - never: { - label: "Never show again", - callback: () => { - game.settings.set(wsID, 'showPrompt', false) - } - }, - install: { - label: "Enable", - callback: () => { - const settings = game.settings.get("core", ModuleManagement.CONFIG_SETTING); - const setting = mergeObject(settings, {[wsID]: true}); - game.settings.set("core", ModuleManagement.CONFIG_SETTING, setting); - } - } - }, - default: 'install' - }); - window.workshopWS.app.render(true); - }; - - Hooks.on("init", () => { - if (window.workshopWS === undefined) { - window.workshopWS = { - modules: [module], - authors: { - [author]: true - }, - app: undefined - }; - } else { - window.workshopWS.modules.push(module); - window.workshopWS.authors[author] = true; - } - }); - - Hooks.on("ready", () => { - if (!game.user.isGM) return; - - const ws = game.modules.get(wsID); - if (ws === undefined) { - installPrompt(); - } else if (!ws.active) { - enablePrompt(); - } - }); -})(); \ No newline at end of file diff --git a/src/control/FQLHooks.js b/src/control/FQLHooks.js new file mode 100644 index 00000000..e1ba64f7 --- /dev/null +++ b/src/control/FQLHooks.js @@ -0,0 +1,555 @@ +import { + FoundryUIManager, + FVTTCompat, + ModuleSettings, + QuestDB, + Socket, + ViewManager, + Utils } from './index.js'; + +import { QuestAPI } from './public/index.js'; + +import { Quest } from '../model/index.js'; + +import { QuestPreview } from '../view/index.js'; + +import { DBMigration } from '../../database/DBMigration.js'; + +import { + constants, + sessionConstants, + settings } from '../model/constants.js'; + +/** + * Provides implementations for all Foundry hooks that FQL responds to and registers under. Please view the + * {@link QuestDB} documentation for hooks that it fires in the QuestDB lifecycle. + * + * Foundry lifecycle: + * - `init` - {@link FQLHooks.foundryInit} + * - `ready` - {@link FQLHooks.foundryReady} - A hook `ForienQuestLog.Lifecycle.ready` is fired after FQL is ready. + * - `setup` - {@link FQLHooks.foundrySetup} + * + * Foundry game hooks: + * - `collapseSidebar` - {@link FoundryUIManager.collapseSidebar} - Handle tracking state of the sidebar. + * - `dropActorSheetData` - {@link FQLHooks.dropActorSheetData} - Handle drop data for reward items in actor sheet. + * - `dropCanvasData` - {@link FQLHooks.dropCanvasData} - Handle drop data for {@link Quest} on Foundry canvas. + * - `getSceneControlButtons` - {@link FQLHooks.getSceneControlButtons} - Add FQL scene controls to 'note'. + * - `hotbarDrop` - {@link FQLHooks.hotbarDrop} - Handle {@link Quest} drops to the macro hotbar. + * - `renderJournalDirectory` - {@link FQLHooks.renderJournalDirectory} - Add 'open quest log' / show FQL folder. + * - `renderJournalSheet` - {@link FQLHooks.renderJournalSheet} - Hide FQL directory from journal sheet option items. + * + * FQL hooks (response): + * - `ForienQuestLog.Open.QuestLog` - {@link FQLHooks.openQuestLog} - Open the quest log. + * - `ForienQuestLog.Open.QuestTracker` - {@link FQLHooks.openQuestTracker} - Open the quest tracker. + * - `ForienQuestLog.Run.DBMigration` - {@link FQLHooks.runDBMigration} - Allow GMs to run the DBMigration manually. + * + * FQL hooks (called): + * - `ForienQuestLog.Lifecycle.ready` - {@link FQLHooks.foundryReady} - Called at the end of the `ready` hook when FQL + * is fully setup. + */ +export class FQLHooks +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated'); + } + + /** + * Initializes all hooks that FQL responds to in the Foundry lifecycle and in game hooks. + */ + static init() + { + // Foundry startup hooks. + Hooks.once('init', FQLHooks.foundryInit); + Hooks.once('ready', FQLHooks.foundryReady); + Hooks.once('setup', FQLHooks.foundrySetup); + + // Respond to Foundry in game hooks. + Hooks.on('dropActorSheetData', FQLHooks.dropActorSheetData); + Hooks.on('dropCanvasData', FQLHooks.dropCanvasData); + Hooks.on('getSceneControlButtons', FQLHooks.getSceneControlButtons); + Hooks.on('hotbarDrop', FQLHooks.hotbarDrop); + Hooks.on('renderJournalDirectory', FQLHooks.renderJournalDirectory); + Hooks.on('renderJournalSheet', FQLHooks.renderJournalSheet); + + // FQL specific hooks. + Hooks.on('ForienQuestLog.Open.QuestLog', FQLHooks.openQuestLog); + Hooks.on('ForienQuestLog.Open.QuestTracker', FQLHooks.openQuestTracker); + Hooks.on('ForienQuestLog.Run.DBMigration', FQLHooks.runDBMigration); + } + + /** + * Responds to when a data drop occurs on an ActorSheet. If there is an {@link FQLDropData} instance attached by + * checking the `_fqlData.type` set to `reward` then process the reward item drop via {@link Socket.questRewardDrop} + * to remove the item from the associated quest. + * + * @param {Actor} actor - The Actor which received the data drop. + * + * @param {ActorSheet} sheet - The ActorSheet which received the data drop. + * + * @param {RewardDropData} data - Any data drop, but only handle RewardDropData. + * + * @returns {Promise} + * @see https://foundryvtt.com/api/classes/client.Actor.html + * @see https://foundryvtt.com/api/classes/client.ActorSheet.html + */ + static async dropActorSheetData(actor, sheet, data) + { + if (typeof data !== 'object' || data?._fqlData?.type !== 'reward') { return; } + + await Socket.questRewardDrop({ + actor: { id: actor.id, name: FVTTCompat.get(actor, 'name') }, + sheet: { id: sheet.id }, + data + }); + } + + /** + * Converts a Quest drop on the canvas type to `JournalEntry` if the quest exists in the QuestDB. + * + * @param {Canvas} foundryCanvas - The Foundry canvas. + * + * @param {object} data - Drop data for canvas. + */ + static dropCanvasData(foundryCanvas, data) + { + if (data.type === Quest.documentName && QuestDB.getQuest(data.id) !== void 0) + { + data.type = 'JournalEntry'; + data.uuid = `JournalEntry.${data.id}`; + } + } + + /** + * Provides FQL initialization during the `init` Foundry lifecycle hook. + */ + static foundryInit() + { + // Set the sheet to render quests. + Quest.setSheet(QuestPreview); + + // Register FQL module settings. + ModuleSettings.register(); + + // Preload Handlebars templates and register helpers. + Utils.preloadTemplates(); + Utils.registerHandlebarsHelpers(); + } + + /** + * Provides the remainder of FQL initialization during the `ready` Foundry lifecycle hook. + * + * @returns {Promise} + */ + static async foundryReady() + { + // Initialize all main GUI views. + ViewManager.init(); + + // Only attempt to run DB migration for GM. + if (game.user.isGM) { await DBMigration.migrate(); } + + // Initialize the in-memory QuestDB. Loads all quests that the user can see at this point. + await QuestDB.init(); + + // Allow and process incoming socket data. + Socket.listen(); + + // Start watching sidebar updates. + FoundryUIManager.init(); + + // Need to track any current primary quest as Foundry settings don't provide a old / new state on setting + // change. The current primary quest state is saved in session storage. + sessionStorage.setItem(sessionConstants.currentPrimaryQuest, + game.settings.get(constants.moduleName, settings.primaryQuest)); + + // Must set initial session storage state for quest tracker background if it doesn't exist. + const showBackgroundState = sessionStorage.getItem(sessionConstants.trackerShowBackground); + if (showBackgroundState !== 'true' && showBackgroundState !== 'false') + { + sessionStorage.setItem(sessionConstants.trackerShowBackground, 'true'); + } + + // Initialize current client based macro images based on current state. + await Utils.setMacroImage([settings.questTrackerEnable, settings.questTrackerResizable]); + + // Show quest tracker if applicable. + ViewManager.renderOrCloseQuestTracker(); + + // Fire our own lifecycle event to inform any other modules that depend on FQL QuestDB. + Hooks.callAll('ForienQuestLog.Lifecycle.ready'); + } + + /** + * Provides the setup FQL initialization during the `setup` Foundry lifecycle hook. Make the public QuestAPI + * accessible from `game.modules('forien-quest-log').public.QuestAPI`. + */ + static foundrySetup() + { + const moduleData = Utils.getModuleData(); + + /** + * @type {FQLPublicAPI} + */ + moduleData.public = { + QuestAPI + }; + + // Freeze the public API so it can't be modified. + Object.freeze(moduleData.public); + } + + /** + * Responds to the in game hook `getSceneControlButtons` to add the FQL quest log and floating quest log to the + * journal / 'notes' tool as sub categories. These controls are always added for the GM, but if FQL is hidden from + * players based on module setting {@link FQLSettings.hideFQLFromPlayers} the note controls do not display. + * + * @param {SceneControl[]} controls - The scene controls to add FQL controls. + * + * @see noteControls + * @see https://foundryvtt.com/api/classes/client.SceneControls.html + */ + static getSceneControlButtons(controls) + { + if (game.user.isGM || !game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) + { + const notes = controls.find((c) => c.name === 'notes'); + if (notes) { notes.tools.push(...FoundryUIManager.noteControls); } + } + } + + /** + * Handles Quest data drops. Also handles setting image state of any macro dropped from the FQL macro compendiums. + * + * @param {object} data - The dropped data object. + * + * @param {number} slot - The target hotbar slot + * + * @returns {Promise} + */ + static async handleMacroHotbarDrop(data, slot) + { + const uuid = Utils.getUUID(data); + const document = await fromUuid(uuid); + + if (!document) { return; } + + const macroCommand = FVTTCompat.get(document, 'command'); + + const existingMacro = game.macros.contents.find((m) => + { + return (FVTTCompat.authorID(m) === game.user.id && FVTTCompat.get(m, 'command') === macroCommand); + }); + + let macro = existingMacro; + + // If there is no existing macro then create one. + if (!existingMacro) + { + const macroData = { + name: FVTTCompat.get(document, 'name'), + type: FVTTCompat.get(document, 'type'), + command: FVTTCompat.get(document, 'command'), + img: FVTTCompat.get(document, 'img'), + flags: FVTTCompat.get(document, 'flags') + }; + + macro = await Macro.create(macroData, { displaySheet: false }); + } + + // If the macro is from the FQL macro compendiums then update the image state. + if (macro) + { + const macroSetting = macro.getFlag(constants.moduleName, 'macro-setting'); + + if (macroSetting) { await Utils.setMacroImage(macroSetting); } + + await game.user.assignHotbarMacro(macro, slot); + } + } + + /** + * Handles creating a macro for a Quest drop on the hotbar. Uses existing macro if possible before creating a macro. + * + * @param {object} data - The dropped data object. + * + * @param {number} slot - The target hotbar slot + * + * @returns {Promise} + */ + static async handleQuestHotbarDrop(data, slot) + { + const questId = data.id; + + const quest = QuestDB.getQuest(questId); + + // Early out if Quest isn't in the QuestDB. + if (!quest) + { + throw new Error(game.i18n.localize('ForienQuestLog.API.Hooks.Notifications.NoQuest')); + } + + // The macro script data to open the quest via the public QuestAPI. + const command = `game.modules.get('${constants.moduleName}').public.QuestAPI.open({ questId: '${questId}' });`; + + const macroData = { + name: game.i18n.format('ForienQuestLog.API.Hooks.Labels.OpenMacro', { name: quest.name }), + type: 'script', + command + }; + + // Determine the image for the macro. Use the splash image if `splashAsIcon` is true otherwise the giver image. + macroData.img = quest.splashAsIcon && quest.splash.length ? quest.splash : quest?.giverData?.img; + + // Search for an already existing macro with the same command. + let macro = game.macros.contents.find((m) => (FVTTCompat.get(m, 'command') === command)); + + // If not found then create a new macro with the command. + if (!macro) + { + macro = await Macro.create(macroData, { displaySheet: false }); + } + + // Assign the macro to the hotbar. + await game.user.assignHotbarMacro(macro, slot); + } + + /** + * Two cases are handled. Because hooks can not be asynchronous an immediate value is returned that reflects whether + * the drop was handled or not. + * + * The first case is when an FQL macro is dropped in from a compendium. + * + * The second is when a quest is dropped into the macro hotbar. A new Quest open macro is created. The macro command + * invokes opening the {@link QuestPreview} via {@link QuestAPI.open} by quest ID. + * + * @param {Hotbar} hotbar - The Hotbar application instance. + * + * @param {object} data - The dropped data object. + * + * @param {number} slot - The target hotbar slot + * + * @returns {boolean} - Whether the callback was handled. + * @see https://foundryvtt.com/api/classes/client.Hotbar.html + */ + static hotbarDrop(hotbar, data, slot) + { + let handled = false; + + // Verify if the hotbar drop is data that is handled; either a quest or macro from FQL macro compendium. + if (data.type === Quest.documentName || FVTTCompat.isFQLMacroDataTransfer(data)) + { + handled = true; + } + + // Wrap the handling code in an async IIFE. If this is a Quest data drop or a macro from the FQL macro compendium + // pack then handle it. + (async () => + { + if (FVTTCompat.isFQLMacroDataTransfer(data)) + { + await FQLHooks.handleMacroHotbarDrop(data, slot); + } + + if (data.type === Quest.documentName) + { + await FQLHooks.handleQuestHotbarDrop(data, slot); + } + })(); + + // Immediately return the handled state in the hook callback. Foundry expects false to stop the callback change. + return !handled; + } + + /** + * Opens the QuestLog if the game user is a GM or if FQL isn't hidden to players by module setting + * {@link FQLSettings.hideFQLFromPlayers}. + * + * @param {object} [opts] - Optional parameters. + * + * @param {number|null} [opts.left] - The left offset position in pixels. + * + * @param {number|null} [opts.top] - The top offset position in pixels. + * + * @param {number|null} [opts.width] - The application width in pixels. + * + * @param {number|string|null} [opts.height] - The application height in pixels. + * + * @param {string} [opts.tabId] - The quest status tab to open. + */ + static openQuestLog(opts) + { + if (!game.user.isGM && game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) { return; } + + let constraints = {}; + + let tabId; + + if (typeof opts === 'object') + { + // Select only constraint related parameters. + constraints = (({ left, top, width, height }) => ({ left, top, width, height }))(opts); + + if (typeof opts.tabId === 'string') { tabId = opts.tabId; } + } + + ViewManager.questLog.render(true, { focus: true, ...constraints, tabId }); + } + + /** + * Opens the {@link QuestTracker} if the game user is a GM or if FQL isn't hidden to players by module setting + * {@link FQLSettings.hideFQLFromPlayers}. + * + * @param {object} [opts] - Optional parameters. + * + * @param {number|null} [opts.left] - The left offset position in pixels. + * + * @param {number|null} [opts.top] - The top offset position in pixels. + * + * @param {number|null} [opts.width] - The application width in pixels. + * + * @param {number|null} [opts.height] - The application height in pixels. + * + * @param {boolean} [opts.pinned] - Sets the pinned state. + * + * @param {boolean} [opts.primary] - Sets whether showing the primary quest is enabled. + * + * @param {boolean} [opts.resizable] - Sets the resizable state. + */ + static async openQuestTracker(opts) + { + if (!game.user.isGM && game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) { return; } + + await game.settings.set(constants.moduleName, settings.questTrackerEnable, true); + + if (typeof opts === 'object') + { + // Handle setting quest tracker primary change. + if (typeof opts.primary === 'boolean') + { + sessionStorage.setItem(sessionConstants.trackerShowPrimary, (opts.primary).toString()); + } + + // Select only constraint related parameters. + const constraints = (({ left, top, width, height, pinned }) => ({ left, top, width, height, pinned }))(opts); + + if (Object.keys(constraints).length > 0) + { + // Set to indicate an override of any pinned state. + constraints.override = true; + + const tracker = ViewManager.questTracker; + + // Defer to make sure quest tracker is rendered before setting position. + setTimeout(() => + { + if (tracker.rendered) { tracker.setPosition(constraints); } + }, 0); + } + + // Handle setting quest tracker resizable change. + if (typeof opts.resizable === 'boolean') + { + setTimeout(() => + { + game.settings.set(constants.moduleName, settings.questTrackerResizable, opts.resizable); + }, 0); + } + } + } + + /** + * Handles adding the 'open quest log' button at the bottom of the journal directory. Always displayed for the GM, + * but only displayed to players if FQL isn't hidden via module setting {@link FQLSettings.hideFQLFromPlayers}. + * + * For GMs if module setting {@link FQLSettings.showFolder} is true then the hidden `_fql_quests` folder is shown. + * + * @param {JournalDirectory} app - The JournalDirectory app. + * + * @param {JQuery} html - The jQuery element for the window content of the app. + * + * @see https://foundryvtt.com/api/classes/client.JournalDirectory.html + */ + static renderJournalDirectory(app, html) + { + if (game.user.isGM || !game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) + { + const button = $(``); + + let footer = html.find('.directory-footer'); + if (footer.length === 0) + { + footer = $(`
    `); + html.append(footer); + } + footer.append(button); + + button.click(() => + { + ViewManager.questLog.render(true); + }); + } + + if (!(game.user.isGM && game.settings.get(constants.moduleName, settings.showFolder))) + { + const folder = Utils.getQuestFolder(); + if (folder !== void 0) + { + const element = html.find(`.folder[data-folder-id="${folder.id}"]`); + if (element !== void 0) + { + element.remove(); + } + } + } + } + + /** + * Remove option item for quest journal folder when any journal entry is rendered. This prevents users from placing + * non-quest journals into the quest journal folder. + * + * @param {JournalSheet} app - The JournalSheet app. + * + * @param {JQuery} html - The jQuery element for the window content of the app. + * + * @see https://foundryvtt.com/api/classes/client.JournalSheet.html + */ + static renderJournalSheet(app, html) + { + const folder = Utils.getQuestFolder(); + if (folder) + { + const option = html.find(`option[value="${folder.id}"]`); + + if (option) { option.remove(); } + } + } + + /** + * Provides a GM only hook to manually run DB Migration. When schemaVersion is not provided + * {@link DBMigration.migrate} will perform migration loading this value from module settings. However, a specific + * migration schema version can be supplied to force DB migration. To run all migration provide `0` otherwise a + * specific schema version to start migration at which is below the max version. + * + * @param {number} [schemaVersion] - A valid schema version from 0 to {@link DBMigration.version} + * + * @returns {Promise} + */ + static async runDBMigration(schemaVersion = void 0) + { + // Only GMs can run the migration. + if (!game.user.isGM) { return; } + + await DBMigration.migrate(schemaVersion); + } +} + +/** + * @typedef {object} FQLPublicAPI - Exposes a few FQL classes and instances publicly. + * + * @property {QuestAPI} QuestAPI - QuestAPI class - Exposes static methods to interact with the quest system. + */ diff --git a/src/control/ModuleSettings.js b/src/control/ModuleSettings.js new file mode 100644 index 00000000..80f32d69 --- /dev/null +++ b/src/control/ModuleSettings.js @@ -0,0 +1,427 @@ +import { + FoundryUIManager, + QuestDB, + Utils, + ViewManager } from './index.js'; + +import { + constants, + questStatus, + sessionConstants, + settings } from '../model/constants.js'; + +/** + * Provides registration for all module settings. + */ +export class ModuleSettings +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * The default location for the QuestTracker + * + * @type {{top: number, width: number}} + */ + static #defaultQuestTrackerPosition = { top: 80, width: 296 }; + + /** + * Constants for setting scope type. + * + * @type {{world: string, client: string}} + */ + static #scope = { + client: 'client', + world: 'world' + }; + + /** + * Registers all module settings. + * + * @see FQLSettings + */ + static register() + { + game.settings.register(constants.moduleName, settings.allowPlayersDrag, { + name: 'ForienQuestLog.Settings.allowPlayersDrag.Enable', + hint: 'ForienQuestLog.Settings.allowPlayersDrag.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.allowPlayersDrag, value); } + + // Must enrich all quests again in QuestDB. + await QuestDB.enrichAll(); + + // Render all views; immediately stops / enables player drag if Quest view is open. + ViewManager.renderAll({ force: true, questPreview: true }); + } + }); + + game.settings.register(constants.moduleName, settings.allowPlayersCreate, { + name: 'ForienQuestLog.Settings.allowPlayersCreate.Enable', + hint: 'ForienQuestLog.Settings.allowPlayersCreate.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.allowPlayersCreate, value); } + + // Render quest log to show / hide add quest button. + if (ViewManager.questLog.rendered) { ViewManager.questLog.render(); } + } + }); + + game.settings.register(constants.moduleName, settings.allowPlayersAccept, { + name: 'ForienQuestLog.Settings.allowPlayersAccept.Enable', + hint: 'ForienQuestLog.Settings.allowPlayersAccept.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.allowPlayersAccept, value); } + + // Must enrich all quests again in QuestDB. + await QuestDB.enrichAll(); + + // Render all views as quest status actions need to be shown or hidden for some players. + ViewManager.renderAll({ questPreview: true }); + } + }); + + game.settings.register(constants.moduleName, settings.trustedPlayerEdit, { + name: 'ForienQuestLog.Settings.trustedPlayerEdit.Enable', + hint: 'ForienQuestLog.Settings.trustedPlayerEdit.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.trustedPlayerEdit, value); } + + // Must perform a consistency check as there are possible quests that need to be added / removed + // from the in-memory DB based on trusted player edit status. + await QuestDB.consistencyCheck(); + + // Render all views as trusted player edit adds / removes capabilities. + ViewManager.renderAll({ questPreview: true }); + } + }); + + game.settings.register(constants.moduleName, settings.countHidden, { + name: 'ForienQuestLog.Settings.countHidden.Enable', + hint: 'ForienQuestLog.Settings.countHidden.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.countHidden, value); } + + // Must enrich all quests again in QuestDB. + await QuestDB.enrichAll(); + + // Must render the quest log / floating quest log / quest tracker. + ViewManager.renderAll(); + } + }); + + game.settings.register(constants.moduleName, settings.dynamicBookmarkBackground, { + name: 'ForienQuestLog.Settings.dynamicBookmarkBackground.Enable', + hint: 'ForienQuestLog.Settings.dynamicBookmarkBackground.EnableHint', + scope: this.#scope.world, + config: true, + default: true, + type: Boolean, + onChange: () => + { + // Must render the quest log. + if (ViewManager.questLog.rendered) { ViewManager.questLog.render(); } + } + }); + + game.settings.register(constants.moduleName, settings.navStyle, { + name: 'ForienQuestLog.Settings.navStyle.Enable', + hint: 'ForienQuestLog.Settings.navStyle.EnableHint', + scope: this.#scope.client, + config: true, + default: 'bookmarks', + type: String, + choices: { + bookmarks: 'ForienQuestLog.Settings.navStyle.bookmarks', + classic: 'ForienQuestLog.Settings.navStyle.classic' + }, + onChange: async () => + { + // Must enrich all quests again in QuestDB. + await QuestDB.enrichAll(); + + // Must render the quest log. + if (ViewManager.questLog.rendered) { ViewManager.questLog.render(); } + } + }); + + game.settings.register(constants.moduleName, settings.showTasks, { + name: 'ForienQuestLog.Settings.showTasks.Enable', + hint: 'ForienQuestLog.Settings.showTasks.EnableHint', + scope: this.#scope.world, + config: true, + default: 'default', + type: String, + choices: { + default: 'ForienQuestLog.Settings.showTasks.default', + onlyCurrent: 'ForienQuestLog.Settings.showTasks.onlyCurrent', + no: 'ForienQuestLog.Settings.showTasks.no' + }, + onChange: async () => + { + // Must enrich all quests again in QuestDB. + await QuestDB.enrichAll(); + + // Must render the quest log. + ViewManager.renderAll(); + } + }); + + game.settings.register(constants.moduleName, settings.defaultPermission, { + name: 'ForienQuestLog.Settings.defaultPermissionLevel.Enable', + hint: 'ForienQuestLog.Settings.defaultPermissionLevel.EnableHint', + scope: this.#scope.world, + config: true, + default: 'Observer', + type: String, + choices: { + OBSERVER: 'ForienQuestLog.Settings.defaultPermissionLevel.OBSERVER', + NONE: 'ForienQuestLog.Settings.defaultPermissionLevel.NONE', + OWNER: 'ForienQuestLog.Settings.defaultPermissionLevel.OWNER' + } + }); + + game.settings.register(constants.moduleName, settings.hideFQLFromPlayers, { + name: 'ForienQuestLog.Settings.hideFQLFromPlayers.Enable', + hint: 'ForienQuestLog.Settings.hideFQLFromPlayers.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async(value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.hideFQLFromPlayers, value); } + + if (!game.user.isGM) + { + // Hide all FQL apps from non GM user and remove the ui.controls for FQL. + if (value) + { + ViewManager.closeAll({ questPreview: true, updateSetting: false }); + + const notes = ui?.controls?.controls.find((c) => c.name === 'notes'); + if (notes) { notes.tools = notes?.tools.filter((c) => !c.name.startsWith(constants.moduleName)); } + + // Remove all quests from in-memory DB. This is required so that users can not retrieve quests + // from the QuestAPI or content links in Foundry resolve when FQL is hidden. + QuestDB.removeAll(); + } + else + { + // Initialize QuestDB loading all quests that are currently observable for the user. + await QuestDB.init(); + + // Add back ui.controls + const notes = ui?.controls?.controls.find((c) => c.name === 'notes'); + if (notes) { notes.tools.push(...FoundryUIManager.noteControls); } + } + + ui?.controls?.render(true); + } + + // Render the journal to show / hide open quest log button & folder. + game?.journal?.render(); + + // Close or open the quest tracker based on active quests (users w/ FQL hidden will have no quests in + // QuestDB) + ViewManager.renderOrCloseQuestTracker({ updateSetting: false }); + } + }); + + game.settings.register(constants.moduleName, settings.notifyRewardDrop, { + name: 'ForienQuestLog.Settings.notifyRewardDrop.Enable', + hint: 'ForienQuestLog.Settings.notifyRewardDrop.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + // Swap macro image based on current state. No need to await. + if (game.user.isGM) { await Utils.setMacroImage(settings.notifyRewardDrop, value); } + } + }); + + game.settings.register(constants.moduleName, settings.showFolder, { + name: 'ForienQuestLog.Settings.showFolder.Enable', + hint: 'ForienQuestLog.Settings.showFolder.EnableHint', + scope: this.#scope.world, + config: true, + default: false, + type: Boolean, + onChange: () => game.journal.render() // Render the journal to show / hide the quest folder. + }); + +// Settings not displayed in the module settings --------------------------------------------------------------------- + + // Currently provides a hidden setting to set the default abstract reward image. + // It may never be displayed in the module settings menu, but if it is in the future this is where it would go. + game.settings.register(constants.moduleName, settings.defaultAbstractRewardImage, { + scope: this.#scope.world, + config: false, + default: 'icons/svg/item-bag.svg', + type: String + }); + + game.settings.register(constants.moduleName, settings.questTrackerEnable, { + scope: this.#scope.client, + config: false, + default: false, + type: Boolean, + onChange: async (value) => + { + // Potentially Post notification that the quest tracker is enabled, but not visible as there are no active + // quests. + if (value && QuestDB.getCount({ status: questStatus.active }) === 0) + { + ViewManager.notifications.info(game.i18n.localize('ForienQuestLog.Notifications.QuestTrackerNoActive')); + } + + // Swap macro image based on current state. No need to await. + await Utils.setMacroImage(settings.questTrackerEnable, value); + + ViewManager.renderOrCloseQuestTracker(); + } + }); + + /** + * This is the most complex module setting handling as quite a bit of logic is contained below to handle + * setting the primary quest. Since the onChange event does not pass the old and new value the old value for + * {@link FQLSettings.primaryQuest} is stored in {@link FQLSessionConstants.currentPrimaryQuest} which is + * initially set in {@link FQLHooks.foundryReady}. + * + * This setting is set from {@link Socket.setQuestPrimary} or the handler in Socket. + * + * `value` may be a quest ID or an empty string. + */ + game.settings.register(constants.moduleName, settings.primaryQuest, { + scope: this.#scope.world, + config: false, + default: '', + type: String, + onChange: async (value) => + { + // Any current primary quest. + const currentQuestEntry = QuestDB.getQuestEntry( + sessionStorage.getItem(sessionConstants.currentPrimaryQuest)); + + // The new primary quest or none at all if value is an empty string. + const newQuestEntry = QuestDB.getQuestEntry(value); + + // Store all quest IDs that need to be updated which include parent / subquests. + const updateQuestIds = []; + + // Store the new primary quest name to post a notification. + let newPrimaryQuestName = void 0; + + // Store the old primary quest IDs that need UI updates. + if (currentQuestEntry && currentQuestEntry.id !== value) + { + updateQuestIds.push(...currentQuestEntry.questIds); + + // If there is a new quest then store the quest name and also all quests that need UI updates. + if (newQuestEntry) + { + newPrimaryQuestName = newQuestEntry.quest.name; + updateQuestIds.push(...newQuestEntry.questIds); + } + } + else if (newQuestEntry) + { + // There was not a presently set primary quest, so store only the new + updateQuestIds.push(...newQuestEntry.questIds); + + if (value.length) { newPrimaryQuestName = newQuestEntry.quest.name; } + } + + // Store the current primary quest. Either Quest ID or empty string. + sessionStorage.setItem(sessionConstants.currentPrimaryQuest, value); + + // If any quest IDs were stored then update all QuestPreviews after enriching the quest data. + if (updateQuestIds.length) + { + await QuestDB.enrichQuests(...updateQuestIds); + ViewManager.refreshQuestPreview(updateQuestIds); + ViewManager.renderAll({ force: true }); + } + + // Post a notification if a new primary quest was set. + if (newPrimaryQuestName) + { + ViewManager.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestPrimary', + { name: newPrimaryQuestName })); + } + } + }); + + game.settings.register(constants.moduleName, settings.questTrackerPinned, { + scope: this.#scope.client, + config: false, + type: Boolean, + default: false, + onChange: () => + { + // The quest tracker pinned state has changed so update any Foundry UI management. + FoundryUIManager.updateTrackerPinned(); + } + }); + + game.settings.register(constants.moduleName, settings.questTrackerPosition, { + scope: this.#scope.client, + config: false, + default: this.#defaultQuestTrackerPosition, + }); + + game.settings.register(constants.moduleName, settings.questTrackerResizable, { + name: 'ForienQuestLog.Settings.questTrackerResizable.Enable', + hint: 'ForienQuestLog.Settings.questTrackerResizable.EnableHint', + scope: this.#scope.client, + config: true, + default: false, + type: Boolean, + onChange: async (value) => + { + ViewManager.renderOrCloseQuestTracker(); + + // Swap macro image based on current state. No need to await. + await Utils.setMacroImage(settings.questTrackerResizable, value); + } + }); + } +} diff --git a/src/control/Socket.js b/src/control/Socket.js new file mode 100644 index 00000000..a8ddb97c --- /dev/null +++ b/src/control/Socket.js @@ -0,0 +1,727 @@ +import { QuestAPI } from './public/index.js'; + +import { + QuestDB, + Utils, + ViewManager } from './index.js'; + +import { + constants, + questStatus, + questStatusI18n, + settings } from '../model/constants.js'; + +/** + * Provides a basic Socket.io implementation to send events between all connected clients. The various methods have + * at as local and remote control mostly of GUI related actions. FQL appears to be a reactive application, but it really + * is Socket doing a lot of the heavy lifting to notify clients that particular GUI apps need to be refreshed when the + * underlying Quest data changes. + * + * There are also various actions that require a GM or trusted played with edit capability to act upon mostly moving + * quests from one status to another. Reward item drops into actor sheets invokes {@link Socket.questRewardDrop} from + * the {@link FQLHooks.dropActorSheetData} hook, but at least one GM level user must be logged in to receive this + * message to perform the drop / removal of the reward from a Quest. + * + * Please see the following view control classes and the QuestDB for socket related usage: + * + * @see HandlerAny + * @see HandlerDetails + * @see HandlerLog + * @see HandlerManage + * @see QuestDB.deleteQuest + */ +export class Socket +{ + /** + * Defines the event name to send all messages to over `game.socket`. + * + * @type {string} + */ + static #eventName = 'module.forien-quest-log'; + + /** + * Defines the different message types that FQL sends over `game.socket`. + */ + static #messageTypes = { + deletedQuest: 'deletedQuest', + questSetPrimary: 'questSetPrimary', + questSetStatus: 'questSetStatus', + questRewardDrop: 'questRewardDrop', + refreshAll: 'refreshAll', + refreshQuestPreview: 'refreshQuestPreview', + savePlayerNotes: 'savePlayerNotes', + showQuestLog: 'showQuestLog', + showQuestPreview: 'showQuestPreview', + showQuestTracker: 'showQuestTracker', + userCantOpenQuest: 'userCantOpenQuest' + }; + + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Refreshes the parent & subquest GUI apps as applicable and closes the associated QuestPreview for the quest that + * was deleted. This method is invoked from the private module method `QuestDB.#handleJournalEntryDelete`. + * + * Handled on the receiving side by `#handleDeletedQuest`. + * + * @param {DeleteData} deleteData - A data object containing the views that need to be updated and which quest was + * deleted by quest ID. + * + * @returns {Promise} + * @see QuestDB / QuestDB.#handleJournalEntryDelete + */ + static async deletedQuest(deleteData) + { + if (typeof deleteData === 'object') + { + const questId = deleteData.deleteId; + const questPreview = ViewManager.questPreview.get(questId); + + // Close the associated QuestPreview for the deleted Quest. + if (questPreview !== void 0) + { + // Must always use `noSave` as the quest has already been deleted; no auto-save of QuestPreview is allowed. + await questPreview.close({ noSave: true }); + } + + game.socket.emit(this.#eventName, { + type: this.#messageTypes.deletedQuest, + payload: { + questId, + } + }); + + // Send a refresh quest preview message for the views that need to be updated. + Socket.refreshQuestPreview({ questId: deleteData.savedIds }); + } + } + + /** + * Provides the main incoming message registration and distribution of socket messages on the receiving side. + */ + static listen() + { + game.socket.on(this.#eventName, this.#handleEvent.bind(this)); + } + + /** + * Handles the reward drop in actor sheet action from the {@link FQLHooks.dropActorSheetData} hook. If the local user + * is a GM handle this action right away otherwise send a message across the wire for the first GM user reached to + * handle the action remotely. The reward is removed from the associated quest. + * + * Handled on the receiving side by `#handleQuestRewardDrop`. + * + * @param {RewardDropData} data - The reward drop data generated from the hook. + * + * @returns {Promise} + */ + static async questRewardDrop(data = {}) + { + let handled = false; + + // Perform the immediate reward removal action if the current user is the GM and set `handled` to true. + if (game.user.isGM) + { + /** + * @type {FQLDropData} + */ + const fqlData = data.data._fqlData; + + const quest = QuestDB.getQuest(fqlData.questId); + if (quest) + { + quest.removeReward(fqlData.uuidv4); + await quest.save(); + Socket.refreshQuestPreview({ questId: fqlData.questId }); + } + handled = true; + } + + // Emit the reward drop event. + game.socket.emit(this.#eventName, { + type: this.#messageTypes.questRewardDrop, + payload: { + ...data, + handled + } + }); + } + + /** + * Renders all GUI apps via {@link ViewManager.renderAll}. With the option `questPreview` set to true all + * QuestPreviews are also rendered. Remaining options are forwarded onto the Foundry Application render method. + * Sends a socket message over the wire for all remote clients to do the same. + * + * Handled on the receiving side by `#handleRefreshAll`. + * + * @param {object} options - Optional parameters + * + * @param {boolean} [options.force] - Forces a data refresh. + * + * @param {boolean} [options.questPreview] - Render all open QuestPreview apps. + */ + static refreshAll(options = {}) + { + // QuestDB Journal update hook is now async, so schedule on next microtask so local display is correct. + setTimeout(() => ViewManager.renderAll({ force: true, ...options }), 10); + + game.socket.emit(this.#eventName, { + type: this.#messageTypes.refreshAll, + payload: { + options + } + }); + } + + /** + * Refreshes local {@link QuestPreview} apps and sends a message indicating which QuestPreview apps need to be + * rendered. + * + * Handled on the receiving side by `#handleRefreshQuestPreview`. + * + * @param {object} opts - Optional parameters. + * + * @param {string|string[]} opts.questId - A single quest ID or an array of IDs to update. + * + * @param {boolean} [opts.updateLog=true] - Updates the quest log and all other GUI apps if true. + * + * @param {...RenderOptions} [opts.options] - Any options to pass onto QuestPreview render method invocation. + */ + static refreshQuestPreview({ questId, updateLog = true, ...options }) + { + // QuestDB Journal update hook is now async, so schedule on next microtask so local display is correct. + setTimeout(() => ViewManager.refreshQuestPreview(questId, options), 10); + + // Send a socket message for remote clients to render. + game.socket.emit(this.#eventName, { + type: this.#messageTypes.refreshQuestPreview, + payload: { + questId, + options + } + }); + + // Also update the quest log and other GUIs + if (updateLog) { Socket.refreshAll(); } + } + + /** + * Saves player notes by delegating to an active GM. + * + * @param {object} opts - Optional parameters. + * + * @param {Quest} opts.quest - The current quest being manipulated. It + * + * @param {string} opts.playernotes - The player notes to save. + */ + static savePlayerNotes({ quest, playernotes }) + { + // Send a socket message for any remote GMs logged in to handle request. + game.socket.emit(this.#eventName, { + type: this.#messageTypes.savePlayerNotes, + payload: { + questId: quest.id, + playernotes, + handled: false + } + }); + } + + /** + * Sets a new primary quest if a GM user or sends a socket message if set by a trusted player w/ edit. If the + * current user is not a GM a GM level user must be logged in for a successful completion of the set status + * operation. + * + * @param {object} opts - Optional parameters. + * + * @param {Quest} opts.quest - The current quest being manipulated. It + * + * @returns {Promise} + */ + static async setQuestPrimary({ quest }) + { + // If the current user is a GM immediately set the primary quest. + if (game.user.isGM) + { + // Get any currently set primary quest. + const currentQuestEntry = QuestDB.getQuestEntry(game.settings.get( + constants.moduleName, settings.primaryQuest)); + + // If the current set primary quest is different from provided quest then set new primary quest. + if (currentQuestEntry !== void 0 && currentQuestEntry.id !== quest.id) + { + await game.settings.set(constants.moduleName, settings.primaryQuest, quest.id); + } + else + { + // There isn't a primary quest set or the same quest is potentially being unset. + await game.settings.set(constants.moduleName, settings.primaryQuest, quest.isPrimary ? '' : quest.id); + } + } + else + { + // Otherwise send a socket message for any remote GMs logged in to handle request. + game.socket.emit(this.#eventName, { + type: this.#messageTypes.questSetPrimary, + payload: { + questId: quest.id, + handled: false + } + }); + } + } + + /** + * Handles setting a new quest status then refreshes the appropriate views including parent and + * subquests as applicable. On the invocation side if the user is a GM or trusted player with edit and ownership of + * the quest being updated then the action is immediately taken and `handled` set to true which is part of the + * message sent across the wire. If this is a player who can accept quests the local action is skipped and a socket + * message is sent out and the first GM level user to receive it will perform the status update for the associated + * quest. If no GM level users are logged in this action is never handled and the user can not change the status of + * a quest. + * + * Handled on the receiving side by `#handleQuestSetStatus`. + * + * @param {object} options - Options. + * + * @param {Quest} options.quest - The quest to move. + * + * @param {string} options.target - The target status. One of five {@link questStatus}. + * + * @returns {Promise} + * @see HandlerAny.questStatusSet + */ + static async setQuestStatus({ quest, target }) + { + let handled = false; + + // If the current user is a GM or trusted player with edit capability and owner of the quest immediately perform + // the status move. + if (game.user.isGM || (Utils.isTrustedPlayerEdit() && quest.isOwner)) + { + await quest.setStatus(target); + handled = true; + + Socket.refreshQuestPreview({ questId: quest.getQuestIds() }); + Socket.refreshAll(); + + const dirname = game.i18n.localize(questStatusI18n[target]); + ViewManager.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestMoved', + { name: quest.name, target: dirname })); + } + else + { + // Provide a sanity check and early out if the player can't accept quests. + const canPlayerAccept = game.settings.get(constants.moduleName, settings.allowPlayersAccept); + if (questStatus.active !== target && !canPlayerAccept) { return; } + } + + game.socket.emit(this.#eventName, { + type: this.#messageTypes.questSetStatus, + payload: { + questId: quest.id, + handled, + target + } + }); + } + + /** + * This handles the `show to players` title bar button found in {@link QuestLog._getHeaderButtons} to open the + * QuestLog for all remote clients. + * + * Handled on the receiving side by `#handleShowQuestLog`. + * + * @param {string} tabId - A specific tab ID for the quest status to open. + */ + static showQuestLog(tabId) + { + game.socket.emit(this.#eventName, { + type: this.#messageTypes.showQuestLog, + payload: { + tabId + } + }); + } + + /** + * This handles the `show to players` title bar button found in {@link QuestPreview._getHeaderButtons} to open the + * associated QuestPreview for all remote clients. + * + * Handled on the receiving side by `#handleShowQuestPreview`. + * + * @param {string} questId - The quest ID to a QuestPreview. + */ + static showQuestPreview(questId) + { + game.socket.emit(this.#eventName, { + type: this.#messageTypes.showQuestPreview, + payload: { + questId + } + }); + } + + /** + * This handles the `show to players` title bar button found in {@link QuestTracker._getHeaderButtons} to open the + * QuestTracker for all remote clients. + * + * Handled on the receiving side by `#handleShowQuestTracker`. + */ + static showQuestTracker() + { + game.socket.emit(this.#eventName, { + type: this.#messageTypes.showQuestTracker + }); + } + + /** + * A message emitted for GM users when a player can't open a particular quest in {@link QuestAPI.open}. This is + * particularly useful if a GM tries to show a quest that the user doesn't have access to via the `show to players` + * header button in {@link QuestPreview._getHeaderButtons}. + * + * Handled on the receiving side by `#handleUserCantOpenQuest`. + */ + static userCantOpenQuest() + { + game.socket.emit(this.#eventName, { + type: this.#messageTypes.userCantOpenQuest, + payload: { + user: game.user.name + } + }); + } + + // Internal implementation (receiving message handling) ----------------------------------------------------------- + + /** + * Provides the main incoming message registration and distribution of socket messages on the receiving side. + * + * @param {object} data - Incoming data object from `game.socket`. + */ + static async #handleEvent(data) + { + if (typeof data !== 'object') { return; } + + try + { + // Dispatch the incoming message data by the message type. + switch (data.type) + { + case this.#messageTypes.deletedQuest: await this.#handleDeletedQuest(data); break; + case this.#messageTypes.questRewardDrop: await this.#handleQuestRewardDrop(data); break; + case this.#messageTypes.questSetPrimary: await this.#handleQuestSetPrimary(data); break; + case this.#messageTypes.questSetStatus: await this.#handleQuestSetStatus(data); break; + case this.#messageTypes.refreshAll: this.#handleRefreshAll(data); break; + case this.#messageTypes.refreshQuestPreview: this.#handleRefreshQuestPreview(data); break; + case this.#messageTypes.savePlayerNotes: await this.#handleSavePlayerNotes(data); break; + case this.#messageTypes.showQuestLog: this.#handleShowQuestLog(data); break; + case this.#messageTypes.showQuestPreview: this.#handleShowQuestPreview(data); break; + case this.#messageTypes.showQuestTracker: this.#handleShowQuestTracker(); break; + case this.#messageTypes.userCantOpenQuest: this.#handleUserCantOpenQuest(data); break; + } + } + catch (err) + { + console.error(err); + } + } + + /** + * Closes the associated QuestPreview for the quest that was deleted on the remote client. The payload is a the + * `questId` to close. QuestPreview by default saves the quest when a QuestPreview is closed. This quest has already + * been deleted, so it is important to pass `noSave: true` to {@link QuestPreview.close}. + * + * This message is sent from {@link Socket.deletedQuest}. + * + * @param {object} data - The data payload. + * + * @returns {Promise} + */ + static async #handleDeletedQuest(data) + { + const questPreview = ViewManager.questPreview.get(data.payload.questId); + if (questPreview !== void 0) + { + // Must always use `noSave` as the quest has already been deleted; no auto-save of QuestPreview is allowed. + await questPreview.close({ noSave: true }); + } + } + + /** + * Handles the reward item drop into actor sheet by the first GM level user receiving this message setting the + * handled state to `true`, so no further GM level users attempt to remove the item from the associated quest. + * + * This message is sent from {@link Socket.questRewardDrop}. + * + * @param {RewardDropData} data - The data payload is the reward drop data. + * + * @returns {Promise} + */ + static async #handleQuestRewardDrop(data) + { + if (game.user.isGM) + { + /** + * @type {FQLDropData} + */ + const fqlData = data.payload.data._fqlData; + + // Notify the GM that a user has dropped a reward item into an actor sheet. + const notify = game.settings.get(constants.moduleName, settings.notifyRewardDrop); + + if (notify) + { + ViewManager.notifications.info(game.i18n.format('ForienQuestLog.API.Socket.Notifications.RewardDrop', { + userName: fqlData.userName, + itemName: fqlData.itemName, + actorName: data.payload.actor.name + })); + } + + // The quest reward has already been removed by a GM user. + if (data.payload.handled) { return; } + + // Set handled to true so no more GM level users act upon this event. + data.payload.handled = true; + + const quest = QuestDB.getQuest(fqlData.questId); + if (quest) + { + quest.removeReward(fqlData.uuidv4); + await quest.save(); + Socket.refreshQuestPreview({ questId: fqlData.questId }); + } + } + } + + /** + * Handles setting a primary quest by a remote GM user. + * + * This message is sent from {@link Socket.setQuestPrimary}. + * + * @param {object} data - The data payload contains `questId` along with `handled`. + * + * @returns {Promise} + */ + static async #handleQuestSetPrimary(data) + { + // If this message has not already been handled and this user is a GM then handle it now then set `handled` to true. + if (game.user.isGM && !data.payload.handled) + { + const quest = QuestDB.getQuest(data.payload.questId); + if (quest === void 0) { return; } + + // Get any currently set primary quest. + const currentQuestEntry = QuestDB.getQuestEntry(game.settings.get(constants.moduleName, settings.primaryQuest)); + + // If the current set primary quest is different from provided quest then set new primary quest. + if (currentQuestEntry !== void 0 && currentQuestEntry.id !== quest.id) + { + await game.settings.set(constants.moduleName, settings.primaryQuest, quest.id); + } + else + { + // There isn't a primary quest set or the same quest is potentially being unset. + await game.settings.set(constants.moduleName, settings.primaryQuest, quest.isPrimary ? '' : quest.id); + } + + // Set handled to true so no other GM level users act upon the action. + data.payload.handled = true; + } + } + + /** + * Sets the associated quest status to the `target` by the first GM level user receiving this message setting the + * handled state to `true`, so no further GM level users attempt to update the quest. + * + * This message is sent from {@link Socket.questSetStatus}. + * + * @param {object} data - The data payload contains `questId` and `target` along with `handled`. + * + * @returns {Promise} + */ + static async #handleQuestSetStatus(data) + { + const target = data.payload.target; + + // If this message has not already been handled and this user is a GM then handle it now then set `handled` to true. + if (game.user.isGM && !data.payload.handled) + { + const quest = QuestDB.getQuest(data.payload.questId); + if (quest) + { + await quest.setStatus(target); + } + + // Set handled to true so no other GM level users act upon the move. + data.payload.handled = true; + + Socket.refreshQuestPreview({ + questId: quest.parent ? [quest.parent, quest.id, ...quest.subquests] : [quest.id, ...quest.subquests] + }); + + Socket.refreshAll(); + + const dirname = game.i18n.localize(questStatusI18n[target]); + ViewManager.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestMoved', + { name: quest.name, target: dirname })); + } + + // For non-GM users close QuestPreview when made hidden / inactive. + if (!game.user.isGM && target === questStatus.inactive) + { + const questPreview = ViewManager.questPreview.get(data.payload.questId); + if (questPreview !== void 0) + { + // Use `noSave` just for sanity in this case as this is a remote close. + await questPreview.close({ noSave: true }); + } + } + } + + /** + * Handles refreshing all GUI apps via {@link ViewManager.renderAll} passing the `options` data payload onward. + * + * This message is sent from {@link Socket.refreshAll}. + * + * @param {object} data - Please see {@link ViewManager.renderAll} for options. + */ + static #handleRefreshAll(data) + { + const options = typeof data.payload.options === 'object' ? data.payload.options : {}; + ViewManager.renderAll({ force: true, ...options }); + } + + /** + * Handles refreshing / rendering all QuestPreview apps specified or closes them if the quests specified in the payload + * are no longer available or observable to the current user. + * + * This message is sent from {@link Socket.refreshQuestPreview}. + * + * @param {object} data - Data payload contains `questId` which can be a string or array of strings. + */ + static #handleRefreshQuestPreview(data) + { + const questId = data.payload.questId; + const options = typeof data.payload.options === 'object' ? data.payload.options : {}; + + if (Array.isArray(questId)) + { + for (const id of questId) + { + const questPreview = ViewManager.questPreview.get(id); + if (questPreview !== void 0) + { + const quest = QuestDB.getQuest(id); + if (!quest) + { + questPreview.close(); + continue; + } + + if (quest.isObservable) { questPreview.render(true, options); } + else { questPreview.close(); } + } + } + } + else + { + const questPreview = ViewManager.questPreview.get(questId); + if (questPreview !== void 0) + { + const quest = QuestDB.getQuest(questId); + if (!quest) + { + questPreview.close(); + return; + } + + if (quest.isObservable) { questPreview.render(true, options); } + else { questPreview.close(); } + } + } + } + + /** + * Handles saving player notes via GM user. + * + * @param {object} data - Data payload contains a single `tabId` as a string. + */ + static async #handleSavePlayerNotes(data) + { + // If this message has not already been handled and this user is a GM then handle it now then set `handled` to true. + if (game.user.isGM && !data.payload.handled) + { + const quest = QuestDB.getQuest(data.payload.questId); + if (quest && typeof data.payload.playernotes === 'string') + { + quest.playernotes = data.payload.playernotes; + + await quest.save(); + + // Set handled to true so no other GM level users act upon the move. + data.payload.handled = true; + + Socket.refreshQuestPreview({ questId: quest.id }); + } + } + } + + /** + * Handles opening the QuestLog app. + * + * This message is sent from {@link Socket.showQuestLog}. + * + * @param {object} data - Data payload contains a single `tabId` as a string. + */ + static #handleShowQuestLog(data) + { + ViewManager.questLog.render(true, { focus: true, tabId: data.payload.tabId }); + } + + /** + * Handles opening a QuestPreview app specified by `questId` via {@link QuestAPI.open}. + * + * This message is sent from {@link Socket.showQuestPreview}. + * + * @param {object} data - Data payload contains a single `questId` as a string. + */ + static #handleShowQuestPreview(data) + { + QuestAPI.open({ questId: data.payload.questId, notify: false }); + } + + /** + * Handles opening the QuestTracker app. + * + * This message is sent from {@link Socket.showQuestTracker}. + */ + static #handleShowQuestTracker() + { + game.settings.set(constants.moduleName, settings.questTrackerEnable, true); + } + + /** + * Handles displaying a UI notification for GM level users regarding an attempt to show a quest that the user doesn't + * have the access to view. Uses {@link ViewManager.notification} to rate limit UI notification display. + * + * This message is sent from {@link Socket.userCantOpenQuest}. + * + * @param {object} data - Data payload contains a `user` as a string for the user name. + */ + static #handleUserCantOpenQuest(data) + { + if (game.user.isGM) + { + ViewManager.notifications.warn(game.i18n.format('ForienQuestLog.Notifications.UserCantOpen', + { user: data.payload.user })); + } + } +} \ No newline at end of file diff --git a/src/control/db/Enrich.js b/src/control/db/Enrich.js new file mode 100644 index 00000000..4f690936 --- /dev/null +++ b/src/control/db/Enrich.js @@ -0,0 +1,497 @@ +import { + QuestDB, + Utils } from '../index.js'; + +import { DOMPurify } from '../../../external/index.js'; + +import { + constants, + questStatus, + questStatusI18n, + settings } from '../../model/constants.js'; + +/** + * Enrich populates content with a lot of additional data that doesn't necessarily have to be saved + * with the Quest itself such as Actor data and provides embellishment for the Handlebars templates for tasks, rewards, + * subquests, status actions, and provides a UUID lookup for the quest giver image. + * + * All enrich methods should only be used in the {@link QuestDB} during the caching phase of the update / create + * lifecycle. + */ +export class Enrich +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Builds the quest status / icons div to control quest status. There are many possible states to construct across + * three different user states from GM, trusted player edit, to player accept, so it is easier to build and cache + * this data as performing this setup in the Handlebars template itself is cumbersome and error-prone. + * + * @param {Quest} quest - The quest to build status action div / icons for based on current user state. + * + * @returns {string} The HTML to insert into a Handlebars template for quest status div / icons. + */ + static statusActions(quest) + { + let result = ''; + + const isTrustedPlayerEdit = Utils.isTrustedPlayerEdit(); + const canAccept = game.settings.get(constants.moduleName, settings.allowPlayersAccept); + const canEdit = game.user.isGM || (isTrustedPlayerEdit && quest.isOwner); + + let addedAction = false; + + result += `
    `; + + if (canEdit || canAccept) + { + if (canEdit && questStatus.active === quest.status) + { + result += `\n`; + + result += `\n`; + + addedAction = true; + } + + // If the quest status is completed add a failed button to be able to move it directly to failed. + if (canEdit && questStatus.completed === quest.status) + { + result += `\n`; + + addedAction = true; + } + + // If the quest status is failed add a completed button to be able to move it directly to completed. + if (canEdit && questStatus.failed === quest.status) + { + result += `\n`; + + addedAction = true; + } + + if ((canEdit && questStatus.inactive === quest.status) || questStatus.available === quest.status) + { + result += `\n`; + + addedAction = true; + } + + if (canEdit && questStatus.inactive !== quest.status) + { + result += `\n`; + + addedAction = true; + } + + if ((canEdit && questStatus.inactive === quest.status) || questStatus.active === quest.status) + { + result += `\n`; + + addedAction = true; + } + + if (canEdit) + { + result += `\n`; + + addedAction = true; + } + + result += `
    \n`; + } + + return isTrustedPlayerEdit || addedAction ? result : ''; + } + + /** + * This method performs content manipulation based on the current state of {@link Quest} preparing data to be + * displayed in a {@link Handlebars} template. This data is cached in a {@link QuestEntry} in the {@link QuestDB} + * and only updated when the underlying {@link Quest} changes. + * + * @param {Quest} quest - Quest data to construct view data. + * + * @returns {Promise} A single quest view or SortedQuests upgraded + */ + static async quest(quest) + { + const data = JSON.parse(JSON.stringify(quest.toJSON())); + data.id = quest.id; + data.isActive = quest.isActive; + data.isHidden = quest.isHidden; + data.isInactive = quest.isInactive; + + const isOwner = quest.isOwner; + const isPrimary = quest.isPrimary; + const personalActors = quest.getPersonalActors(); + + const isTrustedPlayerEdit = Utils.isTrustedPlayerEdit(); + const canEdit = game.user.isGM || (isOwner && isTrustedPlayerEdit); + const playerEdit = isOwner; + + const canPlayerAccept = game.settings.get(constants.moduleName, settings.allowPlayersAccept); + const canPlayerDrag = game.settings.get(constants.moduleName, settings.allowPlayersDrag); + const countHidden = game.settings.get(constants.moduleName, settings.countHidden); + + data.canEdit = canEdit; + + data.wrapNameLengthCSS = 'player'; + if (canPlayerAccept || playerEdit) { data.wrapNameLengthCSS = 'player-edit'; } + if (canEdit) { data.wrapNameLengthCSS = 'can-edit'; } + + data.isPersonal = personalActors.length > 0; + data.personalActors = personalActors.map((a) => a.name).sort((a, b) => a.localeCompare(b)).join(' '); + + data.isPrimary = isPrimary; + + // Enrich w/ TextEditor, but first sanitize w/ DOMPurify, allowing only iframes with YouTube embed. + data.description = await TextEditor.enrichHTML(DOMPurify.sanitize(data.description), { + secrets: canEdit || playerEdit, + async: true + }); + + data.gmnotes = await TextEditor.enrichHTML(DOMPurify.sanitize(data.gmnotes), { async: true }); + + data.playernotes = await TextEditor.enrichHTML(DOMPurify.sanitize(data.playernotes), { async: true }); + + data.questIconType = void 0; + + if (data.splashAsIcon && data.splash.length) + { + data.questIconType = 'splash-image'; + } + else if (data.giverData && data.giverData.img) + { + data.questIconType = 'quest-giver'; + } + + const statusLabel = game.i18n.localize(`ForienQuestLog.QuestTypes.Labels.${data.status}`); + + // The quest status in the details section. + data.statusLabel = game.i18n.format(`ForienQuestLog.QuestTypes.Labels.Status`, { statusLabel }); + + data.statusActions = Enrich.statusActions(quest); + + data.isSubquest = false; + + data.data_parent = {}; + + if (data.parent !== null) + { + const parentQuest = QuestDB.getQuest(data.parent); + if (parentQuest) + { + data.isSubquest = parentQuest.isObservable; + + data.data_parent = { + id: data.parent, + giver: parentQuest.giver, + name: parentQuest.name, + status: parentQuest.status, + isPrimary: parentQuest.isPrimary + }; + } + } + + data.data_subquest = []; + + if (data.subquests !== void 0) + { + for (const questId of data.subquests) + { + const subquest = QuestDB.getQuest(questId); + + // isObservable filters out non-owned hidden quests for trustedPlayerEdit. + if (subquest && subquest.isObservable) + { + // Mirror Task data for state / button state + let state = 'square'; + switch (subquest.status) + { + case questStatus.completed: + state = 'check-square'; + break; + case questStatus.failed: + state = 'minus-square'; + break; + } + + const subPersonalActors = subquest.getPersonalActors(); + + const isInactive = subquest.isInactive; + const subIsPrimary = subquest.isPrimary; + + const statusTooltipData = isInactive ? + { statusI18n: game.i18n.localize(questStatusI18n[questStatus.inactive]) } : + { statusI18n: game.i18n.localize(questStatusI18n[subquest.status]) }; + + const statusTooltip = game.i18n.format('ForienQuestLog.QuestTypes.Tooltips.Status', statusTooltipData); + + const canEditSubquest = game.user.isGM || (subquest.isOwner && isTrustedPlayerEdit); + + data.data_subquest.push({ + id: questId, + giver: subquest.giver, + name: subquest.name, + status: subquest.status, + statusTooltip, + state, + statusActions: Enrich.statusActions(subquest), + canEdit: canEditSubquest, + isActive: subquest.isActive, + isHidden: subquest.isHidden, + isInactive, + isPersonal: subPersonalActors.length > 0, + personalActors: subPersonalActors.map((a) => a.name).sort((a, b) => a.localeCompare(b)).join(' '), + isPrimary: subIsPrimary + }); + } + } + } + + if (countHidden) + { + data.checkedTasks = data.tasks.filter((t) => t.completed).length; + + const finishedSubquests = data.data_subquest.filter((s) => questStatus.completed === s.status).length; + + data.checkedTasks += finishedSubquests; + + data.totalTasks = data.tasks.length + data.subquests.length; + } + else + { + data.checkedTasks = data.tasks.filter((t) => !t.hidden && t.completed).length; + + const finishedSubquests = data.data_subquest.filter( + (s) => !s.isObservable && !s.isInactive && questStatus.completed === s.status).length; + + data.checkedTasks += finishedSubquests; + + data.totalTasks = data.tasks.filter((t) => !t.hidden).length + + data.data_subquest.filter((s) => !s.isObservable && !s.isInactive).length; + } + + switch (game.settings.get(constants.moduleName, settings.showTasks)) + { + case 'default': + data.taskCountLabel = `(${data.checkedTasks}/${data.totalTasks})`; + break; + + case 'onlyCurrent': + data.taskCountLabel = `(${data.checkedTasks})`; + break; + + default: + data.taskCountLabel = ''; + break; + } + + data.data_tasks = await Promise.all(data.tasks.map(async (task) => + { + return { + ...task, + name: await TextEditor.enrichHTML(DOMPurify.sanitize(task.name), { async: true }) + }; + })); + + data.data_rewards = await Promise.all(data.rewards.map(async (item) => + { + const type = item.type.toLowerCase(); + + // Only items are potentially draggable when `can player drag` is enabled or `can edit`. + const draggable = type === 'item' && (canEdit || canPlayerDrag) && (canEdit || !item.locked); + + const lockedTooltip = canEdit ? game.i18n.localize('ForienQuestLog.QuestPreview.Tooltips.RewardLocked') : + game.i18n.localize('ForienQuestLog.QuestPreview.Tooltips.RewardLockedPlayer'); + + const unlockedTooltip = canEdit ? game.i18n.localize('ForienQuestLog.QuestPreview.Tooltips.RewardUnlocked') : + game.i18n.localize('ForienQuestLog.QuestPreview.Tooltips.RewardUnlockedPlayer'); + + // Defines if the pointer cursor is displayed. For abstract or actor reward it is always displayed for GM or + // when unlocked for players. + const isLink = (type === 'abstract' || type === 'actor') && (canEdit || !item.locked); + + // For item rewards make them links when `can player drag` is not enabled. + const itemLink = type === 'item' && !canEdit && !canPlayerDrag && !item.locked; + + return { + name: await TextEditor.enrichHTML(DOMPurify.sanitize(item.data.name), { async: true }), + img: item.data.img, + type, + hidden: item.hidden, + locked: item.locked, + lockedTooltip, + unlockedTooltip, + isLink: isLink || itemLink, + draggable, + transfer: type !== 'abstract' ? JSON.stringify( + { uuid: item.data.uuid, uuidv4: item.uuidv4, name: item.data.name }) : void 0, + uuidv4: item.uuidv4 + }; + })); + + if (!canEdit) + { + data.data_tasks = data.data_tasks.filter((t) => t.hidden === false); + data.data_rewards = data.data_rewards.filter((r) => r.hidden === false); + } + + data.hasObjectives = data.data_tasks.length + data.data_subquest.length > 0; + + // Determine if all rewards are visible / unlocked + data.allRewardsVisible = true; + data.allRewardsUnlocked = true; + for (const reward of data.data_rewards) + { + if (reward.hidden) { data.allRewardsVisible = false; } + if (reward.locked) { data.allRewardsUnlocked = false; } + } + + return data; + } +} + +/** + * @typedef {QuestData} EnrichData + * + * @property {boolean} allRewardsVisible - Are all rewards visible. Controls show all / hide all button. + * + * @property {boolean} allRewardsUnlocked - Are all rewards unlocked. Controls unlock all / lock all button. + * + * @property {boolean} canEdit - Is full editing allowed. Either GM or trusted player w/ edit capability. + * + * @property {number} checkedTasks - Number of completed tasks. + * + * @property {object} data_parent - A data object with parent quest details. + * + * @property {string|null} data_parent.id - The parent quest ID / {@link Quest.id} + * + * @property {string|null} data_parent.giver - The parent quest giver / {@link Quest.giver} + * + * @property {string} data_parent.name - The parent quest name / {@link Quest.name} + * + * @property {boolean} data_parent.isPrimary - The parent quest is the primary quest / {@link Quest.isPrimary} + * + * @property {string} data_parent.status - The parent quest status / {@link Quest.status} + * + * @property {object[]} data_rewards - A list of reward item details. + * + * @property {boolean} data_rewards.draggable - Can the player drag the reward to actor sheet. + * + * @property {boolean} data_rewards.hidden - Is the reward hidden / only 'canEdit' users can see it. + * + * @property {string} data_rewards.img - The image for the reward. + * + * @property {boolean} data_rewards.isLink - Is the reward a link / pointer cursor. + * + * @property {boolean} data_rewards.locked - Is the reward locked / only 'canEdit' manipulate it. + * + * @property {string} data_rewards.lockedTooltip - The tooltip to display for the locked icon. + * + * @property {string} data_rewards.name - The name of the reward. + * + * @property {string} data_rewards.type - The type of reward / 'abstract' for abstract rewards. + * + * @property {object} data_rewards.transfer - The data tranfer object. + * + * @property {string} data_rewards.transfer.name - The reward name. + * + * @property {string} data_rewards.transfer.uuid - The reward Foundry UUID. + * + * @property {string} data_rewards.transfer.uuidv4 - The reward FQL UUIDv4. + * + * @property {string} data_rewards.unlockedTooltip - The tooltip to display for the unlocked icon. + * + * @property {string} data_rewards.uuidv4 - The reward FQL UUIDv4. + * + * @property {object[]} data_subquest - A list of data objects with subquest details. + * + * @property {boolean} data_subquest.canEdit - Is full editing allowed. Either GM or trusted player w/ edit. + * + * @property {string|null} data_subquest.giver - The parent quest giver / {@link Quest.giver} + * + * @property {string|null} data_subquest.id - The parent quest ID / {@link Quest.id} + * + * @property {boolean} data_subquest.isActive - Is quest status 'active' + * + * @property {boolean} data_subquest.isHidden - Is quest hidden by permissions / {@link Quest.isHidden} + * + * @property {boolean} data_subquest.isInactive - Is quest status 'inactive' + * + * @property {boolean} data_subquest.isPersonal - Is quest personal / {@link Quest.isPersonal} + * + * @property {string} data_subquest.name - The parent quest name / {@link Quest.name} + * + * @property {string[]} data_subquest.personalActors - A sorted list of names / {@link Quest.personalActors} + * + * @property {string} data_subquest.state - The CSS class for quest toggle / task state + * + * @property {string} data_subquest.status - The parent quest status / {@link Quest.status} + * + * @property {string} data_subquest.statusActions - HTML for quest status actions / {@link Enrich.statusActions} + * + * @property {string} data_subquest.statusTooltip - The localized quest status tooltip / {@link Quest.status} + * + * @property {QuestTaskData[]} data_tasks - The task data. + * + * @property {string} description - The enriched quest description via {@link TextEditor.enrichHTML}. + * + * @property {string} gmnotes - The GM Notes. + * + * @property {boolean} hasObjectives - Is there visible tasks & subjects. + * + * @property {string} id - Quest ID / {@link Quest.id} + * + * @property {boolean} isActive - Is quest status 'active' + * + * @property {boolean} isHidden - Is quest hidden by permissions / {@link Quest.isHidden} + * + * @property {boolean} isInactive - Is quest status 'inactive' + * + * @property {boolean} isPersonal - Is quest personal / not all players can access it / {@link Quest.isPersonal} + * + * @property {boolean} isSubquest - Is quest a subquest. + * + * @property {string} playerNotes - The player notes. + * + * @property {string[]} personalActors - A sorted list of names for HTML tooltip / {@link Quest.personalActors} + * + * @property {string} questIconType - Indicates which icon to use 'splash-image' or 'quest-giver'. + * + * @property {string} statusActions - HTML for quest status icon actions / {@link Enrich.statusActions} + * + * @property {string} statusLabel - Localized label for {@link Quest.status} + * + * @property {string} taskCountLabel - A label of completed / total tasks depending on module settings. + * + * @property {number} totalTasks - Number of total tasks. + * + * @property {string} wrapNameLengthCSS - The CSS class to add for content length wrapping based on user type. + */ + +/** + * @typedef QuestImgNameData + * + * @property {string} name - Quest giver or item name + * + * @property {string} img - Quest giver or item image + * + * @property {boolean} hasTokenImg - boolean indicating the quest giver has a token prototype image. + * + * @property {string} [uuid] - Any associated Foundry UUID for the quest giver / item. + */ \ No newline at end of file diff --git a/src/control/db/QuestDB.js b/src/control/db/QuestDB.js new file mode 100644 index 00000000..32b8974c --- /dev/null +++ b/src/control/db/QuestDB.js @@ -0,0 +1,1405 @@ +import { Enrich } from './Enrich.js'; + +import { + FVTTCompat, + Socket, + Utils } from '../index.js'; + +import { Quest } from '../../model/index.js'; + +import { QuestPreviewShim } from '../../view/index.js'; + +import { collect } from '../../../external/index.js'; + +import { + constants, + questStatus, + settings } from '../../model/constants.js'; + +/** + * The QuestDB holds quests in-memory that are observable by the current user. By pre-sorting quests by status and + * observability this cuts down on sorting and filtering operations that need to be performed on quests in an ongoing + * basis. Based on the type of user quests may go in and out of observability for permission and status category + * changes. + * + * In time with future refactoring the reliance on {@link Socket} for notifications to connected clients will be + * reduced as the QuestDB lifecycle hooks can replace many of the notification concerns. + * + * All quests and stored in {@link QuestEntry} instances which hold a {@link Quest} and the {@link EnrichData} created + * by {@link Enrich.quest} which is used when rendering {@link Handlebars} templates. There are several data points + * cached in QuestEntry from the Quest itself on any update; mostly the getter functions of Quest are cached each update + * in `#questEntryHydrate`. When an update does occur in `#handleJournalEntryUpdate` a QuestEntry is either + * added, removed, or updated based on the observability test found in `#isObservable`. Another pre-processing + * step for performance is to store all QuestEntry instances by the status of the quest. There are also two different + * views for QuestEntry data. The first is a map of Maps, `#questsMap`, with main index keys being the quest + * status. This preprocessing step allows quick retrieval of all quests by status category and ID without the need to + * filter all quests by status. Additionally, when `#questsMap` is updated a second view of the data is + * constructed as well which is a map of {@link CollectJS} collections found in `#questsCollect`. This allows + * in depth manipulation of all QuestEntry instances as a single collection. CollectJS has many options available for + * chained processing. There are by default two methods which apply a sort ({@link QuestDB.sortCollect}) or filter + * ({@link QuestDB.filterCollect}) operation to retrieve the {@link QuestsCollect} bundle returning a single status + * category or all quests indexed by status category. Iterators for quests are available by + * {@link QuestDB.iteratorQuests} and QuestEntry instances from {@link QuestDB.iteratorEntries}. Additionally, there + * are several direct retrieval methods such as {@link QuestDB.getQuest} and {@link QuestDB.getQuestEntry}. + * + * QuestDB lifecycle hooks ({@link QuestDBHooks}): The QuestDB has familiar lifecycle hooks to Foundry itself such as + * `createQuestEntry`, `deleteQuestEntry` and `updateQuestEntry`, but provides more fine-grained visibility of quest + * data that is loaded into and out of the in-memory QuestDB. Additional lifecycle hooks are: `addedAllQuestEntries`, + * `addQuestEntry`, `removedAllQuestEntries`, and `removeQuestEntry`. These latter unique lifecycle events signify + * observability. A quest may exist in the Foundry document / journal entry system, but only is added to the QuestDB + * when it is observable and this corresponds to the `addedAllQuestEntries` and `addQuestEntry` hooks. Likewise, both + * remove quest hooks relate to when a quest is removed based on observability whether through permission or quest + * status category updates; IE the quest _is not_ deleted, but is no longer observable by the current user and is + * removed from the QuestDB. + * + * ``` + * - `addedAllQuestEntries` - All observable quests have been added in the {@link QuestDB.init} method. + * + * {@link QuestDB.init}: After all quests have been initialized this hook is called to inform any external modules that + * all observable quests have been loaded into the QuestDB in bulk. + * ``` + * + * ``` + * - `addQuestEntry` - A quest has become observable and a QuestEntry instance is added to the QuestDB. + * + * {@link QuestDB.consistencyCheck}: During a consistency check which is mainly used when module settings for + * trusted player edit is enabled / disabled quests can be added to QuestDB. + * + * `#handleJournalEntryUpdate`: During the journal entry update hook a quest may become observable for the current + * user and added to the QuestDB. + * ``` + * + * ``` + * - `createQuestEntry` + * + * `#handleJournalEntryCreate`: A new quest is added to the QuestDB through creation and is observable by the + * current user. + * ``` + * + * ``` + * - `deleteQuestEntry` + * + * `#handleJournalEntryDelete`: A Quest has been deleted and is removed from the QuestDB. + * ``` + * + * ``` + * - `removedAllQuestEntries` + * + * {@link QuestDB.removeAll}: All quests have been removed from QuestDB. + * ``` + * + * ``` + * - `removeQuestEntry` + * + * {@link QuestDB.consistencyCheck}: During a consistency check which is mainly used when module settings for + * trusted player edit is enabled / disabled quests can be removed from QuestDB. + * + * `#handleJournalEntryUpdate`: A quest is no longer observable for permission reasons or status category change. + * ``` + * + * ``` + * - `updateQuestEntry` + * + * `#handleJournalEntryUpdate`: A quest that is currently in QuestDB has been updated. + * ``` + */ +export class QuestDB +{ + /** + * Set to true after the first call to `QuestDB.init`. Protects against adding hooks multiple times. + * + * @type {boolean} + */ + static #initialized = false; + + /** + * Defines the DB Hook callbacks. Please see {@link QuestDB} for more documentation. + * + * @type {QuestDBHooks} + */ + static #dbHooks = Object.freeze({ + addedAllQuestEntries: 'addedAllQuestEntries', + addQuestEntry: 'addQuestEntry', + createQuestEntry: 'createQuestEntry', + deleteQuestEntry: 'deleteQuestEntry', + removedAllQuestEntries: 'removedAllQuestEntries', + removeQuestEntry: 'removeQuestEntry', + updateQuestEntry: 'updateQuestEntry', + }); + + /** + * @type {FilterFunctions} + */ + static #fnFilter = Object.freeze({ + IS_OBSERVABLE: (entry) => entry.isObservable + }); + + /** + * @type {SortFunctions} + */ + static #fnSort = Object.freeze({ + ALPHA: (a, b) => a.quest.name.localeCompare(b.quest.name), + DATE_CREATE: (a, b) => a.quest.date.create - b.quest.date.create, + DATE_START: (a, b) => a.quest.date.start - b.quest.date.start, + DATE_END: (a, b) => b.quest.date.end - a.quest.date.end + }); + + /** + * Stores all {@link QuestEntry} instances in a map of CollectJS collections. This provides rapid sorting, filtering, + * and many other potential operations that {@link collect} / CollectJS collections provide for working with arrays + * of object data. Each collection is built from the values of the `#questMap` per status category. + * + * @type {Record>} + * @see https://collect.js.org/api.html + */ + static #questsCollect = Object.seal({ + active: collect(), + available: collect(), + completed: collect(), + failed: collect(), + inactive: collect() + }); + + /** + * Provides an index into the `#questMap` for all QuestEntry instances by questId and the status category. + * This allows quick retrieval and removal of QuestEntry instances from `#questMap`. + * + * @type {Map} + */ + static #questIndex = new Map(); + + /** + * Stores all {@link QuestEntry} instances in a map of Maps. This provides fast retrieval and quick insert / removal + * with quests pre-sorted by status. + * + * @type {Record>} + */ + static #questsMap = Object.seal({ + active: new Map(), + available: new Map(), + completed: new Map(), + failed: new Map(), + inactive: new Map() + }); + + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Initializes the QuestDB. If FQL is hidden from the current user then no quests load. All quests are loaded based + * on observability by the current user. + * + * This method may be invoked multiple times, but it is generally important to only invoke `init` when the QuestDB + * is empty. + * + * @returns {Promise} + */ + static async init() + { + let folder = await Utils.initializeQuestFolder(); + + // If the folder doesn't exist then simulate the content parameter. This should only ever occur for a player + // logged in when a GM activates FQL for the first time or if the _fql_quests folder is deleted. + if (!folder) + { + if (game.user.isGM) + { + console.warn('ForienQuestLog - Failed to initialize QuestDB as the quest folder / _fql_quests is missing.'); + } + + folder = { content: [] }; + } + + // Skip initialization of data if FQL is hidden from the current player. FQL is never hidden from GM level users. + if (!Utils.isFQLHiddenFromPlayers()) + { + // Cache `isTrustedPlayerEdit`. + const isTrustedPlayerEdit = Utils.isTrustedPlayerEdit(); + + // Iterate over all journal entries in `_fql_quests` folder. + const folderContents = FVTTCompat.folderContents(folder); + + for (const entry of folderContents) + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + if (!content) { continue; } + + // Retrieve the flag content for the quest and if presently observable add a new QuestEntry to QuestDB. + if (this.#isObservable(content, entry, isTrustedPlayerEdit)) + { + const quest = new Quest(content, entry); + + // Must set a QuestEntry w/ an undefined enrich as all quest data must be loaded before enrichment. + // Also set `generate` to false as the CollectJS collections are rebuilt in below. + this.#setQuestEntry(new QuestEntry(quest, void 0), false); + } + else + { + // If JE / Quest is not observable then still set a QuestPreview shim. + entry._sheet = new QuestPreviewShim(entry.id); + } + } + + // Must hydrate all QuestEntry instances after all quests have been added to `#questsMap`. Hydration will build + // the cache of various getter functions and enriched data in QuestEntry. + for (const questEntry of QuestDB.iteratorEntries()) { await this.#questEntryHydrate(questEntry); } + + // Create the CollectJS collections in build after hydration. + for (const key of Object.keys(this.#questsMap)) + { + this.#questsCollect[key] = collect(Array.from(this.#questsMap[key].values())); + } + + Hooks.callAll(QuestDB.hooks.addedAllQuestEntries); + } + + // Only add the Foundry hooks once on first initialization. + if (!this.#initialized) + { + Hooks.on('createJournalEntry', this.#handleJournalEntryCreate.bind(this)); + Hooks.on('deleteJournalEntry', this.#handleJournalEntryDelete.bind(this)); + Hooks.on('updateJournalEntry', this.#handleJournalEntryUpdate.bind(this)); + } + + this.#initialized = true; + } + + /** + * @returns {QuestDBHooks} The QuestDB hooks. + */ + static get hooks() { return this.#dbHooks; } + + /** + * @returns {FilterFunctions} Various useful filter functions. + */ + static get Filter() { return this.#fnFilter; } + + /** + * @returns {SortFunctions} Various useful sorting functions. + */ + static get Sort() { return this.#fnSort; } + + /** + * Verifies all quests by observability removing any quests from QuestDB that are no longer observable by the current + * user or adding quests that are now observable. This only really needs to occur after particular module setting + * changes which right now is when trusted player edit is enabled / disabled. + * + * @see FQLSettings.trustedPlayerEdit + */ + static async consistencyCheck() + { + const folder = Utils.getQuestFolder(); + + // Early out if the folder is not available or FQL is hidden from the current player. + if (!folder || Utils.isFQLHiddenFromPlayers()) { return; } + + // Create a single map of all QuestEntry instances. + const questEntryMap = new Map(QuestDB.getAllQuestEntries().map((e) => [e.id, e])); + + // Cache if the current player has trusted player edit capabilities. + const isTrustedPlayerEdit = Utils.isTrustedPlayerEdit(); + + // Iterate over all quests. + const folderContents = FVTTCompat.folderContents(folder); + + for (const entry of folderContents) + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + if (content) + { + // If the quest is observable attempt to retrieve it. + if (this.#isObservable(content, entry, isTrustedPlayerEdit)) + { + let questEntry = questEntryMap.get(entry.id); + + // If the quest is not retrieved, but is observable add it to the QuestDB. + if (!questEntry) + { + questEntry = new QuestEntry(new Quest(content, entry)); + this.#setQuestEntry(await this.#questEntryHydrate(questEntry)); + + Hooks.callAll(QuestDB.hooks.addQuestEntry, questEntry, entry.flags, { diff: false, render: true }, + entry.id); + } + else + { + // Otherwise update the quest with current data. + await this.#questEntryUpdate(questEntry, content, entry); + } + } + else + { + // The quest is not observable so if it is retrieved from the flat `questEntryMap` remove it from the + // QuestDB. + const questEntry = questEntryMap.get(entry.id); + if (questEntry) + { + questEntryMap.delete(entry.id); + this.#removeQuestEntry(entry.id); + + // This quest is not deleted; it has been removed from the in-memory DB. + Hooks.callAll(QuestDB.hooks.removeQuestEntry, questEntry, entry.flags, { diff: false, render: true }, + entry.id); + } + } + } + } + + // Enrich all after all updates are complete. + await this.enrichAll(); + } + + /** + * Creates a new quest and waits for the journal entry to update and QuestDB to pick up the new Quest which + * is then returned. + * + * @param {object} options - Optional parameters. + * + * @param {object} [options.data] - Quest data to assign to new quest. + * + * @param {string} [options.parentId] - Any associated parent ID; if set then this is a subquest. + * + * @returns {Promise} The newly created quest. + */ + static async createQuest({ data = {}, parentId = void 0 } = {}) + { + // Get the default ownership setting and attempt to set it if found in DOCUMENT_PERMISSION_LEVELS. + const defaultPerm = game.settings.get(constants.moduleName, settings.defaultPermission); + + const ownership = { + default: typeof CONST.DOCUMENT_OWNERSHIP_LEVELS[defaultPerm] === 'number' ? + CONST.DOCUMENT_OWNERSHIP_LEVELS[defaultPerm] : CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER + }; + + // Used for a player created quest setting and the quest as 'available' for normal players or 'hidden' for + // trusted players. + if (!game.user.isGM) + { + data.status = Utils.isTrustedPlayerEdit() ? questStatus.inactive : questStatus.available; + ownership[game.user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER; + } + + const parentQuest = QuestDB.getQuest(parentId); + if (parentQuest) + { + data.parent = parentId; + } + + // Creating a new quest will add any missing data / schema. + const tempQuest = new Quest(data); + + const folder = Utils.getQuestFolder(); + if (!folder) + { + console.warn('ForienQuestLog - QuestDB.createQuest - quest folder not found.'); + return; + } + + const entry = await JournalEntry.create({ + name: tempQuest.name, + folder: folder.id, + content: '', + ownership, + flags: { + [constants.moduleName]: { + json: tempQuest.toJSON() + } + } + }); + + if (parentQuest) + { + parentQuest.addSubquest(entry.id); + await parentQuest.save(); + Socket.refreshQuestPreview({ questId: parentQuest.id }); + } + + // QuestDB Journal update hook is now async, so schedule on next microtask to be able to retrieve new quest. + return new Promise((resolve) => + { + setTimeout(() => + { + const quest = QuestDB.getQuest(entry.id); + + // Players don't see Hidden tab, but assistant GM can, so emit anyway + Socket.refreshAll(); + + resolve(quest); + }, 10); + }); + } + + /** + * Invoke with either a Quest instance or quest ID to delete the quest and update the QuestDB and parent / child + * relationships. This is an atomic sequence such that the quest is deleted via deleting the backing journal entry + * and before control resumes to the invoke point the in-memory DB also has the associated QuestEntry deleted. + * + * Please use await when deleting a quest! + * + * @param {object} options - Optional parameters. + * + * @param {Quest} [options.quest] - The Quest instance to delete. + * + * @param {string} [options.questId] - The ID of the quest instance to delete. + * + * @returns {Promise} The IDs for quests that were updated. + */ + static async deleteQuest({ quest, questId } = {}) + { + const deleteId = quest ? quest.id : questId; + + const deleteQuest = QuestDB.getQuest(deleteId); + + if (!deleteQuest) { return; } + + const parentQuest = QuestDB.getQuest(deleteQuest.parent); + let parentId = null; + + // Stores the quest IDs which have been saved and need GUI / display aspects updated. + const savedIds = []; + + // Remove this quest from any parent + if (parentQuest) + { + parentId = parentQuest.id; + parentQuest.removeSubquest(deleteId); + } + + // Update children to point to any new parent. + for (const childId of deleteQuest.subquests) + { + const childQuest = QuestDB.getQuest(childId); + if (childQuest) + { + childQuest.parent = parentId; + + await childQuest.save(); + savedIds.push(childId); + + // Update parent with new subquests. + if (parentQuest) + { + parentQuest.addSubquest(childId); + } + } + } + + // Save the parent. + if (parentQuest) + { + await parentQuest.save(); + savedIds.push(parentId); + } + + // Delete the backing quest journal entry. This will cause the `deleteJournalEntry` hook to fire and QuestDB to + // delete the QuestEntry from the QuestDB. + if (deleteQuest.entry) + { + await deleteQuest.entry.delete(); + } + + // Return the deleted and saved IDs. + return { + deleteId, + savedIds + }; + } + + /** + * Enriches all stored {@link QuestEntry} instances. This is particularly useful in various callbacks when settings + * change in {@link ModuleSettings}. + */ + static async enrichAll() + { + for (const questEntry of QuestDB.iteratorEntries()) + { + questEntry.enrich = await Enrich.quest(questEntry.quest); + } + } + + /** + * Enriches specific {@link QuestEntry} instances. This is useful in various callbacks when settings state changes + * that is not stored in the {@link Quest} itself. An example is storing the primary quest in world / + * {@link ModuleSettings}. + * + * @param {...string} questIds - The quest IDs to enrich. + */ + static async enrichQuests(...questIds) + { + for (const questId of questIds) + { + const questEntry = QuestDB.getQuestEntry(questId); + if (questEntry) + { + questEntry.enrich = await Enrich.quest(questEntry.quest); + } + } + } + + /** + * Filter the entire QuestDB, returning an Array of entries which match a functional predicate. + * + * @param {Function} predicate The functional predicate to test. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.type] - The quest type / status to iterate. + * + * @returns {QuestEntry[]} An Array of matched values. + * @see Array#filter + */ + static filter(predicate, options) + { + const entries = []; + for (const questEntry of QuestDB.iteratorEntries(options)) + { + if (predicate(questEntry)) { entries.push(questEntry); } + } + return entries; + } + + /** + * Filters the CollectJS collections and returns a single collection if status is specified otherwise filters all + * quest collections and returns a QuestCollect object with all status categories. At minimum, you must provide a + * filter function `options.filter` which will be applied across all collections otherwise you may also provide + * separate filters for each status category. + * + * @param {object} options - Optional parameters. + * + * @param {string} [options.status] - Specific quest status to return filtered. + * + * @param {Function} [options.filter] - The filter function for any quest status that doesn't have a filter + * defined. + * + * @param {Function} [options.filterActive] - The filter function for active quests. + * + * @param {Function} [options.filterAvailable] - The filter function for available quests. + * + * @param {Function} [options.filterCompleted] - The filter function for completed quests. + * + * @param {Function} [options.filterFailed] - The filter function for failed quests. + * + * @param {Function} [options.filterInactive] - The filter function for inactive quests. + * + * @returns {QuestsCollect|collect|void} An object of all QuestEntries filtered by status or individual + * status or undefined. + */ + static filterCollect({ status = void 0, filter = void 0, filterActive = void 0, filterAvailable = void 0, + filterCompleted = void 0, filterFailed = void 0, filterInactive = void 0 } = {}) + { + // A particular status is requested so only filter and return the specific collection. + if (typeof status === 'string') + { + switch (status) + { + case questStatus.active: + return this.#questsCollect[questStatus.active].filter(filterActive ?? filter); + case questStatus.available: + return this.#questsCollect[questStatus.available].filter(filterAvailable ?? filter); + case questStatus.completed: + return this.#questsCollect[questStatus.completed].filter(filterCompleted ?? filter); + case questStatus.failed: + return this.#questsCollect[questStatus.failed].filter(filterFailed ?? filter); + case questStatus.inactive: + return this.#questsCollect[questStatus.inactive].filter(filterInactive ?? filter); + default: + console.error(`Forien Quest Log - QuestDB - filterCollect - unknown status: ${status}`); + return void 0; + } + } + + // Otherwise filter all status categories and return a QuestsCollect object. + return { + active: this.#questsCollect[questStatus.active].filter(filterActive || filter), + available: this.#questsCollect[questStatus.available].filter(filterAvailable || filter), + completed: this.#questsCollect[questStatus.completed].filter(filterCompleted || filter), + failed: this.#questsCollect[questStatus.failed].filter(filterFailed || filter), + inactive: this.#questsCollect[questStatus.inactive].filter(filterInactive || filter) + }; + } + + /** + * Find an entry in the QuestDB using a functional predicate. + * + * @param {Function} predicate - The functional predicate to test. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.status] - The quest type / status to iterate. + * + * @returns {QuestEntry} The QuestEntry, if found, otherwise undefined. + * @see Array#find + */ + static find(predicate, options) + { + for (const questEntry of QuestDB.iteratorEntries(options)) + { + if (predicate(questEntry)) { return questEntry; } + } + + return void 0; + } + + /** + * Returns all QuestEntry instances. + * + * @returns {QuestEntry[]} All QuestEntry instances. + */ + static getAllQuestEntries() + { + return this.#flattenQuestsMap(); + } + + /** + * Returns all Quest instances. + * + * @returns {Quest[]} All quest instances. + */ + static getAllQuests() + { + return this.#flattenQuestsMap().map((entry) => entry.quest); + } + + /** + * Provides a quicker method to get the count of quests by quest status or all quests. + * + * @param {object} [options] - Optional parameters. If no options are provided the count of all quests is returned. + * + * @param {string} [options.status] - The quest status category to count. + * + * @returns {number} Quest count for the specified type or the count for all quests. + */ + static getCount({ status = void 0 } = {}) + { + if (status === void 0) + { + return this.#questsMap[questStatus.active].size + this.#questsMap[questStatus.available].size + + this.#questsMap[questStatus.completed].size + this.#questsMap[questStatus.failed].size + + this.#questsMap[questStatus.inactive].size; + } + + return this.#questsMap[status] ? this.#questsMap[status].size : 0; + } + + /** + * Gets the Quest by quest ID. + * + * @param {string} questId - A Foundry ID + * + * @returns {Quest|void} The Quest. + */ + static getQuest(questId) + { + const entry = this.#getQuestEntry(questId); + return entry ? entry.quest : void 0; + } + + /** + * Retrieves a QuestEntry by quest ID. + * + * @param {string} questId - A Foundry ID + * + * @returns {QuestEntry} The QuestEntry. + */ + static getQuestEntry(questId) + { + return this.#getQuestEntry(questId); + } + + /** + * Provides an iterator across the QuestEntry map of maps returning all {@link QuestEntry} instances or instances of + * a particular status category. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.status] - The quest status category to iterate. + * + * @yields {QuestEntry} The QuestEntry iterator. + */ + static *iteratorEntries({ status = void 0 } = {}) + { + if (status === void 0) + { + for (const value of this.#questsMap[questStatus.active].values()) { yield value; } + for (const value of this.#questsMap[questStatus.available].values()) { yield value; } + for (const value of this.#questsMap[questStatus.completed].values()) { yield value; } + for (const value of this.#questsMap[questStatus.failed].values()) { yield value; } + for (const value of this.#questsMap[questStatus.inactive].values()) { yield value; } + } + else if (this.#questsMap[status]) + { + for (const value of this.#questsMap[status].values()) { yield value; } + } + } + + /** + * Provides an iterator across the QuestEntry map of maps returning all {@link Quest} instances or instances of a + * particular status category. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.status] - The quest status category to iterate. + * + * @yields {Quest} The Quest iterator. + */ + static *iteratorQuests({ status = void 0 } = {}) + { + if (status === void 0) + { + for (const value of this.#questsMap[questStatus.active].values()) { yield value.quest; } + for (const value of this.#questsMap[questStatus.available].values()) { yield value.quest; } + for (const value of this.#questsMap[questStatus.completed].values()) { yield value.quest; } + for (const value of this.#questsMap[questStatus.failed].values()) { yield value.quest; } + for (const value of this.#questsMap[questStatus.inactive].values()) { yield value.quest; } + } + else if (this.#questsMap[status]) + { + for (const value of this.#questsMap[status].values()) { yield value.quest; } + } + } + + /** + * Removes all quests from the QuestDB. + */ + static removeAll() + { + this.#questsMap[questStatus.active].clear(); + this.#questsMap[questStatus.available].clear(); + this.#questsMap[questStatus.completed].clear(); + this.#questsMap[questStatus.failed].clear(); + this.#questsMap[questStatus.inactive].clear(); + + this.#questIndex.clear(); + + this.#questsCollect[questStatus.active] = collect(); + this.#questsCollect[questStatus.available] = collect(); + this.#questsCollect[questStatus.completed] = collect(); + this.#questsCollect[questStatus.failed] = collect(); + this.#questsCollect[questStatus.inactive] = collect(); + + Hooks.callAll(QuestDB.hooks.removedAllQuestEntries); + } + + /** + * Sorts the CollectJS collections and returns a single collection if status is specified otherwise sorts all + * quest collections and returns a QuestCollect object with all status categories. By default, the sort functions + * are `Sort.DATE_END` for status categories of 'completed' / 'failed' and `Sort.ALPHA` for all other + * categories. + * + * @param {object} options - Optional parameters. + * + * @param {string} [options.status] - Quest status to return sorted. + * + * @param {Function} [options.sortActive] - The sort function for active quests. + * + * @param {Function} [options.sortAvailable] - The sort function for available quests. + * + * @param {Function} [options.sortCompleted] - The sort function for completed quests. + * + * @param {Function} [options.sortFailed] - The sort function for failed quests. + * + * @param {Function} [options.sortInactive] - The sort function for inactive quests. + * + * @returns {QuestsCollect|Collection|void} An object of all QuestEntries sorted by status or individual + * status. + */ + static sortCollect({ status = void 0, sortActive = this.Sort.ALPHA, sortAvailable = this.Sort.ALPHA, + sortCompleted = this.Sort.DATE_END, sortFailed = this.Sort.DATE_END, sortInactive = this.Sort.ALPHA } = {}) + { + if (typeof status === 'string') + { + switch (status) + { + case questStatus.active: + return this.#questsCollect[questStatus.active].sort(sortActive); + case questStatus.available: + return this.#questsCollect[questStatus.available].sort(sortAvailable); + case questStatus.completed: + return this.#questsCollect[questStatus.completed].sort(sortCompleted); + case questStatus.failed: + return this.#questsCollect[questStatus.failed].sort(sortFailed); + case questStatus.inactive: + return this.#questsCollect[questStatus.inactive].sort(sortInactive); + default: + console.error(`Forien Quest Log - QuestDB - sortCollect - unknown status: ${status}`); + return void 0; + } + } + + return { + active: this.#questsCollect[questStatus.active].sort(sortActive), + available: this.#questsCollect[questStatus.available].sort(sortAvailable), + completed: this.#questsCollect[questStatus.completed].sort(sortCompleted), + failed: this.#questsCollect[questStatus.failed].sort(sortFailed), + inactive: this.#questsCollect[questStatus.inactive].sort(sortInactive) + }; + } + + // Foundry CRUD hook callbacks ------------------------------------------------------------------------------------ + + /** + * Foundry hook callback when a new JournalEntry is created. For quests there are two cases to consider. The first + * is straight forward when a new quest is created from FQL. The second case is a bit more challenging and that + * occurs when a journal entry / quest is imported from a compendium. In this case we need to scrub the subquests + * that may no longer resolve to valid journal entries in the system. + * + * @param {JournalEntry} entry - A journal entry. + * + * @param {object} options - The create document options. + * + * @param {string} id - journal entry ID. + */ + static async #handleJournalEntryCreate(entry, options, id) + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + // Exit early if no FQL quest data is available. + if (!content) { return; } + + // Process the quest content if it is currently observable and FQL is not hidden from the current user. + if (this.#isObservable(content, entry) && !Utils.isFQLHiddenFromPlayers()) + { + const quest = new Quest(content, entry); + + const questEntry = new QuestEntry(quest); + this.#setQuestEntry(await this.#questEntryHydrate(questEntry)); + + Hooks.callAll(QuestDB.hooks.createQuestEntry, questEntry, options, id); + + // At this point a new quest will not have subquests, but an imported journal entry / quest from a compendium + // may have subquests. These may not resolve to any existing journal entries, so we scrub any non-resolving + // subquests. + if (quest.subquests.length > 0) + { + const removeSubs = []; + + // First push any subquest IDs that don't resolve to journal entries in `removeSubs`. + for (const subquest of quest.subquests) + { + if (!game.journal.get(subquest)) { removeSubs.push(subquest); } + } + + // Remove the non-resolving subquests from the quest. + for (const removeSub of removeSubs) + { + const index = quest.subquests.indexOf(removeSub); + if (index > -1) { quest.subquests.splice(index, 1); } + } + + // And save the quest. This will cause an update to occur and `#handleJournalEntryUpdate` will hydrate the + // change. + if (removeSubs.length > 0) { await quest.save(); } + } + } + else + { + // If JE / Quest is not observable then still set a QuestPreview shim. + entry._sheet = new QuestPreviewShim(entry.id); + } + } + + /** + * Process the Foundry hook for journal entry deletion. + * + * @param {JournalEntry} entry - Deleted journal entry. + * + * @param {object} options - The delete document options. + * + * @param {string} id - Journal entry ID. + * + * @returns {Promise} + */ + static async #handleJournalEntryDelete(entry, options, id) + { + // If the QuestEntry can be retrieved by this journal entry ID then remove it from the QuestDB. + const questEntry = this.#getQuestEntry(entry.id); + if (questEntry && this.#removeQuestEntry(entry.id)) + { + Hooks.callAll(QuestDB.hooks.deleteQuestEntry, questEntry, options, id); + + const quest = questEntry.quest; + const savedIds = quest.parent ? [quest.parent, ...quest.subquests] : [...quest.subquests]; + + // Send the delete quest socket message to all clients. + await Socket.deletedQuest({ + deleteId: entry.id, + savedIds + }); + + Socket.refreshAll(); + } + } + + /** + * Handles the Foundry update JournalEntry hook. If Quest content is retrieved from the flags process it for + * observability changes or update the associated QuestEntry if already in the QuestDB. + * + * @param {JournalEntry} entry - A journal entry. + * + * @param {object} flags - Journal entry flags. + * + * @param {object} options - The update document options. + * + * @param {string} id - The journal entry ID. + */ + static async #handleJournalEntryUpdate(entry, flags, options, id) + { + const content = entry.getFlag(constants.moduleName, constants.flagDB); + + if (content) + { + let questEntry = this.#getQuestEntry(entry.id); + + // Is the quest currently observable and not hidden from the current user. + const isObservable = this.#isObservable(content, entry) && !Utils.isFQLHiddenFromPlayers(); + + if (questEntry) + { + // If the QuestEntry already exists in the QuestDB and is observable then update it. + if (isObservable) + { + await this.#questEntryUpdate(questEntry, content, entry); + Hooks.callAll(QuestDB.hooks.updateQuestEntry, questEntry, flags, options, id); + } + else // Else remove it from the QuestDB (this is not a deletion). + { + this.#removeQuestEntry(questEntry.id); + + // Must hydrate any parent on a change. + if (typeof questEntry.quest.parent === 'string') + { + const parentEntry = this.#getQuestEntry(questEntry.quest.parent); + if (parentEntry) { await this.#questEntryHydrate(parentEntry); } + } + + // Must hydrate any subquests on a change. + for (const subquest of questEntry.quest.subquests) + { + const subquestEntry = this.#getQuestEntry(subquest); + if (subquestEntry) { await this.#questEntryHydrate(subquestEntry); } + } + + // This quest is not deleted; it has been removed from the in-memory DB. + Hooks.callAll(QuestDB.hooks.removeQuestEntry, questEntry, flags, options, id); + } + } + else if (isObservable) // The Quest is not in the QuestDB and is observable so add it. + { + questEntry = new QuestEntry(new Quest(content, entry)); + this.#setQuestEntry(await this.#questEntryHydrate(questEntry)); + + // Must hydrate any parent on a change. + if (typeof questEntry.quest.parent === 'string') + { + const parentEntry = this.#getQuestEntry(questEntry.quest.parent); + if (parentEntry) { await this.#questEntryHydrate(parentEntry); } + } + + // Must hydrate any subquests on a change. + for (const subquest of questEntry.quest.subquests) + { + const subquestEntry = this.#getQuestEntry(subquest); + if (subquestEntry) { await this.#questEntryHydrate(subquestEntry); } + } + + Hooks.callAll(QuestDB.hooks.addQuestEntry, questEntry, flags, options, id); + } + else + { + // If JE / Quest is not observable then still set a QuestPreview shim. + entry._sheet = new QuestPreviewShim(entry.id); + } + } + } + + // Internal implementation ---------------------------------------------------------------------------------------- + + /** + * Flattens the QuestEntry map of maps into and array of all entries. + * + * Please see {@link QuestDB.iteratorEntries} for an iterator across all entries. + * + * @returns {QuestEntry[]} An array of all QuestEntry values stored. + */ + static #flattenQuestsMap() + { + return [ + ...this.#questsMap[questStatus.active].values(), + ...this.#questsMap[questStatus.available].values(), + ...this.#questsMap[questStatus.completed].values(), + ...this.#questsMap[questStatus.failed].values(), + ...this.#questsMap[questStatus.inactive].values() + ]; + } + + /** + * @param {string} questId - The Quest / JournalEntry ID. + * + * @returns {QuestEntry} The stored QuestEntry. + */ + static #getQuestEntry(questId) + { + const currentStatus = this.#questIndex.get(questId); + return currentStatus && this.#questsCollect[currentStatus] ? this.#questsMap[currentStatus].get(questId) : void 0; + } + + /** + * Provides the observability test for a quest based on the user level and permissions of the backing journal entry. + * GM level users always can observe any quests. Trusted players w/ the module setting + * {@link FQLSettings.trustedPlayerEdit} enabled and the owner of the quest can observe quests in the inactive status. + * Otherwise, quests are only observable by players when the default or personal permission is + * {@link CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER} or higher. + * + * @param {QuestData} content - The serialized Quest data stored in the journal entry. + * + * @param {JournalEntry} entry - The backing journal entry. + * + * @param {boolean} [isTrustedPlayerEdit] - Is the user trusted and is the module setting to edit granted. + * + * @returns {boolean} Is quest observable by the current user? + */ + static #isObservable(content, entry, isTrustedPlayerEdit = Utils.isTrustedPlayerEdit()) + { + let isObservable; + + if (game.user.isGM) + { + isObservable = true; + } + else + { + const isInactive = questStatus.inactive === content.status; + + // Special handling for trusted player edit who can only see owned quests in the hidden / inactive category. + if (isTrustedPlayerEdit && isInactive) + { + isObservable = entry.isOwner; + } + else + { + // Otherwise no one can see hidden / inactive quests; perform user permission check for observer. + isObservable = !isInactive && entry.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER); + } + } + + return isObservable; + } + + /** + * Removes a QuestEntry by quest ID. Removes the quest index and then removes the QuestEntry from the map of maps + * If this results in a deletion and generate is true then rebuild the QuestEntry Collection. + * + * @param {string} questId - The Quest ID to delete. + * + * @param {boolean} [generate=true] - Generate the associated QuestEntry Collection. + * + * @returns {boolean} Whether a QuestEntry was deleted. + */ + static #removeQuestEntry(questId, generate = true) + { + const currentStatus = this.#questIndex.get(questId); + this.#questIndex.delete(questId); + + let result = false; + + if (this.#questsMap[currentStatus]) + { + result = this.#questsMap[currentStatus].delete(questId); + } + + if (result && generate) + { + this.#questsCollect[currentStatus] = collect(Array.from(this.#questsMap[currentStatus].values())); + } + + return result; + } + + /** + * Sets the QuestEntry by current status and regenerates any CollectJS collection if the status changes. + * + * @param {QuestEntry} entry - QuestEntry to set. + * + * @param {boolean} [generate=true] - Regenerate `#questsCollect`. + */ + static #setQuestEntry(entry, generate = true) + { + // Retrieve the current status from the quest entry index map. + const currentStatus = this.#questIndex.get(entry.id); + + // If defined and current status is different from the incoming QuestEntry status then delete the QuestEntry from + // the old map of map bin. + if (this.#questsMap[currentStatus] && currentStatus !== entry.status) + { + // If the delete action is successful and generate is true then regenerate the CollectJS collection of the + // old status. + if (this.#questsMap[currentStatus].delete(entry.id) && generate) + { + this.#questsCollect[currentStatus] = collect(Array.from(this.#questsMap[currentStatus].values())); + } + } + + if (!this.#questsMap[entry.status]) + { + console.error(`ForienQuestLog - QuestDB - set quest error - unknown status: ${entry.status}`); + return; + } + + // Set the quest index by quest id and new status and set the map of maps entry. + this.#questIndex.set(entry.id, entry.status); + this.#questsMap[entry.status].set(entry.id, entry); + + // If generate is true regenerate the new entry status CollectJS collection. + if (generate) + { + this.#questsCollect[entry.status] = collect(Array.from(this.#questsMap[entry.status].values())); + } + } + + /** + * Hydrates this QuestEntry caching the enriched data and several getter values from Quest. + * + * @param {QuestEntry} questEntry - Target quest entry. + * + * @returns {QuestEntry} This QuestEntry. + */ + static async #questEntryHydrate(questEntry) + { + questEntry.id = questEntry.quest.id; + questEntry.status = questEntry.quest.status; + + /** + * @type {boolean} + */ + questEntry.isActive = questEntry.quest.isActive; + + /** + * @type {boolean} + */ + questEntry.isHidden = questEntry.quest.isHidden; + + /** + * @type {boolean} + */ + questEntry.isInactive = questEntry.quest.isInactive; + + /** + * @type {boolean} + */ + questEntry.isObservable = questEntry.quest.isObservable; + + /** + * @type {boolean} + */ + questEntry.isOwner = questEntry.quest.isOwner; + + /** + * @type {boolean} + */ + questEntry.isPersonal = questEntry.quest.isPersonal; + + /** + * Stores all adjacent quest IDs including any parent, subquests, and this quest. + * + * @type {string[]} + */ + questEntry.questIds = questEntry.quest.getQuestIds(); + + /** + * @type {EnrichData} + */ + questEntry.enrich = await Enrich.quest(questEntry.quest); + + return questEntry; + } + + /** + * Updates an existing {@link QuestEntry} when the backing quest data changes. + * + * @param {QuestEntry} questEntry - Target quest entry. + * + * @param {QuestData} content - The FQL quest data from journal entry. + * + * @param {JournalEntry} entry - The backing journal entry. + * + * @returns {Promise} Was `#setQuestEntry` invoked. + */ + static async #questEntryUpdate(questEntry, content, entry) + { + questEntry.quest.entry = entry; + questEntry.quest.initData(content); + const status = questEntry.status; + await this.#questEntryHydrate(questEntry); + + // Must hydrate any parent on a change. + if (typeof questEntry.quest.parent === 'string') + { + const parentEntry = QuestDB.getQuestEntry(questEntry.quest.parent); + if (parentEntry) { await this.#questEntryHydrate(parentEntry); } + } + + // Must hydrate any subquests on a change. + for (const subquest of questEntry.quest.subquests) + { + const subquestEntry = QuestDB.getQuestEntry(subquest); + if (subquestEntry) { await this.#questEntryHydrate(subquestEntry); } + } + + if (status !== questEntry.quest.status) + { + this.#setQuestEntry(questEntry); + return true; + } + + return false; + } +} + +/** + * Provides the internal object stored in the QuestDB that contains the Quest and enriched data along with + * several public member variables that are cached from the Quest on any update allowing quick sorting. + */ +class QuestEntry +{ + /** + * @param {Quest} quest - The Quest object + * + * @param {EnrichData} [enrich] - The enriched Quest data. If not set be sure to hydrate. + */ + constructor(quest, enrich = void 0) + { + /** + * @type {string} + */ + this.id = quest.id; + + /** + * @type {string} + */ + this.status = quest.status; + + /** + * @type {Quest} + */ + this.quest = quest; + + /** + * @type {EnrichData} + */ + this.enrich = enrich; + + // Set in `#questEntryHydrate`. + + /** + * @type {boolean} + */ + this.isActive = void 0; + + /** + * @type {boolean} + */ + this.isHidden = void 0; + + /** + * @type {boolean} + */ + this.isInactive = void 0; + + /** + * @type {boolean} + */ + this.isObservable = void 0; + + /** + * @type {boolean} + */ + this.isOwner = void 0; + + /** + * @type {boolean} + */ + this.isPersonal = void 0; + + /** + * Stores all adjacent quest IDs including any parent, subquests, and this quest. + * + * @type {string[]} + */ + this.questIds = void 0; + } +} + +/** + * @typedef {object} DeleteData The data object returned from `delete` indicating which quests were updated. + * + * @property {string} deleteId - This quest ID which was deleted. + * + * @property {string[]} savedIds - The quest IDs of any parent / subquests that were updated. + */ + +/** + * @typedef {object} FilterFunctions + * + * @property {Function} IS_OBSERVABLE - Filters by `isObservable` cached in QuestEntry. + */ + +/** + * @typedef {object} QuestDBHooks + * + * @property {string} addedAllQuestEntries Invoked in {@link QuestDB.init} when all quests have been loaded. + * + * @property {string} addQuestEntry Invoked in {@link QuestDB.consistencyCheck} and `#handleJournalEntryUpdate` when a + * quest is added to the {@link QuestDB}. + * + * @property {string} createQuestEntry Invoked in `#handleJournalEntryCreate` in {@link QuestDB} when a quest is + * created. + * + * @property {string} deleteQuestEntry Invoked in `#handleJournalEntryDelete` in {@link QuestDB} when a quest is + * deleted. + * + * @property {string} removedAllQuestEntries Invoked in {@link QuestDB.removeAll} when all quests are removed. + * + * @property {string} removeQuestEntry Invoked in {@link QuestDB.consistencyCheck} and `#handleJournalEntryUpdate` + * when a quest is removed from the {@link QuestDB}. + * + * @property {string} updateQuestEntry - Invoked in `#handleJournalEntryUpdate` when a quest is updated in + * {@link QuestDB}. + */ + +/** + * @typedef {object} SortFunctions + * + * @property {Function} ALPHA Sort by quest name. + * + * @property {Function} DATE_CREATE Sort by quest creation date. + * + * @property {Function} DATE_END Sort by quest end date. When status is 'completed' or 'failed'. + * + * @property {Function} DATE_START Sort by quest start date. When status is 'active'. + */ + +/** + * @typedef {Record>} QuestsCollect Returns an object with keys indexed by + * {@link questStatus} of CollectJS collections of QuestEntry instances. + * + * @property {Collection} active Active quest entries CollectJS collections. + * + * @property {Collection} available Available quests entries CollectJS collections. + * + * @property {Collection} completed Completed quests entries CollectJS collections. + * + * @property {Collection} failed Failed quests entries CollectJS collections. + * + * @property {Collection} hidden Hidden quests entries CollectJS collections. + */ \ No newline at end of file diff --git a/src/control/index.js b/src/control/index.js new file mode 100644 index 00000000..f924ff99 --- /dev/null +++ b/src/control/index.js @@ -0,0 +1,6 @@ +export * from './db/QuestDB.js'; +export * from './ui/index.js'; +export * from './util/index.js'; +export * from './FQLHooks.js'; +export * from './ModuleSettings.js'; +export * from './Socket.js'; \ No newline at end of file diff --git a/src/control/public/QuestAPI.js b/src/control/public/QuestAPI.js new file mode 100644 index 00000000..9dee7b01 --- /dev/null +++ b/src/control/public/QuestAPI.js @@ -0,0 +1,96 @@ +import { QuestDBShim } from './QuestDBShim.js'; + +import { + Socket, + ViewManager } from '../index.js'; + +import { + constants, + settings } from '../../model/constants.js'; + +/** + * Quest public API. QuestAPI exposes control capabilities publicly. This functionality is gated as necessary depending + * on user level, quest observability and module settings. + * + * A shim to the {@link QuestDB} is available via {@link QuestAPI.DB} which exposes certain QuestDB methods that are + * available for any player as only currently observable quests are loaded into QuestDB. + */ +class QuestAPI +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * @returns {QuestDBShim} Public QuestDB access. + */ + static get DB() { return QuestDBShim; } + + /** + * Opens the Quest sheet / QuestPreview for the given questID. A check for the module setting + * {@link FQLSettings.hideFQLFromPlayers} provides an early out if FQL is hidden from players causing the sheet to + * not render. {@link ViewManager.questPreview} provides an object. + * + * @param {object} options - Optional parameters. + * + * @param {string} options.questId - Quest ID string to open. + * + * @param {boolean} [options.notify=true] - Post UI notification on any error. + */ + static open({ questId, notify = true }) + { + if (!game.user.isGM && game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) { return; } + + try + { + const questPreview = ViewManager.questPreview.get(questId); + + // Optimization to render an existing open QuestPreview with the given quest ID instead of opening a new + // app / view. + if (questPreview !== void 0) + { + questPreview.render(true, { focus: true }); + return; + } + + const quest = QuestDBShim.getQuest(questId); + + if (quest === void 0) + { + if (notify) + { + ViewManager.notifications.warn(game.i18n.localize('ForienQuestLog.Notifications.CannotOpen')); + } + else + { + Socket.userCantOpenQuest(); + } + return; + } + + if (quest.isObservable) + { + quest.sheet.render(true, { focus: true }); + } + } + catch (error) + { + if (notify) + { + ViewManager.notifications.error(game.i18n.localize('ForienQuestLog.Notifications.CannotOpen')); + } + else + { + Socket.userCantOpenQuest(); + } + } + } +} + +Object.freeze(QuestAPI); + +export { QuestAPI }; \ No newline at end of file diff --git a/src/control/public/QuestDBShim.js b/src/control/public/QuestDBShim.js new file mode 100644 index 00000000..0c24972b --- /dev/null +++ b/src/control/public/QuestDBShim.js @@ -0,0 +1,227 @@ +import { QuestDB } from '../index.js'; + +import { + constants, + settings } from '../../model/constants.js'; + +/** + * Provides a shim to the publicly exposed methods of QuestDB. Except for {@link QuestDBShim.createQuest} all other + * methods can be exposed without gating as the QuestDB only loads in-memory quests that are observable to the current + * user. + */ +class QuestDBShim +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * @returns {QuestDBHooks} The QuestDB hooks. + */ + static get hooks() { return QuestDB.hooks; } + + /** + * Creates a new quest and waits for the journal entry to update and QuestDB to pick up the new Quest which + * is returned. + * + * @param {object} options - Optional parameters. + * + * @param {object} [options.data] - Quest data to assign to new quest. + * + * @param {string} [options.parentId] - Any associated parent ID; if set then this is a subquest. + * + * @returns {Promise} The newly created quest. + */ + static async createQuest(options) + { + if (game.user.isGM) { return QuestDB.createQuest(options); } + + return game.settings.get(constants.moduleName, settings.allowPlayersCreate) && + !game.settings.get(constants.moduleName, settings.hideFQLFromPlayers) ? QuestDB.createQuest(options) : null; + } + + /** + * Filter the entire QuestDB, returning an Array of entries which match a functional predicate. + * + * @param {Function} predicate The functional predicate to test. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.type] - The quest type / status to iterate. + * + * @returns {QuestEntry[]} An Array of matched values + * @see Array#filter + */ + static filter(predicate, options) + { + return QuestDB.filter(predicate, options); + } + + /** + * Filters the CollectJS collections and returns a single collection if status is specified otherwise filters all + * quest collections and returns a QuestCollect object with all status categories. At minimum you must provide a + * filter function `options.filter` which will be applied across all collections otherwise you may also provide + * separate filters for each status category. + * + * @param {object} options - Optional parameters. + * + * @param {string} [options.type] - Specific quest status to return filtered. + * + * @param {Function} [options.filter] - The filter function for any quest status that doesn't have a filter + * defined. + * + * @param {Function} [options.filterActive] - The filter function for active quests. + * + * @param {Function} [options.filterAvailable] - The filter function for available quests. + * + * @param {Function} [options.filterCompleted] - The filter function for completed quests. + * + * @param {Function} [options.filterFailed] - The filter function for failed quests. + * + * @param {Function} [options.filterInactive] - The filter function for inactive quests. + * + * @returns {QuestsCollect|collect|void} An object of all QuestEntries filtered by status or individual + * status or undefined. + */ + static filterCollect(options) + { + return QuestDB.filterCollect(options); + } + + /** + * Find an entry in the QuestDB using a functional predicate. + * + * @param {Function} predicate - The functional predicate to test. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.type] - The quest type / status to iterate. + * + * @returns {QuestEntry} The QuestEntry, if found, otherwise undefined. + * @see Array#find + */ + static find(predicate, options) + { + return QuestDB.find(predicate, options); + } + + /** + * Returns all QuestEntry instances. + * + * @returns {QuestEntry[]} All QuestEntry instances. + */ + static getAllQuestEntries() + { + return QuestDB.getAllQuestEntries(); + } + + /** + * Returns all Quest instances. + * + * @returns {Quest[]} All quest instances. + */ + static getAllQuests() + { + return QuestDB.getAllQuests(); + } + + /** + * Provides a quicker method to get the count of quests by quest type / status or all quests. + * + * @param {object} [options] - Optional parameters. If no options are provided the count of all quests is returned. + * + * @param {string} [options.status] - The quest status category to count. + * + * @returns {number} Quest count for the specified type or the count for all quests. + */ + static getCount(options) + { + return QuestDB.getCount(options); + } + + /** + * Gets the Quest by quest ID. + * + * @param {string} questId - A Foundry ID + * + * @returns {Quest|void} The Quest or null. + */ + static getQuest(questId) + { + return QuestDB.getQuest(questId); + } + + /** + * Retrieves a QuestEntry by quest ID. + * + * @param {string} questId - A Foundry ID + * + * @returns {QuestEntry|null} The QuestEntry or null. + */ + static getQuestEntry(questId) + { + return QuestDB.getQuestEntry(questId); + } + + /** + * Provides an iterator across the QuestEntry map of maps. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.status] - The quest status category to iterate. + * + * @returns {Generator} A QuestEntry iterator. + */ + static iteratorEntries(options) + { + return QuestDB.iteratorEntries(options); + } + + /** + * Provides an iterator across the QuestEntry map of maps. + * + * @param {object} [options] - Optional parameters. If no options are provided the iteration occurs across all + * quests. + * + * @param {string} [options.status] - The quest status category to iterate. + * + * @returns {Generator} A QuestEntry iterator. + */ + static iteratorQuests(options) + { + return QuestDB.iteratorQuests(options); + } + + /** + * @param {object} options - Optional parameters. + * + * @param {string} [options.status] - Quest status to return sorted. + * + * @param {Function} [options.sortActive] - The sort function for active quests. + * + * @param {Function} [options.sortAvailable] - The sort function for available quests. + * + * @param {Function} [options.sortCompleted] - The sort function for completed quests. + * + * @param {Function} [options.sortFailed] - The sort function for failed quests. + * + * @param {Function} [options.sortInactive] - The sort function for inactive quests. + * + * @returns {QuestsCollect|collect|void} The complete sorted quests or just a particular quest status. + */ + static sortCollect(options) + { + return QuestDB.sortCollect(options); + } +} + +Object.freeze(QuestDBShim); + +export { QuestDBShim }; \ No newline at end of file diff --git a/src/control/public/index.js b/src/control/public/index.js new file mode 100644 index 00000000..e43c22f3 --- /dev/null +++ b/src/control/public/index.js @@ -0,0 +1 @@ +export * from './QuestAPI.js'; \ No newline at end of file diff --git a/src/control/ui/FoundryUIManager.js b/src/control/ui/FoundryUIManager.js new file mode 100644 index 00000000..942731cb --- /dev/null +++ b/src/control/ui/FoundryUIManager.js @@ -0,0 +1,413 @@ +import { ViewManager } from './ViewManager.js'; + +import { QuestTracker } from '../../view/index.js'; + +import { + constants, + settings } from '../../model/constants.js'; + +/** + * Defines a rectangle with essential contains check. Used to define the pinning rectangle next to the + * upper left of the sidebar. + */ +class FQLRect extends DOMRect +{ + /** + * Tests if the point is contained by this FQLRect. + * + * @param {number} x - Point X + * + * @param {number} y - Point Y + * + * @returns {boolean} Is point contained in rectangle. + */ + contains(x, y) + { + return this.x <= x && x <= this.x + this.width && this.y <= y && y <= this.y + this.height; + } +} + +/** + * Manages the state of the Foundry UI elements including the {@link Hotbar}, {@link SceneNavigation} and + * {@link Sidebar} providing management of the {@link QuestTracker}. Controls pinning the QuestTracker to the sidebar + * and modifications to the SceneNavigation width when pinned. + */ +export class FoundryUIManager +{ + /** + * Buffer space between sidebar and right side of quest tracker. + * + * @type {number} + */ + static #bufferSpaceX = 8; + + /** + * Buffer space between hotbar and bottom side of quest tracker. + * + * @type {number} + */ + static #bufferSpaceY = 8; + + /** + * Buffer space for the navigation bar. + * + * @type {number} + */ + static #bufferSpaceNavX = 22; + + /** + * Defines the left-hand UI control note buttons. + * + * @type {object[]} + */ + static #noteControls = [ + { + name: constants.moduleName, + title: 'ForienQuestLog.QuestLog.Title', + icon: 'fas fa-scroll', + visible: true, + onClick: () => ViewManager.questLog.render(true, { focus: true }), + button: true + }, + { + name: 'forien-quest-log-floating-window', + title: 'ForienQuestLog.QuestTracker.Title', + icon: 'fas fa-tasks', + visible: true, + onClick: async () => { await game.settings.set(constants.moduleName, settings.questTrackerEnable, true); }, + button: true + } + ]; + + /** + * Stores the constraints and other state tracked from various Foundry UI elements. + * + * @type {object} + */ + static #uiState = { + /** + * Stores the bounds of the hotbar. + */ + hotbar: { + gapX: -1, + gapY: -1, + top: -1, + left: -1, + width: -1, + height: -1 + }, + + /** + * Stores the navigation element parameters. + */ + navigation: { + left: '' + }, + + /** + * Stores the state of the sidebar. + */ + sidebar: { + currentCollapsed: false, + + collapsed: { + gapX: -1, + gapY: -1, + top: -1, + left: -1, + width: -1, + height: -1, + rectDock: new FQLRect(0, 0, 15, 30) + }, + + open: { + gapX: -1, + gapY: -1, + top: -1, + left: -1, + width: -1, + height: -1, + rectDock: new FQLRect(0, 0, 15, 30) + } + } + }; + + /** + * @returns {object[]} The left-hand UI note control button data. + */ + static get noteControls() + { + return this.#noteControls; + } + + /** + * Registers browser window resize event callback and Foundry render Hook for {@link SceneNavigation} and + * {@link QuestTracker}. + */ + static init() + { + window.addEventListener('resize', this.#handleWindowResize); + Hooks.on('collapseSidebar', this.collapseSidebar); + Hooks.on('renderSceneNavigation', this.updateTrackerPinned); + Hooks.on('renderQuestTracker', this.#handleQuestTrackerRendered); + + FoundryUIManager.#uiState.sidebar.currentCollapsed = ui?.sidebar?._collapsed || false; + this.#storeState(); + + FoundryUIManager.updateTrackerPinned(); + } + + /** + * Check the position against the sidebar and hotbar. + * + * @param {object} position - The complete position with top, left, width, height keys. + * + * @returns {boolean} True if the new position is within the sidebar pinned rectangle. + */ + static checkPosition(position) + { + const sidebarData = FoundryUIManager.#uiState.sidebar.currentCollapsed ? + FoundryUIManager.#uiState.sidebar.collapsed : FoundryUIManager.#uiState.sidebar.open; + + const tracker = ViewManager.questTracker; + + // Detect if the new position overlaps with the sidebar. + if (sidebarData.gapX >= 0 && position.left + tracker.position.width > sidebarData.left - + FoundryUIManager.#bufferSpaceX) + { + // This is a resize width change, so limit the new position width to the sidebar left side. + if (position.resizeWidth) + { + position.width = sidebarData.left - FoundryUIManager.#bufferSpaceX - position.left; + } + else // Otherwise move the new position to the left pinning the position to the sidebar left. + { + position.left = sidebarData.left - FoundryUIManager.#bufferSpaceX - tracker.position.width; + if (position.left < 0) { position.left = 0; } + } + } + + // If not pinned adjust the position top based on the hotbar top. + if (!tracker.pinned && FoundryUIManager.#uiState.hotbar.gapY >= 0 && + position.top + position.height > FoundryUIManager.#uiState.hotbar.top) + { + if (position.resizeHeight) + { + position.height = FoundryUIManager.#uiState.hotbar.top - FoundryUIManager.#bufferSpaceY - position.top; + tracker.position.height = position.height; + } + else + { + position.top = FoundryUIManager.#uiState.hotbar.top - FoundryUIManager.#bufferSpaceY - position.height; + if (position.top < 0) { position.top = 0; } + } + } + + // If pinned always make sure the position top is the sidebar top. + if (tracker.pinned) { position.top = sidebarData.top; } + + return sidebarData.rectDock.contains(position.left + position.width, position.top); + } + + /** + * The `collapseSidebar` Hook callback. Store the new state and update the tracker. + * + * @param {Sidebar} sidebarUI - The Foundry Sidebar. + * + * @param {boolean} collapsed - The sidebar collapsed state. + */ + static collapseSidebar(sidebarUI, collapsed) + { + FoundryUIManager.#uiState.sidebar.currentCollapsed = collapsed; + FoundryUIManager.#storeState(); + FoundryUIManager.updateTracker(); + } + + /** + * Updates the tracker bounds based on pinned state and invokes {@link QuestTracker.setPosition} if changes occur. + */ + static updateTracker() + { + const tracker = ViewManager.questTracker; + + // Make sure the tracker is rendered or rendering. + if (!tracker.rendered && Application.RENDER_STATES.RENDERING !== tracker._state) { return; } + + const sidebarData = FoundryUIManager.#uiState.sidebar.currentCollapsed ? + FoundryUIManager.#uiState.sidebar.collapsed : FoundryUIManager.#uiState.sidebar.open; + + // Store the current position before any modification. + const position = { + pinned: false, + top: tracker.position.top, + left: tracker.position.left, + width: tracker.position.width, + height: tracker.position.height + }; + + // If the tracker is pinned set the top / left based on the sidebar. + if (tracker.pinned) + { + position.top = sidebarData.top; + position.left = sidebarData.left - tracker.position.width - FoundryUIManager.#bufferSpaceX; + } + else // Make sure the tracker isn't overlapping the sidebar or hotbar. + { + const trackerRight = tracker.position.left + tracker.position.width; + if (trackerRight > sidebarData.left - FoundryUIManager.#bufferSpaceX) + { + position.left = sidebarData.left - tracker.position.width - FoundryUIManager.#bufferSpaceX; + + if (position.left < 0) { position.left = 0; } + } + + const trackerBottom = tracker.position.top + tracker.position.height; + if (trackerBottom > FoundryUIManager.#uiState.hotbar.top - FoundryUIManager.#bufferSpaceY) + { + position.top = FoundryUIManager.#uiState.hotbar.top - tracker.position.height - + FoundryUIManager.#bufferSpaceY; + + if (position.top < 0) { position.top = 0; } + } + } + + // Only post a position change if there are modifications. + if (position.top !== tracker.position.top || position.left !== tracker.position.left || + position.width !== tracker.position.width || position.height !== tracker.position.height) + { + tracker.setPosition(position); + } + } + + /** + * Updates state when the quest tracker is pinned / unpinned. Currently manipulates the Foundry + * {@link SceneNavigation} component width so that it doesn't overlap the pinned quest tracker. + */ + static updateTrackerPinned() + { + const tracker = ViewManager.questTracker; + const pinned = tracker.pinned; + const sidebarData = FoundryUIManager.#uiState.sidebar.open; + + let width = FoundryUIManager.#uiState.navigation.left + sidebarData.width + FoundryUIManager.#bufferSpaceNavX; + width += pinned ? tracker.position.width : 0; + ui?.nav?.element?.css('width', `calc(100% - ${width}px`); + } + + /** + * Unregisters browser window event callback and Foundry render hook for {@link QuestTracker}. + */ + static unregister() + { + window.removeEventListener('resize', this.#handleWindowResize); + Hooks.off('collapseSidebar', FoundryUIManager.collapseSidebar); + Hooks.off('renderSceneNavigation', FoundryUIManager.updateTrackerPinned); + Hooks.off('renderQuestTracker', this.#handleQuestTrackerRendered); + } + + // Internal Implementation ---------------------------------------------------------------------------------------- + + /** + * Invokes `updateTracker` when the QuestTracker is rendered. + * + * @param {Application} app - The Application instance being rendered. + */ + static #handleQuestTrackerRendered(app) + { + if (app instanceof QuestTracker) { FoundryUIManager.updateTracker(); } + } + + /** + * Callback for window resize events. Update tracker position. + */ + static #handleWindowResize() + { + FoundryUIManager.#storeState(); + FoundryUIManager.updateTracker(); + } + + /** + * Stores the current Foundry UI calculated bounds state. + */ + static #storeState() + { + const sidebarElem = ui?.sidebar?.element[0]; + const sidebarRect = sidebarElem?.getBoundingClientRect(); + + const navLeft = ui?.nav?.element?.css('left'); + if (typeof navLeft === 'string') { FoundryUIManager.#uiState.navigation.left = parseInt(navLeft, 10); } + + if (sidebarRect) + { + const sidebarData = FoundryUIManager.#uiState.sidebar.currentCollapsed ? + FoundryUIManager.#uiState.sidebar.collapsed : FoundryUIManager.#uiState.sidebar.open; + + // Store gapX / gapY calculating including any ::before elements if it has not already been set. + // This is only calculated one time on startup. + if (sidebarData.gapX < 0) + { + let beforeWidth; + let beforeHeight; + try + { + const style = window.getComputedStyle(sidebarElem, 'before'); + + const width = parseInt(style.getPropertyValue('width'), 10); + if (!Number.isNaN(width)) { beforeWidth = width; } + + const height = parseInt(style.getPropertyValue('height'), 10); + if (!Number.isNaN(height)) { beforeHeight = height; } + } + catch (err) { /**/ } + + sidebarData.gapX = beforeWidth && beforeWidth > sidebarRect.width ? beforeWidth - sidebarRect.width : 0; + + sidebarData.gapY = beforeHeight && beforeHeight > sidebarRect.height ? + beforeHeight - sidebarRect.height : 0; + } + + sidebarData.left = sidebarRect.left - sidebarData.gapX; + sidebarData.top = sidebarRect.top - sidebarData.gapY; + sidebarData.width = sidebarRect.width + sidebarData.gapX; + sidebarData.height = sidebarRect.height + sidebarData.gapY; + + sidebarData.rectDock.x = sidebarData.left - sidebarData.rectDock.width; + } + + const hotbarElem = ui?.hotbar?.element[0]; + const hotbarRect = hotbarElem?.getBoundingClientRect(); + + if (hotbarRect) + { + // Store gapX / gapY calculating including any ::before elements if it has not already been set. + // This is only calculated one time on startup. + if (FoundryUIManager.#uiState.hotbar.gapX < 0) + { + let beforeWidth; + let beforeHeight; + try + { + const style = window.getComputedStyle(hotbarElem, 'before'); + + const width = parseInt(style.getPropertyValue('width'), 10); + if (!Number.isNaN(width)) { beforeWidth = width; } + + const height = parseInt(style.getPropertyValue('height'), 10); + if (!Number.isNaN(height)) { beforeHeight = height; } + } + catch (err) { /**/ } + + FoundryUIManager.#uiState.hotbar.gapX = beforeWidth && beforeWidth > hotbarRect.width ? + beforeWidth - hotbarRect.width : 0; + + FoundryUIManager.#uiState.hotbar.gapY = beforeHeight && beforeHeight > hotbarRect.height ? + beforeHeight - hotbarRect.height : 0; + } + + FoundryUIManager.#uiState.hotbar.left = hotbarRect.left - FoundryUIManager.#uiState.hotbar.gapX; + FoundryUIManager.#uiState.hotbar.top = hotbarRect.top - FoundryUIManager.#uiState.hotbar.gapY; + FoundryUIManager.#uiState.hotbar.width = hotbarRect.width + FoundryUIManager.#uiState.hotbar.gapX; + FoundryUIManager.#uiState.hotbar.height = hotbarRect.height + FoundryUIManager.#uiState.hotbar.gapY; + } + } +} \ No newline at end of file diff --git a/src/control/ui/UINotifications.js b/src/control/ui/UINotifications.js new file mode 100644 index 00000000..30f8c3a7 --- /dev/null +++ b/src/control/ui/UINotifications.js @@ -0,0 +1,106 @@ +/** + * Provides a helper class to gate UI notifications that may come in from various players in a rapid fashion + * through Socket. By default, a 4-second delay is applied between each notification, but the last notification + * received will always be displayed. + */ +export class UINotifications +{ + /** + * Stores the last notify warn time epoch in MS. + * + * @type {number} + */ + #lastNotifyWarn = Date.now(); + + /** + * Stores the last notify info time epoch in MS. + * + * @type {number} + */ + #lastNotifyInfo = Date.now(); + + + /** + * Stores the last call to setTimeout for info messages, so that they can be cancelled as new notifications + * arrive. + * + * @type {number} + */ + #timeoutInfo = void 0; + + /** + * Stores the last call to setTimeout for warn messages, so that they can be cancelled as new notifications + * arrive. + * + * @type {number} + */ + #timeoutWarn = void 0; + + /** + * Potentially gates `warn` UI notifications to prevent overloading the UI notification system. + * + * @param {string} message - Message to post. + * + * @param {number} delay - The delay in MS between UI notifications posted. + */ + warn(message, delay = 4000) + { + if (Date.now() - this.#lastNotifyWarn > delay) + { + ui.notifications.warn(message); + this.#lastNotifyWarn = Date.now(); + } + else + { + if (this.#timeoutWarn) + { + clearTimeout(this.#timeoutWarn); + this.#timeoutWarn = void 0; + } + + this.#timeoutWarn = setTimeout(() => + { + ui.notifications.warn(message); + }, delay); + } + } + + /** + * Potentially gates `info` UI notifications to prevent overloading the UI notification system. + * + * @param {string} message - Message to post. + * + * @param {number} delay - The delay in MS between UI notifications posted. + */ + info(message, delay = 4000) + { + if (Date.now() - this.#lastNotifyInfo > delay) + { + ui.notifications.info(message); + this.#lastNotifyInfo = Date.now(); + } + else + { + if (this.#timeoutInfo) + { + clearTimeout(this.#timeoutInfo); + this.#timeoutInfo = void 0; + } + + this.#timeoutInfo = setTimeout(() => + { + ui.notifications.info(message); + }, delay); + } + } + + /** + * Post all error messages with no gating. + * + * @param {string} message - Message to post. + */ + error(message) + { + ui.notifications.error(message); + } +} diff --git a/src/control/ui/ViewManager.js b/src/control/ui/ViewManager.js new file mode 100644 index 00000000..57f24ad5 --- /dev/null +++ b/src/control/ui/ViewManager.js @@ -0,0 +1,395 @@ +import { QuestDB } from '../index.js'; + +import { + QuestLog, + QuestPreview, + QuestTracker } from '../../view/index.js'; + +import { UINotifications } from './UINotifications.js'; + +import { + constants, + questStatus, + questStatusI18n, + settings } from '../../model/constants.js'; + +/** + * Stores and manages all the GUI apps / view for FQL. + */ +export class ViewManager +{ + /** + * Locally stores the app instances which are accessible by getter methods. + * + * @type {{questLog: QuestLog, questPreview: Map, questTracker: QuestTracker}} + * + * @see ViewManager.questLog + * @see ViewManager.questPreview + * @see ViewManager.questTracker + */ + static #Apps = { + questLog: void 0, + questTracker: void 0, + questPreview: new Map() + }; + + /** + * Stores the QuestPreview app that is the current newly added quest. It needs to be closed before more quests can be + * added as a gate to prevent many quests from being added rapidly. + * + * @type {QuestPreview} + */ + static #newQuestPreviewApp = void 0; + + /** + * Stores the UINotifications instance to return in {@link ViewManager.notifications}. + * + * @type {UINotifications} + */ + static #uiNotifications = new UINotifications(); + + /** + * Initializes all GUI apps. + */ + static init() + { + this.#Apps.questLog = new QuestLog(); + this.#Apps.questTracker = new QuestTracker(); + + // Load and set the quest tracker position from settings. + try + { + const position = JSON.parse(game.settings.get(constants.moduleName, settings.questTrackerPosition)); + if (position && position.width && position.height) + { + this.#Apps.questTracker.position = position; + } + } + catch (err) { /**/ } + + ViewManager.renderOrCloseQuestTracker(); + + // Whenever a QuestPreview closes and matches any tracked app that is adding a new quest set it to undefined. + Hooks.on('closeQuestPreview', this.#handleQuestPreviewClosed.bind(this)); + Hooks.on('renderQuestPreview', this.#handleQuestPreviewRender.bind(this)); + + // Right now ViewManager responds to permission changes across add, remove, update of quests. + Hooks.on(QuestDB.hooks.addQuestEntry, this.#handleQuestEntryAdd.bind(this)); + Hooks.on(QuestDB.hooks.removeQuestEntry, this.#handleQuestEntryRemove.bind(this)); + Hooks.on(QuestDB.hooks.updateQuestEntry, this.#handleQuestEntryUpdate.bind(this)); + } + + /** + * @returns {UINotifications} Returns the UINotifications helper. + */ + static get notifications() { return this.#uiNotifications; } + + /** + * @returns {QuestLog} The main quest log app accessible from the left hand menu bar or + * `Hook.call('ForienQuestLog.Open.QuestLog')`. + * + * @see FQLHooks.openQuestLog + */ + static get questLog() { return this.#Apps.questLog; } + + /** + * @returns {Map} A Map that contains all currently rendered / visible QuestPreview instances + * indexed by questId / string which is the Foundry 'id' of quests and the + * backing journal entries. + */ + static get questPreview() { return this.#Apps.questPreview; } + + /** + * @returns {QuestTracker} Returns the quest tracker overlap app. This app is accessible when module setting + * {@link FQLSettings.questTrackerEnable} is enabled. + */ + static get questTracker() { return this.#Apps.questTracker; } + + /** + * @param {object} opts - Optional parameters + * + * @param {boolean} [opts.questPreview=false] - If true closes all QuestPreview apps. + * + * @param {...*} [opts.options] - Optional parameters passed onto {@link Application.close} + * + * @see https://foundryvtt.com/api/classes/client.Application.html#close + */ + static closeAll({ questPreview = false, ...options } = {}) + { + if (ViewManager.questLog.rendered) { ViewManager.questLog.close(options); } + if (ViewManager.questTracker.rendered) { ViewManager.questTracker.close(options); } + + if (questPreview) + { + for (const qp of ViewManager.questPreview.values()) { qp.close(options); } + } + } + + /** + * Convenience method to determine if the QuestTracker is visible to the current user. Always for the GM when + * QuestTracker is enabled, but only for users if `hideFromPlayers` is false. There must also be active quests for + * the tracker to be visible. + * + * @returns {boolean} Whether the QuestTracker is visible. + */ + static isQuestTrackerVisible() + { + return game.settings.get(constants.moduleName, settings.questTrackerEnable) && + (game.user.isGM || !game.settings.get(constants.moduleName, settings.hideFQLFromPlayers)) && + QuestDB.getCount({ status: questStatus.active }) > 0; + } + + /** + * Refreshes local {@link QuestPreview} apps. + * + * @param {string|string[]} questId - A single quest ID or an array of IDs to update. + * + * @param {RenderOptions} [options] - Any options to pass onto QuestPreview render method invocation. + */ + static refreshQuestPreview(questId, options = {}) + { + // Handle local QuestPreview rendering. + if (Array.isArray(questId)) + { + for (const id of questId) + { + const questPreview = ViewManager.questPreview.get(id); + if (questPreview !== void 0) { questPreview.render(true, options); } + } + } + else + { + const questPreview = ViewManager.questPreview.get(questId); + if (questPreview !== void 0) { questPreview.render(true, options); } + } + } + + /** + * Renders all GUI apps including the quest tracker which may also be closed depending on + * {@link ViewManager.isQuestTrackerVisible}. With the option `questPreview` set to true all QuestPreviews are also + * rendered. Remaining options are forwarded onto the Foundry Application render method. + * + * @param {object} opts - Optional parameters + * + * @param {boolean} [opts.force] - Forces a data refresh. + * + * @param {boolean} [opts.questPreview] - Render all open QuestPreview apps. + * + * @param {...*} [opts.options] - Remaining options for the {@link Application.render} method. + * + * @see https://foundryvtt.com/api/classes/client.Application.html#render + */ + static renderAll({ force = false, questPreview = false, ...options } = {}) + { + // Never force render the quest log to maintain quest details pages above the log. + if (ViewManager.questLog.rendered) { ViewManager.questLog.render(false, options); } + + ViewManager.renderOrCloseQuestTracker({ updateSetting: false }); + + if (questPreview) + { + for (const qp of ViewManager.questPreview.values()) + { + if (qp.rendered) { qp.render(force, options); } + } + } + } + + /** + * If the QuestTracker is visible then render it otherwise close it. + * + * @param {object} [options] - Optional parameters. + * + * @param {boolean} [options.updateSetting=true] - If closed true then {@link settings.questTrackerEnable} is set + * to false. + */ + static renderOrCloseQuestTracker(options = {}) + { + if (ViewManager.isQuestTrackerVisible()) + { + ViewManager.questTracker.render(true, { focus: false }); + } + else + { + // Necessary to check rendered state as the setting is set to false in the close method. + if (ViewManager.questTracker.rendered) { ViewManager.questTracker.close(options); } + } + } + + /** + * Performs the second half of the quest addition view management. + * + * @param {object} options - Optional parameters. + * + * @param {Quest} options.quest - The new quest being added. + * + * @param {boolean} [options.notify=true] - Post a UI notification with the quest name and the status / category. + * + * @param {boolean} [options.swapTab=true] - If rendered switch to the QuestLog tab of the new quest status. + */ + static questAdded({ quest, notify = true, swapTab = true } = {}) + { + if (notify) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestAdded', { + name: quest.name, + status: game.i18n.localize(questStatusI18n[quest.status]) + })); + } + + if (swapTab) + { + const questLog = ViewManager.questLog; + if (questLog._tabs[0] && quest.status !== questLog?._tabs[0]?.active && null !== questLog?._tabs[0]?._nav) + { + questLog._tabs[0].activate(quest.status); + } + } + + if (quest.isObservable) + { + const questSheet = quest.sheet; + questSheet.render(true, { focus: true }); + + // Set current QuestPreview being tracked as the add app. + this.#newQuestPreviewApp = questSheet; + } + } + + /** + * The first half of the add quest action which verifies if there is a current "add" QuestPreview open. If so it + * will bring the current add QuestPreview app to front, post a UI notification and return false. Otherwise returns + * true indicating that a new quest can be added / created. + * + * @returns {boolean} Whether a new quest can be added. + */ + static verifyQuestCanAdd() + { + if (this.#newQuestPreviewApp !== void 0) + { + if (this.#newQuestPreviewApp.rendered) + { + this.#newQuestPreviewApp.bringToTop(); + ViewManager.notifications.warn(game.i18n.localize('ForienQuestLog.Notifications.FinishQuestAdded')); + return false; + } + else + { + this.#newQuestPreviewApp = void 0; + } + } + + return true; + } + + // Internal implementation ---------------------------------------------------------------------------------------- + + /** + * Handles the `addQuestEntry` hook. + * + * @param {QuestEntry} questEntry - The added QuestEntry. + * + * @param {object} flags - Quest flags. + * + * @returns {Promise} + */ + static async #handleQuestEntryAdd(questEntry, flags) + { + if ('ownership' in flags) + { + ViewManager.refreshQuestPreview(questEntry.questIds); + ViewManager.renderAll(); + } + } + + /** + * Handles the `removeQuestEntry` hook. + * + * @param {QuestEntry} questEntry - The added QuestEntry. + * + * @param {object} flags - Quest flags. + * + * @returns {Promise} + */ + static async #handleQuestEntryRemove(questEntry, flags) + { + const quest = questEntry.quest; + + const questPreview = ViewManager.questPreview.get(quest.id); + if (questPreview && questPreview.rendered) { await questPreview.close({ noSave: true }); } + + if ('ownership' in flags) + { + ViewManager.refreshQuestPreview(questEntry.questIds); + ViewManager.renderAll(); + } + } + + /** + * Handles the `updateQuestEntry` hook. + * + * @param {QuestEntry} questEntry - The added QuestEntry. + * + * @param {object} flags - Quest flags. + */ + static #handleQuestEntryUpdate(questEntry, flags) + { + if ('ownership' in flags) + { + ViewManager.refreshQuestPreview(questEntry.questIds); + ViewManager.renderAll(); + } + } + + /** + * Handles the `closeQuestPreview` hook. Removes the QuestPreview from tracking and removes any current set + * `#newQuestPreviewApp` state if QuestPreview matches. + * + * @param {QuestPreview} questPreview - The closed QuestPreview. + */ + static #handleQuestPreviewClosed(questPreview) + { + if (!(questPreview instanceof QuestPreview)) { return; } + + if (this.#newQuestPreviewApp === questPreview) { this.#newQuestPreviewApp = void 0; } + + const quest = questPreview.quest; + if (quest !== void 0) { this.questPreview.delete(quest.id); } + } + + /** + * Handles the `renderQuestPreview` hook; adding the quest preview to tracking. + * + * @param {QuestPreview} questPreview - The rendered QuestPreview. + */ + static #handleQuestPreviewRender(questPreview) + { + if (questPreview instanceof QuestPreview) + { + const quest = questPreview.quest; + if (quest !== void 0) { ViewManager.questPreview.set(quest.id, questPreview); } + } + } +} + +/** + * @typedef {object} RenderOptions Additional rendering options which are applied to customize the way that the + * Application is rendered in the DOM. + * + * @property {number} [left] - The left positioning attribute. + * + * @property {number} [top] - The top positioning attribute. + * + * @property {number} [width] - The rendered width. + * + * @property {number} [height] - The rendered height. + * + * @property {number} [scale] - The rendered transformation scale. + * + * @property {boolean} [focus=false] - Apply focus to the application, maximizing it and bringing it to the top + * of the vertical stack. + * + * @property {string} [renderContext] - A context-providing string which suggests what event triggered the render. + * + * @property {object} [renderData] - The data change which motivated the render request. + */ \ No newline at end of file diff --git a/src/control/ui/index.js b/src/control/ui/index.js new file mode 100644 index 00000000..7366002e --- /dev/null +++ b/src/control/ui/index.js @@ -0,0 +1,2 @@ +export * from './FoundryUIManager.js'; +export * from './ViewManager.js'; \ No newline at end of file diff --git a/src/control/util/FVTTCompat.js b/src/control/util/FVTTCompat.js new file mode 100644 index 00000000..d165cbde --- /dev/null +++ b/src/control/util/FVTTCompat.js @@ -0,0 +1,186 @@ +import { constants } from '../../model/constants.js'; + +/** + * Provides potential shimming for the Foundry core API and potential support for other 3rd party modules like Monk's + * Enhanced Journal (MEJ). In the case for MEJ this module stores the image for a journal documents it owns in custom + * flags. + * + * Previously `FVTTCompat` provided v9 / v10+ shims for accessing Foundry core API. This compatibility layer is + * maintained in the codebase, but for the time being the latest FQL is released for v11+ and the shimming + * below just returns the current core API call / data. See the below sample code for how the shim is supposed to work + * if necessary to re-implement shims in the future. + * + * Example of how the shimming works: + * ```js + * let isV10 = false; + * + * Hooks.once('init', () => + * { + * isV10 = !foundry.utils.isNewerVersion(10, game.version ?? game?.data?.version); + * }); + * + * export class FVTTCompat + * { + * static get isV10() { return isV10; } + * + * static authorID(doc) + * { + * if (!doc) { return void 0; } + * + * return isV10 ? doc?.author?.id : doc?.data?.author; + * } + * } + * ``` + */ +export class FVTTCompat +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Returns the author ID of a document depending on v10. + * + * @param {foundry.abstract.Document|Document} doc - + * + * @returns {string} Author ID + */ + static authorID(doc) + { + if (!doc) { return void 0; } + + return doc?.author?.id; + } + + /** + * Returns folder contents. + * + * @param {Folder} folder - + * + * @returns {*[]} Folder contents; + */ + static folderContents(folder) + { + if (!folder) { return void 0; } + return folder?.contents ?? []; + } + + /** + * @param {object} data - data transfer from macro hot bar drop. + * + * @returns {boolean} Data transfer object is an FQL macro. + */ + static isFQLMacroDataTransfer(data) + { + if (data?.type !== 'Macro') { return false; } + + return typeof data?.uuid === 'string' && data.uuid.startsWith(`Compendium.${constants.moduleName}`); + } + + /** + * Returns the data property depending on v10. + * + * @param {foundry.abstract.Document|Document} doc - + * + * @param {string} property - Property field. + * + * @returns {string} Data value. + */ + static get(doc, property) + { + if (!doc || typeof property !== 'string') { return void 0; } + return doc[property]; + } + + /** + * Retrieves the content from either TinyMCE or ProseMirror based editors. This is important because the content is + * being retrieved directly from the editor instance to store in flags. Additional 3rd party modules may override + * the default editor (ProseMirror) and use TinyMCE. Treating the editors neutrally allows support for any editor. + * + * @param {object} editor - Editor object from `FormApplication`. + * + * @returns {string | undefined} Editor HTML content. + */ + static getEditorContent(editor) + { + let content; + + try + { + // Attempt to retrieve content from TinyMCE editor instance. + content = editor?.mce?.getContent?.(); + + if (typeof content === 'string') { return content; } + + // Attempt to retrieve content from ProseMirror editor instance. + if (editor?.instance?.view) + { + content = globalThis.ProseMirror.dom.serializeString(editor.instance.view.state.doc.content); + } + } + catch (err) { /**/ } + + return content; + } + + /** + * Returns any associated journal image. For v10 journal docs this is the first page that is an image. + * + * @param {foundry.abstract.Document|Document} doc - + * + * @returns {string | undefined} Journal image. + */ + static journalImage(doc) + { + if (!doc) { return void 0; } + + // Support Monk's Enhanced Journal which stores images in flags. + if (typeof doc?.flags?.['monks-enhanced-journal']?.img === 'string') + { + return doc.flags['monks-enhanced-journal'].img; + } + else + { + // Treat as normal Foundry journal doc and search for the first JournalEntryPage embedded collection for an + // image. + try + { + const pages = doc.getEmbeddedCollection('JournalEntryPage'); + for (const page of pages) + { + if (page?.type === 'image') { return page?.src; } + } + } + catch (err) { /**/ } + } + + return void 0; + } + + /** + * @param {foundry.abstract.Document|Document} doc - + * + * @returns {string} Foundry ownership / permission object. + */ + static ownership(doc) + { + if (!doc) { return void 0; } + return doc.ownership; + } + + /** + * @param {foundry.abstract.Document|Document} doc - + * + * @returns {string} Token image path. + */ + static tokenImg(doc) + { + if (!doc) { return void 0; } + + return doc?.prototypeToken?.texture?.src; + } +} diff --git a/src/control/util/Utils.js b/src/control/util/Utils.js new file mode 100644 index 00000000..bf05a4f0 --- /dev/null +++ b/src/control/util/Utils.js @@ -0,0 +1,472 @@ +import { FVTTCompat } from './index.js'; + +import { + constants, + jquery, + settings } from '../../model/constants.js'; + +/** + * Provides several general utility methods interacting with Foundry via UUID lookups to generating UUIDv4 internal + * FQL IDs. There are also several general methods for Handlebars setup. + */ +export class Utils +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * The hidden FQL quests folder name. + * + * @type {string} + */ + static #questDirName = '_fql_quests'; + + /** + * Uses `navigator.clipboard` if available then falls back to `document.execCommand('copy')` if available to copy + * the given text to the clipboard. + * + * @param {string} text - Text to copy to the browser clipboard. + * + * @returns {Promise} Copy successful. + */ + static async copyTextToClipboard(text) + { + if (typeof text !== 'string') + { + throw new TypeError(`FQL copyTextToClipboard error: 'text' is not a string.`); + } + + let success = false; + + if (navigator.clipboard) + { + try + { + await navigator.clipboard.writeText(text); + success = true; + } + catch (err) { /**/ } + } + else if (document.execCommand instanceof Function) + { + const textArea = document.createElement('textarea'); + + // Place in the top-left corner of screen regardless of scroll position. + textArea.style.position = 'fixed'; + textArea.style.top = '0'; + textArea.style.left = '0'; + + // Ensure it has a small width and height. Setting to 1px / 1em + // doesn't work as this gives a negative w/h on some browsers. + textArea.style.width = '2em'; + textArea.style.height = '2em'; + + // We don't need padding, reducing the size if it does flash render. + textArea.style.padding = '0'; + + // Clean up any borders. + textArea.style.border = 'none'; + textArea.style.outline = 'none'; + textArea.style.boxShadow = 'none'; + + // Avoid flash of the white box if rendered for any reason. + textArea.style.background = 'transparent'; + + textArea.value = text; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try + { + success = document.execCommand('copy'); + } + catch (err) { /**/ } + + document.body.removeChild(textArea); + } + + return success; + } + + /** + * Creates a double click handler with a default delay of 400ms + * + * @param {object} [opts] - Optional parameters. + * + * @param {string} [opts.selector] - Data to pass to callbacks. + * + * @param {Function} [opts.singleCallback] - Single click callback. + * + * @param {Function} [opts.doubleCallback] - Double click callback. + * + * @param {number} [opts.delay=400] - Double click delay. + * + * @param {number} [opts._clicks] - Private data to track clicks. + * + * @param {number} [opts._timer] - Private data to track timer. + * + * @returns {JQuery} The JQuery element. + */ + static createJQueryDblClick({ selector, singleCallback, doubleCallback, delay = 400, _clicks = 0, + _timer = void 0 } = {}) + { + const elem = $(selector); + + elem.on(jquery.click, (event) => + { + _clicks++; + + if (_clicks === 1) + { + _timer = setTimeout(() => + { + if (typeof singleCallback === 'function') { singleCallback(event); } + _clicks = 0; + }, delay); + } + else + { + clearTimeout(_timer); + if (typeof doubleCallback === 'function') { doubleCallback(event); } + _clicks = 0; + } + }).on(jquery.dblclick, (event) => event.preventDefault()); + + return elem; + } + + /** + * A convenience method to return the module data object for FQL. + * + * This is a scoped location where we can store any FQL data. + * + * @returns {object} The FQL module data object. + */ + static getModuleData() + { + return game.modules.get(constants.moduleName); + } + + /** + * Parses a UUID and returns the component data parts. + * + * @param {string|object} data - The UUID as a string or object with UUID key as a string. + * + * @returns {{id: string, type: string}|{id: string, type: string, pack: string}|*} UUID data parts + */ + static getDataFromUUID(data) + { + const uuid = typeof data === 'string' ? data : data.uuid; + + if (typeof uuid !== 'string') { return void 0; } + + const match = uuid.match(/(\w+)/gm); + + switch (match.length) + { + case 2: + return { type: match[0], id: match[1] }; + case 4: + return { type: match[0], pack: `${match[1]}.${match[2]}`, id: match[3] }; + default: + return void 0; + } + } + + /** + * Gets a document for the given UUID. An error message will post if the UUID is invalid and a warning + * message will be posted if the current `game.user` does not have permission to view the document. + * + * @param {string|object} data - The UUID as a string or object with UUID key as a string. + * + * @param {boolean} [permissionCheck] - The UUID as a string or object with UUID key as a string. + * + * @returns {Promise} + */ + static async getDocumentFromUUID(data, { permissionCheck = true } = {}) + { + const uuid = typeof data === 'string' ? data : data.uuid; + + let document = null; + + try + { + const doc = await fromUuid(uuid); + + if (doc === null) + { + ui.notifications.error(game.i18n.format('ForienQuestLog.API.Utils.Notifications.NoDocument', { uuid })); + return null; + } + + const checkPerm = typeof permissionCheck === 'boolean' ? permissionCheck : true; + + if (checkPerm && !doc.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER)) + { + ui.notifications.warn('ForienQuestLog.API.Utils.Notifications.NoPermission', { localize: true }); + return null; + } + + document = doc; + } + catch (err) + { + ui.notifications.error(game.i18n.format('ForienQuestLog.API.Utils.Notifications.NoDocument', { uuid })); + console.error(err); + } + + return document; + } + + /** + * Returns the quest folder or initializes and returns the quest folder if it doesn't exist and `create` is true. + * + * @returns {Folder} The quest folder. + * @see https://foundryvtt.com/api/classes/client.Folder.html + */ + static getQuestFolder() + { + return game.journal.directory.folders.find((f) => f.name === this.#questDirName); + } + + /** + * Builds a UUID for the given actor / journal / item data. + * + * @param {object} data - document data + * + * @param {string[]|undefined} type - Provide a list of Document types to build a UUID from given data. If the type + * doesn't match the data undefined is returned. If type is undefined any document + * will match. + * + * @returns {string|undefined} UUID + */ + static getUUID(data, type = void 0) + { + // Verify data. + if (typeof data !== 'object' || data === null) { return void 0; } + + // 'type' doesn't match the data type. + if (Array.isArray(type) && !type.includes(data.type)) { return void 0; } + if (typeof type === 'string' && data.type !== type) { return void 0; } + + if (typeof data.uuid === 'string') + { + // Must verify that this is not an owned item from an actor. Search for multiple `.` + if (data.uuid.startsWith('Actor') && (data.uuid.match(/\./g) || []).length > 1) + { + return void 0; + } + + return data.uuid; + } + else + { + return void 0; + } + } + + /** + * Returns the quest folder or initializes and returns the quest folder if it doesn't exist and `create` is true. + * + * @returns {Promise} The quest folder. + * @see https://foundryvtt.com/api/classes/client.Folder.html + */ + static async initializeQuestFolder() + { + const folder = game.journal.directory.folders.find((f) => f.name === this.#questDirName); + if (folder !== void 0) { return folder; } + + if (game.user.isGM) + { + await Folder.create({ name: this.#questDirName, type: 'JournalEntry', parent: null }); + } + + return game.journal.directory.folders.find((f) => f.name === this.#questDirName); + } + + /** + * Returns whether the player is a trusted player and `trustedPlayerEdit` is enabled. + * + * @param {User} user - User to check for trusted status and `trustedPlayerEdit`. + * + * @returns {boolean} Is trusted player edit. + */ + static isTrustedPlayerEdit(user = game.user) + { + return user.isTrusted && game.settings.get(constants.moduleName, settings.trustedPlayerEdit); + } + + /** + * Returns true if FQL is hidden from players. This will always return false if the user is a GM. + * + * @returns {boolean} Is FQL hidden from players. + */ + static isFQLHiddenFromPlayers() + { + if (game.user.isGM) { return false; } + + return game.settings.get(constants.moduleName, settings.hideFQLFromPlayers); + } + + /** + * Sets an image based on boolean setting state for FQL macros. + * + * @param {string|string[]} setting - Setting name. + * + * @param {boolean} [value] - Current setting value. + * + * @returns {Promise} + */ + static async setMacroImage(setting, value = void 0) + { + const userID = game.user.id; + + const fqlSettings = Array.isArray(setting) ? setting : [setting]; + + for (const macroEntry of game.macros.contents) + { + for (const currentSetting of fqlSettings) + { + // Test if the FQL `macro-setting` flag value against the setting supplied. + const macroSetting = macroEntry.getFlag(constants.moduleName, 'macro-setting'); + if (macroSetting !== currentSetting) { continue; } + + // Only set macro image if the author of the macro matches the user and the user is an owner. + const macroAuthor = FVTTCompat.authorID(macroEntry); + if (macroAuthor !== userID || !macroEntry.isOwner) { continue; } + + const state = value ?? game.settings.get(constants.moduleName, currentSetting); + + // Pick the correct image for the current state. + const img = typeof state === 'boolean' && state ? + `modules/forien-quest-log/assets/icons/macros/${currentSetting}On.png` : + `modules/forien-quest-log/assets/icons/macros/${currentSetting}Off.png`; + + await macroEntry.update({ img }, { diff: false }); + } + } + } + + /** + * Shows a document sheet for the given UUID. An error message will post if the UUID is invalid and a warning + * message will be posted if the current `game.user` does not have permission to view the document. + * + * @param {string|object} data - The UUID as a string or object with UUID key as a string. + * + * @param {object} [opts] - Optional parameters. + * + * @param {boolean} [opts.permissionCheck=true] - Perform permission check. + * + * @param {...*} [opts.options] - Options to pass to sheet render method. + * + * @returns {Promise} The appId if rendered otherwise null. + */ + static async showSheetFromUUID(data, { permissionCheck = true, ...options } = {}) + { + const uuid = typeof data === 'string' ? data : data.uuid; + + try + { + const document = await fromUuid(uuid); + + if (document === null) + { + ui.notifications.error(game.i18n.format('ForienQuestLog.API.Utils.Notifications.NoDocument', { uuid })); + return null; + } + + if (permissionCheck && !document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER)) + { + ui.notifications.warn('ForienQuestLog.API.Utils.Notifications.NoPermission', { localize: true }); + return null; + } + + if (document?.sheet) + { + if (document.sheet.rendered) + { + document.sheet.bringToTop(); + return null; + } + else + { + document.sheet.render(true, options); + return document.sheet.appId; + } + } + } + catch (err) + { + ui.notifications.error(game.i18n.format('ForienQuestLog.API.Utils.Notifications.NoDocument', { uuid })); + console.error(err); + return null; + } + } + + /** + * Preloads templates for partials + */ + static preloadTemplates() + { + let templates = [ + "templates/partials/quest-log/tab.html", + "templates/partials/quest-preview/details.html", + "templates/partials/quest-preview/gmnotes.html", + "templates/partials/quest-preview/management.html", + "templates/partials/quest-preview/playernotes.html" + ]; + + templates = templates.map((t) => `modules/forien-quest-log/${t}`); + loadTemplates(templates); + } + + /** + * Register additional Handlebars helpers. `format` allows invoking `game.i18n.format` from a Handlebars template. + */ + static registerHandlebarsHelpers() + { + Handlebars.registerHelper('fql_format', (stringId, ...arrData) => + { + let objData; + if (typeof arrData[0] === 'object') + { + objData = arrData[0]; + } + else + { + objData = { ...arrData }; + } + + return game.i18n.format(stringId, objData); + }); + } + + /** + * Generates a UUID v4 compliant ID. This is used by Quest to attach a UUID to any data that isn't backed by a + * FoundryVTT document. Right now that is particularly {@link Task}. All GUI interaction and storage in Quest data + * that isn't based on an FVTT document must use a UUIDv4 to interact with this data. Lookups in Quest data must be + * by UUIDv4 to find an index in Quest data arrays before modifying data. FQL is potentially a multi-user module + * where many users could potentially be modifying Quest data that isn't backed by an FVTT document, so the Foundry + * core DB won't be synching or resolving this data. + * + * This code is an evolution of the following Gist. + * https://gist.github.com/jed/982883 + * + * There is a public domain / free copy license attached to it that is not a standard OSS license... + * https://gist.github.com/jed/982883#file-license-txt + * + * @returns {string} UUIDv4 + */ + static uuidv4() + { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + (c ^ (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); + } +} diff --git a/src/control/util/index.js b/src/control/util/index.js new file mode 100644 index 00000000..e8521f7e --- /dev/null +++ b/src/control/util/index.js @@ -0,0 +1,2 @@ +export * from './FVTTCompat.js'; +export * from './Utils.js'; \ No newline at end of file diff --git a/src/init.js b/src/init.js new file mode 100644 index 00000000..461bd92c --- /dev/null +++ b/src/init.js @@ -0,0 +1,4 @@ +import { FQLHooks } from './control/index.js'; + +// Initialize all hooks. +FQLHooks.init(); \ No newline at end of file diff --git a/src/model/Quest.js b/src/model/Quest.js new file mode 100644 index 00000000..434516a9 --- /dev/null +++ b/src/model/Quest.js @@ -0,0 +1,1128 @@ +import { + FVTTCompat, + Utils } from '../control/index.js'; + +import { QuestPreviewShim } from '../view/index.js'; + +import { + constants, + questStatus, + settings } from './constants.js'; + +/** + * Stores and makes accessible the minimum amount of data that defines a quest. A Quest is loaded from the backing + * JournalEntry and has the JournalEntry stored for the ability to perform permissions checks. Please see QuestDB + * as when a Quest is loaded it is stored in a QuestEntry which also contains the enriched quest data for display + * in Handlebars templates along with caching of several of the methods available in Quest for fast sorting. + * + * {@link Quest.giverFromQuest} / {@link Quest.giverFromUUID} are used in {@link HandlerDetails} to look up + * and store the quest giver image / name in {@link Quest.giverData} when a quest giver is set. + * + * @see QuestDB + * @see QuestEntry + */ +export class Quest +{ + /** + * Stores the sheet class for Quest which is {@link QuestPreview}. This class / sheet is used to render Quest. + * While directly accessible from Quest the main way a QuestPreview is shown is through {@link QuestAPI.open} which + * provides the entry point for external API access and is also used internally when opening a quest. + * + * @type {typeof Application} + * @see Quest.sheet + */ + static #SheetClass; + + /** + * The backing JournalEntry document. + * + * @type {JournalEntry} + */ + #entry; + + /** @type {string | null} */ + #id; + + /** @type {string} */ + #name; + + /** + * Lookup the Quest giver by UUID and return the data stored in {@link Quest.giverData}. + * + * @param {Quest} quest - The quest to look up the quest giver. + * + * @returns {Promise} The image / name data associated with this Foundry UUID. + */ + static async giverFromQuest(quest) + { + let data = null; + + if (quest.giver === 'abstract') + { + data = { + name: quest.giverName, + img: quest.image, + hasTokenImg: false + }; + } + else if (typeof quest.giver === 'string') + { + data = Quest.giverFromUUID(quest.giver, quest.image); + } + + return data; + } + + /** + * @param {string} uuid - The Foundry UUID to lookup for image / name data. + * + * @param {string} [imageType] - The image type: 'actor' or 'token' + * + * @returns {Promise} The image / name data associated with this Foundry UUID. + */ + static async giverFromUUID(uuid, imageType = 'actor') + { + let data = null; + + if (typeof uuid === 'string') + { + const document = await fromUuid(uuid); + + if (document !== null) + { + switch (document.documentName) + { + case Actor.documentName: + { + const actorImage = document.img; + const tokenImage = FVTTCompat.tokenImg(document); + + const hasTokenImg = typeof tokenImage === 'string' && tokenImage !== actorImage; + + data = { + uuid, + name: document.name, + img: imageType === 'token' && hasTokenImg ? tokenImage : actorImage, + hasTokenImg + }; + break; + } + + case Item.documentName: + data = { + uuid, + name: document.name, + img: document.img, + hasTokenImg: false + }; + break; + + case JournalEntry.documentName: + data = { + uuid, + name: document.name, + img: FVTTCompat.journalImage(document), + hasTokenImg: false + }; + break; + } + } + } + + return data; + } + + /** + * @param {QuestData} data - The serialized quest data to set. + * + * @param {JournalEntry} entry - The associated Foundry JournalEntry. + */ + constructor(data = {}, entry = null) + { + this.#id = entry !== null ? entry.id : null; + + this.initData(data); + + this.#entry = entry; + + if (this.#entry && this.#id !== null) + { + this.#entry._sheet = new QuestPreviewShim(this.#id); + } + } + + /** + * @returns {boolean} Returns whether the current user can update the backing journal document. + */ + get canUserUpdate() + { + const entry = this.entry ? this.entry : game.journal.get(this.#id); + + return entry?.canUserModify?.(game.user, 'update') ?? false; + } + + /** + * @returns {JournalEntry} The associated backing journal entry document. + */ + get entry() + { + return this.#entry; + } + + /** + * Gets the Foundry ID associated with this Quest. + * + * @returns {string} The ID of the quest. + */ + get id() + { + return this.#id; + } + + /** + * Sets the associated backing journal entry document. + * + * @param {JournalEntry} entry - A journal entry document. + */ + set entry(entry) + { + this.#entry = entry; + } + + /** + * Sets the Foundry ID of the quest. + * + * @param {string} id - A Foundry ID. + */ + set id(id) + { + this.#id = id; + } + + /** + * @returns {boolean} Is the quest active / in progress. + */ + get isActive() + { + return questStatus.active === this.status; + } + + /** + * True when no players have OBSERVER or OWNER permissions for this quest. + * + * @returns {boolean} Quest is hidden. + */ + get isHidden() + { + let isHidden = true; + + if (this.entry && typeof FVTTCompat.ownership(this.entry) === 'object') + { + if (FVTTCompat.ownership(this.entry).default >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) { return false; } + + for (const [userId, permission] of Object.entries(FVTTCompat.ownership(this.entry))) + { + if (userId === 'default') { continue; } + + const user = game.users.get(userId); + + if (!user || user.isGM) { continue; } + + if (permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) + { + isHidden = false; + break; + } + } + } + + return isHidden; + } + + /** + * @returns {boolean} Is the quest in the inactive state. + */ + get isInactive() + { + return questStatus.inactive === this.status; + } + + /** + * Returns true if this quest is observable for the given player. For trusted player edit when the status is + * `inactive` the test is ownership instead of simply OBSERVER or higher. + * + * @returns {boolean} Is the quest observable. + */ + get isObservable() + { + if (game.user.isGM) { return true; } + + const isInactive = this.isInactive; + + // Special handling for trusted player edit who can only see owned quests in the hidden / inactive category. + if (Utils.isTrustedPlayerEdit() && isInactive) { return this.isOwner; } + + // Otherwise no one can see hidden / inactive quests; perform user permission check for observer. + return !isInactive && this.entry.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER); + } + + /** + * Gets whether the current user has owner permissions. + * + * @returns {boolean} Is owner. + */ + get isOwner() + { + return game.user.isGM || + (this.entry && this.entry.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)); + } + + /** + * Gets whether this quest is a personal quest. A personal quest has one or more players with OBSERVER or OWNER + * permissions. + * + * @returns {boolean} Is this quest personal. + */ + get isPersonal() + { + let isPersonal = false; + + if (this.entry && typeof FVTTCompat.ownership(this.entry) === 'object' && + FVTTCompat.ownership(this.entry).default < CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) + { + for (const [userId, permission] of Object.entries(FVTTCompat.ownership(this.entry))) + { + if (userId === 'default') { continue; } + + const user = game.users.get(userId); + + if (!user || user.isGM) { continue; } + + if (permission < CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) { continue; } + + isPersonal = true; + break; + } + } + + return isPersonal; + } + + /** + * Returns whether this quest is set as the primary quest. + * + * @returns {boolean} Primary quest state. + */ + get isPrimary() + { + return this.#id === game.settings.get(constants.moduleName, settings.primaryQuest); + } + + /** + * Gets the name of the quest. + * + * @returns {string} Quest name. + */ + get name() + { + return this.#name; + } + + /** + * Sets the name of the quest. + * + * @param {string} value - The new name. + */ + set name(value) + { + this.#name = typeof value === 'string' && value.length > 0 ? value : + game.i18n.localize('ForienQuestLog.API.QuestDB.Labels.NewQuest'); + } + + /** + * Creates a new Reward and pushes to the reward array. + * + * @param {object} data - The reward data. + */ + addReward(data = {}) + { + const reward = new Reward(data); + if (reward.type !== null) { this.rewards.push(reward); } + } + + /** + * Pushes a subquest ID to the subquest array. + * + * @param {string} questId - A Foundry ID + */ + addSubquest(questId) + { + if (!this.subquests.includes(questId)) + { + this.subquests.push(questId); + } + } + + /** + * Creates a new Task and pushes to the task array. + * + * @param {object} data - Task data. + */ + addTask(data = {}) + { + const task = new Task(data); + if (task.name && task.name.length) { this.tasks.push(task); } + } + + /** + * Gets all adjacent quest IDs including self. This includes any parent and subquests. + * + * @returns {string[]} All adjacent quests including self. + */ + getQuestIds() + { + return this.parent ? [this.parent, this.id, ...this.subquests] : [this.id, ...this.subquests]; + } + + /** + * Gets a Reward by Foundry VTT UUID or UUIDv4 for abstract Rewards. + * + * @param {string} uuidv4 - The FVTT UUID to find. + * + * @returns {Reward} The task or null. + */ + getReward(uuidv4) + { + const index = this.rewards.findIndex((t) => t.uuidv4 === uuidv4); + return index >= 0 ? this.rewards[index] : null; + } + + /** + * Returns a list of Actor data for whom this quest is personal. + * + * @returns {object[]} A list of actors who are assigned to this quest. + */ + getPersonalActors() + { + if (!this.isPersonal) { return []; } + + const users = []; + + if (this.entry && typeof FVTTCompat.ownership(this.entry) === 'object') + { + for (const [userId, permission] of Object.entries(FVTTCompat.ownership(this.entry))) + { + if (userId === 'default') { continue; } + + const user = game.users.get(userId); + + if (!user || user.isGM) { continue; } + + if (permission < CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) { continue; } + + users.push(user); + } + } + + return users; + } + + /** + * Returns any stored Foundry sheet class. + * + * @returns {typeof Application} The associated sheet class. + */ + static getSheet() { return Quest.#SheetClass; } + + /** + * Gets a task by UUID v4. + * + * @param {string} uuidv4 - The UUID v4 to find. + * + * @returns {Task} The task or null. + */ + getTask(uuidv4) + { + const index = this.tasks.findIndex((t) => t.uuidv4 === uuidv4); + return index >= 0 ? this.tasks[index] : null; + } + + /** + * Normally would be in constructor(), but is extracted for usage in different methods as well + * + * @param {QuestData} data - The serialized Quest data to initialize. + */ + initData(data) + { + this.name = data.name || game.i18n.localize('ForienQuestLog.API.QuestDB.Labels.NewQuest'); + + /** + * @type {string} + */ + this.status = data.status || questStatus.inactive; + + /** + * @type {string|null} + */ + this.giver = data.giver || null; + + /** + * @type {object|null} + */ + this.giverData = data.giverData || null; + + /** + * @type {string} + */ + this.description = data.description || ''; + + /** + * @type {string} + */ + this.gmnotes = data.gmnotes || ''; + + /** + * @type {string} + */ + this.image = data.image || 'actor'; + + /** + * @type {string} + */ + this.giverName = data.giverName || 'actor'; + + /** + * @type {string} + */ + this.splash = data.splash || ''; + + /** + * @type {string} + */ + this.splashPos = data.splashPos || 'center'; + + /** + * @type {boolean} + */ + this.splashAsIcon = typeof data.splashAsIcon === 'boolean' ? data.splashAsIcon : false; + + /** + * @type {string|null} + */ + this.location = data.location || null; + + /** + * @type {string} + */ + this.playernotes = data.playernotes || ''; + + /** + * @type {number} + */ + this.priority = data.priority || 0; + + /** + * @type {string|null} + */ + this.type = data.type || null; + + /** + * @type {string|null} + */ + this.parent = data.parent || null; + + /** + * @type {string[]} + */ + this.subquests = data.subquests || []; + + /** + * @type {Task[]} + */ + this.tasks = Array.isArray(data.tasks) ? data.tasks.map((task) => new Task(task)) : []; + + /** + * @type {Reward[]} + */ + this.rewards = Array.isArray(data.rewards) ? data.rewards.map((reward) => new Reward(reward)) : []; + + // Sanity check. If status is incorrect set it to inactive. + if (!questStatus[this.status]) { this.status = questStatus.inactive; } + + if (typeof data.date === 'object') + { + /** + * Provides timestamps for quest create, start, end. + * + * @type {{start: (number|null), create: (number|null), end: (number|null)}} + */ + this.date = { + create: typeof data.date.create === 'number' ? data.date.create : null, + start: typeof data.date.start === 'number' ? data.date.start : null, + end: typeof data.date.end === 'number' ? data.date.end : null + }; + } + else + { + this.date = { + create: Date.now(), + }; + + switch (this.status) + { + case questStatus.active: + this.date.start = Date.now(); + this.date.end = null; + break; + + case questStatus.completed: + case questStatus.failed: + this.date.start = Date.now(); + this.date.end = Date.now(); + break; + + case questStatus.inactive: + case questStatus.available: + default: + this.date.start = null; + this.date.end = null; + break; + } + } + } + + /** + * Deletes Reward from Quest. + * + * @param {string} uuidv4 - The UUIDv4 associated with a Reward. + */ + removeReward(uuidv4) + { + const index = this.rewards.findIndex((t) => t.uuidv4 === uuidv4); + if (index >= 0) { this.rewards.splice(index, 1); } + } + + /** + * Removes subquest from Quest. + * + * @param {string} questId - The subquest ID to remove. + */ + removeSubquest(questId) + { + this.subquests = this.subquests.filter((id) => id !== questId); + } + + /** + * Removes the task from this quest by UUIDv4. + * + * @param {string} uuidv4 - The UUIDv4 associated with a Task. + * + * @see Utils.uuidv4 + */ + removeTask(uuidv4) + { + const index = this.tasks.findIndex((t) => t.uuidv4 === uuidv4); + if (index >= 0) { this.tasks.splice(index, 1); } + } + + /** + * Resets the quest giver. + */ + resetGiver() + { + this.giver = null; + this.image = 'actor'; + this.giverData = null; + this.giverName = 'actor'; + } + + /** + * Saves Quest to JournalEntry's content, and if needed, moves JournalEntry to different folder. + * Can also update JournalEntry's permissions. + * + * @returns {Promise} The ID of the quest saved or undefined if user couldn't save the quest. + */ + async save() + { + const entry = this.entry ? this.entry : game.journal.get(this.#id); + + // If the entry doesn't exist or the user can't update the journal entry via ownership then early out. + if (!entry || !this.canUserUpdate) { return; } + + // Save Quest JSON, but also potentially update the backing JournalEntry folder name. + const update = { + name: typeof this.#name === 'string' && this.#name.length > 0 ? this.#name : + game.i18n.localize('ForienQuestLog.API.QuestDB.Labels.NewQuest'), + flags: { + [constants.moduleName]: { json: this.toJSON() } + } + }; + + this.entry = await entry.update(update, { diff: false }); + + return this.#id; + } + + /** + * Sets any stored Foundry sheet class. + * + * @param {typeof Application} NewSheetClass - The sheet class. + */ + static setSheet(NewSheetClass) { Quest.#SheetClass = NewSheetClass; } + + /** + * Sets new status for the quest. Also updates any timestamp / date data depending on status set. + * + * @param {string} target - The target status to set. + * + * @returns {Promise} + */ + async setStatus(target) + { + if (!this.entry || !questStatus[target]) { return; } + + this.status = target; + + // Update the tracked date data based on status. + switch (this.status) + { + case questStatus.active: + this.date.start = Date.now(); + this.date.end = null; + break; + + case questStatus.completed: + case questStatus.failed: + this.date.end = Date.now(); + break; + + case questStatus.inactive: + case questStatus.available: + default: + this.date.start = null; + this.date.end = null; + break; + } + + // Potentially reset any tracked primary quest when the status is no longer active. + if (this.status !== questStatus.active) + { + const primaryQuestId = game.settings.get(constants.moduleName, settings.primaryQuest); + if (this.#id === primaryQuestId) + { + await game.settings.set(constants.moduleName, settings.primaryQuest, ''); + } + } + + await this.entry.update({ + flags: { + [constants.moduleName]: { json: this.toJSON() } + } + }); + + return this.#id; + } + + /** + * Locates and swaps the rewards indicated by the source and target UUIDv4s provided. + * + * @param {string} sourceUuidv4 - The source UUIDv4 + * + * @param {string} targetUuidv4 - The target UUIDv4 + */ + sortRewards(sourceUuidv4, targetUuidv4) + { + const index = this.rewards.findIndex((t) => t.uuidv4 === sourceUuidv4); + const targetIdx = this.rewards.findIndex((t) => t.uuidv4 === targetUuidv4); + + if (index >= 0 && targetIdx >= 0) + { + const entry = this.rewards.splice(index, 1)[0]; + this.rewards.splice(targetIdx, 0, entry); + } + } + + /** + * Locates and swaps the tasks indicated by the source and target UUIDv4s provided. + * + * @param {string} sourceUuidv4 - The source UUIDv4 + * + * @param {string} targetUuidv4 - The target UUIDv4 + */ + sortTasks(sourceUuidv4, targetUuidv4) + { + // If there are sub quests in the objectives above tasks then an undefined targetUuidv4 can occur. + if (!targetUuidv4) { return; } + + const index = this.tasks.findIndex((t) => t.uuidv4 === sourceUuidv4); + const targetIdx = this.tasks.findIndex((t) => t.uuidv4 === targetUuidv4); + + if (index >= 0 && targetIdx >= 0) + { + const entry = this.tasks.splice(index, 1)[0]; + this.tasks.splice(targetIdx, 0, entry); + } + } + + /** + * @returns {QuestData} The serialized JSON for this Quest. + */ + toJSON() + { + return { + name: this.#name, + status: this.status, + giver: this.giver, + giverData: this.giverData, + description: this.description, + gmnotes: this.gmnotes, + playernotes: this.playernotes, + image: this.image, + giverName: this.giverName, + splash: this.splash, + splashPos: this.splashPos, + splashAsIcon: this.splashAsIcon, + location: this.location, + priority: this.priority, + type: this.type, + parent: this.parent, + subquests: this.subquests, + tasks: this.tasks, + rewards: this.rewards, + date: this.date + }; + } + + /** + * Toggles Actor image between sheet's and token's images + */ + toggleImage() + { + this.image = this.image === 'actor' ? 'token' : 'actor'; + } + +// Document simulation ----------------------------------------------------------------------------------------------- + + /** + * The canonical name of this Document type, for example "Actor". + * + * @returns {string} The document name. + */ + static get documentName() + { + return 'Quest'; + } + + /** + * The canonical name of this Document type, for example "Actor". + * + * @returns {string} The document name. + */ + get documentName() + { + return 'Quest'; + } + + /** + * This mirrors document.sheet and constructs a new instance of the sheet class. + * + * @returns {Application} An associated sheet instance. + */ + get sheet() + { + const SheetClass = Quest.#SheetClass; + + return SheetClass ? new SheetClass(this) : void 0; + } +} + +/** + * Rewards can be either an item from a Foundry VTT compendium / world item or be an abstract reward. It should be + * noted that FVTT item data will have a Foundry VTT UUID, but abstract rewards entered by the user will have a UUIDv4 + * generated for them. This UUID regardless of type is accessible in `this.uuid`. + * + */ +export class Reward +{ + /** + * @param {object} data - Serialized reward data. + */ + constructor(data = {}) + { + /** + * @type {string|null} + */ + this.type = data.type || null; + + /** + * @type {object} + */ + this.data = data.data || {}; + + /** + * @type {boolean} + */ + this.hidden = typeof data.hidden === 'boolean' ? data.hidden : false; + + /** + * @type {boolean} + */ + this.locked = typeof data.locked === 'boolean' ? data.locked : true; + + /** + * @type {string} + */ + this.uuidv4 = data.uuidv4 || Utils.uuidv4(); + } + + /** + * Returns the name of the reward. + * + * @returns {string} Reward name. + */ + get name() { return this.data.name; } + + /** + * Returns the Foundry UUID associated with this reward. Abstract rewards do not have a Foundry UUID. + * + * @returns {string|void} The Foundry UUID. + */ + get uuid() { return this.data.uuid; } + + /** + * Serializes this reward. + * + * @returns {object} A JSON object. + */ + toJSON() + { + return JSON.parse(JSON.stringify({ + type: this.type, + data: this.data, + hidden: this.hidden, + locked: this.locked, + uuidv4: this.uuidv4 + })); + } + + /** + * Toggles the locked status. + * + * @returns {boolean} Current locked status. + */ + toggleLocked() + { + this.locked = !this.locked; + return this.locked; + } + + /** + * Toggles the hidden status. + * + * @returns {boolean} Current hidden status. + */ + toggleVisible() + { + this.hidden = !this.hidden; + return this.hidden; + } +} + +/** + * Encapsulates an objective / task. + */ +export class Task +{ + /** + * @param {object} data - The task data. + */ + constructor(data = {}) + { + /** + * @type {string|null} + */ + this.name = data.name || null; + + /** + * @type {boolean} + */ + this.completed = data.completed || false; + + /** + * @type {boolean} + */ + this.failed = data.failed || false; + + /** + * @type {boolean} + */ + this.hidden = data.hidden || false; + + /** + * @type {string} + */ + this.uuidv4 = data.uuidv4 || Utils.uuidv4(); + } + + /** + * Gets the current CSS class based on state. + * + * @returns {string} CSS class + */ + get state() + { + if (this.completed) + { + return 'check-square'; + } + else if (this.failed) + { + return 'minus-square'; + } + return 'square'; + } + + /** + * Serializes the task. + * + * @returns {object} JSON object. + */ + toJSON() + { + return JSON.parse(JSON.stringify({ + name: this.name, + completed: this.completed, + failed: this.failed, + hidden: this.hidden, + state: this.state, + uuidv4: this.uuidv4 + })); + } + + /** + * Toggles the task state between completed, failed, incomplete. + */ + toggle() + { + if (this.completed === false && this.failed === false) + { + this.completed = true; + } + else if (this.completed === true) + { + this.failed = true; + this.completed = false; + } + else + { + this.failed = false; + } + } + + /** + * Toggles the hidden state. + * + * @returns {boolean} Current hidden state. + */ + toggleVisible() + { + this.hidden = !this.hidden; + + return this.hidden; + } +} + +/** + * @typedef {object} QuestData + * + * @property {string} name - The quest name. + * + * @property {string} status - The quest status; one of {@link questStatus}. + * + * @property {string|null} giver - The Foundry UUID or 'abstract' for a custom source. + * + * @property {QuestImgNameData} giverData - The Foundry image / name data looked up by UUID. + * + * @property {string} description - The quest description. + * + * @property {string} gmnotes - The GM Notes. + * + * @property {string} image - `actor` or `token` for UUID based givers or the image link for custom source. + * + * @property {string} giverName - The name of the quest giver. + * + * @property {string} splash - The splash image. + * + * @property {string} splashPos - The splash position (top, center, bottom). + * + * @property {boolean} splashAsIcon - Use the splash image as the quest icon. + * + * @property {string|null} location - Unused / future use for quest location. + * + * @property {string} playernotes - The Player Notes. + * + * @property {number} priority - Unused / future use for quest priority sorting. + * + * @property {string|null} type - Unused / future use for sorting type of quest. + * + * @property {string|null} parent - The parent quest ID. + * + * @property {string[]} subquests - An array of quest IDs that are subquests. + * + * @property {QuestTaskData[]} tasks - An array of tasks. + * + * @property {QuestRewardData[]} rewards - An array of rewards. + * + * @property {QuestDateData} date - The create, end, start dates of the quest. + */ + +/** + * @typedef QuestDateData + * + * @property {number|null} create - Time ms since 1970 / Date.now() when quest was created. + * + * @property {number|null} end - Time ms since 1970 / Date.now() when quest ended (status: failed / complete). + * + * @property {number|null} start - Time ms since 1970 / Date.now() when quest was started (status: active). + */ + +/** + * @typedef QuestRewardData + * + * @property {string} type - Reward type. + * + * @property {QuestRewardAddData} data - Reward add data. + * + * @property {boolean} hidden - Reward hidden. + * + * @property {boolean} locked - Reward locked. + * + * @property {string} uuidv4 - The FQL UUIDv4 / unique ID. + */ + +/** + * @typedef QuestRewardAddData + * + * @property {string} type - Reward type. + * + * @property {QuestImgNameData} data - Reward image / name from {@link Enrich.giverFromUUID}. + * + * @property {boolean} hidden - Reward hidden. + */ + +/** + * @typedef QuestTaskData + * + * @property {string} name - Task name. + * + * @property {boolean} completed - Task completed. + * + * @property {boolean} failed - Task failed. + * + * @property {boolean} hidden - Task hidden. + * + * @property {string} state - Task state. + * + * @property {string} uuidv4 - The FQL UUIDv4 / unique ID. + */ + diff --git a/src/model/constants.js b/src/model/constants.js new file mode 100644 index 00000000..21f9cb29 --- /dev/null +++ b/src/model/constants.js @@ -0,0 +1,157 @@ +/** + * Defines the main FQL constants for module name and the DB flag. + * + * @type {{folderState: string, flagDB: string, moduleName: string, moduleLabel: string, primaryState: string}} + */ +const constants = { + moduleName: 'forien-quest-log', + moduleLabel: `Forien's Quest Log`, + flagDB: 'json' +}; + +/** + * Defines the {@link JQuery} events that are used in FQL. + * + * @type {{click: string, dblclick: string, dragstart: string, drop: string, focus: string, focusout: string, mousedown: string}} + */ +const jquery = { + click: 'click', + dblclick: 'dblclick', + dragenter: 'dragenter', + dragstart: 'dragstart', + drop: 'drop', + focus: 'focus', + focusout: 'focusout', + keydown: 'keydown', + mousedown: 'mousedown' +}; + +/** + * Stores strings for quest types (statuses) + * + * @returns {{active: string, available: string, completed: string, failed: string, inactive: string}} + */ +const questStatus = { + active: 'active', + available: 'available', + completed: 'completed', + failed: 'failed', + inactive: 'inactive' +}; + +/** + * Stores localization strings for quest types (statuses) + * + * @type {{active: string, available: string, completed: string, failed: string, inactive: string}} + */ +const questStatusI18n = { + active: 'ForienQuestLog.QuestTypes.Labels.Active', + available: 'ForienQuestLog.QuestTypes.Labels.Available', + completed: 'ForienQuestLog.QuestTypes.Labels.Completed', + failed: 'ForienQuestLog.QuestTypes.Labels.Failed', + inactive: 'ForienQuestLog.QuestTypes.Labels.InActive' +}; + +/** + * Stores the QuestLog tab indexes. This is used by QuestLog.setPosition to select the current table based on status + * name. + * + * @type {{inactive: number, available: number, active: number, completed: number, failed: number}} + */ +const questTabIndex = { + active: 1, + available: 0, + completed: 2, + failed: 3, + inactive: 4 +}; + +/** + * Stores the keys used with session storage. + * + * @type {FQLSessionConstants} + */ +const sessionConstants = { + currentPrimaryQuest: 'forien.questlog.currentPrimaryQuest', + trackerFolderState: 'forien.questtracker.folderState-', + trackerShowBackground: 'forien.questtracker.showBackground', + trackerShowPrimary: 'forien.questtracker.showPrimary' +}; + +/** + * @type {FQLSettings} Defines all the module settings for world and client. + */ +const settings = { + allowPlayersAccept: 'allowPlayersAccept', + allowPlayersCreate: 'allowPlayersCreate', + allowPlayersDrag: 'allowPlayersDrag', + countHidden: 'countHidden', + defaultAbstractRewardImage: 'defaultAbstractRewardImage', + defaultPermission: 'defaultPermission', + dynamicBookmarkBackground: 'dynamicBookmarkBackground', + hideFQLFromPlayers: 'hideFQLFromPlayers', + navStyle: 'navStyle', + notifyRewardDrop: 'notifyRewardDrop', + primaryQuest: 'primaryQuest', + questTrackerEnable: 'questTrackerEnable', + questTrackerPinned: 'questTrackerPinned', + questTrackerPosition: 'questTrackerPosition', + questTrackerResizable: 'questTrackerResizable', + showFolder: 'showFolder', + showTasks: 'showTasks', + trustedPlayerEdit: 'trustedPlayerEdit' +}; + +export { constants, jquery, questStatus, questStatusI18n, questTabIndex, sessionConstants, settings }; + +/** + * @typedef {object} FQLSessionConstants + * + * @property {string} currentPrimaryQuest - Stores current primary quest set from {@link FQLSettings.primaryQuest}. + * + * @property {string} trackerFolderState - Stores a boolean with tacked on quest ID for whether objectives are shown. + * + * @property {string} trackerShowBackground - Shows / hides the quest tracker background. + * + * @property {string} trackerShowPrimary - Stores a boolean if the tracker is showing the primary quest or all quests. + */ + +/** + * @typedef {object} FQLSettings + * + * @property {string} allowPlayersAccept - Allow players to accept quests. + * + * @property {string} allowPlayersCreate - Allow players to create quests. + * + * @property {string} allowPlayersDrag - Allow players to drag reward items to actor sheet. + * + * @property {string} countHidden - Count hidden objectives / subquests. + * + * @property {string} defaultAbstractRewardImage - Sets the default abstract reward image path. + * + * @property {string} defaultPermission - Sets the default permission level for new quests. + * + * @property {string} dynamicBookmarkBackground - Uses jQuery to dynamically set the tab background image. + * + * @property {string} hideFQLFromPlayers - Completely hides FQL from players. + * + * @property {string} navStyle - Navigation style / classic / or bookmark tabs. + * + * @property {string} notifyRewardDrop - Post a notification UI message when rewards are dropped in actor sheets. + * + * @property {string} primaryQuest - Stores the quest ID of a quest that is the current primary quest. + * + * @property {string} questTrackerEnable - Enables the quest tracker. + * + * @property {string} questTrackerPinned - Is the QuestTracker pinned to the side bar. + * + * @property {string} questTrackerPosition - Hidden setting to store current quest tracker position. + * + * @property {string} questTrackerResizable - Stores the current window handling mode ('auto' or 'resize'). + * + * @property {string} showFolder - Shows the `_fql_quests` directory in the journal entries sidebar. + * + * @property {string} showTasks - Determines if objective counts are rendered. + * + * @property {string} trustedPlayerEdit - Allows trusted players to have full quest editing capabilities. + */ diff --git a/src/model/index.js b/src/model/index.js new file mode 100644 index 00000000..8c5c4997 --- /dev/null +++ b/src/model/index.js @@ -0,0 +1 @@ +export * from './Quest.js'; \ No newline at end of file diff --git a/src/typedefs.js b/src/typedefs.js new file mode 100644 index 00000000..395d836d --- /dev/null +++ b/src/typedefs.js @@ -0,0 +1,55 @@ +/* eslint-disable jsdoc/valid-types */ // ESDoc uses a non-conformant external tag. + +/** + * @external {collect} https://collect.js.org/api.html + */ + +/** + * @external {CollectJS} https://collect.js.org/api.html + */ + +/** + * @external {Collection} https://collect.js.org/api.html + */ + +/** + * @external {Handlebars} https://handlebarsjs.com/api-reference/ + */ + +/** + * @external {JQuery} https://api.jquery.com/ + */ + +/** + * @external {JQuery.ClickEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {JQuery.DragEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {JQuery.DragStartEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {JQuery.DropEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {JQuery.FocusOutEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {JQuery.MouseDownEvent} https://api.jquery.com/category/events/event-object/ + */ + +/** + * @external {PointerEvent} https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent + */ + +/** + * @external {sessionStorage} https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage + */ + +/* eslint-enable jsdoc/valid-types */ diff --git a/src/view/index.js b/src/view/index.js new file mode 100644 index 00000000..11db5408 --- /dev/null +++ b/src/view/index.js @@ -0,0 +1,4 @@ +export * from './log/QuestLog.js'; +export * from './preview/QuestPreview.js'; +export * from './preview/QuestPreviewShim.js'; +export * from './tracker/QuestTracker.js'; \ No newline at end of file diff --git a/src/view/internal/FQLContextMenu.js b/src/view/internal/FQLContextMenu.js new file mode 100644 index 00000000..d07d6028 --- /dev/null +++ b/src/view/internal/FQLContextMenu.js @@ -0,0 +1,68 @@ +/** + * Provides a fixed / free placement context menu used in QuestLog. With a few modifications below the Foundry + * ContextMenu is converted into a free placement context menu. This is useful to free the context menu from being bound + * within the overflow constraints of a parent element and allow the context menu to display at the exact mouse point + * clicked in a larger element. Note: be mindful that CSS style `position: fixed` is used to make the context menu + * display relative to the main page viewport which defines the containing block, however if you use `filter`, + * `perspective`, or `transform` in styles then that element becomes the containing block higher up than the main + * window. FQLContextMenu does not reposition the inserted HTML which is relative to the element containing the context + * menu. + */ +export class FQLContextMenu extends ContextMenu +{ + /** + * Defines the default CSS styles for the context menu. + * + * @type {{"box-shadow": string, width: string, "font-size": string, "font-family": string, position: string}} + */ + static #defaultStyle = { + position: 'fixed', + width: 'fit-content', + 'font-family': '"Signika", sans-serif', + 'font-size': '14px', + 'box-shadow': '0 0 10px #000' + }; + + /** + * @type {{top: number, left: number}} + */ + #position; + + /** + * @inheritDoc + * @override + */ + constructor(element, selector, menuItems, options = {}) + { + super(element, selector, menuItems, options); + } + + /** + * Stores the pageX / pageY position from the the JQuery event to be applied in `_setPosition`. + * + * @inheritDoc + * @override + */ + bind() + { + this.element.on(this.eventName, this.selector, (event) => + { + event.preventDefault(); + + this.#position = { left: event.pageX, top: event.pageY }; + }); + super.bind(); + } + + /** + * Delegate to the parent `_setPosition` then apply the stored position from the callback in `bind`. + * + * @inheritDoc + * @override + */ + _setPosition(html, target) + { + super._setPosition(html, target); + html.css(foundry.utils.mergeObject(this.#position, FQLContextMenu.#defaultStyle)); + } +} \ No newline at end of file diff --git a/src/view/internal/FQLDialog.js b/src/view/internal/FQLDialog.js new file mode 100644 index 00000000..fc0e315e --- /dev/null +++ b/src/view/internal/FQLDialog.js @@ -0,0 +1,306 @@ +/** + * Provides a single dialog for confirming quest, task, & reward deletion. + * + * Note: You have been warned. This is tricky code. Please understand it before modifying. Feel free to ask questions: + * + * There presently is no modal dialog in Foundry and this dialog implementation repurposes a single dialog instance + * through potentially multiple cycles of obtaining and resolving Promises storing the resolve function in the dialog + * itself. There are four locations in the codebase where a delete confirmation dialog is invoked and awaited upon. Each + * time one of the static methods below is invoked the previous the current promise resolves with undefined / void 0 + * and then the same dialog instance is reconfigured with new information about a successive delete confirmation + * operation and brings the dialog to front and renders again. This provides reasonable semi-modal behavior from just a + * single dialog instance shared across confirmation to delete quests, tasks, and rewards. + */ +export class FQLDialog +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + + /** + * Stores any open FQLDialogImpl. + * + * @type {FQLDialogImpl} + */ + static #deleteDialog = void 0; + + /** + * Closes any open FQLDialogImpl that is associated with the questId or quest log. FQLDialogImpl gets associated + * with the last app that invoked the dialog. + * + * @param {object} [options] - Optional parameters. + * + * @param {string} [options.questId] - The quest ID associated with a QuestPreview app. + * + * @param {boolean} [options.isQuestLog] - Is the quest log closing. + */ + static closeDialogs({ questId, isQuestLog = false } = {}) + { + if (this.#deleteDialog && (this.#deleteDialog.fqlQuestId === questId || + this.#deleteDialog.fqlIsQuestLog === isQuestLog)) + { + this.#deleteDialog.close(); + this.#deleteDialog = void 0; + } + } + + /** + * Show a dialog to confirm quest deletion. + * + * @param {options} options - Optional parameters. + * + * @param {string} options.name - The name for the reward to delete. + * + * @param {string} options.result - The UUID of the reward to delete. + * + * @param {string|void} options.questId - The questId to track to auto-close the dialog when the QuestPreview closes. + * + * @returns {Promise} Result of the delete confirmation dialog. + */ + static async confirmDeleteQuest({ name, result, questId, isQuestLog = false }) + { + if (this.#deleteDialog && this.#deleteDialog.rendered) + { + return this.#deleteDialog.updateFQLData({ + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.Labels.Quest'), + body: 'ForienQuestLog.DeleteDialog.BodyQuest' + }); + } + + this.#deleteDialog = void 0; + + return new Promise((resolve) => + { + this.#deleteDialog = new FQLDialogImpl({ + resolve, + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.Labels.Quest'), + body: 'ForienQuestLog.DeleteDialog.BodyQuest' + }); + + this.#deleteDialog.render(true); + }); + } + + /** + * Show a dialog to confirm reward deletion. + * + * @param {options} options - Optional parameters. + * + * @param {string} options.name - The name for the reward to delete. + * + * @param {string} options.result - The UUID of the reward to delete. + * + * @param {string|void} options.questId - The questId to track to auto-close the dialog when the QuestPreview closes. + * + * @returns {Promise} Result of the delete confirmation dialog. + */ + static async confirmDeleteReward({ name, result, questId, isQuestLog = false }) + { + if (this.#deleteDialog && this.#deleteDialog.rendered) + { + return this.#deleteDialog.updateFQLData({ + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.QuestPreview.Labels.Reward'), + body: 'ForienQuestLog.DeleteDialog.BodyReward' + }); + } + + this.#deleteDialog = void 0; + + return new Promise((resolve) => + { + this.#deleteDialog = new FQLDialogImpl({ + resolve, + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.QuestPreview.Labels.Reward'), + body: 'ForienQuestLog.DeleteDialog.BodyReward' + }); + + this.#deleteDialog.render(true); + }); + } + + /** + * Show a dialog to confirm task deletion. + * + * @param {options} options - Optional parameters. + * + * @param {string} options.name - The name for the task to delete. + * + * @param {string} options.result - The UUIDv4 of the task to delete. + * + * @param {string|void} options.questId - The questId to track to auto-close the dialog when the QuestPreview closes. + * + * @returns {Promise} Result of the delete confirmation dialog. + */ + static async confirmDeleteTask({ name, result, questId, isQuestLog = false }) + { + if (this.#deleteDialog && this.#deleteDialog.rendered) + { + return this.#deleteDialog.updateFQLData({ + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.QuestPreview.Labels.Objective'), + body: 'ForienQuestLog.DeleteDialog.BodyObjective' + }); + } + + this.#deleteDialog = void 0; + + return new Promise((resolve) => + { + this.#deleteDialog = new FQLDialogImpl({ + resolve, + name, + result, + questId, + isQuestLog, + title: game.i18n.localize('ForienQuestLog.QuestPreview.Labels.Objective'), + body: 'ForienQuestLog.DeleteDialog.BodyObjective' + }); + + this.#deleteDialog.render(true); + }); + } +} + +/** + * Provides the FQL dialog implementation. + */ +class FQLDialogImpl extends Dialog +{ + /** + * Stores the options specific to the dialog + * + * @type {FQLDialogOptions} + */ + #fqlOptions; + + /** + * @param {FQLDialogOptions} options FQLDialogImpl Options + */ + constructor(options) + { + super(void 0, { minimizable: false, height: 'auto' }); + + this.#fqlOptions = options; + + /** + * The Dialog options to set. + * + * @type {object} + * @see https://foundryvtt.com/api/classes/client.Dialog.html + */ + this.data = { + title: game.i18n.format('ForienQuestLog.DeleteDialog.TitleDel', this.#fqlOptions), + content: `

    ${game.i18n.format('ForienQuestLog.DeleteDialog.HeaderDel', this.#fqlOptions)}

    ` + + `

    ${game.i18n.localize(this.#fqlOptions.body)}

    `, + buttons: { + yes: { + icon: '', + label: game.i18n.localize('ForienQuestLog.DeleteDialog.Delete'), + callback: () => this.#fqlOptions.resolve(this.#fqlOptions.result) + }, + no: { + icon: '', + label: game.i18n.localize('ForienQuestLog.DeleteDialog.Cancel'), + callback: () => this.#fqlOptions.resolve(void 0) + } + } + }; + } + + /** + * Overrides the close action to resolve the cached Promise with undefined. + * + * @returns {Promise} + */ + async close() + { + this.#fqlOptions.resolve(void 0); + return super.close(); + } + + /** + * @returns {boolean} Returns {@link FQLDialogOptions.isQuestLog} from options. + */ + get fqlIsQuestLog() { return this.#fqlOptions.isQuestLog; } + + /** + * @returns {string} Returns {@link FQLDialogOptions.questId} from options. + */ + get fqlQuestId() { return this.#fqlOptions.questId; } + + /** + * Updates the FQLDialogOptions when a dialog is already showing and a successive delete operation is initiated. + * + * Resolves the currently cached Promise with undefined and cache a new Promise which is returned. + * + * @param {FQLDialogOptions} options - The new options to set for Dialog rendering and success return value. + * + * @returns {Promise} The new Promise to await upon. + */ + updateFQLData(options) + { + // Resolve old promise with undefined + this.#fqlOptions.resolve(void 0); + + // Set new options + this.#fqlOptions = options; + + // Create a new Promise that will store the resolve function in this FQLDialogImpl. + const promise = new Promise((resolve) => { this.#fqlOptions.resolve = resolve; }); + + // Update title and content with new data. + this.data.title = game.i18n.format('ForienQuestLog.DeleteDialog.TitleDel', this.#fqlOptions); + this.data.content = `

    ${game.i18n.format('ForienQuestLog.DeleteDialog.HeaderDel', this.#fqlOptions)}

    ` + + `

    ${game.i18n.localize(this.#fqlOptions.body)}

    `; + + // Bring the dialog to top and render again. + this.bringToTop(); + this.render(true); + + // Return the new promise which is resolved from another update with undefined or the dialog confirmation action, + // or the dialog being closed. + return promise; + } +} + +/** + * @typedef FQLDialogOptions + * + * @property {Function} [resolve] - The cached resolve function of the Dialog promise. + * + * @property {string} name - The name of the data being deleted. + * + * @property {result} result - The result to resolve when `OK` is pressed. + * + * @property {string} questId - The associated QuestPreview by quest ID. + * + * @property {boolean} isQuestLog - boolean indicating that the QuestLog owns the dialog. + * + * @property {string} title - The title of the dialog. + * + * @property {string} body - The body language file ID to use for dialog rendering. + */ diff --git a/src/view/internal/FQLDocumentOwnershipConfig.js b/src/view/internal/FQLDocumentOwnershipConfig.js new file mode 100644 index 00000000..65153942 --- /dev/null +++ b/src/view/internal/FQLDocumentOwnershipConfig.js @@ -0,0 +1,33 @@ +/** + * Provides a custom override to DocumentOwnershipConfig enabling GM & trusted player w/ edit capabilities to alter + * quest ownership. The default DocumentOwnershipConfig only allows GM level users permission editing. + * + * When the underlying document / {@link JournalEntry} is updated the {@link QuestDB} will receive this update and + * fire {@link QuestDBHooks} that other parts of FQL can respond to handle as necessary. In particular + * {@link ViewManager} handles these hooks to update the GUI on local and remote clients when ownership change. + */ +export class FQLDocumentOwnershipConfig extends DocumentOwnershipConfig // eslint-disable-line no-undef +{ + /** @override */ + async _updateObject(event, formData) + { + event.preventDefault(); + + // Collect new ownership levels from the form data + const omit = CONST.DOCUMENT_META_OWNERSHIP_LEVELS.DEFAULT; + const ownershipLevels = {}; + + for (const [user, level] of Object.entries(formData)) + { + if (level === omit) + { + delete ownershipLevels[user]; + continue; + } + ownershipLevels[user] = level; + } + + // Update a single Document + return this.document.update({ ownership: ownershipLevels }, { diff: false, recursive: false, noHook: true }); + } +} diff --git a/src/view/internal/index.js b/src/view/internal/index.js new file mode 100644 index 00000000..8ba6c6ab --- /dev/null +++ b/src/view/internal/index.js @@ -0,0 +1,3 @@ +export * from './FQLContextMenu.js'; +export * from './FQLDialog.js'; +export * from './FQLDocumentOwnershipConfig.js'; \ No newline at end of file diff --git a/src/view/log/HandlerLog.js b/src/view/log/HandlerLog.js new file mode 100644 index 00000000..3b4a5681 --- /dev/null +++ b/src/view/log/HandlerLog.js @@ -0,0 +1,99 @@ +import { + QuestDB, + Socket, + ViewManager } from '../../control/index.js'; + +import { QuestAPI } from '../../control/public/index.js'; + +import { Quest } from '../../model/index.js'; + +import { FQLDialog } from '../internal/index.js'; + +/** + * Provides all {@link JQuery} callbacks for the {@link QuestLog}. + */ +export class HandlerLog +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Handles the quest add button. + * + * @returns {Promise} + */ + static async questAdd() + { + if (ViewManager.verifyQuestCanAdd()) + { + const quest = await QuestDB.createQuest(); + ViewManager.questAdded({ quest }); + } + } + + /** + * Handles deleting a quest. The trashcan icon. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @returns {Promise} + */ + static async questDelete(event) + { + const questId = $(event.target).data('quest-id'); + const name = $(event.target).data('quest-name'); + + const result = await FQLDialog.confirmDeleteQuest({ name, result: questId, questId, isQuestLog: true }); + if (result) + { + await QuestDB.deleteQuest({ questId: result }); + } + } + + /** + * Prepares the data transfer when a quest is dragged from the {@link QuestLog}. + * + * @param {JQuery.DragStartEvent} event - JQuery.DragStartEvent + */ + static questDragStart(event) + { + const dataTransfer = { + type: Quest.documentName, + id: $(event.target).data('quest-id') + }; + + event.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(dataTransfer)); + } + + /** + * Handles the quest open click via {@link QuestAPI.open}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + */ + static questOpen(event) + { + const questId = $(event.target)?.closest('.drag-quest')?.data('quest-id'); + QuestAPI.open({ questId }); + } + + /** + * Handles changing the quest status via {@link Socket.setQuestStatus}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @returns {Promise} + */ + static async questStatusSet(event) + { + const target = $(event.target).data('target'); + const questId = $(event.target).data('quest-id'); + + const quest = QuestDB.getQuest(questId); + if (quest) { await Socket.setQuestStatus({ quest, target }); } + } +} \ No newline at end of file diff --git a/src/view/log/QuestLog.js b/src/view/log/QuestLog.js new file mode 100644 index 00000000..ffdda860 --- /dev/null +++ b/src/view/log/QuestLog.js @@ -0,0 +1,320 @@ +import { + QuestDB, + Socket, + Utils } from '../../control/index.js'; + +import { + FQLContextMenu, + FQLDialog } from '../internal/index.js'; + +import { HandlerLog } from './HandlerLog.js'; + +import { + constants, + jquery, + questStatus, + questStatusI18n, + questTabIndex, + settings } from '../../model/constants.js'; + +/** + * Provides the main quest log app which shows the quests separated by status either with bookmark or classic tabs. + * + * In {@link QuestLog.getData} the {@link QuestsCollect} data is retrieved from {@link QuestDB.sortCollect} which + * provides automatic sorting of each quest status category by either {@link SortFunctions.ALPHA} or + * {@link SortFunctions.DATE_END} for status categories {@link questStatus.completed} and {@link questStatus.failed}. + * Several module settings and whether the current user is a GM is also passed back as data to be used in rendering the + * {@link Handlebars} template. + * + * {@link JQuery} control callbacks are setup in {@link QuestLog.activateListeners} and are located in a separate static + * control class {@link HandlerLog}. + */ +export class QuestLog extends Application +{ + /** + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.Application.html + */ + constructor(options = {}) + { + super(options); + } + + /** + * Default Application options + * + * @returns {object} options - Application options. + * @see https://foundryvtt.com/api/classes/client.Application.html#options + */ + static get defaultOptions() + { + return foundry.utils.mergeObject(super.defaultOptions, { + id: constants.moduleName, + classes: [constants.moduleName], + template: 'modules/forien-quest-log/templates/quest-log.html', + width: 700, + height: 480, + minimizable: true, + resizable: true, + title: game.i18n.localize('ForienQuestLog.QuestLog.Title'), + tabs: [{ navSelector: '.log-tabs', contentSelector: '.log-body', initial: 'active' }] + }); + } + + /** + * Specify the set of config buttons which should appear in the Application header. Buttons should be returned as an + * Array of objects. + * + * Provides an explicit override of Application._getHeaderButtons to add one additional buttons for the app header + * for showing the quest log to users via {@link Socket.showQuestLog} + * + * @returns {ApplicationHeaderButton[]} The app header buttons. + * @override + */ + _getHeaderButtons() + { + const buttons = super._getHeaderButtons(); + + // Share QuestLog w/ remote clients. + if (game.user.isGM) + { + buttons.unshift({ + label: game.i18n.localize('ForienQuestLog.Labels.AppHeader.ShowPlayers'), + class: 'share-quest', + icon: 'fas fa-eye', + onclick: () => + { + Socket.showQuestLog(this._tabs[0].active); + } + }); + } + + return buttons; + } + + + /** + * Defines all jQuery control callbacks with event listeners for click, drag, drop via various CSS selectors. + * + * @param {JQuery} html - The jQuery instance for the window content of this Application. + * + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#activateListeners + */ + activateListeners(html) + { + super.activateListeners(html); + + // Here we use a bit of jQuery to retrieve the background image of .window-content to match the game system + // background image for the bookmark tabs. This is only done if the module setting is checked which it is by + // default and the background image actually exists. The fallback is the default parchment image set in the + // FQL styles. + const navStyle = game.settings.get(constants.moduleName, settings.navStyle); + const dynamicBackground = game.settings.get(constants.moduleName, settings.dynamicBookmarkBackground); + if ('bookmarks' === navStyle && dynamicBackground) + { + const windowContent = $('#forien-quest-log .window-content'); + const fqlBookmarkItem = $('#forien-quest-log .item'); + + const backImage = windowContent.css('background-image'); + const backBlendMode = windowContent.css('background-blend-mode'); + const backColor = windowContent.css('background-color'); + + fqlBookmarkItem.css('background-image', backImage); + fqlBookmarkItem.css('background-color', backColor); + fqlBookmarkItem.css('background-blend-mode', backBlendMode); + } + + html.on(jquery.click, '.new-quest-btn', HandlerLog.questAdd); + + html.on(jquery.click, '.actions.quest-status i.delete', HandlerLog.questDelete); + + // This registers for any element and prevents the circle / slash icon displaying for not being a drag target. + html.on(jquery.dragenter, (event) => event.preventDefault()); + + html.on(jquery.dragstart, '.drag-quest', void 0, HandlerLog.questDragStart); + + html.on(jquery.click, '.open-quest', void 0, HandlerLog.questOpen); + + html.on(jquery.click, '.actions.quest-status i.move', HandlerLog.questStatusSet); + + this.#contextMenu(html); + } + + /** + * Handle closing any confirm delete quest dialog attached to QuestLog. + * + * @override + * @inheritDoc + */ + async close(options) + { + FQLDialog.closeDialogs({ isQuestLog: true }); + return super.close(options); + } + + /** + * Create the context menu. There are two separate context menus for the active / in progress tab and all other tabs. + * + * @param {JQuery} html - JQuery element for this application. + */ + #contextMenu(html) + { + const menuItemCopyLink = { + name: 'ForienQuestLog.QuestLog.ContextMenu.CopyEntityLink', + icon: '', + callback: async (menu) => + { + const questId = $(menu)?.closest('.drag-quest')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + + if (quest && await Utils.copyTextToClipboard(`@JournalEntry[${quest.id}]{${quest.name}}`)) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.LinkCopied')); + } + } + }; + + /** + * @type {object[]} + */ + const menuItemsOther = [menuItemCopyLink]; + + /** + * @type {object[]} + */ + const menuItemsActive = [menuItemCopyLink]; + + if (game.user.isGM) + { + const menuItemQuestID = { + name: 'ForienQuestLog.QuestLog.ContextMenu.CopyQuestID', + icon: '', + callback: async (menu) => + { + const questId = $(menu)?.closest('.drag-quest')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + + if (quest && await Utils.copyTextToClipboard(quest.id)) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestIDCopied')); + } + } + }; + + menuItemsActive.push(menuItemQuestID); + menuItemsOther.push(menuItemQuestID); + + menuItemsActive.push({ + name: 'ForienQuestLog.QuestLog.ContextMenu.PrimaryQuest', + icon: '', + callback: (menu) => + { + const questId = $(menu)?.closest('.drag-quest')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + if (quest) { Socket.setQuestPrimary({ quest }); } + } + }); + } + + // Must show two different context menus as only the active / in progress tab potentially has the menu option to + // allow the GM to set the primary quest. + new FQLContextMenu(html, '.tab:not([data-tab="active"]) .drag-quest', menuItemsOther); + new FQLContextMenu(html, '.tab[data-tab="active"] .drag-quest', menuItemsActive); + } + + /** + * Retrieves the sorted quest collection from the {@link QuestDB.sortCollect} and sets several state parameters for + * GM / player / trusted player edit along with several module settings: {@link FQLSettings.allowPlayersAccept}, + * {@link FQLSettings.allowPlayersCreate}, {@link FQLSettings.showTasks} and {@link FQLSettings.navStyle}. + * + * @override + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#getData + */ + async getData(options = {}) + { + return foundry.utils.mergeObject(super.getData(), { + options, + isGM: game.user.isGM, + isPlayer: !game.user.isGM, + isTrustedPlayerEdit: Utils.isTrustedPlayerEdit(), + canAccept: game.settings.get(constants.moduleName, settings.allowPlayersAccept), + canCreate: game.settings.get(constants.moduleName, settings.allowPlayersCreate), + showTasks: game.settings.get(constants.moduleName, settings.showTasks), + style: game.settings.get(constants.moduleName, settings.navStyle), + questStatusI18n, + quests: QuestDB.sortCollect() + }); + } + + /** + * Overrides the internal Application._render method to select the tab if the quest log is rendered with optional: + * `tabId` data that matches an entry in `constants.questStatus`. This comes into play as when a GM uses the + * `show to players` button in the app header as not only will the quest log open for players, but the specific tab + * selected by the GM will show. It is also possible to add `tabId` to the `ForienQuestLog.Open.QuestLog` hook to + * open a specific tab. + * + * @inheritDoc + */ + async _render(force = false, options = {}) + { + await super._render(force, options); + + if (this._state === Application.RENDER_STATES.RENDERED && typeof options.tabId === 'string' && + options.tabId in questStatus) + { + if (options.tabId === questStatus.inactive) + { + // Only switch to inactive tab if GM or trusted player w/ edit. + if (game.user.isGM || Utils.isTrustedPlayerEdit()) { this._tabs[0].activate(options.tabId); } + } + else + { + this._tabs[0].activate(options.tabId); + } + } + } + + /** + * Some game systems and custom UI theming modules provide hard overrides on overflow-x / overflow-y styles. Alas, we + * need to set these for '.window-content' to 'visible' which will cause an issue for very long tables. Thus, we must + * manually set the table max-heights based on the position / height of the {@link Application}. + * + * @param {object} opts - Optional parameters. + * + * @param {number|null} opts.left - The left offset position in pixels. + * + * @param {number|null} opts.top - The top offset position in pixels. + * + * @param {number|null} opts.width - The application width in pixels. + * + * @param {number|string|null} opts.height - The application height in pixels. + * + * @param {number|null} opts.scale - The application scale as a numeric factor where 1.0 is default. + * + * @returns {{left: number, top: number, width: number, height: number, scale:number}} + * The updated position object for the application containing the new values. + */ + setPosition(opts) + { + const currentPosition = super.setPosition(opts); + + // Retrieve all the table elements. + const tableElements = $('#forien-quest-log .table'); + + // Retrieve the active table. + const tabIndex = questTabIndex[this?._tabs[0]?.active]; + const table = tableElements[tabIndex]; + + if (table) + { + const fqlPosition = $('#forien-quest-log')[0].getBoundingClientRect(); + const tablePosition = table.getBoundingClientRect(); + + // Manually calculate the max height for the table based on the position of the main window div and table. + tableElements.css('max-height', `${currentPosition.height - (tablePosition.top - fqlPosition.top + 16)}px`); + } + + return currentPosition; + } +} diff --git a/src/view/preview/HandlerAny.js b/src/view/preview/HandlerAny.js new file mode 100644 index 00000000..e433397d --- /dev/null +++ b/src/view/preview/HandlerAny.js @@ -0,0 +1,70 @@ +import { + QuestDB, + Socket } from '../../control/index.js'; + +import { QuestAPI } from '../../control/public/index.js'; + +import { FQLDialog } from '../internal/index.js'; + +/** + * These handler {@link JQuery} callbacks can be called on any tab. + */ +export class HandlerAny +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Confirms deleting a quest with {@link FQLDialog.confirmDeleteQuest} before invoking {@link QuestDB.deleteQuest}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @returns {Promise} + */ + static async questDelete(event, quest) + { + const questId = $(event.target).data('quest-id'); + const name = $(event.target).data('quest-name'); + + const result = await FQLDialog.confirmDeleteQuest({ name, result: questId, questId: quest.id }); + if (result) + { + await QuestDB.deleteQuest({ questId: result }); + } + } + + /** + * Opens a {@link QuestPreview} via {@link QuestAPI.open}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent. + */ + static questOpen(event) + { + const questId = $(event.currentTarget).data('quest-id'); + QuestAPI.open({ questId }); + } + + /** + * Potentially sets a new {@link Quest.status} via {@link Socket.setQuestStatus}. If the current user is not a GM + * a GM level user must be logged in for a successful completion of the set status operation. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @returns {Promise} + */ + static async questStatusSet(event) + { + const target = $(event.target).data('target'); + const questId = $(event.target).data('quest-id'); + + const quest = QuestDB.getQuest(questId); + if (quest) { await Socket.setQuestStatus({ quest, target }); } + } +} \ No newline at end of file diff --git a/src/view/preview/HandlerDetails.js b/src/view/preview/HandlerDetails.js new file mode 100644 index 00000000..e6c6481f --- /dev/null +++ b/src/view/preview/HandlerDetails.js @@ -0,0 +1,1081 @@ +import { + Socket, + Utils } from '../../control/index.js'; + +import { Quest } from '../../model/index.js'; + +import { FQLDialog } from '../internal/index.js'; + +import { + constants, + jquery, + settings } from '../../model/constants.js'; + +/** + * Provides all {@link JQuery} callbacks for the `details` tab. + */ +export class HandlerDetails +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent. + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static questEditName(event, quest, questPreview) + { + const target = $(event.target).data('target'); + + let value = quest[target]; + + value = value.replace(/"/g, '"'); + + const input = $(``); + + const parent = $(event.target).closest('.actions-single').prev('.editable-container'); + + parent.html(''); + parent.append(input); + input.trigger(jquery.focus); + + // If the HTMLElement has setSelectionRange then set cursor to the end. + if (input[0]?.setSelectionRange) { input[0].setSelectionRange(value.length, value.length); } + + /** + * Store the input focus callback in the associated QuestPreview instance so that it can be invoked if the app is + * closed in {@link QuestPreview.close} while the input field is focused / being edited allowing any edits to be + * saved. Otherwise the callback is invoked normally below as part of the input focus out event. + * + * @param {JQuery.FocusOutEvent|void} event - JQuery.FocusOutEvent + * + * @param {object} saveOptions - Options to pass to `saveQuest`; used in {@link QuestPreview.close}. + * + * @returns {Promise} + * @package + * + * @see QuestPreview.close + * @see QuestPreview._activeFocusOutFunction + */ + questPreview._activeFocusOutFunction = async (event, saveOptions = void 0) => + { + const valueOut = input.val(); + questPreview._activeFocusOutFunction = void 0; + + switch (target) + { + case 'name': + quest.name = valueOut; + questPreview.options.title = game.i18n.format('ForienQuestLog.QuestPreview.Title', quest); + break; + } + await questPreview.saveQuest(saveOptions); + }; + + input.on(jquery.focusout, questPreview._activeFocusOutFunction); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview._activeFocusOutFunction = void 0; + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static questGiverCustomEditName(event, quest, questPreview) + { + const target = $(event.target).data('target'); + + let value = quest[target]; + + value = value.replace(/"/g, '"'); + + const input = $(``); + + const parent = $(event.target).closest('.actions-single').prev('.editable-container'); + + parent.css('flex', '0 0 230px'); + parent.html(''); + parent.append(input); + input.trigger(jquery.focus); + + // If the HTMLElement has setSelectionRange then set cursor to the end. + if (input[0]?.setSelectionRange) { input[0].setSelectionRange(value.length, value.length); } + + /** + * Store the input focus callback in the associated QuestPreview instance so that it can be invoked if the app is + * closed in {@link QuestPreview.close} while the input field is focused / being edited allowing any edits to be + * saved. Otherwise the callback is invoked normally below as part of the input focus out event. + * + * @param {JQuery.FocusOutEvent|void} event - JQuery.FocusOutEvent + * + * @param {object} saveOptions - Options to pass to `saveQuest`; used in {@link QuestPreview.close}. + * + * @returns {Promise} + * @package + * + * @see QuestPreview.close + * @see QuestPreview._activeFocusOutFunction + */ + questPreview._activeFocusOutFunction = async (event, saveOptions = void 0) => + { + const valueOut = input.val(); + questPreview._activeFocusOutFunction = void 0; + + switch (target) + { + case 'giverName': + quest.giverName = valueOut; + if (typeof quest.giverData === 'object') { quest.giverData.name = valueOut; } + questPreview.options.title = game.i18n.format('ForienQuestLog.QuestPreview.Title', quest); + await questPreview.saveQuest(saveOptions); + break; + } + }; + + input.on(jquery.focusout, questPreview._activeFocusOutFunction); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview._activeFocusOutFunction = void 0; + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static questGiverCustomSelectImage(quest, questPreview) + { + const currentPath = quest.giver === 'abstract' ? quest.image : void 0; + + new FilePicker({ + type: 'image', + current: currentPath, + callback: async (path) => + { + quest.giver = 'abstract'; + quest.image = path; + quest.giverName = game.i18n.localize('ForienQuestLog.QuestPreview.Labels.CustomSource'); + quest.giverData = await Quest.giverFromQuest(quest); + delete quest.giverData.uuid; + + await questPreview.saveQuest(); + }, + }).browse(currentPath); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async questGiverDelete(quest, questPreview) + { + quest.resetGiver(); + return questPreview.saveQuest(); + } + + /** + * @param {JQuery.DropEvent} event - JQuery.DropEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async questGiverDropDocument(event, quest, questPreview) + { + event.preventDefault(); + + let data; + + try + { + data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); + } + catch (err) + { + console.warn(`ForienQuestLog HandlerDetails.questGiverDropDocument warning: failed to parse data transfer`); + } + + const uuid = Utils.getUUID(data, ['Actor', 'Item', 'JournalEntry']); + + if (typeof uuid === 'string') + { + const giverData = await Quest.giverFromUUID(uuid); + if (giverData) + { + quest.giver = uuid; + quest.giverData = giverData; + await questPreview.saveQuest(); + } + else + { + ui.notifications.warn(game.i18n.format('ForienQuestLog.QuestPreview.Notifications.BadUUID', { uuid })); + } + } + else + { + // Slightly awkward as we need to check if this is an actor owned item specifically. + if (typeof data?.uuid === 'string' && + data.uuid.startsWith('Actor') && (data.uuid.match(/\./g) || []).length > 1) + { + ui.notifications.warn(game.i18n.localize('ForienQuestLog.QuestPreview.Notifications.WrongDocType')); + } + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async questGiverShowActorSheet(event, questPreview) + { + const uuid = $(event.target).data('actor-uuid'); + + if (typeof uuid === 'string' && uuid.length) + { + const appId = await Utils.showSheetFromUUID(uuid, { editable: false }); + + // If a new sheet is rendered push it to the opened appIds. + if (appId && !questPreview._openedAppIds.includes(appId)) { questPreview._openedAppIds.push(appId); } + } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async questGiverToggleImage(quest, questPreview) + { + quest.toggleImage(); + + const giverData = await Quest.giverFromQuest(quest); + if (giverData) + { + quest.giverData = giverData; + await questPreview.saveQuest(); + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static rewardAbstractEditName(event, quest, questPreview) + { + const target = $(event.target).data('target'); + + let value = quest[target]; + let uuidv4; + + if (target === 'reward.name') + { + uuidv4 = $(event.target).data('uuidv4'); + + const reward = quest.getReward(uuidv4); + if (!reward) { return; } + + value = reward.name; + } + + value = value.replace(/"/g, '"'); + + const input = $(``); + + // This consumes any clicks on the input element preventing the abstract reward image popup from showing when + // clicking on the input element. + input.on(jquery.click, (event) => { event.stopImmediatePropagation(); }); + + const parent = $(event.target).closest('.actions').prev('.editable-container'); + + parent.html(''); + parent.append(input); + input.trigger(jquery.focus); + + // If the HTMLElement has setSelectionRange then set cursor to the end. + if (input[0]?.setSelectionRange) { input[0].setSelectionRange(value.length, value.length); } + + /** + * Store the input focus callback in the associated QuestPreview instance so that it can be invoked if the app is + * closed in {@link QuestPreview.close} while the input field is focused / being edited allowing any edits to be + * saved. Otherwise the callback is invoked normally below as part of the input focus out event. + * + * @param {JQuery.FocusOutEvent|void} event - JQuery.FocusOutEvent + * + * @param {object} saveOptions - Options to pass to `saveQuest`; used in {@link QuestPreview.close}. + * + * @returns {Promise} + * @package + * + * @see QuestPreview.close + * @see QuestPreview._activeFocusOutFunction + */ + questPreview._activeFocusOutFunction = async (event, saveOptions = void 0) => + { + const valueOut = input.val(); + questPreview._activeFocusOutFunction = void 0; + + switch (target) + { + case 'reward.name': + { + uuidv4 = input.data('uuidv4'); + const reward = quest.getReward(uuidv4); + if (!reward) { return; } + + reward.data.name = valueOut; + await questPreview.saveQuest(saveOptions); + break; + } + } + }; + + input.on(jquery.focusout, questPreview._activeFocusOutFunction); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview._activeFocusOutFunction = void 0; + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * Creates a new abstract reward if the input entry is successful or contains data and a focus out event occurs. + * + * The module setting: {@link FQLSettings.defaultAbstractRewardImage} stores the default abstract reward image. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static rewardAddAbstract(event, quest, questPreview) + { + const li = $('
  • '); + + const input = $(``); + + const box = $(event.target).closest('.quest-rewards').find('.rewards-box ul'); + + li.append(input); + box.append(li); + + input.trigger(jquery.focus); + + input.on(jquery.focusout, async (event) => + { + const value = $(event.target).val(); + if (value !== void 0 && value.length) + { + quest.addReward({ + data: { + name: value, + img: game.settings.get(constants.moduleName, settings.defaultAbstractRewardImage) + }, + hidden: true, + type: 'Abstract' + }); + } + await questPreview.saveQuest(); + }); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardDelete(event, quest, questPreview) + { + const target = $(event.target); + const uuidv4 = target.data('uuidv4'); + const name = target.data('reward-name'); + + // Await a semi-modal dialog. + const result = await FQLDialog.confirmDeleteReward({ name, result: uuidv4, questId: quest.id }); + if (result) + { + quest.removeReward(result); + + await questPreview.saveQuest(); + } + } + + /** + * @param {JQuery.DragStartEvent} event - JQuery.DragStartEvent + * + * @param {Quest} quest - The current quest being manipulated. + */ + static async rewardDragStartItem(event, quest) + { + const data = $(event.target).data('transfer'); + + const document = await Utils.getDocumentFromUUID(data, { permissionCheck: false }); + if (document) + { + const uuidData = Utils.getDataFromUUID(data); + + /** + * @type {RewardDropData} + */ + const dataTransfer = { + _fqlData: { + type: 'reward', + questId: quest.id, + uuidv4: data.uuidv4, + itemName: data.name, + userName: game.user.name, + }, + type: 'Item', + uuid: data.uuid, + id: document.id + }; + + // Add compendium pack info if applicable. + if (uuidData && uuidData.pack) { dataTransfer.pack = uuidData.pack; } + + event.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(dataTransfer)); + } + } + + /** + * @param {JQuery.DragStartEvent} event - JQuery.DragStartEvent + */ + static rewardDragStartSort(event) + { + event.stopPropagation(); + + const li = event.target.closest('li') || null; + if (!li) { return; } + + const dataTransfer = { + type: 'Reward', + mode: 'Sort', + uuidv4: $(li).data('uuidv4') + }; + event.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(dataTransfer)); + } + + /** + * Handles an external item reward drop. Also handles the sort reward item drop. + * + * @param {JQuery.DropEvent} event - JQuery.DropEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardDropItem(event, quest, questPreview) + { + event.preventDefault(); + + let data; + try + { + data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); + } + catch (e) + { + return; + } + + if (data?.mode === 'Sort' && data?.type === 'Reward') + { + const dt = event.target.closest('li.reward') || null; + quest.sortRewards(data.uuidv4, dt?.dataset.uuidv4); + await quest.save(); + Socket.refreshQuestPreview({ questId: quest.id }); + } + + if (data?._fqlData !== void 0) { return; } + + if (data?.type === 'Actor') + { + const uuid = Utils.getUUID(data); + + if (typeof uuid === 'string') + { + const actor = await Quest.giverFromUUID(uuid); + if (actor) + { + quest.addReward({ type: 'Actor', data: actor, hidden: true }); + await questPreview.saveQuest(); + } + else + { + ui.notifications.warn(game.i18n.format('ForienQuestLog.QuestPreview.Notifications.BadUUID', { uuid })); + } + } + } + else if (data?.type === 'Item') + { + const uuid = Utils.getUUID(data); + + if (typeof uuid === 'string') + { + const item = await Quest.giverFromUUID(uuid); + if (item) + { + quest.addReward({ type: 'Item', data: item, hidden: true }); + await questPreview.saveQuest(); + } + else + { + ui.notifications.warn(game.i18n.format('ForienQuestLog.QuestPreview.Notifications.BadUUID', { uuid })); + } + } + else + { + // Slightly awkward as we need to check if this is an actor owned item specifically. + if (typeof data?.uuid === 'string' && + data.uuid.startsWith('Actor') && (data.uuid.match(/\./g) || []).length > 1) + { + ui.notifications.warn(game.i18n.localize('ForienQuestLog.QuestPreview.Notifications.WrongItemType')); + } + } + } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardsHideAll(quest, questPreview) + { + for (const reward of quest.rewards) { reward.hidden = true; } + if (quest.rewards.length) { await questPreview.saveQuest(); } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardsLockAll(quest, questPreview) + { + for (const reward of quest.rewards) { reward.locked = true; } + if (quest.rewards.length) { await questPreview.saveQuest(); } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardSelectImage(event, quest, questPreview) + { + const uuidv4 = $(event.target).data('uuidv4'); + + let reward = quest.getReward(uuidv4); + if (!reward) { return; } + + const currentPath = reward.data.img; + await new FilePicker({ + type: 'image', + current: currentPath, + callback: async (path) => + { + reward = quest.getReward(uuidv4); + if (reward) + { + reward.data.img = path; + await questPreview.saveQuest(); + } + }, + }).browse(currentPath); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardsShowAll(quest, questPreview) + { + for (const reward of quest.rewards) { reward.hidden = false; } + if (quest.rewards.length) { await questPreview.saveQuest(); } + } + + /** + * If an abstract reward has an image set then show an image popout. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent. + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardShowImagePopout(event, quest, questPreview) + { + // Check the event target and make sure it is `p.reward-name` otherwise early out. + if (event.target && !$(event.target).is('p.reward-name')) { return; } + + event.stopPropagation(); + + const uuidv4 = $(event.currentTarget).data('uuidv4'); + + const reward = quest.getReward(uuidv4); + + if (reward && (questPreview.canEdit || !reward.locked)) + { + if (questPreview._rewardImagePopup !== void 0 && questPreview._rewardImagePopup.rendered) + { + if (reward.data?.img?.length) + { + questPreview._rewardImagePopup.object = reward.data.img; + questPreview._rewardImagePopup.render(true); + questPreview._rewardImagePopup.bringToTop(); + } + } + else + { + if (reward.data?.img?.length) + { + questPreview._rewardImagePopup = new ImagePopout(reward.data.img, { shareable: true }); + questPreview._rewardImagePopup.render(true); + } + } + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent. + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardShowSheet(event, quest, questPreview) + { + event.stopPropagation(); + const data = $(event.currentTarget).data('transfer'); + const uuidv4 = $(event.currentTarget).data('uuidv4'); + + const reward = quest.getReward(uuidv4); + + if (reward && (questPreview.canEdit || !reward.locked)) + { + const appId = await Utils.showSheetFromUUID(data, { permissionCheck: false, editable: false }); + + // If a new sheet is rendered push it to the opened appIds. + if (appId && !questPreview._openedAppIds.includes(appId)) { questPreview._openedAppIds.push(appId); } + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardToggleHidden(event, quest, questPreview) + { + const uuidv4 = $(event.target).data('uuidv4'); + const reward = quest.getReward(uuidv4); + if (reward) + { + reward.toggleVisible(); + await questPreview.saveQuest(); + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardToggleLocked(event, quest, questPreview) + { + const uuidv4 = $(event.target).data('uuidv4'); + const reward = quest.getReward(uuidv4); + if (reward) + { + reward.toggleLocked(); + await questPreview.saveQuest(); + } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async rewardsUnlockAll(quest, questPreview) + { + for (const reward of quest.rewards) { reward.locked = false; } + if (quest.rewards.length) { await questPreview.saveQuest(); } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static async splashImagePopupShow(quest, questPreview) + { + if (questPreview._splashImagePopup !== void 0 && questPreview._splashImagePopup.rendered) + { + questPreview._splashImagePopup.bringToTop(); + } + else + { + questPreview._splashImagePopup = new ImagePopout(quest.splash, { shareable: true }); + questPreview._splashImagePopup.render(true); + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static taskAdd(event, quest, questPreview) + { + event.preventDefault(); + + const li = $('
  • '); + + const placeholder = $(''); + + const input = $(``); + + const box = $(event.target).closest('.quest-tasks').find('.tasks-box ul'); + + li.append(placeholder); + li.append(input); + box.append(li); + + input.trigger(jquery.focus); + + input.on(jquery.focusout, async (event) => + { + const value = $(event.target).val(); + if (value !== void 0 && value.length) + { + quest.addTask({ name: value, hidden: questPreview.canEdit }); + } + await questPreview.saveQuest(); + }); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async taskDelete(event, quest, questPreview) + { + const target = $(event.target); + const uuidv4 = target.data('uuidv4'); + const name = target.data('task-name'); + + const result = await FQLDialog.confirmDeleteTask({ name, result: uuidv4, questId: quest.id }); + if (result) + { + quest.removeTask(result); + + await questPreview.saveQuest(); + } + } + + /** + * @param {JQuery.DragStartEvent} event - JQuery.DragStartEvent + */ + static taskDragStartSort(event) + { + event.stopPropagation(); + + const li = event.target.closest('li') || null; + if (!li) { return; } + + const dataTransfer = { + type: 'Task', + mode: 'Sort', + uuidv4: $(li).data('uuidv4') + }; + + event.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(dataTransfer)); + } + + /** + * @param {JQuery.DropEvent} event - JQuery.DropEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @returns {Promise} + */ + static async taskDropItem(event, quest) + { + event.preventDefault(); + + let data; + try + { + data = JSON.parse(event.originalEvent.dataTransfer.getData('text/plain')); + } + catch (e) + { + return; + } + + if (data?.mode === 'Sort' && data?.type === 'Task') + { + const dt = event.target.closest('li.task') || null; + quest.sortTasks(data.uuidv4, dt?.dataset.uuidv4); + await quest.save(); + Socket.refreshQuestPreview({ questId: quest.id }); + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + */ + static taskEditName(event, quest, questPreview) + { + const target = $(event.target).data('target'); + let uuidv4 = $(event.target).data('uuidv4'); + let task = quest.getTask(uuidv4); + + // Early out conditional if the target isn't `task.name` or the task doesn't exist. + if (target === void 0 || target !== 'task.name' || !task) { return; } + + let value = task.name; + + value = value.replace(/"/g, '"'); + + const input = $(``); + + const parent = $(event.target).closest('.actions').prev('.editable-container'); + + parent.html(''); + parent.append(input); + input.trigger(jquery.focus); + + // If the HTMLElement has setSelectionRange then set cursor to the end. + if (input[0]?.setSelectionRange) { input[0].setSelectionRange(value.length, value.length); } + + /** + * Store the input focus callback in the associated QuestPreview instance so that it can be invoked if the app is + * closed in {@link QuestPreview.close} while the input field is focused / being edited allowing any edits to be + * saved. Otherwise the callback is invoked normally below as part of the input focus out event. + * + * @param {JQuery.FocusOutEvent|void} event -JQuery.FocusOutEvent + * + * @param {object} saveOptions - Options to pass to `saveQuest`; used in {@link QuestPreview.close}. + * + * @returns {Promise} + * @protected + * @see QuestPreview.close + * @see QuestPreview._activeFocusOutFunction + */ + questPreview._activeFocusOutFunction = async (event, saveOptions = void 0) => + { + const valueOut = input.val(); + questPreview._activeFocusOutFunction = void 0; + + switch (target) + { + case 'task.name': + { + uuidv4 = input.data('uuidv4'); + task = quest.getTask(uuidv4); + if (task) + { + task.name = valueOut; + await questPreview.saveQuest(saveOptions); + } + break; + } + } + }; + + input.on(jquery.focusout, questPreview._activeFocusOutFunction); + input.on(jquery.keydown, (event) => + { + // Handle `Esc` key down to cancel editing. + if (event.which === 27) + { + questPreview._activeFocusOutFunction = void 0; + questPreview.render(true, { focus: true }); + return false; + } + }); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async taskToggleHidden(event, quest, questPreview) + { + const uuidv4 = $(event.target).data('uuidv4'); + const task = quest.getTask(uuidv4); + if (task) + { + task.toggleVisible(); + await questPreview.saveQuest(); + } + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async taskToggleState(event, quest, questPreview) + { + const uuidv4 = $(event.target).data('uuidv4'); + + const task = quest.getTask(uuidv4); + if (task) + { + task.toggle(); + await questPreview.saveQuest(); + } + } +} + +/** + * @typedef {object} FQLDropData An object attached to drop data transfer which describes the FQL reward item and who + * is dropping it into an actor sheet. + * + * @property {string} type - The type of FQL drop data; one of: ['reward'] + * + * @property {string} questId - The Quest ID + * + * @property {string} uuidv4 - The associated UUIDv4 of a quest reward. + * + * @property {string} itemName - The reward item name. + * + * @property {string} userName - The username who is dropping the item. + */ + +/** + * @typedef {object} RewardDropData + * + * @property {FQLDropData} _fqlData - FQL drop data used to remove the reward from a quest. + * + * @property {string} type - Type of document. + * + * @property {object} [data] - Document data on V9 + * + * @property {string} uuid - The UUID of the document. + * + * @property {id} id - The ID of the document. + * + * @property {string} [pack] - Any associated compendium pack. + */ diff --git a/src/view/preview/HandlerManage.js b/src/view/preview/HandlerManage.js new file mode 100644 index 00000000..1d40e755 --- /dev/null +++ b/src/view/preview/HandlerManage.js @@ -0,0 +1,139 @@ +import { + QuestDB, + ViewManager } from '../../control/index.js'; + +import { FQLDocumentOwnershipConfig } from '../internal/index.js'; + +/** + * Provides all {@link JQuery} callbacks for the `management` tab. + */ +export class HandlerManage +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async addSubquest(quest, questPreview) + { + // If a permission control app / dialog is open close it. + if (questPreview._ownershipControl) + { + questPreview._ownershipControl.close(); + questPreview._ownershipControl = void 0; + } + + if (ViewManager.verifyQuestCanAdd()) + { + const subquest = await QuestDB.createQuest({ parentId: quest.id }); + ViewManager.questAdded({ quest: subquest }); + } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async configurePermissions(quest, questPreview) + { + if (quest.entry) + { + if (!questPreview._ownershipControl) + { + questPreview._ownershipControl = new FQLDocumentOwnershipConfig(quest.entry, { + top: Math.min(questPreview.position.top, window.innerHeight - 350), + left: questPreview.position.left + 125 + }).render(true, { focus: true }); + } + + questPreview._ownershipControl.render(true, { + top: Math.min(questPreview.position.top, window.innerHeight - 350), + left: questPreview.position.left + 125, + focus: true + }); + } + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async deleteSplashImage(quest, questPreview) + { + quest.splash = ''; + await questPreview.saveQuest(); + } + + /** + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async setSplashAsIcon(event, quest, questPreview) + { + quest.splashAsIcon = $(event.target).is(':checked'); + await questPreview.saveQuest(); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async setSplashImage(quest, questPreview) + { + const currentPath = quest.splash; + await new FilePicker({ + type: 'image', + current: currentPath, + callback: async (path) => + { + quest.splash = path; + await questPreview.saveQuest(); + }, + }).browse(currentPath); + } + + /** + * @param {Quest} quest - The current quest being manipulated. + * + * @param {QuestPreview} questPreview - The QuestPreview being manipulated. + * + * @returns {Promise} + */ + static async setSplashPos(quest, questPreview) + { + if (quest.splashPos === 'center') + { + quest.splashPos = 'top'; + } + else + { + quest.splashPos = quest.splashPos === 'top' ? 'bottom' : 'center'; + } + + await questPreview.saveQuest(); + } +} \ No newline at end of file diff --git a/src/view/preview/QuestPreview.js b/src/view/preview/QuestPreview.js new file mode 100644 index 00000000..82b43dc1 --- /dev/null +++ b/src/view/preview/QuestPreview.js @@ -0,0 +1,723 @@ +import { + FVTTCompat, + QuestDB, + Socket, + Utils } from '../../control/index.js'; + +import { FQLDialog } from '../internal/index.js'; + +import { HandlerAny } from './HandlerAny.js'; +import { HandlerDetails } from './HandlerDetails.js'; +import { HandlerManage } from './HandlerManage.js'; + +import { + constants, + jquery, + settings } from '../../model/constants.js'; + +/** + * QuestPreview is the main app / window of FQL for modifying individual Quest data. It appears reactive, but every + * single time a data value is manipulated in the quest it is saved and this app renders again. There are many cases + * when parent and subquests of the current quest also requires those QuestPreviews if visible and the {@link QuestLog} + * to be rendered again. Additionally, for remote clients socket events are broadcast to all users logged in to Foundry + * in the same world. This is facilitated through {@link Socket} which controls local rendering and remote rendering. + * In the future it will be possible to reduce reliance on {@link Socket} as the {@link QuestDB} has many lifecycle + * hooks, {@link QuestDBHooks} which can replace manual control aspects found in {@link Socket}. + * + * QuestPreview is the {@link Quest} sheet in Foundry parlance. In {@link FQLHooks.foundryInit} QuestPreview is set as + * the Quest sheet. All Quests are opened through this reference in Quest which is accessible by {@link Quest.sheet} + * + * The main source of QuestPreview creation is through {@link QuestAPI.open}. Both Socket, QuestLog and external + * API usage invokes `QuestAPI.open`. The constructor of QuestPreview requires a Quest and passes on options to t + * the FormApplication. + * + * The {@link JQuery} control handling of callbacks is facilitated through three separate static control classes and + * are setup in {@link QuestPreview.activateListeners}. Two of the control classes {@link HandlerDetails} and + * {@link HandlerManage} contain {@link JQuery} callbacks specific to the `details` and `management` tabs visible for GM + * users and trusted players with ownership permissions when the module setting {@link FQLSettings.trustedPlayerEdit} is + * enabled. {@link HandlerAny} contains callbacks utilized across both `details` and `management` tabs particularly + * around handling the action icons for manipulating the quest tasks. + * + * In {@link QuestPreview.getData} the cached {@link EnrichData} from {@link QuestDB} of the associated {@link Quest} + * is used in rendering the {@link Handlebars} template. + * + * It is worth noting that all internal array data such as tasks and rewards from {@link Quest} a separate + * `UUIDv4` identifier which provides a unique ID for each {@link Task} and {@link Reward}. Tasks and Rewards that are + * manipulated in Quest use this UUIDv4 value passed through the template via the enriched data of a quest. As part of + * the caching process of {@link QuestDB} {@link QuestEntry} instances are stored with both the Quest and enriched data + * from {@link Enrich.quest}. + * + * In {@link QuestPreview.getData} several local variables are set that are utilized both in the Handlebars template + * rendering process and in {@link QuestPreview.activateListeners} to assign certain capabilities that are accessible + * to the user. The GM and trusted players with edit capabilities have full access to editing all parameters of a quest + * except no players have access to the GM notes tab which is for private notes for the GM only. + * + * The general control of Foundry when {@link https://foundryvtt.com/api/classes/client.Application.html#render} is invoked goes as + * follows: + * - {@link QuestPreview.getData} prepares all data for the Handlebars template and sets the local user tracking + * variables. + * + * - {@link QuestPreview.activateListeners} Receives a jQuery element for the window content of the app and is where + * all the control callbacks are registered. + * + * In the handler callbacks for the delete action for quests, tasks, & rewards a special semi-modal dialog is invoked + * via {@link FQLDialog}. A single instance of it is rendered and reused across all delete actions. Please refer to the + * documentation. + * + * {@link ViewManager} responds to `closeQuestPreview` and `renderQuestPreview` tracking the opened QuestPreview + * instances. + * + * @see HandlerAny + * @see HandlerDetails + * @see HandlerManage + */ +export class QuestPreview extends FormApplication +{ + /** + * Stores the quest being displayed / edited. + * + * @type {Quest} + */ + #quest; + + /** + * Constructs a QuestPreview instance with a Quest and passes on options to FormApplication. + * + * @param {Quest} quest - The quest to preview / edit. + * + * @param {object} options - The FormApplication options. + * + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#options + */ + constructor(quest, options = {}) + { + super(void 0, options); + + this.#quest = quest; + + // Set the title of the FormApplication with the quest name. + this.options.title = game.i18n.format('ForienQuestLog.QuestPreview.Title', this.#quest); + + /** + * Set in `getData`. Determines if the player can accept quests which for non-GM / trusted players w/ edit allows + * a minimal set of options to set quests as `available` or `active`. + * + * @type {boolean} + * @package + * + * @see QuestPreview.getData + */ + this.canAccept = false; + + /** + * Set in `getData`. Determines if the current user can fully edit the Quest; a GM or trusted player w/ edit. + * + * @type {boolean} + * @package + * + * @see QuestPreview.getData + */ + this.canEdit = false; + + /** + * Set in `getData`. Determines if the player has ownership of the quest and thereby limited editing capabilities. + * + * @type {boolean} + * @package + * + * @see QuestPreview.getData + */ + this.playerEdit = false; + + /** + * Store the input focus callback in the associated QuestPreview instance so that it can be invoked if the app is + * closed in {@link QuestPreview.close} while the input field is focused / being edited allowing any edits to be + * saved. Otherwise the callback is invoked as part of the input focus out event in the jQuery handler. Please + * see the associated jQuery callback methods in {@link HandlerDetails} linked below. + * + * @param {JQuery.FocusOutEvent|void} event - JQuery.FocusOutEvent + * + * @param {object} [saveOptions] - Options to pass to `saveQuest`; used in {@link QuestPreview.close}. + * + * @returns {Promise} + * + * @type {Function} + * @package + * + * @see HandlerDetails.questEditName + * @see HandlerDetails.questGiverCustomEditName + * @see HandlerDetails.rewardAbstractEditName + * @see HandlerDetails.taskEditName + */ + this._activeFocusOutFunction = void 0; + + /** + * Tracks all opened sheets whether quest giver actor sheet or reward items. Close all sheets when QuestPreview + * closes. + * + * @type {number[]} + * @package + */ + this._openedAppIds = []; + + /** + * Tracks any open FQLPermissionControl dialog that can be opened from the management tab, so that it can be + * closed if this QuestPreview is closed or the tab is changed. + * + * @type {FQLDocumentOwnershipConfig} + * @package + * + * @see HandlerManage.configurePermissions + * @see QuestPreview.close + */ + this._ownershipControl = void 0; + + /** + * Stores a single instance of the ImagePopup for the abstract reward image opened in + * {@link HandlerDetails.rewardShowImagePopout} preventing multiple copies of reward images from being opened + * at the same time. If open this ImagePopup is also closed when this QuestPreview closes in + * {@link QuestPreview.close}. + * + * @type {ImagePopout} + * @package + * + * @see https://foundryvtt.com/api/classes/client.ImagePopout.html + */ + this._rewardImagePopup = void 0; + + /** + * Stores a single instance of the ImagePopup for the splash image opened in + * {@link HandlerDetails.splashImagePopupShow} preventing multiple copies of the splash image from being opened + * at the same time. If open this ImagePopup is also closed when this QuestPreview closes in + * {@link QuestPreview.close}. + * + * @type {ImagePopout} + * @package + * + * @see https://foundryvtt.com/api/classes/client.ImagePopout.html + */ + this._splashImagePopup = void 0; + } + + /** + * Default Application options + * + * @returns {object} options - FormApplication options. + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#options + */ + static get defaultOptions() + { + return foundry.utils.mergeObject(super.defaultOptions, { + classes: ['forien-quest-preview'], + template: 'modules/forien-quest-log/templates/quest-preview.html', + width: 1000, + height: 640, + minimizable: true, + resizable: true, + submitOnChange: false, + submitOnClose: false, + title: game.i18n.localize('ForienQuestLog.QuestPreview.Title'), + tabs: [{ navSelector: '.quest-tabs', contentSelector: '.quest-body', initial: 'details' }] + }); + } + + /** + * Returns the CSS application ID which uniquely references this UI element. + * + * @returns {string} The CSS app ID. + * @override + */ + get id() + { + return `quest-${this.#quest.id}`; + } + + /** + * Returns the associated Quest as the FormApplication target object. + * + * @returns {Quest} The FormApplication target object. + * @override + */ + get object() + { + return this.#quest; + } + + /** + * Prevent setting of the FormApplication target object. + * + * @param {object} value - Ignored + * + * @override + */ + set object(value) {} + + /** + * Specify the set of config buttons which should appear in the Application header. Buttons should be returned as an + * Array of objects. + * + * Provides an explicit override of Application._getHeaderButtons to add three additional buttons for the app header + * including copying the content link for the Quest, showing the quest to users via {@link Socket.showQuestPreview} + * and showing the splash image popup. + * + * @returns {ApplicationHeaderButton[]} The app header buttons. + * @override + */ + _getHeaderButtons() + { + const buttons = super._getHeaderButtons(); + + // Share QuestPreview w/ remote clients. + if (game.user.isGM) + { + buttons.unshift({ + label: game.i18n.localize('ForienQuestLog.Labels.AppHeader.ShowPlayers'), + class: 'share-quest', + icon: 'fas fa-eye', + onclick: () => Socket.showQuestPreview(this.#quest.id) + }); + } + + // Show splash image popup if splash image is defined. + if (this.#quest.splash.length) + { + buttons.unshift({ + label: '', + class: 'splash-image', + icon: 'far fa-image', + onclick: async () => + { + // Only show popup if a splash image is defined. + if (this.#quest.splash.length) + { + await HandlerDetails.splashImagePopupShow(this.#quest, this); + } + } + }); + } + + // Copy quest content link. + buttons.unshift({ + label: '', + class: 'copy-link', + icon: 'fas fa-link', + onclick: async () => + { + if (await Utils.copyTextToClipboard(`@JournalEntry[${this.#quest.id}]{${this.#quest.name}}`)) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.LinkCopied')); + } + } + }); + + return buttons; + } + + /** + * Close any tracked permission control app / dialog when tabs change. + * + * @protected + * @inheritDoc + */ + _onChangeTab(event, tabs, active) + { + if (this._ownershipControl) + { + this._ownershipControl.close(); + this._ownershipControl = void 0; + } + + super._onChangeTab(event, tabs, active); + } + + /** + * This might be a FormApplication, but we don't want the submit event to fire. + * + * @protected + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#_onSubmit + */ + async _onSubmit(event, options) // eslint-disable-line + { + event.preventDefault(); + return false; + } + + /** + * This method is called upon form submission after form data is validated. The default _updateObject workflow + * is prevented. + * + * @override + * @protected + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#_updateObject + */ + async _updateObject(event, formData) // eslint-disable-line no-unused-vars + { + event.preventDefault(); + } + + /** + * Returns the associated {@link Quest} + * + * @returns {Quest} Associated Quest. + */ + get quest() { return this.#quest; } + + /** + * Defines all jQuery control callbacks with event listeners for click, drag, drop via various CSS selectors. + * The callbacks are gated by several local variables defined in {@link QuestPreview.getData}. + * + * @param {JQuery} html - The jQuery instance for the window content of this Application. + * + * @see HandlerAny + * @see HandlerDetails + * @see HandlerManage + * @see QuestPreview.canAccept + * @see QuestPreview.canEdit + * @see QuestPreview.playerEdit + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#activateListeners + */ + activateListeners(html) + { + super.activateListeners(html); + + // Callbacks for any user. + + html.on(jquery.click, '.quest-giver-name .open-actor-sheet', async (event) => + await HandlerDetails.questGiverShowActorSheet(event, this)); + + // This CSS selector responds to any subquest attached to the details section or subquests listed in objectives. + html.on(jquery.click, '.quest-name-link', (event) => HandlerAny.questOpen(event)); + + // This registers for any element and prevents the circle / slash icon displaying for not being a drag target. + html.on(jquery.dragenter, (event) => event.preventDefault()); + + html.on(jquery.dragstart, '.item-reward .editable-container', async (event) => + await HandlerDetails.rewardDragStartItem(event, this.#quest)); + + html.on(jquery.dragstart, '.quest-rewards .fa-sort', (event) => HandlerDetails.rewardDragStartSort(event)); + + html.on(jquery.click, '.abstract-reward .editable-container', async (event) => + await HandlerDetails.rewardShowImagePopout(event, this.#quest, this)); + + html.on(jquery.click, '.actor-reward .editable-container', async (event) => + await HandlerDetails.rewardShowSheet(event, this.#quest, this)); + + html.on(jquery.click, '.item-reward .editable-container', async (event) => + await HandlerDetails.rewardShowSheet(event, this.#quest, this)); + + html.on(jquery.click, '.splash-image-link', () => HandlerDetails.splashImagePopupShow(this.#quest, this)); + + html.on(jquery.dragstart, '.quest-tasks .fa-sort', (event) => HandlerDetails.taskDragStartSort(event)); + + // Callbacks for GM, trusted player edit, and players with ownership + if (this.canEdit || this.playerEdit) + { + html.on(jquery.click, '.actions-single.quest-name .editable', (event) => + HandlerDetails.questEditName(event, this.#quest, this)); + + html.on(jquery.drop, '.quest-giver-gc', async (event) => + await HandlerDetails.questGiverDropDocument(event, this.#quest, this)); + + html.on(jquery.click, '.quest-giver-gc .toggleImage', async () => + await HandlerDetails.questGiverToggleImage(this.#quest, this)); + + html.on(jquery.click, '.quest-giver-gc .deleteQuestGiver', async () => + await HandlerDetails.questGiverDelete(this.#quest, this)); + + html.on(jquery.click, '.quest-tasks .add-new-task', + (event) => HandlerDetails.taskAdd(event, this.#quest, this)); + + html.on(jquery.click, '.actions.tasks .delete', async (event) => + await HandlerDetails.taskDelete(event, this.#quest, this)); + + html.on(jquery.drop, '.tasks-box', async (event) => await HandlerDetails.taskDropItem(event, this.#quest)); + + html.on(jquery.click, '.actions.tasks .editable', + (event) => HandlerDetails.taskEditName(event, this.#quest, this)); + + html.on(jquery.click, 'li.task .toggleState', async (event) => + await HandlerDetails.taskToggleState(event, this.#quest, this)); + } + + // Callbacks for GM, trusted player edit, or players who can accept quests. + if (this.canEdit || this.canAccept) + { + html.on(jquery.click, '.actions.quest-status i.delete', async (event) => + await HandlerAny.questDelete(event, this.#quest)); + + html.on(jquery.click, '.actions.quest-status i.move', async (event) => + { + await this.saveQuest({ refresh: false }); + await HandlerAny.questStatusSet(event); + }); + } + + // Callbacks only for the GM and trusted player edit. + if (this.canEdit) + { + html.on(jquery.click, '.quest-giver-name .actions-single .editable', (event) => + HandlerDetails.questGiverCustomEditName(event, this.#quest, this)); + + html.on(jquery.click, '.quest-giver-gc .drop-info', () => + HandlerDetails.questGiverCustomSelectImage(this.#quest, this)); + + html.on(jquery.click, '.quest-tabs .is-primary', () => Socket.setQuestPrimary({ quest: this.#quest })); + + html.on(jquery.click, '.quest-rewards .add-abstract', (event) => + HandlerDetails.rewardAddAbstract(event, this.#quest, this)); + + html.on(jquery.click, '.actions.rewards .editable', (event) => + HandlerDetails.rewardAbstractEditName(event, this.#quest, this)); + + html.on(jquery.click, '.actions.rewards .delete', async (event) => + await HandlerDetails.rewardDelete(event, this.#quest, this)); + + html.on(jquery.drop, '.rewards-box', + async (event) => await HandlerDetails.rewardDropItem(event, this.#quest, this)); + + html.on(jquery.click, '.quest-rewards .hide-all-rewards', async () => + await HandlerDetails.rewardsHideAll(this.#quest, this)); + + html.on(jquery.click, '.quest-rewards .lock-all-rewards', async () => + await HandlerDetails.rewardsLockAll(this.#quest, this)); + + html.on(jquery.click, '.reward-image', async (event) => + await HandlerDetails.rewardSelectImage(event, this.#quest, this)); + + html.on(jquery.click, '.quest-rewards .show-all-rewards', async () => + await HandlerDetails.rewardsShowAll(this.#quest, this)); + + html.on(jquery.click, '.actions.rewards .toggleHidden', async (event) => + await HandlerDetails.rewardToggleHidden(event, this.#quest, this)); + + html.on(jquery.click, '.actions.rewards .toggleLocked', async (event) => + await HandlerDetails.rewardToggleLocked(event, this.#quest, this)); + + html.on(jquery.click, '.quest-rewards .unlock-all-rewards', async () => + await HandlerDetails.rewardsUnlockAll(this.#quest, this)); + + html.on(jquery.click, '.actions.tasks .toggleHidden', async (event) => + await HandlerDetails.taskToggleHidden(event, this.#quest, this)); + + // Management view callbacks ------------------------------------------------------------------------------- + + html.on(jquery.click, '.add-subquest-btn', async () => await HandlerManage.addSubquest(this.#quest, this)); + + html.on(jquery.click, '.configure-perm-btn', () => HandlerManage.configurePermissions(this.#quest, this)); + + html.on(jquery.click, '.delete-splash', async () => await HandlerManage.deleteSplashImage(this.#quest, this)); + + html.on(jquery.click, `.quest-splash #splash-as-icon-${this.#quest.id}`, async (event) => + await HandlerManage.setSplashAsIcon(event, this.#quest, this)); + + html.on(jquery.click, '.quest-splash .drop-info', + async () => await HandlerManage.setSplashImage(this.#quest, this)); + + html.on(jquery.click, '.change-splash-pos', async () => await HandlerManage.setSplashPos(this.#quest, this)); + } + } + + /** + * When closing this Foundry app: + * - Close any associated dialogs via {@link FQLDialog.closeDialogs} + * - Close any associated {@link QuestPreview._ownershipControl} + * - Close any associated {@link QuestPreview._rewardImagePopup} + * - Close any associated {@link QuestPreview._splashImagePopup} + * - If set invoke {@link QuestPreview._activeFocusOutFunction} or {@link QuestPreview.saveQuest} if the current + * user is the owner of the quest and options `noSave` is false. + * + * Save the quest on close with no refresh of data. + * + * @param {object} opts - Optional params + * + * @param {boolean} [opts.noSave] - When true the quest is not saved on close otherwise save quest. + * + * @param {...*} [opts.options] - Options which are passed through to {@link FormApplication.close} + * + * @returns {Promise} + * @inheritDoc + * @see FormApplication.close + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#close + */ + async close({ noSave = false, ...options } = {}) + { + FQLDialog.closeDialogs({ questId: this.#quest.id }); + + // If a permission control app / dialog is open close it. + if (this._ownershipControl) + { + this._ownershipControl.close(); + this._ownershipControl = void 0; + } + + // Close any opened actor or reward item sheets. + for (const appId of this._openedAppIds) + { + const app = ui.windows[appId]; + if (app && app.rendered) { app.close(); } + } + + // If a reward ImagePopup is open close it. + if (this._rewardImagePopup) + { + this._rewardImagePopup.close(); + this._rewardImagePopup = void 0; + } + + // If a splash ImagePopup is open close it. + if (this._splashImagePopup) + { + this._splashImagePopup.close(); + this._splashImagePopup = void 0; + } + + // Only potentially save the quest if the user is the owner and noSave is false. + if (!noSave && this.#quest.isOwner) + { + // If there is an active input focus function set then invoke it so that the input field is saved. + if (typeof this._activeFocusOutFunction === 'function') + { + await this._activeFocusOutFunction(void 0, { refresh: false }); + + // Send a socket refresh event to all clients. This will also render all local apps as applicable. + // Must update parent and any subquests / children. + Socket.refreshQuestPreview({ + questId: this.#quest.parent ? [this.#quest.parent, this.#quest.id, ...this.#quest.subquests] : + [this.#quest.id, ...this.#quest.subquests], + focus: false, + }); + } + else + { + // Otherwise save the quest as normal. + await this.saveQuest({ refresh: false }); + } + } + + return super.close(options); + } + + /** + * Retrieves the cached enriched data from QuestDB to be used in the Handlebars template. Also sets the local + * variables used in {@link QuestPreview.activateListeners} to enable various control handling based on user + * permissions and module settings. + * + * @override + * @inheritDoc + * @see QuestPreview.canAccept + * @see QuestPreview.canEdit + * @see QuestPreview.playerEdit + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#getData + */ + async getData(options = {}) // eslint-disable-line no-unused-vars + { + const content = QuestDB.getQuestEntry(this.#quest.id).enrich; + + this.canAccept = game.settings.get(constants.moduleName, settings.allowPlayersAccept); + this.canEdit = game.user.isGM || (this.#quest.isOwner && Utils.isTrustedPlayerEdit()); + this.playerEdit = this.#quest.isOwner; + + // Player notes can be edited if current user is the owner of the journal document or there is an active GM + // online. + const canEditPlayerNotes = this.#quest.canUserUpdate || game.users.activeGM !== null; + + // By default, all normal players and trusted players without ownership of a quest are always on the default + // tab 'details' or 'playernotes'. In the case of a trusted player who has permissions revoked to access the + // quest and is on the 'management' the details tab needs to be activated. This is possible in 'getData' as it + // is fairly early in the render process. At this time the internal state of the application is '1' for + // 'RENDERING'. + if (!this.canEdit && this._tabs[0] && this._tabs[0].active !== 'details' && this._tabs[0].active !== 'playernotes') + { + this._tabs[0].activate('details'); + } + + const data = { + isGM: game.user.isGM, + isPlayer: !game.user.isGM, + + canAccept: this.canAccept, + canEdit: this.canEdit, + canEditPlayerNotes, + playerEdit: this.playerEdit + }; + + return foundry.utils.mergeObject(data, content); + } + + /** + * Refreshes the QuestPreview window and emits {@link Socket.refreshQuestPreview} so remote clients view of data is + * updated as well. Any rendered / visible parent and subquests of this quest are also refreshed. + * + * @returns {Promise} + */ + async refresh() + { + Socket.refreshQuestPreview({ + questId: this.#quest.parent ? [this.#quest.parent, this.#quest.id, ...this.#quest.subquests] : + [this.#quest.id, ...this.#quest.subquests], + focus: false, + }); + + this.render(true, { focus: true }); + } + + /** + * When the editor is saved we simply save the quest. The editor content if any is available is saved inside + * 'saveQuest'. + * + * @override + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#saveEditor + */ + async saveEditor(name) + { + // Any user regardless of ownership may edit player notes. If the user can't update the backing journal document + // Then send a socket request to a GM user who can perform the update. + if (name === 'playernotes' && !this.#quest.canUserUpdate && game.users.activeGM) + { + const playernotes = FVTTCompat.getEditorContent(this.editors?.playernotes); + + if (typeof playernotes === 'string') + { + Socket.savePlayerNotes({ quest: this.#quest, playernotes }); + } + + return super.saveEditor(name); + } + + return this.saveQuest(); + } + + /** + * Save the associated quest and refresh this app. + * + * @param {object} options - Optional parameters + * + * @param {boolean} options.refresh - Execute `QuestPreview.refresh` + * + * @returns {Promise} + * @see QuestPreview.refresh + */ + async saveQuest({ refresh = true } = {}) + { + // Save any altered content from the editors. + for (const key of Object.keys(this.editors)) + { + const editor = this.editors[key]; + + const content = FVTTCompat.getEditorContent(editor); + + if (content) + { + this.#quest[key] = content; + await super.saveEditor(key); + } + } + + await this.#quest.save(); + + return refresh ? this.refresh() : void 0; + } +} diff --git a/src/view/preview/QuestPreviewShim.js b/src/view/preview/QuestPreviewShim.js new file mode 100644 index 00000000..5db4ebe7 --- /dev/null +++ b/src/view/preview/QuestPreviewShim.js @@ -0,0 +1,65 @@ +import { QuestAPI } from '../../control/public/index.js'; + +/** + * Provides a very lightweight shim for {@link JournalEntry} documents that are FQL quests. It defers to + * opening the {@link Quest} to the {@link QuestAPI.open} method. Foundry will invoke this shim when a JournalEntry + * is clicked in the {@link JournalDirectory} via {@link DocumentDirectory._onClickEntryName}. This shim + * is set to {@link JournalEntry._sheet} in {@link QuestDB} when JE docs are created or loaded. + */ +export class QuestPreviewShim +{ + /** + * @type {string} + */ + #questId; + + /** + * Stores the associated JournalEntry / quest ID + * + * @param {string} questId - The quest ID to shim. + */ + constructor(questId) + { + this.#questId = questId; + } + + /** + * Always return false so `render` is invoked. + * + * @returns {boolean} False. + */ + get rendered() { return false; } + + /** + * Noop shim + */ + bringToTop() {} + + /** + * Noop shim + */ + close() {} + + /** + * Noop shim + */ + maximize() {} + + /** + * Defer to render as in some misuse cases by various modules _render can be invoked directly. + * + * @protected + */ + async _render() + { + this.render(); + } + + /** + * Defers to the {@link QuestAPI.open} to potentially open a quest. + */ + render() + { + QuestAPI.open({ questId: this.#questId }); + } +} \ No newline at end of file diff --git a/src/view/tracker/HandlerTracker.js b/src/view/tracker/HandlerTracker.js new file mode 100644 index 00000000..9617a8e0 --- /dev/null +++ b/src/view/tracker/HandlerTracker.js @@ -0,0 +1,174 @@ +import { + FoundryUIManager, + QuestDB, + Socket } from '../../control/index.js'; + +import { QuestAPI } from '../../control/public/index.js'; + +import { + constants, + sessionConstants, + settings } from '../../model/constants.js'; + +/** + * Provides all {@link JQuery} and {@link PointerEvent} callbacks for the {@link QuestTracker}. + */ +export class HandlerTracker +{ + /** + * @private + */ + constructor() + { + throw new Error('This is a static class that should not be instantiated.'); + } + + /** + * Handles the pointer down event from the header to reset the pinned state. + * + * @param {PointerEvent} event - PointerEvent + * + * @param {HTMLElement} header - The app header element. + * + * @param {QuestTracker} questTracker - The QuestTracker + */ + static async headerPointerDown(event, header, questTracker) + { + if (event.target.classList.contains('window-title') || + event.target.classList.contains('window-header')) + { + questTracker._dragHeader = true; + + questTracker._pinned = false; + + await game.settings.set(constants.moduleName, settings.questTrackerPinned, false); + + header.setPointerCapture(event.pointerId); + } + } + + /** + * Handles the pointer up event from the header to check for and set the pinned state. + * + * @param {PointerEvent} event - PointerEvent + * + * @param {HTMLElement} header - The app header element. + * + * @param {QuestTracker} questTracker - The QuestTracker + */ + static async headerPointerUp(event, header, questTracker) + { + header.releasePointerCapture(event.pointerId); + questTracker._dragHeader = false; + + if (questTracker._inPinDropRect) + { + questTracker._pinned = true; + await game.settings.set(constants.moduleName, settings.questTrackerPinned, true); + questTracker.element.css('animation', ''); + FoundryUIManager.updateTracker(); + } + } + + /** + * Handles the quest open click via {@link QuestAPI.open}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + */ + static questOpen(event) + { + const questId = event.currentTarget.dataset.questId; + QuestAPI.open({ questId }); + } + + /** + * Data for the quest folder open / close state is saved in {@link sessionStorage}. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + * + * @param {QuestTracker} questTracker - The QuestTracker. + */ + static questClick(event, questTracker) + { + const questId = event.currentTarget.dataset.questId; + + const questEntry = QuestDB.getQuestEntry(questId); + if (questEntry && questEntry.enrich.hasObjectives) + { + const folderState = sessionStorage.getItem(`${sessionConstants.trackerFolderState}${questId}`); + const collapsed = folderState !== 'false'; + sessionStorage.setItem(`${sessionConstants.trackerFolderState}${questId}`, (!collapsed).toString()); + + questTracker.render(); + } + } + + /** + * Handles the header button to show the primary quest or all quests. + * + * @param {QuestTracker} questTracker - The QuestTracker. + */ + static questPrimaryShow(questTracker) + { + const newPrimary = !(sessionStorage.getItem(sessionConstants.trackerShowPrimary) === 'true'); + sessionStorage.setItem(sessionConstants.trackerShowPrimary, (newPrimary).toString()); + + const showPrimaryIcon = $('#quest-tracker .header-button.show-primary i'); + showPrimaryIcon.attr('class', newPrimary ? 'fas fa-star' : 'far fa-star'); + showPrimaryIcon.attr('title', game.i18n.localize(newPrimary ? + 'ForienQuestLog.QuestTracker.Tooltips.PrimaryQuestShow' : + 'ForienQuestLog.QuestTracker.Tooltips.PrimaryQuestUnshow')); + + questTracker.render(); + } + + /** + * Handles toggling {@link Quest} tasks when clicked on by a user that is the GM or owner of quest. + * + * @param {JQuery.ClickEvent} event - JQuery.ClickEvent + */ + static async questTaskToggle(event) + { + // Don't handle any clicks of internal anchor elements such as entity content links. + if ($(event.target).is('.quest-tracker-task a')) { return; } + + const questId = event.currentTarget.dataset.questId; + const uuidv4 = event.currentTarget.dataset.uuidv4; + + const quest = QuestDB.getQuest(questId); + + if (quest) + { + const task = quest.getTask(uuidv4); + if (task) + { + task.toggle(); + await quest.save(); + + Socket.refreshQuestPreview({ + questId, + focus: false + }); + } + } + } + + /** + * Handles the header button to show the quest tracker background or hide it. + * + * @param {QuestTracker} questTracker - The QuestTracker. + */ + static showBackground(questTracker) + { + const newBackgroundState = !(sessionStorage.getItem(sessionConstants.trackerShowBackground) === 'true'); + sessionStorage.setItem(sessionConstants.trackerShowBackground, (newBackgroundState).toString()); + + const showBackgroundIcon = $('#quest-tracker .header-button.show-background i'); + showBackgroundIcon.attr('class', newBackgroundState ? 'fas fa-star' : 'far fa-star'); + showBackgroundIcon.attr('title', game.i18n.localize(newBackgroundState ? + 'ForienQuestLog.QuestTracker.Tooltips.BackgroundUnshow' : + 'ForienQuestLog.QuestTracker.Tooltips.BackgroundShow')); + + questTracker.render(); + } +} \ No newline at end of file diff --git a/src/view/tracker/QuestTracker.js b/src/view/tracker/QuestTracker.js new file mode 100644 index 00000000..c3541a4e --- /dev/null +++ b/src/view/tracker/QuestTracker.js @@ -0,0 +1,605 @@ +import { + FoundryUIManager, + QuestDB, + Socket, + Utils } from '../../control/index.js'; + +import { HandlerTracker } from './HandlerTracker.js'; + +import { FQLContextMenu } from '../internal/index.js'; + +import { collect } from '../../../external/index.js'; + +import { + constants, + jquery, + questStatus, + sessionConstants, + settings } from '../../model/constants.js'; + +/** + * Provides the quest tracker which provides an overview of active quests and objectives which can be opened / closed + * to show all objectives for a given quest. The folder / open state is stored in {@link sessionStorage}. + * + * In the {@link QuestTracker.getData} method {@link QuestTracker.prepareQuests} is invoked which gets all sorted + * {@link questStatus.active} via {@link QuestDB.sortCollect}. They are then mapped creating the specific data which is + * used in the {@link Handlebars} template. In the future this may be cached in a similar way that {@link Quest} data + * is cached for {@link QuestLog}. + */ +export class QuestTracker extends Application +{ + /** + * Provides the default width for the QuestTracker if not defined. + * + * @type {Readonly} + */ + static #DEFAULT_WIDTH = 296; + + /** + * Provides the default position for the QuestTracker if not defined. + * + * @type {Readonly<{top: number, width: number}>} + */ + static #DEFAULT_POSITION = { top: 80, width: QuestTracker.#DEFAULT_WIDTH }; + + /** + * Defines the timeout length to gate saving position to settings. + * + * @type {Readonly} + */ + static #TIMEOUT_POSITION = 1000; + + /** + * Stores the app / window extents from styles. + * + * @type {{minHeight: number, maxHeight: number, minWidth: number, maxWidth: number}} + */ + #appExtents; + + /** + * @type {JQuery} The window header element. + */ + #elemWindowHeader; + + /** + * @type {JQuery} The window content element. + */ + #elemWindowContent; + + /** + * @type {JQuery} The window resize handle. + */ + #elemResizeHandle; + + /** + * Stores whether the scroll bar is active. + * + * @type {boolean} + */ + #scrollbarActive; + + /** + * Stores the last call to setTimeout for {@link QuestTracker.setPosition} changes, so that they can be cancelled as + * new updates arrive gating the calls to saving position to settings. + * + * @type {number} + */ + #timeoutPosition = void 0; + + /** + * Stores the state of {@link FQLSettings.questTrackerResizable}. + * + * @type {boolean} + */ + #windowResizable; + + /** + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.Application.html + */ + constructor(options = {}) + { + super(options); + + try + { + /** + * Stores the current position of the quest tracker. + * + * @type {object} + * {@link Application.position} + */ + this.position = JSON.parse(game.settings.get(constants.moduleName, settings.questTrackerPosition)); + + // When upgrading to `v0.7.7` it is necessary to set the default width. + if (!this.position?.width) { this.position.width = QuestTracker.#DEFAULT_WIDTH; } + + } + catch (err) + { + this.position = QuestTracker.#DEFAULT_POSITION; + } + + /** + * Stores whether the header is being dragged. + * + * @type {boolean} + * @package + */ + this._dragHeader = false; + + /** + * Stores whether the QuestTracker is pinned to the sidebar. + * + * @type {boolean} + * @package + */ + this._pinned = game.settings.get(constants.moduleName, settings.questTrackerPinned); + + /** + * Stores whether the current position is in the sidebar pin drop rectangle. + * + * @type {boolean} + * @package + */ + this._inPinDropRect = false; + } + + /** + * Default {@link Application} options + * + * @returns {object} options - Application options. + * @see https://foundryvtt.com/api/classes/client.Application.html#options + */ + static get defaultOptions() + { + return foundry.utils.mergeObject(super.defaultOptions, { + id: 'quest-tracker', + template: 'modules/forien-quest-log/templates/quest-tracker.html', + minimizable: false, + resizable: true, + popOut: false, + width: 300, + height: 480, + title: game.i18n.localize('ForienQuestLog.QuestTracker.Title') + }); + } + + /** + * Create the context menu. There are two separate context menus for the active / in progress tab and all other tabs. + * + * @param {JQuery} html - JQuery element for this application. + */ + #contextMenu(html) + { + const menuItemCopyLink = { + name: 'ForienQuestLog.QuestLog.ContextMenu.CopyEntityLink', + icon: '', + callback: async (menu) => + { + const questId = $(menu)?.closest('.quest-tracker-header')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + + if (quest && await Utils.copyTextToClipboard(`@JournalEntry[${quest.id}]{${quest.name}}`)) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.LinkCopied')); + } + } + }; + + /** + * @type {object[]} + */ + const menuItems = [menuItemCopyLink]; + + if (game.user.isGM) + { + menuItems.push({ + name: 'ForienQuestLog.QuestLog.ContextMenu.CopyQuestID', + icon: '', + callback: async (menu) => + { + const questId = $(menu)?.closest('.quest-tracker-header')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + + if (quest && await Utils.copyTextToClipboard(quest.id)) + { + ui.notifications.info(game.i18n.format('ForienQuestLog.Notifications.QuestIDCopied')); + } + } + }); + + menuItems.push({ + name: 'ForienQuestLog.QuestLog.ContextMenu.PrimaryQuest', + icon: '', + callback: (menu) => + { + const questId = $(menu)?.closest('.quest-tracker-header')?.data('quest-id'); + const quest = QuestDB.getQuest(questId); + if (quest) { Socket.setQuestPrimary({ quest }); } + } + }); + } + + new FQLContextMenu(html, '.quest-tracker-header', menuItems); + } + + /** + * Specify the set of config buttons which should appear in the Application header. Buttons should be returned as an + * Array of objects. + * + * Provides an explicit override of Application._getHeaderButtons to add + * + * @returns {ApplicationHeaderButton[]} The app header buttons. + * @override + */ + _getHeaderButtons() + { + const buttons = super._getHeaderButtons(); + + // Remove default `Close` label for close button. + const closeButton = buttons.find((button) => button?.class === 'close'); + if (closeButton) { closeButton.label = void 0; } + + const showBackgroundState = sessionStorage.getItem(sessionConstants.trackerShowBackground) === 'true'; + const showBackgroundIcon = showBackgroundState ? 'fas fa-fill on' : 'fas fa-fill off'; + const showBackgroundTitle = showBackgroundState ? 'ForienQuestLog.QuestTracker.Tooltips.BackgroundUnshow' : + 'ForienQuestLog.QuestTracker.Tooltips.BackgroundShow'; + + buttons.unshift({ + title: showBackgroundTitle, + class: 'show-background', + icon: showBackgroundIcon + }); + + const primaryState = sessionStorage.getItem(sessionConstants.trackerShowPrimary) === 'true'; + const primaryIcon = primaryState ? 'fas fa-star' : 'far fa-star'; + const primaryTitle = primaryState ? 'ForienQuestLog.QuestTracker.Tooltips.PrimaryQuestUnshow' : + 'ForienQuestLog.QuestTracker.Tooltips.PrimaryQuestShow'; + + buttons.unshift({ + title: primaryTitle, + class: 'show-primary', + icon: primaryIcon + }); + + // Share QuestLog w/ remote clients. + if (game.user.isGM) + { + buttons.unshift({ + title: game.i18n.localize('ForienQuestLog.Labels.AppHeader.ShowPlayers'), + class: 'share-tracker', + icon: 'fas fa-eye' + }); + } + + return buttons; + } + + /** + * Gets the minimum width of this Application. + * + * @returns {number} Minimum width. + */ + get minWidth() { return this.#appExtents.minWidth || 275; } + + /** + * Is the QuestTracker pinned to the sidebar. + * + * @returns {boolean} QuestTracker pinned. + */ + get pinned() { return this._pinned; } + + /** + * Defines all {@link JQuery} control callbacks with event listeners for click, drag, drop via various CSS selectors. + * + * @param {JQuery} html - The jQuery instance for the window content of this Application. + * + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#activateListeners + */ + activateListeners(html) + { + super.activateListeners(html); + + const showBackgroundState = sessionStorage.getItem(sessionConstants.trackerShowBackground) === 'true'; + if (!showBackgroundState) + { + this.element[0].classList.add('no-background'); + } + + // Make the window draggable + const header = html.find('header'); + new Draggable(this, html, header[0], this.options.resizable); + + header[0].addEventListener('pointerdown', async (event) => + HandlerTracker.headerPointerDown(event, header[0], this)); + + header[0].addEventListener('pointerup', async (event) => + HandlerTracker.headerPointerUp(event, header[0], this)); + + html.on(jquery.click, '.header-button.close', void 0, this.close); + + if (game.user.isGM) + { + html.on(jquery.click, '.header-button.share-tracker i', void 0, () => Socket.showQuestTracker()); + } + + html.on(jquery.click, '.header-button.show-background i', void 0, () => HandlerTracker.showBackground(this)); + + html.on(jquery.click, '.header-button.show-primary i', void 0, () => HandlerTracker.questPrimaryShow(this)); + + // Add context menu. + this.#contextMenu(html); + + Utils.createJQueryDblClick({ + selector: '#quest-tracker .quest-tracker-header', + singleCallback: (event) => HandlerTracker.questClick(event, this), + doubleCallback: HandlerTracker.questOpen, + }); + + html.on(jquery.click, '.quest-tracker-link', void 0, HandlerTracker.questOpen); + + html.on(jquery.click, '.quest-tracker-task', void 0, async (event) => + await HandlerTracker.questTaskToggle(event)); + + this.#elemWindowHeader = $('#quest-tracker .window-header'); + this.#elemWindowContent = $('#quest-tracker .window-content'); + this.#elemResizeHandle = $('#quest-tracker .window-resizable-handle'); + + this.#appExtents = { + minWidth: parseInt(this.element.css('min-width')), + maxWidth: parseInt(this.element.css('max-width')), + minHeight: parseInt(this.element.css('min-height')), + maxHeight: parseInt(this.element.css('max-height')) + }; + + this.#windowResizable = game.settings.get(constants.moduleName, settings.questTrackerResizable); + + if (this.#windowResizable) + { + this.#elemResizeHandle.show(); + this.element.css('min-height', this.#appExtents.minHeight); + } + else + { + this.#elemResizeHandle.hide(); + this.element.css('min-height', this.#elemWindowHeader[0].scrollHeight); + + // A bit of a hack. We need to call the Application setPosition now to make sure the element parameters + // are correctly set as the exact height for the element is calculated in this.setPosition which is called + // by Application right after this method completes. + // Must set popOut temporarily to true as there is a gate in `Application.setPosition`. + this.options.popOut = true; + super.setPosition(this.position); + this.options.popOut = false; + } + + this.#scrollbarActive = this.#elemWindowContent[0].scrollHeight > this.#elemWindowContent[0].clientHeight; + + // Set current scrollbar active state and potentially set 'point-events' to 'auto'. + if (this.#scrollbarActive) { this.element.css('pointer-events', 'auto'); } + } + + /** + * Override default Application `bringToTop` to stop adjustment of z-index. + * + * @override + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.Application.html#bringToTop + */ + bringToTop() {} + + /** + * Sets `questTrackerEnable` to false. + * + * @param {object} [options] - Optional parameters. + * + * @param {boolean} [options.updateSetting=true] - If true then {@link settings.questTrackerEnable} is set to false. + * + * @returns {Promise} + */ + async close({ updateSetting = true } = {}) + { + await super.close(); + + if (updateSetting) + { + await game.settings.set(constants.moduleName, settings.questTrackerEnable, false); + } + } + + /** + * Parses quest data in {@link QuestTracker.prepareQuests}. + * + * @override + * @inheritDoc + * @see https://foundryvtt.com/api/classes/client.FormApplication.html#getData + */ + async getData(options = {}) + { + const showOnlyPrimary = sessionStorage.getItem(sessionConstants.trackerShowPrimary) === 'true'; + const primaryQuest = QuestDB.getQuestEntry(game.settings.get(constants.moduleName, settings.primaryQuest)); + + // Stores the primary quest ID when all in progress quests are shown so that the star icon is drawn for the + // primary quest. + const primaryQuestId = !showOnlyPrimary && primaryQuest ? primaryQuest.id : ''; + + const quests = await this.prepareQuests(showOnlyPrimary, primaryQuest); + + return foundry.utils.mergeObject(super.getData(options), { + title: this.options.title, + headerButtons: this._getHeaderButtons(), + hasQuests: quests.count() > 0, + primaryQuestId, + quests + }); + } + + /** + * Transforms the quest data from sorted active quests. In this case we need to determine which quests can be + * manipulated for trusted player edit. + * + * @param {boolean} showOnlyPrimary - Shows only the primary quest. + * + * @param {QuestEntry|void} primaryQuest - Any currently set primary quest. + * + * @returns {Promise>} Sorted active quests. + */ + async prepareQuests(showOnlyPrimary, primaryQuest) + { + /** + * If showOnlyPrimary and the primaryQuest exists then build a Collection with just the primary quest otherwise + * get all sorted in progress quests from the QuestDB. + * + * @type {Collection} + */ + const questEntries = showOnlyPrimary ? collect(primaryQuest ? [primaryQuest] : []) : + QuestDB.sortCollect({ status: questStatus.active }); + + const isGM = game.user.isGM; + const isTrustedPlayerEdit = Utils.isTrustedPlayerEdit(); + + return questEntries.transform((entry) => + { + const q = entry.enrich; + const collapsed = sessionStorage.getItem(`${sessionConstants.trackerFolderState}${q.id}`) === 'false'; + + const tasks = collapsed ? q.data_tasks : []; + const subquests = collapsed ? q.data_subquest : []; + + return { + id: q.id, + canEdit: isGM || (entry.isOwner && isTrustedPlayerEdit), + playerEdit: entry.isOwner, + source: q.giver, + name: q.name, + isGM, + isHidden: q.isHidden, + isInactive: q.isInactive, + isPersonal: q.isPersonal, + personalActors: q.personalActors, + hasObjectives: q.hasObjectives, + subquests, + tasks + }; + }); + } + + /** + * Some game systems and custom UI theming modules provide hard overrides on overflow-x / overflow-y styles. Alas we + * need to set these for '.window-content' to 'visible' which will cause an issue for very long tables. Thus we must + * manually set the table max-heights based on the position / height of the {@link Application}. + * + * @param {object} [opts] - Optional parameters. + * + * @param {number|null} [opts.left] - The left offset position in pixels. + * + * @param {number|null} [opts.top] - The top offset position in pixels. + * + * @param {number|null} [opts.width] - The application width in pixels. + * + * @param {number|string|null} [opts.height] - The application height in pixels. + * + * @param {number|null} [opts.scale] - The application scale as a numeric factor where 1.0 is default. + * + * @param {boolean} [opts.override] - Forces any manual pinned setting to take effect. + * + * @param {boolean} [opts.pinned] - Sets the pinned state. + * + * @returns {{left: number, top: number, width: number, height: number, scale:number}} + * The updated position object for the application containing the new values. + */ + setPosition({ override, pinned = this._pinned, ...opts } = {}) + { + // Potentially force override any pinned state. This is done from FQLHooks.openQuestTracker. + if (typeof override === 'boolean') + { + if (pinned) + { + this._pinned = true; + this._inPinDropRect = true; + game.settings.set(constants.moduleName, settings.questTrackerPinned, true); + FoundryUIManager.updateTracker(); + return opts; // Early out as updateTracker above calls setPosition again. + } + else + { + this._pinned = false; + this._inPinDropRect = false; + game.settings.set(constants.moduleName, settings.questTrackerPinned, false); + } + } + + const initialWidth = this.position.width; + const initialHeight = this.position.height; + + if (pinned) + { + if (typeof opts.left === 'number') { opts.left = this.position.left; } + if (typeof opts.top === 'number') { opts.top = this.position.top; } + if (typeof opts.width === 'number') { opts.width = this.position.width; } + } + + // Must set popOut temporarily to true as there is a gate in `Application.setPosition`. + this.options.popOut = true; + const currentPosition = super.setPosition(opts); + this.options.popOut = false; + + if (!this.#windowResizable) + { + // Add the extra `2` for small format (1080P and below screen size). + currentPosition.height = this.#elemWindowHeader[0].scrollHeight + this.#elemWindowContent[0].scrollHeight + 2; + } + + // Pin width / height to min / max styles if defined. + if (currentPosition.width < this.#appExtents.minWidth) { currentPosition.width = this.#appExtents.minWidth; } + if (currentPosition.width > this.#appExtents.maxWidth) { currentPosition.width = this.#appExtents.maxWidth; } + if (currentPosition.height < this.#appExtents.minHeight) { currentPosition.height = this.#appExtents.minHeight; } + if (currentPosition.height > this.#appExtents.maxHeight) { currentPosition.height = this.#appExtents.maxHeight; } + + const el = this.element[0]; + + currentPosition.resizeWidth = initialWidth < currentPosition.width; + currentPosition.resizeHeight = initialHeight < currentPosition.height; + + // Mutates `checkPosition` to set maximum left position. Must do this calculation after `super.setPosition` + // as in some cases `super.setPosition` will override the changes of `FoundryUIManager.checkPosition`. + const currentInPinDropRect = this._inPinDropRect; + this._inPinDropRect = FoundryUIManager.checkPosition(currentPosition); + + // Set the jiggle animation if the position movement is coming from dragging the header and the pin drop state + // has changed. + if (!this._pinned && this._dragHeader && currentInPinDropRect !== this._inPinDropRect) + { + this.element.css('animation', this._inPinDropRect ? 'fql-jiggle 0.3s infinite' : ''); + } + + el.style.top = `${currentPosition.top}px`; + el.style.left = `${currentPosition.left}px`; + el.style.width = `${currentPosition.width}px`; + el.style.height = `${currentPosition.height}px`; + + const scrollbarActive = this.#elemWindowContent[0].scrollHeight > this.#elemWindowContent[0].clientHeight; + + if (scrollbarActive !== this.#scrollbarActive) + { + this.#scrollbarActive = scrollbarActive; + this.element.css('pointer-events', scrollbarActive ? 'auto' : 'none'); + } + + if (currentPosition && currentPosition.width && currentPosition.height) + { + if (this.#timeoutPosition) + { + clearTimeout(this.#timeoutPosition); + } + + this.#timeoutPosition = setTimeout(() => + { + game.settings.set(constants.moduleName, settings.questTrackerPosition, JSON.stringify(currentPosition)); + }, QuestTracker.#TIMEOUT_POSITION); + } + + return currentPosition; + } +} \ No newline at end of file diff --git a/styles/basicapp.scss b/styles/basicapp.scss new file mode 100644 index 00000000..9cc9c08b --- /dev/null +++ b/styles/basicapp.scss @@ -0,0 +1,84 @@ +// Defines the styles for that mimics a popout Application. Used by QuestTracker to appear like a +// popout app, but be managed directly. +.fql-app { + max-height: 100%; + background: url(../../../ui/denim075.png) repeat; + border-radius: 5px; + box-shadow: 0 0 20px #000; + margin: 3px 0; + color: #f0f0e0; + position: absolute; +} + +.fql-window-app { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + padding: 0; + z-index: 99; + + .window-content { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + padding: 8px; + color: #191813; + overflow-y: auto; + overflow-x: hidden; + } + + .window-header { + flex: 0 0 30px; + overflow: hidden; + padding: 0 8px; + line-height: 30px; + border-bottom: 1px solid #000; + pointer-events: auto; + + a { + flex: none; + margin: 0 0 0 8px; + } + + h4 { + font-family: Signika, sans-serif; + } + + i[class^=fa] { + margin-right: 3px; + } + + .window-title { + margin: 0; + word-break: break-all; + } + } + + .window-resizable-handle { + width: 20px; + height: 20px; + position: absolute; + bottom: -1px; + right: 0; + background: #444; + padding: 2px; + border: 1px solid #111; + border-radius: 4px 0 0 0; + + i.fas { + transform: rotate(45deg); + } + } + + &.minimized { + .window-header { + border: 1px solid #000; + } + + .window-resizable-handle { + display: none; + } + } +} \ No newline at end of file diff --git a/styles/global-mixin.scss b/styles/global-mixin.scss new file mode 100644 index 00000000..7162c56e --- /dev/null +++ b/styles/global-mixin.scss @@ -0,0 +1,89 @@ +@mixin button { + display: flex; + justify-content: center; + align-items: center; + background: $primary-color-bg-buttonspan; + border-radius: 5px; + width: 22px; + height: 22px; + transition: color .3s ease; + cursor: pointer; + + &:hover { + color: $primary-color-accent; + } + + i { + font-size: 16px; + border-radius: 50%; + line-height: 1; + } +} + +@mixin fonts { + /* almendra-regular - latin */ + @font-face { + font-family: 'Almendra'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/almendra-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/almendra-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } + + /* audiowide-regular - latin */ + @font-face { + font-family: 'Audiowide'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/audiowide-v9-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/audiowide-v9-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } + + /* bilbo-swash-caps-regular - latin */ + @font-face { + font-family: 'Bilbo Swash Caps'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/bilbo-swash-caps-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/bilbo-swash-caps-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } + + /* medievalsharp-regular - latin */ + @font-face { + font-family: 'MedievalSharp'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/medievalsharp-v14-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/medievalsharp-v14-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } + + /* metamorphous-regular - latin */ + @font-face { + font-family: 'Metamorphous'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/metamorphous-v13-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/metamorphous-v13-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } + + /* nova-square-regular - latin */ + @font-face { + font-family: 'Nova Square'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../assets/fonts/nova-square-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../assets/fonts/nova-square-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + } +} + +@mixin header-buttons { + display: flex; + border-bottom: 2px solid $primary-color-borderheader; + border-block-end: 2px solid $primary-color-borderheader; +} \ No newline at end of file diff --git a/styles/global-variables.scss b/styles/global-variables.scss new file mode 100644 index 00000000..d1793d54 --- /dev/null +++ b/styles/global-variables.scss @@ -0,0 +1,44 @@ +// Support for Whetstone and nascent lib-themer (unfinished) +$background-color-light: rgba(255, 255, 255, .5); +$log-bookmark-image-background: var(--palette-app-background-image, url(../../../ui/parchment.jpg)) repeat; + +$primary-color-accent: var(--palette-primary, var(--default-primary-accent, #ff6400)); + +$primary-color-borderheader: var(--palette-primary, var(--default-primary-accent, #782e22)); + +$primary-color-bg-buttonspan: var(--default-secondary-accent, rgba(255, 255, 255, .75)); + +$primary-color-border-drop: rgba(0, 0, 0, .5); +$primary-color-bg-drop: rgba(0, 0, 0, .1); +$primary-color-hover-drop: rgba(0, 0, 0, .075); + +$primary-color-bg-li: rgba(255, 255, 255, .4); +$primary-color-bg-li-hidden: rgba(255, 255, 255, .2); + +$primary-color-icon: rgba(0,0,0,.75); + +$primary-color-bg-nav: rgba(255,255,255,.2); + +$primary-color-text: var(--default-primary-color, #EEE); +$primary-color-text-hidden: #888888; +$primary-color-text-hover: var(--default-primary-accent, red); + +$icon-color-primary-quest: gold; +$icon-color-show-background: lightblue; +$icon-color-completed: rgba(0, 175, 0, .8); +$icon-color-failed: rgba(200, 0, 0, .8); +$icon-color-trashcan: rgba(255, 0, 0, .6); + +// LibThemer support for QuestTracker +$tracker-color-background: var(--palette-fql-qt-color-background, #00000000); +$tracker-image-background: var(--palette-fql-qt-image-background, url(../../../ui/denim075.png)) repeat; +$tracker-image-background-blend-mode: var(--palette-fql-qt-image-background-blend-mode, normal); + +$tracker-color-text: var(--palette-fql-qt-text-color, #{$primary-color-text}); +$tracker-color-text-hidden: var(--palette-fql-qt-text-color-shaded-text, #{$primary-color-text-hidden}); + +$tracker-color-background-entitylink: var(--palette-fql-qt-color-background-entitylink, #ddd); +$tracker-color-text-entitylink: var(--palette-fql-qt-color-background-entitylink-contrast-text, black); + +// Doesn't work quite right as game systems can provide style overrides. +//$tracker-color-text-hover: var(--palette-fql-qt-text-color-light, #{$primary-color-text-hover}); diff --git a/styles/init.css b/styles/init.css deleted file mode 100644 index 4611368b..00000000 --- a/styles/init.css +++ /dev/null @@ -1,820 +0,0 @@ -#forien-quest-log .window-content, -#forien-quest-log-form .window-content, -.window-app.forien-quest-preview .window-content { - padding: 0; - height: 100%; } -#forien-quest-log .tab, -#forien-quest-log-form .tab, -.window-app.forien-quest-preview .tab { - height: 100%; - display: none; } - #forien-quest-log .tab.active, - #forien-quest-log-form .tab.active, - .window-app.forien-quest-preview .tab.active { - display: block; } -#forien-quest-log h1, -#forien-quest-log-form h1, -.window-app.forien-quest-preview h1 { - flex: 0 0 1px; - font-size: 22px; - line-height: 1; - font-weight: 700; - padding: 0 0 4px 0; - margin: 0 0 8px 0; } -#forien-quest-log h2, -#forien-quest-log-form h2, -.window-app.forien-quest-preview h2 { - font-size: 18px; - line-height: 1; - font-weight: 700; - padding: 0 0 2px 0; - margin: 0 0 4px 0; - border-width: 2px; } -#forien-quest-log label, -#forien-quest-log-form label, -.window-app.forien-quest-preview label { - display: block; - margin-bottom: 3px; } -#forien-quest-log input[type="text"], -#forien-quest-log-form input[type="text"], -.window-app.forien-quest-preview input[type="text"] { - border: none; - background: rgba(255, 255, 255, 0.5); - padding: 4px 8px; - box-shadow: 0 0 3px 1px transparent inset; - transition: box-shadow .3s ease; - height: 26px; } - #forien-quest-log input[type="text"]:hover, - #forien-quest-log-form input[type="text"]:hover, - .window-app.forien-quest-preview input[type="text"]:hover { - box-shadow: 0 0 0 1px #ff6400 inset; } -#forien-quest-log button, -#forien-quest-log-form button, -.window-app.forien-quest-preview button { - background: #F2F1EA; - height: 30px; - border: 1px solid #333; - border-radius: 5px; - margin: 0 0 0 8px; - transition: border-color .3s ease, background .3s ease, box-shadow .3s ease; - cursor: pointer; } - #forien-quest-log button:hover, - #forien-quest-log-form button:hover, - .window-app.forien-quest-preview button:hover { - box-shadow: 0 0 2px #ff6400 inset; - border-color: #ff6400; - background: #efefef; } - #forien-quest-log button:first-child, - #forien-quest-log-form button:first-child, - .window-app.forien-quest-preview button:first-child { - margin-left: 0; } -#forien-quest-log nav, -#forien-quest-log-form nav, -.window-app.forien-quest-preview nav { - flex: 0 0 40px; - background: rgba(255, 255, 255, 0.3); - justify-content: flex-start; - align-items: center; - padding: 0 16px; } - #forien-quest-log nav .item, - #forien-quest-log-form nav .item, - .window-app.forien-quest-preview nav .item { - text-align: left; - flex: 0 0 1px; - margin-left: 1rem; - white-space: nowrap; - transition: color .3s ease; } - #forien-quest-log nav .item:hover, - #forien-quest-log-form nav .item:hover, - .window-app.forien-quest-preview nav .item:hover { - text-shadow: none; - color: #ff6400; } - #forien-quest-log nav .item:first-child, - #forien-quest-log-form nav .item:first-child, - .window-app.forien-quest-preview nav .item:first-child { - margin-left: 0; } - #forien-quest-log nav .item.active, #forien-quest-log nav .item.active:hover, - #forien-quest-log-form nav .item.active, - #forien-quest-log-form nav .item.active:hover, - .window-app.forien-quest-preview nav .item.active, - .window-app.forien-quest-preview nav .item.active:hover { - font-weight: 700; - text-shadow: none; - color: inherit; } -#forien-quest-log .hidden, -#forien-quest-log-form .hidden, -.window-app.forien-quest-preview .hidden { - display: none; } -#forien-quest-log .editor, -#forien-quest-log-form .editor, -.window-app.forien-quest-preview .editor { - height: 100%; - padding: 8px; - background: rgba(255, 255, 255, 0.5); - border-radius: 5px; } - #forien-quest-log .editor .editor-content, - #forien-quest-log-form .editor .editor-content, - .window-app.forien-quest-preview .editor .editor-content { - height: 100%; - padding: 0; - padding: 0 4px 0 0; - overflow: auto; } -#forien-quest-log .actions, -#forien-quest-log-form .actions, -.window-app.forien-quest-preview .actions { - flex: 0 0 100px; - border-left: 1px solid rgba(0, 0, 0, 0.15); - height: 100%; - display: flex; - justify-content: center; - align-items: center; } - #forien-quest-log .actions i, - #forien-quest-log-form .actions i, - .window-app.forien-quest-preview .actions i { - font-size: 16px; - margin-left: 4px; - cursor: pointer; - color: rgba(0, 0, 0, 0.75); - transition: color .3s ease; } - #forien-quest-log .actions i.delete, - #forien-quest-log-form .actions i.delete, - .window-app.forien-quest-preview .actions i.delete { - color: rgba(255, 0, 0, 0.4); } - #forien-quest-log .actions i.fa-play, - #forien-quest-log-form .actions i.fa-play, - .window-app.forien-quest-preview .actions i.fa-play { - font-size: 14px; - padding-top: 2px; } - #forien-quest-log .actions i:hover, - #forien-quest-log-form .actions i:hover, - .window-app.forien-quest-preview .actions i:hover { - color: #ff6400; } - #forien-quest-log .actions i:first-child, - #forien-quest-log-form .actions i:first-child, - .window-app.forien-quest-preview .actions i:first-child { - margin: 0; } - -#forien-quest-log { - min-width: 500px; - min-height: 640px; } - #forien-quest-log .quest-log { - height: 100%; - overflow-y: auto; - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.1); - padding: 0 0 24px 0; } - #forien-quest-log .quest-log.bookmarks nav { - position: absolute; - left: 0; - transform: translateX(-100%); - flex-direction: column; - align-items: flex-end; - background: none; - padding: 0; - flex: 0; } - #forien-quest-log .quest-log.bookmarks nav .item { - background: url("/ui/parchment.jpg") repeat; - text-align: right; - margin: 0; - margin-bottom: 4px; - padding: 8px 16px; - width: 150px; - border-radius: 5px 0 0 5px; - position: relative; - z-index: 1; - box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.25) inset, 0 5px 5px -5px rgba(0, 0, 0, 0.3), 0 -5px 5px -5px rgba(0, 0, 0, 0.3), -2px 0 5px -2px rgba(0, 0, 0, 0.3); - transition: padding .3s ease, width .3s ease, color .3s ease; } - #forien-quest-log .quest-log.bookmarks nav .item:hover { - padding-right: 32px; - width: 166px; } - #forien-quest-log .quest-log.bookmarks nav .item.active { - padding-right: 32px; - width: 166px; } - #forien-quest-log .quest-log.bookmarks nav .item.active::after { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background: rgba(0, 0, 0, 0.1); - border-radius: 5px 0 0 5px; - z-index: -1; } - #forien-quest-log .quest-log .log-body { - flex: 1; - overflow-y: hidden; - padding: 0 16px; } - #forien-quest-log .quest-log .tab { - flex-direction: column; - padding: 16px 0 0 0; } - #forien-quest-log .quest-log .tab.active { - display: flex; } - #forien-quest-log .quest-log .tab .table { - flex: 1; - overflow-y: auto; } - #forien-quest-log .quest-log .table ul { - list-style: none; - margin: 0; - padding: 0; } - #forien-quest-log .quest-log .table ul li { - display: flex; - justify-content: flex-start; - align-items: center; - margin: 0 4px 2px 0; - background: rgba(255, 255, 255, 0.3); - border: 1px solid transparent; - border-radius: 5px; - height: 42px; - transition: border-color .3s ease, box-shadow .3s ease; } - #forien-quest-log .quest-log .table ul li:hover { - border-color: #ff6400; - box-shadow: 0 0 2px #ff6400 inset; } - #forien-quest-log .quest-log .table ul .img { - flex: 0 0 40px; - width: 40px; - height: 40px; - border-radius: 5px 0 0 5px; - background-size: cover; - background-position: center; } - #forien-quest-log .quest-log .table ul .personal-quest-icon { - margin-left: 8px; } - #forien-quest-log .quest-log .table ul .title { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - height: 100%; - padding: 0 8px; - cursor: pointer; } - #forien-quest-log .quest-log .table ul .title h2 { - margin: 0; - padding: 0; - line-height: 1; - border: none; - font-size: 16px; - font-weight: 700; } - #forien-quest-log .quest-log .table ul .title p { - margin: 0; - padding: 0; - font-size: 12px; - font-weight: 400; } - #forien-quest-log .quest-log .table ul .tasks { - flex: 0 0 60px; - border-left: 1px solid rgba(0, 0, 0, 0.15); - height: 100%; - display: flex; - justify-content: center; - align-items: center; } - #forien-quest-log .quest-log footer { - flex: 0 0 1px; - padding: 8px 16px 0 16px; - display: flex; } - -#forien-quest-log-form form { - padding: 1rem; - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.1); - height: 100%; } -#forien-quest-log-form form header { - flex: 0 0 1px; } - #forien-quest-log-form form header .source-details { - display: flex; } - #forien-quest-log-form form header .source-image { - flex: 0 0 100px; - height: 100px; - font-size: 12px; - line-height: 1.2; - font-weight: 700; - text-align: center; - margin-right: 8px; } - #forien-quest-log-form form header .source-image .giver-portrait { - width: 100%; - height: 100%; - background-size: cover; - background-position: center; - border-radius: 5px; } - #forien-quest-log-form form header .source-image .hidden { - display: none; } - #forien-quest-log-form form header .source-image span { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - border: 2px dashed rgba(0, 0, 0, 0.5); - border-radius: 5px; - padding: 8px; } - #forien-quest-log-form form header .source-info { - flex: 1; - height: 100px; } - #forien-quest-log-form form header .quest-giver { - margin-bottom: 8px; } -#forien-quest-log-form .quest-title { - margin-top: 8px; } -#forien-quest-log-form .quest-text { - margin-top: 8px; - display: flex; - flex: 1; - overflow-y: hidden; } - #forien-quest-log-form .quest-text .quest-description, - #forien-quest-log-form .quest-text .quest-notes { - flex: 1; } - #forien-quest-log-form .quest-text .quest-notes { - margin-left: 8px; } - #forien-quest-log-form .quest-text .editor { - padding: 8px; - background: rgba(255, 255, 255, 0.5); - border-radius: 5px; - height: calc(100% - 30px); } - #forien-quest-log-form .quest-text .editor .tox .tox-toolbar-overlord { - background-color: transparent; - border-bottom: 1px solid #222; - padding-bottom: 4px; } - #forien-quest-log-form .quest-text .editor .tox .tox-toolbar, - #forien-quest-log-form .quest-text .editor .tox .tox-toolbar__overflow, - #forien-quest-log-form .quest-text .editor .tox .tox-toolbar__primary { - background: transparent; - background-color: transparent; } - #forien-quest-log-form .quest-text .editor .tox.tox-tinymce .tox-tbtn { - padding: 0; - margin: 0 0 0 4px; - width: 32px; } - #forien-quest-log-form .quest-text .editor .tox.tox-tinymce .tox-tbtn[title="Formats"] { - width: 90px; } - #forien-quest-log-form .quest-text .editor .editor-content { - height: 100%; - overflow-y: auto; - margin: 0; - padding: 0 12px 0 0; } -#forien-quest-log-form footer { - flex: 0 0 1px; - margin-top: 8px; } - -.window-app.forien-quest-preview { - min-width: 940px; - min-height: 640px; } - .window-app.forien-quest-preview .tab.active { - display: flex; - flex-direction: column; } - .window-app.forien-quest-preview .quest-preview { - height: 100%; - overflow-y: hidden; - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.1); - padding: 0 0 24px 0; } - .window-app.forien-quest-preview .quest-body { - height: 100%; - flex: 1; - overflow-y: auto; - padding: 16px 16px 0 16px; } - .window-app.forien-quest-preview .quest-body .details-header { - display: flex; - flex: 0 0 1px; - margin-bottom: 16px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc { - width: 100px; - height: 100px; - background-color: rgba(0, 0, 0, 0.1); - border-radius: 5px; - flex: 0 0 100px; - margin-right: 16px; - position: relative; } - .window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .quest-giver-image { - height: 100%; - width: 100%; - background-size: cover; - background-position: center; - cursor: pointer; - border-radius: 5px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage { - position: absolute; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - background: #efefef; - border-radius: 5px; - width: 22px; - height: 22px; - transition: color .3s ease; } - .window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .details-header .quest-giver-gc .toggleImage i { - font-size: 16px; - border-radius: 50%; - line-height: 1; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup { - flex: 1; - display: flex; - flex-direction: column; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-title { - display: flex; - justify-content: space-between; - align-items: center; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .editable-container { - flex: 1; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .editable-container input { - margin-bottom: 8px; - height: 28px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link { - flex: 0 0 100px; - background-size: cover; - background-position: center; - position: relative; - cursor: pointer; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link span { - position: absolute; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba(0, 0, 0, 0.3); - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 28px; - color: rgba(255, 255, 255, 0.65); - opacity: 1; - transition: opacity .3s ease; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .splash-image-link span:hover { - opacity: 0; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .actions { - flex: 0 0 1px; - padding: 0 8px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .actions i { - font-size: 18px; - transition: color .3s ease; - cursor: pointer; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .actions i:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-title .actions { - border: none; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup section { - flex: 1; - display: flex; - background: rgba(255, 255, 255, 0.15); - border-radius: 5px; - overflow: hidden; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-details { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - padding: 8px 16px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name h2 { - display: inline-block; - margin: 0; - border: none; - cursor: pointer; - transition: color .3s ease; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-giver-name h2:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status { - display: flex; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p { - margin: 0 8px 0 0; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p::after { - content: '|'; - margin-left: 8px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p:last-child { - margin: 0; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status p:last-child::after { - content: none; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name { - transition: color .3s ease; - cursor: pointer; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name i { - font-size: 12px; } - .window-app.forien-quest-preview .quest-body .details-header .quest-setup .quest-status .quest-name:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .quest-info { - display: flex; - flex: 1; - overflow-y: hidden; } - .window-app.forien-quest-preview .quest-body .quest-info header { - display: flex; - justify-content: space-between; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right button { - flex: 0 0 1px; - white-space: nowrap; - height: 18px; - font-size: 12px; - line-height: 1; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right button i { - font-size: 10px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-description { - flex: 0 0 50%; - height: 100%; - overflow-y: hidden; - margin-right: 8px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-description .description { - height: calc(100% - 26px); - overflow: hidden; - background: rgba(255, 255, 255, 0.4); - border-radius: 5px; - padding: 8px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-description .description .description-content { - height: 100%; - overflow: auto; - padding: 0 4px 0 0; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right { - flex: 1; - display: flex; - flex-direction: column; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right h2 { - border: none; - margin: 0; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right header { - border-bottom: 2px solid #782e22; - margin-bottom: 4px; - flex: 0 0 1px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards { - flex: 0 0 calc(50% - 8px); - display: flex; - flex-direction: column; - overflow-y: hidden; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-box, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .quest-box { - flex: 1; - overflow-y: hidden; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks ul, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards ul { - height: 100%; - overflow-y: auto; - margin: 0; - padding: 0; - list-style: none; - display: flex; - flex-direction: column; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks ul li, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards ul li { - display: flex; - border-radius: 5px; - background: rgba(255, 255, 255, 0.3); - margin: 0 4px 2px 0; - align-items: center; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions { - flex: 0 0 100px; - height: 100%; - cursor: default; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions i, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions i { - min-width: 16px; - text-align: center; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions .fa-sort, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions .fa-sort { - cursor: move; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions .del-btn, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions .del-btn { - color: rgba(255, 0, 0, 0.4); } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions .del-btn:hover, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions .del-btn:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .actions .fa-pen, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .actions .fa-pen { - font-size: 14px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container { - flex: 1; - padding: 4px 8px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container p, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container p { - margin: 0; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .editable-container input, - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .editable-container input { - padding: 0 4px; - line-height: 14px; - height: 16px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks { - margin-bottom: 16px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .toggleState { - display: flex; - align-items: center; - justify-content: center; - flex: 0 0 32px; - height: 100%; - border-right: 1px solid rgba(0, 0, 0, 0.15); - font-size: 18px; - cursor: pointer; - transition: color .3s ease; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .toggleState:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container { - display: flex; - align-items: center; - justify-content: center; - flex: 0 0 32px; - height: 100%; - border-right: 1px solid rgba(0, 0, 0, 0.15); - font-size: 18px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container .state-display { - background: rgba(0, 0, 0, 0.05); - border: 1px solid rgba(0, 0, 0, 0.3); - width: 16px; - height: 16px; - border-radius: 2px; - display: flex; - justify-content: center; - align-items: center; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .state-container .state-display i { - font-size: 11px; - line-height: 16px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name { - cursor: pointer; - transition: color .3s ease; - margin: 0; - padding: 4px 8px; - display: inline-block; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name:hover { - color: #ff6400; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .quest-name i { - font-size: 12px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .task-hidden { - background: rgba(0, 0, 0, 0.15); } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-tasks .task-hidden .task-name { - opacity: .5; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward { - flex: 0 0 25px; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .drop-info { - flex: 1 0 25px; - line-height: 20px; - border: 2px dashed rgba(0, 0, 0, 0.5); - border-radius: 5px; - padding: 0 16px; - text-align: center; - margin-right: 4px; - margin-bottom: 4px; - background: transparent; - justify-content: center; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden { - background: rgba(0, 0, 0, 0.15); } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden .reward-image { - opacity: .5; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-hidden .reward-name { - opacity: .5; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-image-container { - height: 100%; - flex: 0 0 25px; - display: flex; - align-items: center; - border-radius: 5px 0 0 5px; - overflow: hidden; - background-color: #222; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-image { - width: 25px; - height: 25px; - background-size: cover; - background-position: center; } - .window-app.forien-quest-preview .quest-body .quest-info .quest-col-right .quest-rewards .reward-name { - flex: 1; - font-size: 14px; - font-weight: 400; - margin: 0; - padding-right: 8px; } - .window-app.forien-quest-preview .quest-body .management .row { - display: flex; - flex: 0 0 1px; } - .window-app.forien-quest-preview .quest-body .management .quest-settings { - display: flex; - flex-direction: column; - flex: 1; - margin-right: 8px; - height: 226px; } - .window-app.forien-quest-preview .quest-body .management .quest-settings .setting-groups { - flex: 0 0 1px; } - .window-app.forien-quest-preview .quest-body .management .quest-settings .setting-groups .personal-quest-description { - font-size: 13px; - margin: 4px 0 2px 26px; } - .window-app.forien-quest-preview .quest-body .management .quest-settings .input-group { - display: flex; - align-items: center; - background: rgba(255, 255, 255, 0.4); - border-radius: 5px; - padding: 2px; - margin-bottom: 2px; } - .window-app.forien-quest-preview .quest-body .management .quest-settings input[type="checkbox"] { - flex: 0 0 20px; - width: 20px; - height: 20px; - margin: 0; } - .window-app.forien-quest-preview .quest-body .management .quest-settings label { - margin: 0 0 0 4px; - width: calc(100% - 20px); - overflow: hidden; - text-overflow: ellipsis; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings { - margin-left: 26px; - flex: 1; - overflow: hidden; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul { - margin: 0; - padding: 0 2px 0 0; - list-style: none; - display: flex; - flex-wrap: wrap; - width: calc(100% + 2px); - margin-left: -2px; - height: 100%; - overflow-y: auto; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul.disabled { - opacity: .5; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul.disabled li { - cursor: default; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul.disabled li:hover { - background: inherit; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul.disabled input, .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul.disabled label { - cursor: default; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul li { - cursor: pointer; - flex: 0 0 calc(100% / 4 - 4px); - display: flex; - align-items: center; - background: rgba(255, 255, 255, 0.4); - border-radius: 5px; - padding: 2px 8px 2px 2px; - margin: 2px; - white-space: nowrap; - overflow: hidden; } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul li:hover { - background: rgba(255, 255, 255, 0.6); } - .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul li input, .window-app.forien-quest-preview .quest-body .management .personal-quest-settings ul li label { - cursor: pointer; } - .window-app.forien-quest-preview .quest-body .management .quest-splash { - flex: 0 0 calc(100% / 3); } - .window-app.forien-quest-preview .quest-body .management .quest-splash .splash-image { - width: 100%; - height: 200px; - background-size: cover; - background-position: center; - background-color: rgba(255, 255, 255, 0.4); - border-radius: 5px; - cursor: pointer; } - .window-app.forien-quest-preview .quest-body .management .quest-splash .splash-image:hover { - background-color: rgba(255, 255, 255, 0.6); } - .window-app.forien-quest-preview .quest-body .management .subquests { - flex: 1; - display: flex; - flex-direction: column; - margin-top: 16px; - overflow: hidden; } - .window-app.forien-quest-preview .quest-body .management .subquests h2 { - flex: 0 0 1px; } - .window-app.forien-quest-preview .quest-body .management .subquests .subquests-box { - flex: 1; - overflow-y: auto; - margin: 0; - padding: 0; - list-style: none; } - .window-app.forien-quest-preview .quest-body .management .subquests .subquests-box li { - display: flex; - align-items: center; - background: rgba(255, 255, 255, 0.3); - height: 30px; - border-radius: 5px; - margin: 0 4px 2px 0; - border: 1px solid transparent; - transition: border-color .3s ease, box-shadow .3s ease; } - .window-app.forien-quest-preview .quest-body .management .subquests .subquests-box li:hover { - border-color: #ff6400; - box-shadow: 0 0 2px #ff6400 inset; } - .window-app.forien-quest-preview .quest-body .management .subquests .subquests-box h2 { - flex: 1; - border: none; - margin: 0 8px; - font-size: 14px; - line-height: 30px; - cursor: pointer; - transition: color .3s ease; } - .window-app.forien-quest-preview .quest-body .management .subquests .subquests-box .actions { - flex: 0 0 100px; - height: 100%; } - .window-app.forien-quest-preview .quest-body .management .subquests footer { - flex: 0 0 1px; - margin: 8px 0 0 0; } - .window-app.forien-quest-preview .quest-body .editor { - height: calc(100% - 26px); } - .window-app.forien-quest-preview .quest-body .gmnotes .editor { - height: calc(100% - 36px); } - .window-app.forien-quest-preview .quest-body .tox .tox-toolbar-overlord { - background-color: transparent; - border-bottom: 1px solid #222; - padding-bottom: 4px; } - .window-app.forien-quest-preview .quest-body .tox .tox-toolbar, - .window-app.forien-quest-preview .quest-body .tox .tox-toolbar__overflow, - .window-app.forien-quest-preview .quest-body .tox .tox-toolbar__primary { - background: transparent; - background-color: transparent; } - .window-app.forien-quest-preview .quest-body .tox.tox-tinymce .tox-tbtn { - padding: 0; - margin: 0 0 0 4px; - width: 32px; } - .window-app.forien-quest-preview .quest-body .tox.tox-tinymce .tox-tbtn[title="Formats"] { - width: 90px; } - -/*# sourceMappingURL=init.css.map */ diff --git a/styles/init.css.map b/styles/init.css.map deleted file mode 100644 index 234a97d1..00000000 --- a/styles/init.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["quest-general.scss","init.scss","quest-log.scss","quest-form.scss","quest-preview.scss"], -"names": [], -"file": "init.css" -} diff --git a/styles/init.scss b/styles/init.scss index 784ee59d..d4477f38 100644 --- a/styles/init.scss +++ b/styles/init.scss @@ -1,11 +1,2 @@ -$background-parchment: url("/ui/parchment.jpg") repeat; -$background-parchment-dark: url("/modules/dnd5e-dark-mode/ui/parchment_dark.jpg") repeat; - -$background-color-light: rgba(255,255,255,.5); -$primary-accent-color: #ff6400; - -$button-background: #F2F1EA; -$button-hover: #efefef; -$button-border: #333; - -@import 'quest-general', 'quest-log', 'quest-form', 'quest-preview'; \ No newline at end of file +@import 'global-mixin', 'global-variables', 'basicapp', 'quest-general', 'quest-log', 'quest-preview', + 'quest-tracker'; diff --git a/styles/quest-form.scss b/styles/quest-form.scss deleted file mode 100644 index 4bf1e96a..00000000 --- a/styles/quest-form.scss +++ /dev/null @@ -1,125 +0,0 @@ -#forien-quest-log-form { - - form { - padding: 1rem; - display: flex; - flex-direction: column; - background: rgba(0,0,0,.1); - height: 100%; - // overflow-y: hidden; - } - - form header { - flex: 0 0 1px; - - .source-details { - display: flex; - } - - .source-image { - flex: 0 0 100px; - height: 100px; - font-size: 12px; - line-height: 1.2; - font-weight: 700; - text-align: center; - margin-right: 8px; - - .giver-portrait { - width: 100%; - height: 100%; - background-size: cover; - background-position: center; - border-radius: 5px; - } - - .hidden { - display: none; - } - - span { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - border: 2px dashed rgba(0,0,0,.5); - border-radius: 5px; - padding: 8px; - } - } - - .source-info { - flex: 1; - height: 100px; - } - - .quest-giver { - margin-bottom: 8px; - } - - - } - - .quest-title { - margin-top: 8px; - } - - .quest-text { - margin-top: 8px; - display: flex; - flex: 1; - overflow-y: hidden; - - .quest-description, - .quest-notes { - flex: 1; - } - - .quest-notes { - margin-left: 8px; - } - - .editor { - padding: 8px; - background: $background-color-light; - border-radius: 5px; - height: calc(100% - 30px); - - .tox .tox-toolbar-overlord { - background-color: transparent; - border-bottom: 1px solid #222; - padding-bottom: 4px; - } - - .tox .tox-toolbar, - .tox .tox-toolbar__overflow, - .tox .tox-toolbar__primary { - background: transparent; - background-color: transparent; - } - - .tox.tox-tinymce .tox-tbtn { - padding: 0; - margin: 0 0 0 4px; - width: 32px; - } - - .tox.tox-tinymce .tox-tbtn[title="Formats"] { - width: 90px; - } - - .editor-content { - height: 100%; - overflow-y: auto; - margin: 0; - padding: 0 12px 0 0; - } - } - - } - - footer { - flex: 0 0 1px; - margin-top: 8px; - } -} diff --git a/styles/quest-general.scss b/styles/quest-general.scss index 0384a5de..dc1cd3e4 100644 --- a/styles/quest-general.scss +++ b/styles/quest-general.scss @@ -1,10 +1,46 @@ #forien-quest-log, -#forien-quest-log-form, +#quest-tracker, +.window-app.forien-quest-preview { + .pad-l-4 { + padding-left: 4px; + } + + .pad-l-8 { + padding-left: 8px; + } + + i { + flex: none; + + &.fas.fa-star { + color: $icon-color-primary-quest; + filter: drop-shadow(0 0 2px #000); + } + + &.fas.fa-fill { + color: $icon-color-show-background; + filter: drop-shadow(0 0 2px #000); + } + + &.fas.fa-fill.off { + color: white; + filter: drop-shadow(0 0 2px #000); + } + } +} + +#forien-quest-log, .window-app.forien-quest-preview { + // Some systems such as Blades In the Dark require this parameter. + .window-header { + margin: 0; + } + .window-content { padding: 0; - height: 100%; + margin: 0; + border-radius: 0 0 5px 5px; } .tab { @@ -27,7 +63,6 @@ h2 { font-size: 18px; - line-height: 1; font-weight: 700; padding: 0 0 2px 0; margin: 0 0 4px 0; @@ -48,39 +83,34 @@ height: 26px; &:hover { - box-shadow: 0 0 0 1px $primary-accent-color inset; + box-shadow: 0 0 0 1px $primary-color-accent inset; } } button { - background: $button-background; height: 30px; - border: 1px solid $button-border; border-radius: 5px; - margin: 0 0 0 8px; + margin-top: 2px; + margin-right: 4px; + margin-bottom: 2px; transition: border-color .3s ease, background .3s ease, box-shadow .3s ease; cursor: pointer; - &:hover { - box-shadow: 0 0 2px $primary-accent-color inset; - border-color: $primary-accent-color; - background: $button-hover; - } - &:first-child { margin-left: 0; } } - nav { + nav.tabs { flex: 0 0 40px; - background: rgba(255,255,255,.3); + background: $primary-color-bg-nav; justify-content: flex-start; align-items: center; padding: 0 16px; + font-size: larger; .item { text-align: left; @@ -91,7 +121,7 @@ &:hover { text-shadow: none; - color: $primary-accent-color; + color: $primary-color-accent; } &:first-child { @@ -111,6 +141,10 @@ display: none; } + .icon-button { + flex: none; + } + .editor { height: 100%; padding: 8px; @@ -120,43 +154,122 @@ .editor-content { height: 100%; padding: 0; - padding: 0 4px 0 0; overflow: auto; } } + // See `Enrich.statusActions` for building actions for quests. .actions { - flex: 0 0 100px; - border-left: 1px solid rgba(0,0,0,.15); - height: 100%; - display: flex; - justify-content: center; - align-items: center; - - i { - font-size: 16px; - margin-left: 4px; - cursor: pointer; - color: rgba(0,0,0,.75); - transition: color .3s ease; - - &.delete { - color: rgba(255,0,0,.4); - } - - &.fa-play { - font-size: 14px; - padding-top: 2px; - } - - &:hover { - color: $primary-accent-color; - } - - &:first-child { - margin: 0; - } + flex: 0 0 100px; + border-left: 1px solid rgba(0,0,0,.15); + height: 100%; + display: flex; + justify-content: center; + align-items: center; + + // The flex size is reduced for players who have less actions available. + &.is-player { + flex: 0 0 60px; + } + + // Used to justify center tasks and rewards + span.justify-center { + flex: 1; + margin: 1px 1px 1px auto; + visibility: hidden; + } + + span.spacer { + flex: 0 0 4px; + } + + i { + flex: 0 0 18px; + font-size: 16px; + padding: 0; + text-align: center; + border: none; + cursor: pointer; + color: $primary-color-icon; + transition: color .3s ease; + + // Special handling to align sort icon to the left and use margin-right: auto to push rest of content right. + // In this case add span.justify-center to the right hand of the action div to center the content. + &.fa-sort { + flex: 0 0 18px; + cursor: move; + width: 14px; + border-right: 1px solid rgba(0, 0, 0, 0.15); + } + + // fa-eye-slash is slightly larger and offsets so provide specific flex settings and padding for fa-eye + &.fa-eye { + flex: 0 0 20px; + padding-left: 1px; + } + + &.fa-eye-slash { + flex: 0 0 20px; + } + + &.fa-check-circle { + color: $icon-color-completed; + } + + &.fa-times-circle { + color: $icon-color-failed; + } + + &.fa-trash { + color: $icon-color-trashcan; + } + + &.fa-play { + font-size: 14px; + padding-top: 2px; + } + + &:hover { + color: $primary-color-accent; + } + + &:hover.is-player { + color: $primary-color-icon; + cursor: default; + } + + &:first-child { + margin: 0; } } + } + + // Used for action divs that have a single icon (see: QuestPreview quest name / fa-pen) + .actions-single { + flex: 0 0 1px; + padding: 0 8px; + i { + font-size: 18px; + transition: color .3s ease; + cursor: pointer; + + &:hover { + color: $primary-color-accent; + } + } + } + + // Provides specific overrides to make sure the layout is consistent across game systems. + // In particular this is needed for Blades In the Dark `v3.3.0`. + section { + flex-direction: row; + display: block; + justify-content: flex-start; + } + + // Defines the corner of any scrollbars. + ::-webkit-scrollbar-corner { + background: rgba(0, 0, 0, 0.1); + } } \ No newline at end of file diff --git a/styles/quest-log.scss b/styles/quest-log.scss index e5922721..fb88c7a8 100644 --- a/styles/quest-log.scss +++ b/styles/quest-log.scss @@ -2,42 +2,49 @@ min-width: 500px; min-height: 640px; + // Necessary to ensure the bookmark tabs show. See `QuestLog.setPosition` for the manual positioning necessary. + // Some game systems and UI theming modules override `overflow`, so we must visible, but then handle very long + // list of quests / `.table` below manually based on the Application / setPosition. + &.window-app .window-content { + overflow: visible; + } + + $quest-min-height: 42px; // Defines the height of the quest
  • and children elements. + .quest-log { - height: 100%; - overflow-y: auto; display: flex; flex-direction: column; - background: rgba(0,0,0,.1); - padding: 0 0 24px 0; + padding: 0 0 16px 0; } - .quest-log.bookmarks nav { + .quest-log.bookmarks nav.log-tabs { position: absolute; left: 0; - transform: translateX(-100%); + transform: translateX(-97%); flex-direction: column; align-items: flex-end; background: none; padding: 0; flex: 0; + border-block-end: none; .item { - background: $background-parchment; + // The dynamic jQuery module setting overrides this with the window content background image. This is the fallback. + background: $log-bookmark-image-background; + text-align: right; - margin: 0; - margin-bottom: 4px; + margin: 0 0 4px 0; padding: 8px 16px; width: 150px; border-radius: 5px 0 0 5px; position: relative; z-index: 1; - box-shadow: - -5px 0 5px -5px rgba(0, 0, 0, 0.25) inset, + box-shadow: 0 5px 5px -5px rgba(0, 0, 0, 0.3), - 0 -5px 5px -5px rgba(0, 0, 0, 0.3), - -2px 0 5px -2px rgba(0, 0, 0, 0.3); + 0 -5px 5px -5px rgba(0, 0, 0, 0.3); + transition: padding .3s ease, width .3s ease, color .3s ease; - + &:hover { padding-right: 32px; width: 166px; @@ -55,7 +62,6 @@ height: 100%; top: 0; left: 0; - background: rgba(0,0,0,.1); border-radius: 5px 0 0 5px; z-index: -1; } @@ -64,13 +70,31 @@ .quest-log .log-body { flex: 1; - overflow-y: hidden; padding: 0 16px; + + header { + @include header-buttons; + justify-content: space-between; + margin-top: 0; + padding-top: 0; + margin-bottom: 4px; + + h1 { + align-self: flex-end; + border: none; + margin: 0; + padding-bottom: 4px; + } + + button { + flex: 0 0 fit-content; + } + } } .quest-log .tab { flex-direction: column; - padding: 16px 0 0 0; + padding: 4px 0 0 0; &.active { display: flex; @@ -79,6 +103,9 @@ .table { flex: 1; overflow-y: auto; + + // For Firefox. + scrollbar-width: thin; } } @@ -87,7 +114,7 @@ margin: 0; padding: 0; - li { + li.drag-quest { display: flex; justify-content: flex-start; align-items: center; @@ -95,26 +122,25 @@ background: rgba(255, 255, 255, .3); border: 1px solid transparent; border-radius: 5px; - height: 42px; + min-height: $quest-min-height; transition: border-color .3s ease, box-shadow .3s ease; &:hover { - border-color: $primary-accent-color; - box-shadow: 0 0 2px $primary-accent-color inset; + border-color: $primary-color-accent; + box-shadow: 0 0 2px $primary-color-accent inset; } } + .open-quest { + cursor: pointer; + } + .img { flex: 0 0 40px; width: 40px; height: 40px; - border-radius: 5px 0 0 5px; + border-radius: 5px; background-size: cover; - background-position: center; - } - - .personal-quest-icon { - margin-left: 8px } .title { @@ -122,9 +148,9 @@ display: flex; flex-direction: column; justify-content: center; - height: 100%; - padding: 0 8px; - cursor: pointer; + padding-left: 2px; + padding-right: 8px; + min-height: $quest-min-height; h2 { margin: 0; @@ -143,20 +169,22 @@ } } + // The height parameter hard codes the height for the border to show, but in the future this may need to be + // adjustable. .tasks { - flex: 0 0 60px; + font-size: 18px; + flex: 0 0 50px; border-left: 1px solid rgba(0,0,0,.15); - height: 100%; + min-height: $quest-min-height; display: flex; justify-content: center; align-items: center; } - } - .quest-log footer { - flex: 0 0 1px; - padding: 8px 16px 0 16px; - display: flex; + // The height parameter hard codes the height for the border to show, but in the future this may need to be + // adjustable. + .actions { + min-height: $quest-min-height; + } } - } \ No newline at end of file diff --git a/styles/quest-preview.scss b/styles/quest-preview.scss index 7c3c7320..66f6731c 100644 --- a/styles/quest-preview.scss +++ b/styles/quest-preview.scss @@ -1,5 +1,5 @@ .window-app.forien-quest-preview { - min-width: 940px; + min-width: 1000px; min-height: 640px; .tab.active { @@ -13,35 +13,49 @@ display: flex; flex-direction: column; background: rgba(0, 0, 0, .1); - padding: 0 0 24px 0; + padding: 0; } .quest-body { height: 100%; flex: 1; + overflow-x: hidden; overflow-y: auto; - padding: 16px 16px 0 16px; + padding: 6px 14px 14px 14px; .details-header { display: flex; flex: 0 0 1px; - margin-bottom: 16px; + margin-bottom: 6px; .quest-giver-gc { - width: 100px; - height: 100px; - background-color: rgba(0, 0, 0, .1); + width: 116px; + height: 116px; + background-color: $primary-color-bg-drop; border-radius: 5px; - flex: 0 0 100px; - margin-right: 16px; + flex: 0 0 116px; + margin-right: 8px; position: relative; + font-size: 12px; + line-height: 1.2; + font-weight: 700; + text-align: center; + + .drop-info { + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + height: 100%; + border: 2px dashed rgba(0,0,0,.5); + border-radius: 5px; + } + .quest-giver-image { height: 100%; width: 100%; background-size: cover; - background-position: center; - cursor: pointer; border-radius: 5px; } @@ -49,24 +63,14 @@ position: absolute; top: 0; left: 0; - display: flex; - justify-content: center; - align-items: center; - background: #efefef; - border-radius: 5px; - width: 22px; - height: 22px; - transition: color .3s ease; - - &:hover { - color: $primary-accent-color; - } + @include button; + } - i { - font-size: 16px; - border-radius: 50%; - line-height: 1; - } + .deleteQuestGiver { + position: absolute; + top: 0; + right: 0; + @include button; } } @@ -83,6 +87,7 @@ .editable-container { flex: 1; + padding-left: 6px; input { margin-bottom: 8px; @@ -93,7 +98,6 @@ .splash-image-link { flex: 0 0 100px; background-size: cover; - background-position: center; position: relative; cursor: pointer; @@ -119,31 +123,13 @@ } } - .actions { - flex: 0 0 1px; - padding: 0 8px; - - i { - font-size: 18px; - transition: color .3s ease; - cursor: pointer; - - &:hover { - color: $primary-accent-color; - } - } - } - - .quest-title .actions { - border: none; - } - section { flex: 1; display: flex; background: rgba(255, 255, 255, .15); border-radius: 5px; overflow: hidden; + margin-right: 4px; } .quest-details { @@ -151,7 +137,23 @@ display: flex; flex-direction: column; justify-content: center; - padding: 8px 16px; + padding-right: 16px; + } + + .quest-giver-name { + display: inline-flex; + justify-content: left; + flex-direction: row; + } + + .quest-giver-name .editable-container { + flex: 0 0 auto; + + input { + margin-bottom: 2px; + padding: 0; + height: 22px; + } } .quest-giver-name h2 { @@ -162,12 +164,17 @@ transition: color .3s ease; &:hover { - color: $primary-accent-color; + color: $primary-color-accent; } } + .quest-giver-name .action-single { + flex: 0 0 1px; + } + .quest-status { display: flex; + padding-left: 6px; p { margin: 0 8px 0 0; @@ -186,7 +193,7 @@ content: none; } - .quest-name { + .quest-name-link { transition: color .3s ease; cursor: pointer; @@ -195,7 +202,7 @@ } &:hover { - color: $primary-accent-color; + color: $primary-color-accent; } } } @@ -215,8 +222,8 @@ .quest-col-right button { flex: 0 0 1px; white-space: nowrap; - height: 18px; - font-size: 12px; + height: 20px; + font-size: 15px; line-height: 1; i { @@ -225,14 +232,14 @@ } .quest-description { - flex: 0 0 50%; + flex: 0 0 48%; height: 100%; overflow-y: hidden; margin-right: 8px; .description { - height: calc(100% - 26px); - overflow: hidden; + height: calc(100% - 30px); + overflow: auto; background: rgba(255, 255, 255, .4); border-radius: 5px; padding: 8px; @@ -246,21 +253,25 @@ } .quest-col-right { - flex: 1; + flex: 0 0 51%; display: flex; flex-direction: column; h2 { border: none; - margin: 0; + margin: 0 auto 0 0; } header { - border-bottom: 2px solid #782e22; + @include header-buttons; margin-bottom: 4px; flex: 0 0 1px; } + span.spacer-edit { + flex: 0 0 18px; + } + .quest-tasks, .quest-rewards { flex: 0 0 calc(50% - 8px); @@ -285,45 +296,40 @@ li { display: flex; border-radius: 5px; - background: rgba(255, 255, 255, .3); + background: $primary-color-bg-li; margin: 0 4px 2px 0; align-items: center; } - } - .actions { - flex: 0 0 100px; - height: 100%; - cursor: default; - - i { - min-width: 16px; - text-align: center; - } - - .fa-sort { - cursor: move; - } - - .del-btn { - color: rgba(255, 0, 0, .4); - - &:hover { - color: $primary-accent-color; - } + li:last-of-type { + margin-bottom: 0; } + } - .fa-pen { - font-size: 14px; - } + .is-link { + cursor: pointer; } .editable-container { flex: 1; - padding: 4px 8px; + padding: 4px 4px; p { margin: 0; + max-width: 290px; + word-wrap: break-word; + + &.can-edit { + max-width: 290px; + } + + &.player-edit { + max-width: 330px; + } + + &.player { + max-width: 400px; + } } input { @@ -349,7 +355,7 @@ transition: color .3s ease; &:hover { - color: $primary-accent-color; + color: $primary-color-accent; } } @@ -379,15 +385,28 @@ } } - .quest-name { + .quest-name-link { cursor: pointer; transition: color .3s ease; margin: 0; - padding: 4px 8px; - display: inline-block; + padding: 4px 4px; + flex: 1; + word-wrap: break-word; + + .can-edit { + max-width: 290px; + } + + .player-edit { + max-width: 330px; + } + + .player { + max-width: 390px; + } &:hover { - color: $primary-accent-color; + color: $primary-color-accent; } i { @@ -396,7 +415,7 @@ } .task-hidden { - background: rgba(0, 0, 0, .15); + background: $primary-color-bg-li-hidden; .task-name { opacity: .5; @@ -405,26 +424,38 @@ } .quest-rewards { + button { + &.hide-all-rewards, &.show-all-rewards { + flex: 0 0 90px; + } + + &.lock-all-rewards, &.unlock-all-rewards { + flex: 0 0 98px; + } + } .reward { flex: 0 0 25px; } + span.spacer-edit { + flex: 0 0 18px; + } + .drop-info { flex: 1 0 25px; line-height: 20px; - border: 2px dashed rgba(0, 0, 0, .5); + border: 2px dashed $primary-color-border-drop; border-radius: 5px; padding: 0 16px; text-align: center; margin-right: 4px; - margin-bottom: 4px; background: transparent; justify-content: center; } .reward-hidden { - background: rgba(0, 0, 0, .15); + background: $primary-color-bg-li-hidden; .reward-image { opacity: .5; @@ -443,6 +474,10 @@ border-radius: 5px 0 0 5px; overflow: hidden; background-color: #222; + + &.can-edit { + cursor: pointer; + } } .reward-image { @@ -461,11 +496,23 @@ } } } + } + .playernotes { + .quest-playernotes { + height: 100%; + overflow-y: hidden; + } } - .management { + .gmnotes { + .quest-gmnotes { + height: 100%; + overflow-y: hidden; + } + } + .management { .row { display: flex; flex: 0 0 1px; @@ -480,27 +527,6 @@ .setting-groups { flex: 0 0 1px; - - .personal-quest-description { - font-size: 13px; - margin: 4px 0 2px 26px; - } - } - - .input-group { - display: flex; - align-items: center; - background: rgba(255, 255, 255, .4); - border-radius: 5px; - padding: 2px; - margin-bottom: 2px; - } - - input[type="checkbox"] { - flex: 0 0 20px; - width: 20px; - height: 20px; - margin: 0; } label { @@ -511,76 +537,73 @@ } } - .personal-quest-settings { - margin-left: 26px; - flex: 1; - overflow: hidden; - - ul { - margin: 0; - padding: 0 2px 0 0; - list-style: none; - display: flex; - flex-wrap: wrap; - width: calc(100% + 2px); - margin-left: -2px; - height: 100%; - overflow-y: auto; - - &.disabled { - opacity: .5; - - li { - cursor: default; + .quest-splash { + flex: 0 0 calc(100% / 2.5); + position: relative; - &:hover { - background: inherit; - } - } + .splash-image { + width: 100%; + height: 200px; + background-size: cover; + background-color: $primary-color-bg-drop; + border-radius: 5px; - input, label { - cursor: default; - } + &:hover { + background-color: $primary-color-hover-drop; } + } - li { - cursor: pointer; - flex: 0 0 calc(100% / 4 - 4px); - display: flex; - align-items: center; - background: rgba(255, 255, 255, .4); - border-radius: 5px; - padding: 2px 8px 2px 2px; - margin: 2px; - white-space: nowrap; - overflow: hidden; + .state-container { + margin-left: 12px; + position: relative; - &:hover { - background: rgba(255, 255, 255, .6); - } + input[type="checkbox"] { + vertical-align: center; + display: inline; + position: absolute; + top: 1px; + width: 18px; + height: 18px; + margin: 0; + cursor: pointer; + } - input, label { - cursor: pointer; - } + label { + position: absolute; + left: 22px; + width: 260px; + display: inline; + font-weight: lighter; } } - } - .quest-splash { - flex: 0 0 calc(100% / 3); - - .splash-image { - width: 100%; - height: 200px; - background-size: cover; - background-position: center; - background-color: rgba(255, 255, 255, .4); + .drop-info { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + border: 2px dashed $primary-color-border-drop; border-radius: 5px; cursor: pointer; + } - &:hover { - background-color: rgba(255, 255, 255, .6); - } + .splash-border { + border: 2px dashed $primary-color-border-drop; + } + + .delete-splash { + position: relative; + top: 0; + left: calc(100% - 22px); + @include button; + } + + .change-splash-pos { + position: relative; + top: calc(100% - 44px); + left: calc(100% - 22px); + right: 0; + @include button; } } @@ -591,8 +614,23 @@ margin-top: 16px; overflow: hidden; + header { + @include header-buttons; + justify-content: space-between; + margin-top: 0; + padding-top: 0; + margin-bottom: 4px; + } + h2 { - flex: 0 0 1px; + align-self: flex-end; + border: none; + margin: 0; + padding-bottom: 0; + } + + button { + flex: 0 0 fit-content; } .subquests-box { @@ -613,65 +651,31 @@ transition: border-color .3s ease, box-shadow .3s ease; &:hover { - border-color: $primary-accent-color; - box-shadow: 0 0 2px $primary-accent-color inset; + border-color: $primary-color-accent; + box-shadow: 0 0 2px $primary-color-accent inset; } } h2 { flex: 1; border: none; - margin: 0 8px; + margin: 0 4px; + align-self: center; font-size: 14px; line-height: 30px; cursor: pointer; transition: color .3s ease; } - - .actions { - flex: 0 0 100px; - height: 100%; - } - } - - footer { - flex: 0 0 1px; - margin: 8px 0 0 0; } } - } .editor { - height: calc(100% - 26px); + height: calc(100% - 30px); } .gmnotes .editor { height: calc(100% - 36px); } - - .tox .tox-toolbar-overlord { - background-color: transparent; - border-bottom: 1px solid #222; - padding-bottom: 4px; - } - - .tox .tox-toolbar, - .tox .tox-toolbar__overflow, - .tox .tox-toolbar__primary { - background: transparent; - background-color: transparent; - } - - .tox.tox-tinymce .tox-tbtn { - padding: 0; - margin: 0 0 0 4px; - width: 32px; - } - - .tox.tox-tinymce .tox-tbtn[title="Formats"] { - width: 90px; - } - } } diff --git a/styles/quest-tracker.scss b/styles/quest-tracker.scss new file mode 100644 index 00000000..5e1b1bfc --- /dev/null +++ b/styles/quest-tracker.scss @@ -0,0 +1,246 @@ +#quest-tracker { + pointer-events: none; + min-width: 275px; + min-height: 72px; + max-width: 400px; + max-height: 750px; + + @keyframes fql-jiggle { + 0% { + transform: rotate(-0.25deg); + animation-timing-function: ease-in; + } + + 50% { + transform: rotate(0.5deg); + animation-timing-function: ease-out; + } + } + + .window-content { + // For Firefox. + scrollbar-width: thin; + } + + a.content-link { + background: $tracker-color-background-entitylink; + border: none; + color: $tracker-color-text-entitylink; + } + + &.fql-app { + background: $tracker-image-background; + background-color: $tracker-color-background; + background-blend-mode: $tracker-image-background-blend-mode; + box-shadow: 0 0 12px #000; + + // The no-background class is added by QuestTrackerShell.svelte removing the background and setting the scrollbar + // and window resizable transparent. + &.no-background { + background: none; + box-shadow: none; + + // For Firefox. + scrollbar-color: rgba(80, 80, 80, 0.7) rgba(60, 60, 60, 0.5); + + ::-webkit-scrollbar-thumb { + background: rgba(60, 60, 60, 0.5); + border: rgba(80, 80, 80, 0.7); + } + + .window-resizable-handle { + opacity: 0.4; + } + } + + // Doesn't work quite right as game systems can provide specific colors. + //a:hover { + // text-shadow: 0 0 8px $tracker-color-text-hover; + //} + } + + .window-content { + padding: 0 8px 0 8px; + color: $tracker-color-text; + font-family: "Open Sans", Lato, Signika, sans-serif; + overflow-y: auto; + } + + .window-header { + color: $tracker-color-text; + pointer-events: auto; + + h4 { + font-family: Signika, sans-serif; + } + } + + .window-resizable-handle { + pointer-events: auto; + } + + * { + box-sizing: border-box; + } + + #hidden { + color: $tracker-color-text-hidden; + } + + .quest:not(:last-child) { + margin-bottom: 16px; + } + + .quests { + flex: none; + padding: 8px 0 8px 0; + } + + .no-quests { + flex: none; + padding: 12px 0 8px 0; + + // Must specifically target elements to support context menu. + filter: drop-shadow(1px 1px 1px #000); + } + + .quest { + overflow-x: hidden; + overflow-y: hidden; + height: auto; + + display: flex; + flex-direction: column; + flex: 1; + + .title { + a, i { + // Must specifically target elements to support context menu. + filter: drop-shadow(1px 1px 1px #000); + } + } + + i { + cursor: pointer; + pointer-events: auto; + + // Add additional width to last icon such that there is space between any previous icon. + &:last-of-type { + flex: 0 0 26px; + text-align: right; + } + } + + .title { + display: flex; + flex-direction: row; + margin: 0; + font-size: 18px; + align-items: center; + } + + .quest-tracker-header { + cursor: pointer; + pointer-events: auto; + width: fit-content; + height:auto; + } + + .quest-tracker-span { + flex: 1; + } + + .quest-tracker-link { + pointer-events: auto; + } + + .tasks { + margin: 3px 0 0 0; + list-style: none; + padding-left: 4px; + + i { + // Add additional width to last icon such that there is space between any previous icon. + &:last-of-type { + flex: 0 0 21px; + text-align: right; + } + } + + .subquest { + // Must specifically target elements to support context menu. + filter: drop-shadow(1px 1px 1px #000); + } + + .quest-tracker-task { + cursor: pointer; + width: fit-content; + + // Must specifically target elements to support context menu. + filter: drop-shadow(1px 1px 1px #000); + + span { + cursor: pointer; + pointer-events: auto; + &.check-square, &.minus-square { + text-decoration: line-through; + } + } + } + + .subquest-separator { + margin-top: 3px; + margin-bottom: 4px; + width: 50px; + height: 1px; + background-color: rgba(255, 255, 255, .5); + } + + .task { + margin: 2px 0 0 0; + display: flex; + align-items: center; + + span { + cursor: pointer; + &.check-square, &.minus-square { + text-decoration: line-through; + } + } + + &::before { + content: "\f0c8"; + display: inline-block; + padding-right: 4px; + font-weight: 400; + font-family: "Font Awesome 5 Free"; + min-width: 14px; + width: fit-content; + pointer-events: auto; + align-self: flex-start; + } + + &.minus-square { + &::before { + content: "\f00d"; + display: inline-block; + font-weight: 900; + padding-left: 1px; + min-width: 13px; + width: fit-content; + } + } + + &.check-square { + &::before { + display: inline-block; + content: "\f00c"; + font-weight: 900; + min-width: 14px; + width: fit-content; + } + } + } + } + } +} \ No newline at end of file diff --git a/templates/partials/quest-form/task.html b/templates/partials/quest-form/task.html deleted file mode 100644 index b3c443ea..00000000 --- a/templates/partials/quest-form/task.html +++ /dev/null @@ -1,4 +0,0 @@ -
    - - -
    diff --git a/templates/partials/quest-log/tab.html b/templates/partials/quest-log/tab.html index a25eb723..e5357fde 100644 --- a/templates/partials/quest-log/tab.html +++ b/templates/partials/quest-log/tab.html @@ -1,45 +1,39 @@ -

    {{format 'ForienQuestLog.Quests' (localize (lookup questTypes tab))}}

    +
    +

    {{fql_format 'ForienQuestLog.QuestLog.Labels.TableHeader' (localize (lookup questStatusI18n tab))}}

    + {{#if (or isGM canCreate)}} + + {{/if}} +
      {{#each quests}} + {{#with enrich}}
    • - {{#if giver.img}}
      {{/if}} - {{#if (and personal ../isGM)}} - + {{#if (eq questIconType 'quest-giver')}} +
      {{/if}} -
      - -

      {{title}}

      + {{#if (eq questIconType 'splash-image')}} +
      + {{/if}} + {{#if isPrimary}}{{/if}} + {{#if canEdit}} + {{#if isHidden}}{{/if}} + {{#if isPersonal}}{{/if}} + {{/if}} +
      +

      {{name}}

      {{#if isSubquest}} -

      {{format 'ForienQuestLog.QuestPreview.SubTitle' parent.name}}

      +

      {{fql_format 'ForienQuestLog.QuestLog.Labels.SubTitle' data_parent.name}}

      {{/if}}
      - {{#unless (eq ../showTasks 'no')}} -
      {{checkedTasks}}{{#unless (eq ../showTasks 'onlyCurrent')}}/{{totalTasks}}{{/unless}}
      + {{#unless (eq ../../showTasks 'no')}} +
      {{checkedTasks}}{{#unless (eq ../../showTasks 'onlyCurrent')}}/{{totalTasks}}{{/unless}}
      {{/unless}} - {{#if (or ../isGM ../canAccept)}} -
      - {{#if (or (eq ../tab 'hidden') (eq ../tab 'available'))}} - - {{/if}} - {{#if ../isGM}} - {{#if (and (eq ../tab 'hidden') ../availableTab)}} - - {{/if}} - {{/if}} - {{#if ../isGM}} - {{#if (eq ../tab 'active')}} - - - {{/if}} - {{#unless (eq ../tab 'hidden')}} - - {{/unless}} - - {{/if}} -
      + {{#if statusActions.length}} + {{{statusActions}}} {{/if}}
    • + {{/with}} {{/each}}
    diff --git a/templates/partials/quest-preview/details.html b/templates/partials/quest-preview/details.html index e7e9d3d4..e4ba3706 100644 --- a/templates/partials/quest-preview/details.html +++ b/templates/partials/quest-preview/details.html @@ -1,24 +1,38 @@
    - {{#with giver}} -
    - {{#if (and ../canEdit ../image)}} - + {{#if (eq giver null)}} + {{#if (or canEdit playerEdit)}} + + {{#if canEdit}} + {{localize 'ForienQuestLog.QuestPreview.Labels.DragDropActor'}} + {{else}} + {{localize 'ForienQuestLog.QuestPreview.Labels.DragDropActorPlayer'}} + {{/if}} + + {{/if}} + {{else}} + {{#with giverData}} +
    + {{#if (and (or ../canEdit ../playerEdit) ../image img)}} + {{#if hasTokenImg}} + + {{/if}} + + {{/if}} + {{/with}} {{/if}} - - {{/with}}

    - {{title}} + {{name}}

    - {{#if canEdit}} -
    - + {{#if (or canEdit playerEdit)}} +
    +
    {{/if}}
    @@ -26,42 +40,38 @@

    - {{#with giver}} -

    {{name}}

    + {{#with giverData}} +
    +

    {{name}}

    +
    {{/with}} + {{#if (and canEdit (eq giver 'abstract'))}} +
    + +
    + {{/if}}
    -
    +

    - Quest is {{this.statusLabel}} + {{statusLabel}}

    {{#if isSubquest}} -

    {{format 'ForienQuestLog.QuestPreview.SubTitle' parent.name}}

    + {{/if}}
    {{#if splash.length}} -

  • 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 f)wcQ@CPhauq7@rE!i{Nw5Suu*|U1OWU$6Co>~ literal 0 HcmV?d00001 diff --git a/assets/fonts/medievalsharp-v14-latin-regular.woff2 b/assets/fonts/medievalsharp-v14-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b79e0c0594ef5647242e5404fa4cb7a08b46ac84 GIT binary patch literal 38772 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 A?EnA( literal 0 HcmV?d00001 diff --git a/assets/fonts/metamorphous-v13-latin-regular.woff b/assets/fonts/metamorphous-v13-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..bac16eaf0b1892e517a397f5b6c9e8dc5926696f GIT binary patch literal 28632 zcmYg$b8IHg_w`fTwrzK7+xFIOx3+COwQbwBx9wJ2+jh73_4Cd9$9t2L$vL@qZf24@ z%D5{^NB}?p-}Y-2fb?Jc*8a`^r~JqMf0GmwmjD1jw7xaW{{aQCrl`uq`mH&9^Z#^1 zM|sXc6FZ}C4l@4DgTB#R6W`!x;^smO0D#JUbB1p)#QyWFMeRj{pyUCIrF+NezwYsA1?}sHB8yynW{m2L|>JladGmGHinQM=C*eUqCV_ z7#RRB1-|;fehm#ljm?QML4YxanW07?2^vO9hK3-6JYiokVKD=8W9jxRo65+_2`UMy zN-9dK^(qd^T1Dl>p@p!t==<+Mf+Fc3KPw6Yn{h6pt1<7{p*hgs-e(`EH}5kuCd4c1_1!`UPhV!jZFv=3CAhm1twwIV*l$a>=J7# zmds;mHCabM@F~;7(;R&wYIoUyMbC@7BGoF5k&( zKIa;yYLiCDueZl)yQT4gqQQtsA*Qu?xl@E<#6T!WJ^Ips(GEajK-j$T?s`TaBW}`DS7KtmrzI zrcu+xH_KaNC;t(n%2Vf~8yBfKp2$TOzp!!C9NuG>(zfo~pt=)>s*5&Z`%q*A;*dU` zohTrZ8GInS!kskgrZti>2YT%65z#XUK6C>iVZ%GkDuTc8!vP1;`aiJTN-MYi!RLo?J+n2L#V%W&}tLHi_TaG(kZd2&0c}jDSzv(p1 z$uWm`jG8=lyTGs<6LI54&#H?aR$w zw$(imLhgYyI3?wl7Gi`)I!iP`su?Gni)inhvSqx({;HW1$ZQJCfJReF@XRkEC|Lg+ zWBb~`PUbti5Vdgs%o6ekWZ7I!SauhShyqE;JS+!faI~tvq=I#16jStfsrlt4I@iN$ z8tPt%EB0dj70(5wN%YA;rF1xSs#~SY3q+$HoAvMv$ucA#`;&aiO6-={a=EpMZycD{ zK&|Sms(ymwEzf$wRz{$t;Ot9tW@crst%OC96Xp`c($RJZ_*o`z6b*9*(hWneRFKb> z!JW?$oUnrZ*9 zX5*esCi+Y1(cGi`#WlDp)hTG~%rY+qpzB8_D~rB`@A>M#GZu&-agp11aJ$Kp(=Y9~tcX5GB9+YdfFxF56qI+E#5AFmdiDK;ghp0{M6 z10An={iXeuMZ4IFeA(_xWrcQx0Szjv5cm%uOKYSA$Urs2=2N@TfH|8MnZnJ(ROXYr zG^k*WXz65fy3UlUE5m-92AyDP@!Br^!@ztzB6K%>y^nY5aGT$WMWU5Hxqvt%L~N&r z-@nzW=Ht=cGnULKJi`$YYi>--Qm4i~N>L@Z2FOISTl3%P!Y1W$m=B~Le3eL?sX?Rn zF;+$SsR@(?!~_t*GkJ0cs7AVk5hiv#ume5|C@X^!q$yzekk%%oGsOrSkwKz5RDEG% zLYzB-H4;s_fE&N6GGi-{1pg!yQG_D#yCB8`Pr2JzT;3k?OrNW+X9Rtp=#kT>?e?z9 z@<>EbO|#Xh97249IHk!VL3`3`kg1Znqq2kBgGEetuYP85b2ttS-AyH`zwBn~1;>A_ zoG#8|1oSfyY(uk!!X+TCF|#D6Bqk>2B<7@KWEykgAb90){!nI^&v5`JiS)B%rU`Ud zJJkTy236#4k%D#t?=O;0<^~r6q}@@02Ji}tuVOevUF_lu=gmueY5&0cI8MT!6l|Lx z?MUq1iQPW#Nh0$<{~UF*;EXF^`sroR@^Rof=a;76yY5FtGn;tbu**T^_#v&ANxxm) zot@m4lYC6E&-f-H!%F$?z4^QQcbCYek1e+eK#HIi9tfZKme? z2$Li`!rywA?E#x*HNruLqspG|_WfzS3H=uJc z(1a+j;2i3{xy0Y)dDtW~vPwx(2tfdvl8^?2sWcenA56vKCJPi-0oQ%}iZnO1EGWzy zQ3?!!HyD7RRHxKCM^6SPkSdYc=pWTru zsUxC7^P$)!cxc=i3fP?^U!7A|R{W-_Rl{)zrmw-Tnp=7Pm(g4D-uyhGzU+i5N>4a? z?*soyL3|!Q|GV8|&YmZG`3Lmutust!c8L62dAeM;vBm>h@&q@WqMxZCUAFiDw2DA=D_Nw$ zQIPGlGai)AT~W=Cd6r=KB+17?!QnvzaLPg8JU>NGjD?k9;Sfkbg-0;7f*7By)jg=i z^}=Nv>ovL7tO;EA0}E(|o{|NA_MZRByL#Z)y$8A;415gLtYk(w+cQAZ?Ml(O^q-Bh7J}Uotqi6>fa%#EThn^}* zsupIMoREJOgC<6+2Zf9d9S|*gfC3I)dJ_UY%>ZlbcxMaNnlFF7xK5t6C43aZbhz8) zzPs*u7tu8?sJPSBxF3=|MJ}kP&@b754XmgZGHh(rS*wGQ1E1)2vewS z&i~-Jx`7eGme}uJ)Pl$N1})?ZJdiMD(PfEVK!$Yj8K#J`p%F8BKr0Lk3sXh{HAdx; z@{-zoZB2LK0dKsJdO;c+ZV{XT0lnw>9Q7xG2SGa!c9yzyDlI($s*`R@GeQ8kLGhdL z8tMaqM+>5@FS_G$(R7f5m{fBD^I8U?s zL*G}ZKH0qo2_zM!pfcsJK=!Ao^0aw=b^A&|$(d#KLI&tEBnP03hOyIk{!wZXM&^l^ zp+y#Y+S%Df4zM8IeI?Jeo0-2PoC6E0f{S2CoPn^3_*s`O(E8gfcH$dQSiZNw{1CCbVDdupH`D~34p?MBWPlugA@sB~fE?sepn&9y z098o2AA@WJvnw{R+>c(C}u5dvg7k>&hyo1p0k{IvG( z=TV{kWvI$hJ1u$-c5}PgjUuk+%?9s5zgJx!J8^ll`DRZtNw3e>{W=S|Px)~#LngnK zpEHgsGNJx!r~mwZ_%G#6Mx{;(P_9*((g`Z9f)iq6EYL{u&s|Qs{%x$mG)D+J4FL%2 z>Hx!n>32Ljt%3r;-vP+T37XX*(Vqj7%_$5D7`%i$fn^;AtdWGz`Fl_$v+kT-=xa6c z$A{rc{4;Cq_n$ChM2sG1ifu?vDQR^c&Ez90pLZ=bc1~ZVDw6Xtm#V0ca1?j*c~N=z z???Azb&Oq=#U(FCDUx_`)eO4yrR0?Ch<$c*m%evcyHyAP@UV&O8$3r6?0$GrQOcru zOU}%cVW}ZGLPa$f{}D>^bOgR#I&=yM2We6e5MCrQQX?;!1hFI%GN;}MK77Wsp@ARV zx{TpN?MRndxKU2gW%?ZA52gZ^8|A;Qi5nT;kyBxp(olOmZ4MISf*c@Ur~K}8+Od%- zRc4=27=zF-L)j~6Q&H9M%&TKcyZWn-!nBvUHs^Q=kkM#8Tv}^{h*^E){MKc(tXG zu3Pn&n543#*+mt3KbfPHyb<$U*cVxr24Z*Z+`AD9O8fLta9;B}Scg(uY4@6n*U(BzA(X z#irNI78&Lp8L3rX$7lh>>@s3WWc$%$9<526hRQCgwcS7PYBFWj+jpP4hu|XbD%d}(im!&1OU!8r=lYi#hb!>4 z`xB!C0e{d%EqAJq0X~?WIy5tZN05n)j3!Yu7q%2Rp(1BVB$+yn3|pBO5X2u^oGiO) zzmHvD5rYh2{`hNdjKrVUde#yEFfCjq9+k$&b%B?>(!r zMD<>mk9PKC!cM@+-K4w^3CZ4G`$c7`LNk2ZZJXv*_4Ox~Vy^QHz2^~2GY;G0q$Ji% zUYB{W`{|<{(q^|4y?5m<`{$1#A}B<1rJO@?Vscb4oKrz^c0`^P9Jt%phtOU46to)@ zh_QYL)J_L4v0v~XE{wkIrFvE+~q&2vO7_!QP=k0Znt$hQB z2)0~Ky0?!*cZ{CLM(<$WQFzj*U(|g%o=!ihHD-)ijc_Al_T`ZAvG^HKWF^}zW2}n{ zi2prPBjvhHs~Ws6Q60uBio{dxQ5;6futb=@iFscBfluC9RKFQkDqoyi=*;G30ylYUuHIe@Fa$w z0By1kR4@byF|5Omn7&Z)mk?26RZ09biUa?9cy+PvXQ6y6Rr-teX?zch=RoSf7%JI!rX%L;>|gF%bmrfbY>a!C=|11%d8NIx?rPJxUDuhR z=ga@@?nbXH-c;a;yGh>)kb@lfis@)+VKE`#;IiXl9>`Ma06y@2X5;>X#;ILyu^0NjhyZ@ZIAn26-;A)0!Z)KWe z4w?a-Ex&HYy3^qC-_Euu4&P!zC{;_T+}#3B60=v;b^RUocLjSXh^o_1Cs$77<>mjv zpN9nbe^j|e=$2WN;w5gp?p#0T>TmlWS`jn%?vw2Xq{AzekExP~+Vw>l=FJo_=bo zoEN$ZFtLF<8YN;+>=1CWyFv)F!y5Mwv`bC!`Ds^lS_%;zoZ}*WJ;s9Y#=Sxs`-z^_ zD?d*t#%I0@6>Y>-O+gAgr)kf$J?q<5xj)RkeJq~=JHyHZ6caQ5nEA?hE+v!Z{HCQy z!Hny8EJ?XSzee+o7hL_4Xo1OLgS9c|AbK&WVhFqmAxi=R&EvHC8t3v6Iv@h-JNMCc zRh5w_>IFB!%LNvc)g5>scT5D^VL;-J%1<2X4o_|POpu@bSLmP`V5S< zRa-0EU#9y=E{bN+{iXDj9M9t;BYGK9)zlBixL4%(Q}R#8LQQdN)b+s?K8u&Sq}u6k z912(V$L;j!ol6sizsQ#vZ=V<5`A@#!*2p!Ozu>+aCNDO`$c22Kx@y9R$parGIp8Cq zjAaw~@>tT0je_!C>&k(&mFXt%C)7=La?cK4q74=|q+G3h|BjFSn26H( zj7_wo-tEnLNUEB9Q8fh@sRE$J%s3HyG(JDCc5wzN$b($IejR|_EyoLLQoyVhFW|DS zw=<1zYw?iL z=-ZgU|A*_m3+j!rA>s0L7w^x?HqY_=r^VExjrkV}o#V;&ueurK^O!UEN(-{ab8|$6 zM+H3R@b^>T9H9p&vJL=TgQ;FvavUI}sjJXBpa16<1jUn@GGU52$qgm{E_6dAH6Ta{ z-A=P!f6Uq$<$mhNaQP-<7e3O5U_AEa+GE&w07R*OE;lM{rqGOa9X9?h?cRKZO3bN& ze`2Srnyt*^kG+ijl-1GOsp*Ogvy}<;;vf9))vb+oG9J=uX0Ls-hv7^asufevf(>en zRh2F0sF{T_Z?6l3~PepU~I5fQ|a3~GtY$e;ijwaRu}4cHJV^~8?M-~KXU;8Ms1P(KDpXeMcSoJg&$ z?{$h~Dqj-QPyft2u#L~RRbP`w$s7@vU%kt0eH>dbc8B6|(N|{6+3h_|@F80L)%U*M z#KTpMUcRQflE>{`b)~Bqzq73N83?O9`XxAMUF~}fg~t)iS|KN|zwK_QqjK1MIpoGq z-}ZHMX?CIq%*f<6k13zGXluDPC7S4()yS*s{giI3*fRsp$(-c1!d3>u#DVw@UN`j(E*HKD z?9P?n{Wz;^pG!kmKD5C=b3L6plzx#F$68yDF}qCl;205{%B2W>U?9c^BR-~)Tr~Pz zbI~cH$cbSuqoe|j58$M@h1SmZ3VS9nchmUuuk0r@e!6x!%l()2)I600 zA*r*~KeD^+K`5J*nwq|=gQMN^K_SD`_fGCi0a;d$on9qYz@qXSV}@Zh>$#&1nmS*& z<&@On2{0)@4>LY-0;jZ$-_CRw1DSi&6l-XQ+MG(EyqU`(=y&Aq>7b#knquNz;3bi= zh&2fd;{!XDGYgF4zewiRWgzL?zRLMJ-OXzMlg`+Sp6f(_3{aP&zvAiP79%7N<;v1d zzM91%q_6iupCW#Ei}`ksMmXuG?h=gz$-Kb|7o|ipz-@yRXqblZz}I3-_MvXanF zWWJu!Y7|MtZ5>`8^dVMD3J1ByX&b_(TILRciacaZ&7VgG;j2y@SDL4VNHU#vP|2=8 z)ilrt_q8m9HNXFo9=*ab<dYH zT#IZi%rk}Q0>uD!wnX~-ax6tFXmYn%j`bmHJnLr27lcCWzD3N51Wnkuz7Yb&1G4Pf zW}kyI1zhBDT#ewx;%%Eqi<0jQQ${+?WUc@m?D8%Ug+)O z{9)eJ*rehjO^cj?Q^>T2Ib5BN5se6^j{;AEZG&z42`|=wY$UA2VkT@l(!?lBN`fZ1 z?xQ@f)no(zEMc(hRd|oY-X+nxe#hEI5&F{(H7QB;JoK$v_H{#Fm6c(7g~EEVOwVU- zvTxg99cac0q$IAd+?Q=o`x69`&CFNadR**!4O<2>2I58#Xiwo`Q*0QKfCV-3quro$ z;LjseqZGN{^SM(B>|$m2yp81cKMDn(-HndpgY`q*ydVGEMF)0vChxh;6ms8R>T&LB zn(oHi7IVFB97ZZ-i6#{%<9lu&1-IVrG{b8db0SsU`9)YY%*MGc%urAOUn%8aMDG;E z_bS_$v+}YnI;d#SGC74+kl+sm&@|>E+_Oh9h*OdHVrO>Uq$4MZ>eJ*Ps8j7l@_)A? zhIMLKj0Huh)INxSI|0nY-P}4S38Y8t_D)rcQ%z_pL$0p^zvzp~I?yxH`hLaQNJ($L zD%Joge~H;K`}7#zLAadC+zC9M-ms}VYg_^S%k7D~)O^953B5foIw=qpyLxC%%Q%}G z67!R7#|_4Pxms3U^Jr`P;Gr`ek0dZV4(yCB{QNNm_{|rz3hkNTqur z8?)g;o4T4sMahha$RFwJ@f*Pag2$sp_wYsH1AtZ;ky6yciUj*a9fzK;sTOnD-XK)0 z;#s^%T#r2-ffZ{}W9S^-#@y;nYggZ^_0|aP#q%yjsiph4zim>|l;_axknWWE{`4k` zI#|f<9seG2rHz>bV=)a)||A z)ojUta@N~!=V2*Wo$}VU*Kl;ja~|L^o6B6C6q)gw$DIjU`8mwHB2DLL>uz)Y z5~{>R?gk8svb#-$rD@yCuh?StY0dmSXy5o-Axk=5Adj95HjI&2tDWX?Jf1=!3`h5YeQ-h!&l-pZ7u%H>py+NTucFNkYfmXI`V$H;wy>Ihxqw zcc*|lQiSg!tX>jyEG6MkXRDF_-9YbYPvpB?f*^A>|F^QNfT-_LEuRwaItecWtK`!g z~Ve}{EG>tRb zVcZOq&AE%!BFyactlIk90_DwAjS1V#@&?W-%ZT-CZ5F?!-NdJUo6j4DK@AX~VP+SvE>W0_5pL(lCe4B}#MDMI^W9+EK`9128A`&_)WTq1h z-b=EW^KOZt-0swNE*C()_djq3|$+Nj{n}4P2O-1uRt}6=^`(!cjq_?p@0UbZ_`Pt*pnyS$$refvMpH{`{7s>< zN*hbDgF=bv@-x$X_j)GX88|J35UlcRX5``Qt244fV&)=ZlEose1=YWJlq31k`Niz~ zH(KhKf)`+ zda!bnixfEe93%I?fPxvh1uR;2s#15!KFT>d2lzctzt9%ZlAObKHQDYTfdVf&FF#fJjr*3z1PJm-PMtNvzm}>eXYY}4`|6$6r+FC>aTf&Fs;#XWv{=tZ znV{{hxC8#q`_cnjOT<$$(zO4Lf(14@-?@v&3Drv0sB&;cLngURBQP1b=e?_&L@twC z51R{NgAi{>9v%nJAf=&~m6oF!>*N{e9LP1Dp{kREAlrc#)s&J)EGe=wK^dW5g2Q%r zZ^irdl)@pCXvhiY7+$f?`jrV>C5XKe!4K!*4^Xa99&sVUZoAkKOC#P&S1dwLH>`{C zWc+csAA5X-(JAu9bdytHxz7s`^xF-$yp_^a(tR9)FlMUb>O!BgU8;!;<~7L&He6 zFB@jbS9#X`x#Q&oc_lOTMo~Cesb;#>eVQ!1Snaovs#J}Jc|}p8Cn8&6zaet+4Ufts z<%FK;K^pZd)H)0?sDXj43FOkjeTG%Z`bB-T`3CoW^TkLS(F7CHOdbsNl3Q`gy&)7k}8yDp`s^Pn=f-eSKsa0FK7);&5CKjoE zbQ;|AroE6KDkv7p7RPO6P9KMyyl)%kxhdM+f39{-yfi;#`Wy}WHtURJRdtL6zv4xy z1V8@T^`1WW1g#%3*$*s+gb4O-dRy9;1ST~}YI?~PE$CA6gbAv$(RaIhN;m$lW>rIv z-}H6ZXITQP8?T7?ad+N^Y4aFLRtW+cM7$gh^xYct!6GPR&ML%^NxWOE zGcpnLI)D(0v*<=H#7TIa+=ra5r+BAtd^%3-`MOk$s}$B&GzAYF%MFHgjG#AYXGNSt z;auE=W7N$yZd(gW|H*pJ+f`&v0Eddd8II?Ys8HcanPcuyN>9>Zhq)4BVy5fX)?)gw z#&tO!A&h4JUaDk2#t|4urJ%=gr!*2<6>TAYgk_Kpw3o8AF04tkx^rE0`eVjG2YJyI z+nT}oy6}f`I_IM1^)Pp?-jTp=go^K5oa9oG^9u;BKO#c z=31dyipS2XJLJAFjwWm!pd{N%6F!r%K?7+5;Z8!-B|?;?g0oI}WdcH@{Xk)Z94qT~ zMDgbjFSVk9jssp40mb;2=fsg5q=v}tC zke?%E*Q-yFKF_5<$D&&0i=#9jl1FPyhry2m(@B)73_s2)K{xp>tpIB0JwAO;R6E5l z`d@s?$sS!p3Euk&&lW~?(`9<|nDZ%GzS7LUZ;(>1*TuZ|e0DkRR_@}Vo;SUwkdBXM z-k0|8Afe*CY8d#yEo|v?cMSyW9r_czZ)&~ciZE-AXW8M`y;kmWviZDWKV{y`wi~A4 z9&?40f@J|lxPUh0#vm|_Fkr@%WkCC|E0{ z<*mDEXbU9zUDBZ#R)<$KiFDvx^S!S*FVZ1nDdg3$J)ir3ytZ7%r)Zw5a+n14Kip`O z4=`gAUVm(F8#9yGTG~&+rKU%gcc3D8}2S?w)_?8177QO{^O!b%y)UiVX=y- ztnO^~4c$=a6Kv?;;&GV5BiC23wbv20Wg~bDaKIMwknw@7G?JGhfcLmdzcG1gC?Cv| z76LGC*C-yLXjP?&MvMzYp1NPe?x9Y41wy$I>hY_<1SJLt@*rauzu7jYH@>W%h@0Y0 z5eNcN;Pp7mg_`$!JN!2g)~so2s;8?F{l`by=v(2x?t+6Ys_?-ohkhjqJif7W)+NeH zVmEdu66tX{&f~luWFq0-0o9~3GmFVZk6JN^@(j+h_^jTOH<>1%5wH`>)Hyf`i#bf` z_lWf6@D7?E^5;t!K!};cdaE&+K%v%{pKRSy4J3KiQWC9x-%a*Il&RS_r346S+_^q? zZ+fE^-wb0n%V5LnIkN97ym27CLP>&L(o^5#*zPO%7x2Eo89NzU zMM_v&p>VuC9PT>G-Y2EdAS~R1<}9q%UJOF|DpsM@J0l&PG?i$fsVAPo*Qh|U7`XMM zpZh4)Zuq|LNYsawA^C?19EW5-lnhTuw9=kUNq+rMGOWZyb+DG3Oqx7YU7U%WL^G#{ zyH4oyGfC+)^7iemFn@_yp49FG14STkGeU`dT+GLA4gGUL7i(4VeKSZ+rKo^`A|%%{ z@`Al_X~DokDTzgA8`(5B(Zbo2;qDg~8w3$XzIGC(ZGNd_#M`l~kLNOH z#!&M}m@2j08o1{Uh-(b>(w_f4UKAFqY!T#=%RA?UkvM3vUg7y=ieJnMTyx}zw51_UV4i^&`OEQyw zlxeNW_%F5L_p3vw=p?kEYG1E?*$)^s@CXKVMdq$^?H0FOvYgl0FW4P;a4CqPNChA9 z3l81F#;81SqnQY)4<2);2o7`SAjpxudM{3}vqo{AC<3MfJXXq%KO-M>j^cs-@0Ic# z&fP@{;MQ}ByqOgW(+@`-gOgGWs6TgdT`@3pnk3R#Y53m}d5c<9C9iS0XY~)|;rdpF zsSY2j$mimp$!{6z2Z@nQ5jyy3S`IXRh=TaMs6!iF3WwQLvHBC!Nnc`f(d z2D{%EIzDN_uMuCg3SZ3<&z>W((7NefD9!Ocb&r=?%Lj;-iV-z3O{ctEeGa4f;5&jU zLCc%rwWmXWUx$oelfz|)i#hPt2TC%_WlS-Rx!R8$?5Z9~qau(F1CZr!f1Y1|m z1b=g#3BK_9pnm&;591SnoIaTV+~SVFY#RT`SFZWNE{#21@l*OUeK{<)yhQvut}Zb9 z>mskAZ9g0g8kUxm8i*m!Z|=l z{{`Zcbh8PpTWg5*9B6C?JDi;l3dK`AdtI2El|Tg!VZeYwd9MYG$r)8g#{MOyCc-7g zFCOOyQPNChui3dyXV7eMxBV$c3G-#vj!zdiPl7uO zR?LJDAcHlqo;&UnpB`zt6-Da2~=Yy4ggVo$ev+(V<6H1gY?(_@B`O`&tp*Va(-tnj}J)Bc_u@g|qhQ`^iORvjJQhVLP`D zb0!0g23@N-AF2$3^-YzEk1Ne@OwQKVvPT^&kDN55$@$@Bn1h3CUzFOHDANs#81m=P z;O$f*H+s!iQr%o)PCJtjQ7D2CNf(P6N{IX96lS$sNHLwR6P$$e)(ER;kxP3Ry=EAa zEQ#x)GVQk7=7w@I*JlNomBmJIIccydITrDe{zJtM4e^so*(L6F1s;!b&Q$JE`RlGo0)h2McSrYz&KO<`aMlf#b94Iz! zIQIu(^7auOPlPYrUkrfl+R0nn-mrJEa}217|}3Cz%45oe-AJFFT#m>nD41QzWksg~}hEwa@BCsI^f9A&Fy zYc#Fc%65+zFMut!9)^0a3s%p&2`PPeLb`nn4A$O9-ir9zXz2}3GrJr^ZH5UP{@-8g zd>`xlUe9}cOF_=lUAt%V3cAJvz~p2Sx2cR6gvDh%ZI?qOLrl>VRy{;I!*HA3#2Fhh z(z&^jmC8>L@#k*|iPK_-nX?TnjMGI-R(yi=MaFzPtga~EZ4>5e3OEIaisw$kkrb}?K(lq$;s&w@(h{%Z1}9UXSSZ+A4ZIpOtx}Cx77Ct> zKfy>^)sCcem`s;>M~~*<94M^kD^$3coNlnM(ZS!meXIYYRwQ7?Bb}QuroC{kd4Z!` zFohlMPpE4vm9Vkp*fo#Milagm-j|_AoVfsHySk!h=T?)T9$RS}Kl5-|x4fmrQ$W8~ zY;T*qpz4h4la+VDz9Qv^!IAEp8jfO+2wuRJck3+7*EsH@cjkso(=bT8dYU zSaKfSE}`~aH&CvE?IZNX#5z%M4VbLq2I|{Po){#UP$jpP6*o~e^QG1Kva7miMf+W% zeM?%!$GSS)oJpOIuk%PcinjdmGpp@Q?Aix9qxrN=mRWjqD}H2s%4}_OHDjxUSg!AJ z+XMa}RxY0lphB8Dyj*yXI!|QXzML9yU`%Xu!`tt3m9^ee>v8WB!W zR6KenRlh!338CUP9IY*ka)2{K%BG`-&>$TxH7pRiS_6)l1zmB)qA{g2ZS~r_fPu&H zG#Viv+!z13h4#;9Zm16}k)C>r(Vbi#n>K$spB2oyDNQ&R<*)QNNPK@>ih`J~&ZuUNF=u4oO70;`~Is8|@U(GoM#pxnUs(rrut|A*Oe*uahMck$trdwDO(4w0Hy} zMj~E!(Y^$$!9SeC-dk5Ts4Lj^u%CTTy`c3qWT*ZXL^7=FEJ<=v(h}0f|R~#~4yXf#STJ-NhQuDe1B-e_-_&Dt4D2WKAu6!fV?_cpkUw_AIy>Z|nZuj^+h@D#4k4bx{fW;%1flMIaxhvjhBKem9a6~S?U0haO1h>-tOfwt55I^>QK8S^HKQF z?o(iwz?g!0+w=+&gA?7n6!jIeL~h6btU(eN7~6S^Bx77^yoLNv4X_)#Z^8zU#?pA z8QY2;f8-(WII|yYF;cZTar1K$d8&pCx}~90Ewei zJkgOwJVn;ZXZo{*5|3e1jVE29hfWK>|rfP>TNPeLj|uVYC010Rd~m)7E5cXZGOM}jr4MEwBO(+_A|Nq zHdomBYM1wo&|0>8(7V0Ex0fL5R2^&OegnI)EVc!`V;1*i&BfN^@Chsw%p2=r7^_@@0@lF z6Lxr5B<5nfh7}nG5H1`op5GptpIwPcndDd{Dx?p;fRz^7nE)==9_xs7J}N*$shKeA z1;YCjcD9b=!*Q3k4_<0!ax=yxpRN9LG%vu`aVE_j;vnjm=2QPPds(sBoIg+X>w>%Q{}&58vra-j5T-6smaAv+>Kx8K0o`ESCiB1JlMoIrWC0 z$E?G|tHb>M zsaMO*7WA&$o;^a5b%uFR^#bFolii8s0EV!p2@7e~+W3KcERdx zGiP&U1)W6$yVu+Ld#3Ezc1~N(h1b@dwZ3?OgQ{tzi%#D@eR@ytx(yRN>FdkNU8{C( zDJ@y<&Z_miSTJ=~Zu{IBYd5-NIc@^Vd4X^}cdIz0*On9{;IK|4GXaI{ht?k6zu&Ww z{Sy23?>}&W{Sel&XK0hJ4m8{gDeTQk;{os}3b zYPbaGNwu`LP{FK4R3+_H46E@AS~Y%wh*S`b>WX^tBLhDmmd9;e_b~+6XM{IP{K&L| z#aLz4we=PPLgDHeiHP=q@q}D91LNboC07J>I_8Pq%sjPnpie#UpK#ge`TW{nt@!I( z2d}DKvu5Ry$N!|<|K)Y{nQIm=xcy!j09f$SGv_@r|BXj)IlpWk_ZYQiwH{iN*Lqw1 zU6*uM&)MzVv#;sQb1r;$s&gPO$(&}XpGEJ2Szq7KnBBPQy17sP@efZuvS!^^*T1!5 z!;`!3U3T(@rEh=(%73-Pnc-Zreaf!D_#j@Me(~^^-EZ)4@W;LVSmPiF=_0X5$ z0ZT^<0#{Cm2*%Nl0H9|(p=(9~@U;MscgHaVsE+^$Q~)}R5Y-7$ zMu<>+(No%qUrKwfapuIPvLQ*Qn$n)1$dA#F>Kq(a-~4J${jFhAE{LV_H)>yVG1h-K3Os#3YH!Inh*F z(7DpSrgG4siLg6g_5h4%^n}MR4@M@)200|P+-$F&N zauY1?_1x@z!$0CsB*o;QWz=rGQ{xKoHvcr=%xFzHtQl<15NVcr4#Qees&3JZU_8DQ zun2A@&X2kgK33<9m05J_VcvBA(bM^6&&}}oiP!e$18hk@86a=C(<|%)v!+b$Y{&XS z_Wp`~!lo!kW?2AN9vSd=NgJ5Q#$^3{$0XHcl z6Qz#usGhi~VatpEk+PATudhK8aPien%^XEwZRq|sb4)_U1Z5HJPRtpT+XYAd)}Q$% zlr|`fR^GL|G&8;C)rhRk7nCah8kdkRSCs=R3)Dpywy;*BJh_6_IhU!(f-Te0I)wkTXYV~O)`Tfh6P3-UQJ?Z4WiE7*h()llhL&QR2NtZhT z1E2oL9O&1S2O@G1L8RKoMbaXXTKth{;YVQ@Mh7~PUYw5iiWyFalFu(G{{A-Zw)#dy}mmimiEbAs(2HfNcvVo%jc^nI` zCItW|2v%R6eyhzzP*Ak?lP$BZn3SK-AQLXz;XL)UQ%3&!Q4eN-Zm%v-79tum5vpi zstVk(7v^WAvzmM+?^@`}p_KC3SiJ%h8wAl;kM$yiIVu)bC!v7E_rRk(#a_qb0(zA zxz?^TW^_*CV=QB4wXQ#DV?*g`cthY#E%=Px!X&n~4)|{2smolq=Pl(bVH>=)O*t1I z{%)4bGQ?KJdX}Rch5lqwVMe;>%Ve>a7iXqPyhuqraMV#<%JCd$1<+HqI6}R*t>SSX zI6?okDB6#pR=eHrnH(%cratwZDcHTmb%z!OUA^6Tt4nG zX9F}9)t08if9ULD3(E;rb}WAPja6f_&hxx}a&jTJb88bGxA3f<*)*l?+ndYtpMYsF zb&EqkZE2X&=2Rl?97qo<6O>@s{!oS45B!lFUZSI6TtG?YHD_SF3I@;B8h8`rFT9TvbV zk3u?>KK6^KglXo=#)|(`%ZvVfySy;N^X~UMFQWvJfxrX%x#d1x!kBe0OFyRjSeh|v zTa@P@eUMO+fLX+`F`6;vktbu&DT)J*fK_#kN(ogn_RzwqL*ey8Aer7q;5xRA+vfi< zN4UCxSPRu~1&mUJP|Ko9lGE@7*xYl%2XDnW~;OxBzUN`kQZ1ZtSJY zJU92gZoHuv!?zC4Tb^Gz;NQkOWaS;o?WR9V2M9-!Ng63*@&P9QV zM02KSLW*N#N(BMgi0^Q_W0SOPPk}{8uR0dW##YDy94l(!7uR`&8-*u}lGio5N@p*f z#V~Hpiry6MxiFnxnxM@8Zd;%(NC*D)xn%l&UvM2=}49JpT@qiuibV&X2V3U!U`j z9V@5@kLwfhC`t3B(mq|&dttM?C?%zLLPvYs_||4eZFyN?elTs1H~giO>oa-I63sAI zQ+cxmQ$b^hi?KJxMOf>oXvTVrIm%MXcuY+r%my=)5}LQ-I2prw0*^|sNtB>OlcMsY zb^q#=@V?GmbHd-}-uOd&RV;~$Mx814|59U~#|@w7F|%ifoavFfcH*hmd-xlKXKiEF zHPw|4pdrXSJ7%L{212)Ha5MXb=ERuJwBD}p)# z9S#GNYM{VCo^o!9a;b&_qgV<{g$3$b$Z4n^(moZ{qmev1BCbbS00c*4Lwy}ja)QHq z7^f@2`;36{fyrUPnuh`QA&nmFBhdws0)9-~0MF-+8uf#p^N#ZAod4lFqzIAn9iHFd z`E>M*&xYi8uJvjBewFhrSQW6myrJHo_maW;>XzoF#yWurehlKQDx8yOFp>t9K!~2m zSpV)mIkbfAWJp6aq`}@G0Zkh8grvc&i&Pk?K+^v9=-=E7oA{g2%On%hl#kqd_6(Cs zKP+?S*4LGn_fF{SXdmxxX>6$LukZJlQM4hWrU2zNffNOTC<$sD)(m*^&)!;sOH0hq zu(4Z*!3&AJNO;HbX&Gd6p-&7XW0GXaBxA(OEQn?YA!gpp$P$05#Eg`K5XCUs?6Bx* zS`nP8p(>U@RWZ*#0bR+H^8FyJwNp}CQG~kl{G_<~Vo&FsrX`bX`rGmYd@cU6qoFnvSjafgQ2!XWxbgUWcWd!urr+RQ2 zhT52hsSU$54j_U_%@PqDK4Owej7UgJ3Pnq1cH;!JFfTB?Q-nJb?-_bha-`b1V#A~< zQzmT~oXq}vy1KqPaqO7Hu`{a^ijzmJu3S%h$EuZG>}Y4@s*d(;@$qqaGwpHt3GoHf zDhS0YF!H^kleCa7_{^Qx+Db@kS8Esho6Y1pXH{i|y{t4lYmADGAaF58b>YcvAd5Mf zF&rhBtR|aesa&mu0p-LL1!jv06BMEWZ{k}x_ExKWF3Wm)Cwor_+HV~Pz{nY$dMsU& z0||3L9HXXO8A#bUU*R@()WVTPKGMWkC$)m{tkO=k zQ%mRYQ*fh9stZ5T&?0drt}V+|y>PGG?u&aX|Aqs`N%#YEXs3LzWD{{6YBH=b7-uS`_|k+yx^sD0?= z`}aO|PsQuy>FHS_a0R756z>@fm8gj6y@?ghs}%;k@a zNGAmb=(!u->Q|mWvTGRX+@hcmb-l_LPZtFS^IysR@Rv{?h(b34VBO$0?xeuTKh^Nn zqz+lMObUmanh=pmEvhmWI$`k^~O*HLgTGTqrh8pffO<3+F7_Y4;y$*T(54$ z|G(!XqzI97Qr&Ea&&pcdTzfgWpK;Pb6n8q1s>)!z^k(dIpxvnus7YlBZgMC!l^&O+ z<^Yx&)}{SeVkTF_wA|yuC1V~@NTZOFwgrz^P$>@Fd58LGnXK&JNNBh+hE#TR?*lHN=hs?S{rSD7>2)4QeQiH}Q9d4gG&*tY{8{ zk5x5!AqRW2Zsq0^Lcf>xtC5}eF((`2@I1!D3OLf7QPZqq=3}JMt3?T z^>xg4RhEp!8!m`7EODfO7FZ0%)Qtg7WCKBzY8eC*@S?yI>ILmKQy*%#W+nq6w;KKW z6HcTeM;#&P3@3p`zdi^FwY?+|bh87<`4fzU+IErRXDgF`PS9zh;t zLU23lBMs|KL>@sH5WQET9OJY`IFR#lXjGT@EIqDF&<7Q+fw$sn467epvGZuqfzkr-5vj!e#pihABKTz=YsN zDx4X+blB;dE}H}T%q=5Jg3R5*GE_P?H|5atH_zAZ1n02ftA&Y;nr}F7;jm!9>%#%r z1)cnTLOZb#aX)9l>|#tF)vjj2F4(S|aXM^=3r|2RTP zhGqfp5i7+RB!ls>oNQzDjEi#A?Sz+$t{9-Cys#iMo)a;_7&y)v7fVSF1+A*FkFOl( z5B%V+4c(I?z#*soNKh?HyAZE^b44n@bJbhliOFhFvRptm<8?=a?>6}D$%|J$SsSNv z9QNF@aM7Y)HzeR+4=T;@&ES2=>6H^teGWOlwfElU-FHCB%*RxAPrIS{ru&uO&U@yW zJy$r^3rnXnKC|HT1M^oQ<6+K2gisBOP};}1Q$^YX(FjxVz=aw9;h=6fQoY=W|>EBS$F|PsIiC|AMhXiV*%-)m3m5gRRF!(I?scY_zpx=Hbc;953hH z52`7`0-<2_j!WIk>f`3wx*w{Eogc;cwN))_7924awo!1wWh-8hmolK*_^n*5aIsutEG{k=@d`B7}*Bw*u zvNOZ4A$W@hD;tXPDbJOGdgBfnKu{sH*>e&?1WI&ADJrn?ny;8_ND5d<%||9U1qVhm zLQ}wh3Sy&qj`To}xBg<0 zyxl>=)-e9@S@!Kcnyd+ zPV>}~7!xZcQ9UU4OGkIq8Wn2|N!U4?=5L@>=-Y}%*|NSiYWv_XA$?VmwK~hykXfF2 z{(0pK&fm2ErX>p;mCjmgL-YB)8FdRw2NyOcS7qC4QyfjL;&|n_yl{p9}~7M}|L~3=>lzG8rnX@Ct9lLgZKLcYX~iw&_xA zf?Rh}ool!pO@>8~!`$H2AE(jVzrn5#x@W+*`l}%5GaDv|T z7a)I{q5MtxTjUa61}`X$B`{NYz$<0(30=z5;bV86)9IY;jjCfRIq#DH-D%iyR?SnhaK;2g17Ovphj4;ES*qR|oh;l3^*jITrGJ1Ok1 zGxWvxwI*UACJVkho}sa1xYzx7UldGPqh_Cgwi*?=@IsWWMt9MSbN`eGwfH=tIInx@ zz#&&fa)~%76z5M^GJa}Va&>oUyiJT;v45J|&dM%bpHfyxpGjZ6WaH@32o`x@1H0W?Fl z(qvt>9b^VfaOZV(x}1|HcFyRU(c0|naCHoqb&MhFnIoVzd~0|Qe|KYc3ueMU!K zOHFyl+T!Sp4U}Y^uFG%j;2OOEsJ-R7Zv8^vOIwpNu&^E?Cst8X{k&KH5}n2QO)|Wh}5E`z>1QL z%rybW`A}cXpr8ALUJhN;!M;f85I-_`#BBDXX&9WIK$@%{BSE!m^g-x{pvcTkf273B zMAaxWA!dB_(!K+Rc{*XqX8Y>G z9p@HL@r}S*FvxevHKK&Bz zqRn@%hCR~0);TN7;-+`*P_{Q-J~O+ufAU$7luQsa+jCIG%&ws?xsxg@Y^*dzPF9L~ zQ9sH|!DO64wp(+lz;Pf7RUl(xwM2+4=@9}SW;w_C;93MhuS~>bCCl-$Ds@wsv|_`c z74-u?7ghuBJRU6yIx*iL!Kr2ZfKP^Vc>Hi$lyHJtcs3~2Ae6Kmj3AU`BG*MgPV}b! zxPwvx!gGM8I~dIXI(YjiY!U(yCBdj6q^|?o$|f0;75_7G_i?rc#|p2}OMeHZ>(hJQ zn)LShrv}3g?_~AASHINKY70!ze=Yye178M16aR^8YgHU~N?=Alr{QT!{UljE6@4x^ zqP78ft)(_VP8h)229{lAV9(>?Ya>WwV3+V=wxzIPwi8)YCp@U_u`HN#e7J4y11)-E z@N?k58$T0MAUu9Pf`OIeGnC$}M^X%qwy7K~CBJpE5|jQsl?x1bc#Mwq206mu_SFGV4di&WIHc=v8F_sKEq3aP@YTCVc3c##_o%fM#SQl`qlj6*}m-J>Jc)~WAh@; zE!VRLL*&sXN;87NaHliFH!TDRxA-!eJRMK`CTZaR;26;Q1RcZaXlz0a!YI;62~P-p zRccf7<4^X_kFO4q^p2w$RU&&Ba?$2`&|yvSPVJCmJI^<%xuKT`?mmX}O!mcoate{j zj-v}dKRs-D8FMS>;C%V%p$6wy!<~|qLx1I;mf}b@v6G*<&BbG_xh(ld%SXz>l1VAR z0a(@Iv1-{^GhlX?&pc7;XJT~oR2rm{uO?tX7l9=%g>D^KK@gwWcL153Qpn6qVsadn zM5}M}Pi=y&u*jCE9yi9v8CBb%`OgnPO#L6AyfmN{$QSLSV2-c-I>@WL|>fAjC%Pc4Mf^RJz|xi|0I zXUEK&b{W)yX?pt1&htM|wh%%!>}~N0;v_Sm)1B>dxn{U#Oqtx*)6qVzwWY})jXTNuiAb8|f zT)hLbq(?xd%`qAVMJGqoG&ZnB2t?X&LCSG^5Ef8*E?XqS0V@}VaIy4pX5jx-&froT z7H1yDr8gYb@J|??zRsIAl{e+&UUyXSSc5x)!JT5PQ)&yAK^_}C<=i%`gTV`0JUpql zGDOQ@Toc3Qn!cEa#kdsj;vN?F4*C{(gM;D|DhE4YygS`yvvt@y#<>y2tBRHSF!*UP z?Djb0dWsoLvLu`E)(nwNysU*ab)@d7yb<|qLIWK(p@h(cP+-j=2>Gtu1Xp?t-gHLX zKRDh&_|gq+sl$?bQz#1^mLmLmBx}s;S}~;C96Px_h}9{ymuovJISk8_?`s^w`jiE4 zb%GYia2~^AD{MBL$*`>S7Q?CJ$WpS4At1c2VhLGD^+AL_K(vQK9bgjS5O~NQ!2@Pv z!RJJn0|BvDj_%#F$MZ)O;edAS*|S&3-?QhT_wV~+&)&W2tUZ%|TbNB!5pR1Q}ppt1gD8LDFs8IiMao!_uqByIg5X~waB7M7zWO}V$t>c zcHUSy8Q zgMT=a5UQb|OZ~&M)T>9zQjZOlr5+h7Iwp{Xjf}30VGc!P@aW5l| ze~kB{YY^EWg>KDBFh<#SYzBVy@iOpZ!^yypblkYEhd*@B2j0a!!tuNP_VOAJ#Gzxe z@2f*)-^YfNeINeVjiiOJ2Y-=aiX+tT7~f7`Lmy{4UQ6moPaytyMjhKbF+~o<8#jiX zHo~WNZnS9RsPmB^l4~i2qsAo{{$b331GQU___`sAW{H&*>*$NHI>jhEfxdEeQ2@4W;4*VbKqhW(`M6y=GfX$%2nDzI8w zi=jt&ZjlOzVu{OGqFlNp*IYI8)Q-z;SB^gRU(mL&y5-JGK7pxc+slfkZ6Jix=7Tt- z&W9#4HE>4c=xI$3d8Ap96{5xHXNF-JBAFfDWTsJ15b;s3od7i^eFlGoWRTv#Naq-D z7}FQtL{9i3pus&l{&+FXps~zQ5llkK`k@cy_rwfRO6s}S-PwfHxhl%pU!^5uiwZK* zG20Sni!lNr2$DeoBU9aDHrmcTq?(=Zcgq1H8 zar;&ropZrc%7kh;zPP*YRM>hB-#fU1RnPR?H|Y5pE4VrSQe~ECHaD-iZtelN0Mb|d z$&##0fz&=FVfwzkxBRs7WEB-@>(Iy2_bhv_gw&Bf^0hm;yR)&Orn*e6+>)6wCedu- zz-$;%cPfZdiAXqsSIYzIH3Lkbauav8Ywz{xHbvuN)Jx|GvZ@{6VmtWwD@n=R#;Dd zvuoeY=giM(*?A+#-(79bUHhx9pIu$8o*$<^K7Jk^AisUh-nGRW=i>RXr+Rqg;+kD| z)VN=6N~)fHM%N{G4efn$Pi^b#O-Ut1`l<3q3-Z{xGS@Nr-VJu`T-meb*oX!pK>j04 z=bn_>h)7cRQvepjh(_cvB9LrCh@E2GMcc>x$Gbc6KRcx4ePJ?}Elnn|B*(z4OiPK& ziO(4YX65m+TRkHstO}Du0rEKgMrw$x|DVNK#ozAM`!D3S!i(ZAVj|*x z6OY)4VqA)b;sg8FTyS82?B>c&anmizA1>Ip@9W=BpG1I6<}QM##l0kk^&tZGNlC^` zIDOXHK-gy*-?L?6U%HfHognVrKe+qZs~xMaEGg(LuAhM4+OL@4NwAMhf%B&T_TdyL zJ~#KE`rL^`KA0F|;;H|$3qeLfYlDr);WsowactZ@>e#Xv-Pj}|&|{viFw}7AjiCm= z|JadCR!rPIVE>`M5$wnLMu2vBgFnLmf+UeDx0w+3nq-zarZ_nayg)EAJiyQ&{g6~Q z4Tv3VbE#(5mBJp1nOORGec8bU~IaZA)%wE>7Smya5TP&0g2Iv2MGNc?bet{h?_3J+b$TdvIl{Pq}G01Rnw7Q1)@JsknP7-Wg>^Mz{!oo$BCN zTnz)Yx{+blDfrPPLm!J<#RSqq9%n|D=yls&EPzv9R$?nub51gtrBg9+MIp|p!O{^Q zM=2mg9I;3yi&{HeijAQnkr4Jx&@P=5(7@%;&ohJS=uzssS1q$8HUc`7aM*dQKfx%i z_9@`5F@>3k1OXEoe8BTuzN4n7*2R8n4iSofSV2_DD$y1S^x6#1)h$5hJ$Z)nq}kOQ zzMA~qw{s6x{puykz5F}J;g_J`?4>oGh1F^~>+G(or62EZTAxo}&fuEHrjLz^9#o!L zYa27BWPaO$+Jr?@?*{W=W?R7^i1!_``q#0Z+OhflK|;wsE>o@$50D(v#AZ)vBcF`3 z$Eo64vH$y!18f|Z&vBv#iHA4I5sN)P(OXj8fWhW|)tt^9YWU|@CA-9!#2V$99-h)^ z?^b@WNN7(=RbKM!>o1a*b(Uw(ZKL0|446!owCWXcDKnMz+{JuO0{w?)J-ytMG1eTz z&zdP`nq%O3&y{qo(o$;SIaa?hAtiyXSl$U#QEb%(F}a@W3T3l-7HZK_hHU-?+H%xt z3el>yzF0kvKx_TK067Xqp#T5?c-muNWMBYdN8N|2KJolEUllkx7(n3k3b|Jx`b_xr znE&2?w+P6yZvk>S7??n!07X{}6951Jc-muNWME+5@^=dZgJ9`@@Ba+~@<0((a1#KT zss_dYc-mrn1!$WbU@ZxvAX=??jJb}vwrvj9wr$(CZQF>~wqrZ_=4|!q^Cc(Mx_zgs z@^A%(e)0?f0xdAeQ8;MQ@gRBuuT38IaJ|3E#}o2apFfvJky(Xou~siU!yOfK6ShCu*TMrj;!5Cwp-;nKYAW#Og^fbZ1giZnC%EO=N;o% z*V8$U!Ol^PW}m(CT=<#mBe~u&dKs0RQ>a2_8INa9V&LENl*ip>Lc2GJqtx z7WtP$ajd6SZ5D;GSJY0A>JY0GI&A0Wksl0@wri1RMlI1Zo811sMf8 z1zH7b1&;;%21*9$2UZ8B2pb5a2-FE}3EBzt3LOeJ3T6s_3i%8X47v^Y4uTIU555p} z5g!rA5-SpM6Alxf6ebj!6#f;w7Bm*!7i<^?7;G5n8H5^S8uJ^98_OH-955VQ9DW>+ z9bO((A8{Z0AdevcA_5|tBK{*(BjY44B<>}KCIBYxCyFS8DIzJ7DfKFED+nvPEG#U; zEhH^NEu<~+E%7cbFRL)tF-I~KGC(s3Ga@toG|4pYH7GSmHaRw0Hmx@CH-|VuI8-?4 zIcGU|IovuLI(9moJ1jgAJxe|OKDa-1KtMrgLNP;eO*&1kPDxJ}PnJ)+P)tz5Q8`h)Qaw`OQ^!<^RclsGS3y{`S)y9TTkc(=UP@l` zU#wtZV8dZ1VU}V9Vyt7$WLjkCWr=2#XD(-CXccIOX!>bc>*v{NnHQ{ zc-m~igP}qJ006-2ecQHe+eS7gYpD3zNJ>e|$jZqpC@LwdGzfx+tv~<(0D!ap&b6(K zm+iV_+qTV@dCsnLGhV7!CR&UExemojm83w8@<&f3+7TtowHqna(qN}*bJZrv-@ zV8)b2ue_G-jX7^ko3&)#f<;H(S+#6MllLxV*sx~Z2Pe)X_~fI{zWU;uV&DDr!!N)6 z^~XQ|9Saa7P_R%Tx|IkQCPJiB=Xz~w)?&-PZLQjL>N2ifhY4}&3>wn^=&58EFCJE! zmuX;NUCj#;?~00;nMAg}==L?EyOBXF=4MIa!s zC}3tFid9&!0wrOv0YzgYVz2@uM6(JD0|G0v3=snYE3*<80|F~qvIHmxMN&kw3=sqZ PE4Tswg|GyTu>}A`fC?N? literal 0 HcmV?d00001 diff --git a/assets/fonts/metamorphous-v13-latin-regular.woff2 b/assets/fonts/metamorphous-v13-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..950132c9cfbf2d1a9b954ec8b37d8b1bd0ea8008 GIT binary patch literal 23108 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 literal 0 HcmV?d00001 diff --git a/assets/fonts/nova-square-v15-latin-regular.woff b/assets/fonts/nova-square-v15-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..871f00be38f9e2a6fd64a292d009e918fcb9ff92 GIT binary patch literal 19556 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