From f5a837736e221bb72961e5877dcb728eb5704299 Mon Sep 17 00:00:00 2001 From: Sky Lundy Date: Tue, 12 Dec 2023 20:44:24 -0800 Subject: [PATCH] Add translate all feature to core translation pages --- CHANGELOG.md | 15 +- Fluency.info.php | 4 +- Fluency.module.php | 12 +- README.md | 335 ++++++++++++++++- app/FluencyLocalization.php | 3 + app/FluencyMarkup.php | 2 +- assets/scripts/fluency.bundle.js | 2 +- .../fluency_language_translator.bundle.js | 2 +- assets/scripts/maps/fluency.bundle.js.map | 2 +- .../fluency_language_translator.bundle.js.map | 2 +- gulpfile.babel.js | 2 +- src/scripts/global/FtConfig.js | 86 ++++- .../FtLanguageTranslatorInputfields.js | 341 ++++++++---------- src/scripts/ui/FtUiElements.js | 49 ++- 14 files changed, 611 insertions(+), 246 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f51e98..602694c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,19 @@ # Fluency for ProcessWire Changelog +## 1.0.2 2023-12-17 + +### Enhancement, Documentation, Bugfix + +- Added single-click translation for ProcessWire core translation pages. Any module or file using + `__()` can be translated with one click. +- Expanded README to include documentation on using the markup output features for front end HTML +- Expanded README to include additional details on interacting with Fluency programmatically +- Expanded README to include additional information on caching, performance, and usage +- Fixed issue where separators in language link list markup were not rendering correctly + ## 1.0.1 2023-12-12 -## Documentation & Fixes +### Documentation & Fixes - Updated README.md with current module information - Fix spelling errors in Fluency module docblock @@ -10,7 +21,7 @@ ## 1.0.0 2023-12-02 -## Enhancement, Bugfixes, Potential breaking changes +### Enhancement, Bugfixes, Potential breaking changes - Added the ability to enable a "Translate to all languages" button for inputfields. This enables cross-language translation to all languages with one click. The old style of per-field buttons diff --git a/Fluency.info.php b/Fluency.info.php index 676dba5..e9efb67 100644 --- a/Fluency.info.php +++ b/Fluency.info.php @@ -6,10 +6,10 @@ $info = [ 'title' => 'Fluency', - 'version' => '100', + 'version' => '102', 'href' => 'https://processwire.com/talk/topic/24567-fluency-integrated-deepl-powered-content-translation', 'icon' => 'language', - 'summary' => 'The complete translation suite for ProcessWire.', + 'summary' => 'The complete translation enhancement suite for ProcessWire.', 'autoload' => true, 'singular' => true, 'requires' => [ diff --git a/Fluency.module.php b/Fluency.module.php index ffe5cb3..67cddb1 100644 --- a/Fluency.module.php +++ b/Fluency.module.php @@ -580,20 +580,24 @@ public function renderLanguageLinks( string|array|null $classes = null, string $id = '', string $divider = null, - string $languageSource = 'fluency' + ?string $activeClass = 'active', + string $languageSource = 'fluency', ): string { $languages = $this->getLanguagesForMarkup($languageSource); - $items = array_reduce($languages, function($tags, $language) { + $items = array_reduce($languages, function($tags, $language) use ($activeClass, $divider) { $tags[] = Markup::a( href: $this->page->localUrl($language->id), - content: $language->title + content: $language->title, + classes: $language->isCurrentLanguage ? $activeClass : null ); + $divider && $tags[] = $divider; + return $tags; }, []); - $divider && $items = implode($divider, $items); + end($items) === $divider && array_pop($items); return Markup::ul( items: Markup::li($items), diff --git a/README.md b/README.md index 291c3bb..b0de4ca 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Fluency - The complete translation enhancement suite for ProcessWire -Fluency is a module that brings third party translation services to the ProcessWire CMF/CMS with a user friendly interface for translating content on any page. +Fluency is a module that brings third party translation services to the ProcessWire CMF/CMS with a user friendly interface for translating content on any multi-language field on any page. Fluency can be added to new websites in development, existing websites adding multi-language abilities, or to websites that already have multi-language capabilities where it is desireable to have high quality translation built in. -Please help out by filing Github issues when bugs are found, or submit a pull request with fixes. +You can help out by filing Github issues when bugs are found, or submit a pull request with fixes. ## Requirements @@ -12,11 +12,11 @@ Fluency has been developed and tested on ProcessWire 3.0.218 - Requires at least PHP 8.1 (is compatible with PHP 8.2+) - Module dependencies: ProcessLanguage, LanguageSupport, LanguageTabs -- The UIKit or UIKit-based admin theme -- At least 2 languages configured in ProcessWire (the default, and at least one other, no limit on how many are added) +- The UIKit admin theme +- At least 2 languages configured in ProcessWire (the default, and at least one other, no limit on how many are added) to add translation to fields - An API key for the Translation Engine selected on the module config page -## Features +## Features & Module Details Fluency can translate content in any type of field on any page. These include: @@ -35,35 +35,47 @@ etc. can all be translated into the language the website is built in. Translation service usage can be controlled by enabling the user permission requirement on the module config page and assigning the `fluency-translate` permission. +### Modified Content Indication + +When content in a ProcessWire field changes, Fluency adds a green line will the top of the language tab for that field. If the content is reverted to it's original value, the indicating line is removed. This lets users who are editing and translating content know which fields have been changed without clicking to another language tab to see that it has changed to help prevent content deviation between langauges. + +### Caching + +All translations are cached by default for a period of one month. This helps reduce API account usage where the same content is translated more than once and significantly increases translation speed. Caching can be toggled on/off on the Fluency module config page. The translation cache can also be manually cleared either on the module config page, via the Fluency API using `$fluency` in your code, or via an AJAX request to the Fluency admin REST API- usage is documented below. + +Translation caching relies on _exact_ value matching including punctuation, spelling, and capitalization. This ensures that an exact translation is always returned accurately. + +Fluency uses lists of recognized languages from the selected third party translation service to determine what languages to make available when configuring and using Fluency. **This is cached forever until manually cleared** the first time that a translation engine is selected/configured to increase the speed of Fluency's operations. This is cached on a per-engine basis. This means that if a translation service adds additional translatable languages, this cache must be cleared on the module config page, via the Fluency API using `$fluency` in your code, or via an AJAX request to the Fluency admin REST API- usage is documented below. + ### Changes and Updates -Adding, upgrading, or removing Fluency from your ProcessWire application will not affect content or come with any risk of data loss. At most, you _may_ (but not always) need to reconfigure your translation settings. +Adding, upgrading, or removing Fluency from your ProcessWire application will not affect or remove content. At most, you _may_ (but not always) need to reconfigure your translation settings. Settings are saved individually for each translation engine, so it is possible to switch between engines without losing your configurations for each. Be sure to review the Fluency module config page after upgrading to configure new features and ensure that your existing settings were not affected. Review the `CHANGELOG.md` file for an always up-to-date list of features and changes. ## Translation Engines -Fluency is modular. It contains a framework for adding additional third party services as "Translation Engines". You can choose which Translation Engine you prefer and provide the credentials to connect via their API. Currently Fluency has the ability to use [DeepL](https://www.deepl.com) and [Google Cloud](https://cloud.google.com/translate) +Fluency is modular in that it contains a framework for adding additional third party services as "Translation Engines". You can choose which Translation Engine you prefer and provide the credentials to connect via their API. Currently Fluency has the ability to use [DeepL](https://www.deepl.com) and [Google Cloud](https://cloud.google.com/translate). Each have their strengths, however not all features exist for all engines as Fluency relies on what abilities are available via each translation service, so review each and choose the one that is right for your project. -This project is open source so contributions for new third party services via Translation Engines are welcome. +As this project is open source, contributions for new third party services as Translation Engines are welcome! Developer documentation for integrating third party translation services as Translation Engines is located in `Fluency/app/Engines/DEVDOC.md` ### Third Party Translation Services -To use Fluency you must have credentials, such as an API key, for the third party service associated with a Translation Engine. When a Translation Engine is selected, service-specific information, settings, and necessary authentication details will be shown on the Fluency module config page. +Fluency may require credentials, such as an API key, for the third party service associated with a Translation Engine. When a Translation Engine is selected, service-specific information, settings, and necessary authentication details will be shown on the Fluency module config page. ## Instructions -1. Download and unzip the contents into /site/modules +1. Download and unzip the contents into /site/modules, or install from the [ProcessWire Modules directory](https://processwire.com/modules/fluency/). 2. Install the module in the developer admin 3. Open the module configuration page, choose a Translation Engine and save -4. Complete the Translation Engine specific configs +4. Complete the Translation Engine setup 5. Create language associations and save -All multi-language fields should now have click to translate buttons and a translator tool is available in the Admin menu bar. +All multi-language fields will now have click to translate buttons and a translator tool is available in the Admin menu bar. -If no langauges are present in ProcessWire or if languages are present and not configured with Fluency, it is still possible to use the translator tool in the Admin menu as long as a valid API key is present and the current user has permission to translate if permission restrictions are enabled in Fluency. +If no langauges are present in ProcessWire or if languages are present and not configured with Fluency, it is still possible to use the translator tool in the Admin menu as long as a valid API key is present and the current user has the Fluency permission. ### Localizing the Fluency UI @@ -71,15 +83,180 @@ All text for the Fluency UI elements can be translated including messages, error All translatable texts are located in `Fluency/app/FluencyLocalization.php` +## Multi-Language Markup Rendering + +Fluency provides tools to help make building websites with multi-language capabilities faster and easier. There are HTML best practices that help users with accessibility and improve SEO performance, many of these are available out of the box with Fluency. + +### Current Language Code + +An HTML best practice is to indicate the current language of the page including the `lang` attribute on the `` tag. Fluency can output the code for the current language as provided by the Translation Engine. + +Language names and ARIA attributes are automatically localized when you configure Fluency and use the ProcessWire core translation pages to translate the module. + +To get the code for the language the page is currently being viewed in: + +```html + + + + + + <?php $page->title; ?> + + +``` + +You can also get the language code for another language that is configured in Fluency by passing it's ProcessWire ID: + +```php +$fluency->getLanguageCode(1034); // 'de' +``` + +### Language Meta Tags + +Fluency van render a list of languages `` tags that you can use in the `` of your HTML document. This helps users and search engines find the content for your page in all languages. The URLs will render as configured in ProcessWire. + +To render the tags: + +```html + + + + + + <?php $page->title; ?> + renderAltLanguageMetaLinkTags(); ?> + + +``` + +Output: + +```html + + + + + + <?= $page->title; ?> + + + + + + + + +``` + +### Language Select Element + +You can easily render a ` + + + + + + + +``` + +With options: + +```html +
+ renderLanguageSelect( addInlineJs: false, id: 'my-custom-id', classes: ['some', + 'classes'] ) ?> +
+``` + +Output: + +```html +
+ +
+``` + +### Language Links + +You can also render an unordered list of links to the current page in other languages. + +```html +
renderLanguageLinks(); ?>
+``` + +Output: + +```html +
+ +
+``` + +With options: + +```html +
+ renderLanguageLinks( id: 'my-language-links', classes: ['my-class'], divider: '|', + activeClass: 'current'); ?> +
+``` + +Output: + +```html +
+ +
+``` + ## Using Fluency Programatically Fluency can be accessed anywhere in ProcessWire using the `$fluency` variable. The following are some simple examples. For more in-depth details, review the docblocks for each method in `Fluency.module.php`. Fluency is fully documented and formatted for the API Explorer tool in the outstanding (and personally recommended) [ProDevTools](https://processwire.com/talk/store/product/22-prodevtools/) module. -All methods return [Data Transfer Objects](https://medium.com/@sjoerd_bol/how-to-use-data-transfer-objects-dtos-for-clean-php-code-3bbd47a2b3ab) that are immutable and predictable in structure and features. They can be converted to an array using the `toArray()` method, encoded to json directly using `json_encode()`, and translation results can be counted using `count()`. +All methods return [Data Transfer Objects](https://medium.com/@sjoerd_bol/how-to-use-data-transfer-objects-dtos-for-clean-php-code-3bbd47a2b3ab) that are immutable and predictable in structure and features. All values can be accessed via object properties, or be converted to an array using the `toArray()` method, encoded to json directly using `json_encode()`, and translation results can be counted using `count()`. -To translate content: +### Translating Content ```php $translation = $fluency->translate( @@ -87,7 +264,7 @@ $translation = $fluency->translate( string $targetLanguage, // Language code used by the translation service array|string $content, // String or array of strings to translate array|null $options, // Translation Engine specific options - bool $caching // Override default caching behavior, false disables cache + bool $caching // Override default caching behavior, false disables caching ); // This method returns an immutable EngineTranslationData object @@ -112,8 +289,9 @@ $translation = $fluency->translate( // } ``` -This method returns all translatable languages that the current translation service recognizes. The -codes for each language are used when calling `$fluency->translate()`; +### Translatable Languages + +This method returns all translatable languages that the current translation service recognizes. The codes for each language are used when calling `$fluency->translate()`; ```php $translatableLanguages = $fluency->getTranslatableLanguages(); @@ -198,9 +376,128 @@ $translatableLanguages = $fluency->getTranslatableLanguages(); // } ``` +### API Usage + +Get API usage (must be supported by the translation engine in use): + +```php +$usage = $fluency->getTranslationApiUsage(); + +// Returns an immutable EngineApiUsageData instance +// +// $usage->toArray(); Outputs the following: +// +// array(7) { +// ["used"]=> +// int(222822) +// ["limit"]=> +// int(500000) +// ["remaining"]=> +// int(277178) +// ["percentUsed"]=> +// string(3) "45%" +// ["unit"]=> +// string(9) "Character" +// ["error"]=> +// NULL +// ["message"]=> +// NULL +// } +``` + +### Translation Engine + +Get information about the current translation engine in use + +```php +$engineInfo = $fluency->getTranslationEngineInfo(); + +// Returns an instance of EngineInfoData +// +// $engineInfo->toArray() outputs the following: +// +// array(12) { +// ["name"]=> +// string(5) "DeepL" +// ["version"]=> +// string(3) "1.1" +// ["provider"]=> +// string(5) "DeepL" +// ["providerApiVersion"]=> +// string(3) "2.0" +// ["providerApiDocs"]=> +// string(31) "https://www.deepl.com/docs-api/" +// ["configId"]=> +// string(64) "f71ee845229943abd3e5863227d5706600f472b3d31b4de4768878a072b681f1" +// ["providesUsageData"]=> +// bool(true) +// ["details"]=> +// string(645) "{Engine description as shown on the Fluency config page}" +// ["authorName"]=> +// string(8) "FireWire" +// ["authorUrl"]=> +// string(51) "https://processwire.com/talk/profile/3976-firewire/" +// ["error"]=> +// NULL +// ["message"]=> +// NULL +// } +``` + +### Caching + +Get the current number of cached translations: + +```php +$fluency->getCachedTranslationCount(); // Int +``` + +Clear the translation cache: + +```php +$fluency->clearTranslationCache(); // 0 on success +``` + +Check if the list of languages translatable by the translation engine are cached: + +```php +$fluency->translatableLanguagesAreCached(); // Boolean +``` + +Clear the translatable languages cache: + +```php +$fluency->clearTranslatableLanguagesCache(); // 0 on success +``` + +### Admin Fluency REST API Endpoints + +AJAX calls can be made to endpoints in the ProcessWire admin to interact with Fluency. The current user must have the `fluency-translate` permission. Refer to `Fluency.module.php` method docblocks to review accepted methods and responses. Base admin URL will match your ProcessWire installation. + +```php +$endpoints = $fluency->getApiEndpoints(); + +// Returns a stdClass object +// +// object(stdClass)#376 (6) { +// ["endpoints"]=> +// string(19) "/processwire/fluency/api/" +// ["usage"]=> +// string(25) "/processwire/fluency/api/usage/" +// ["translation"]=> +// string(31) "/processwire/fluency/api/translation/" +// ["languages"]=> +// string(29) "/processwire/fluency/api/languages/" +// ["translationCache"]=> +// string(37) "/processwire/fluency/api/cache/translations" +// ["translatableLanguagesCache"]=> +// string(34) "/processwire/fluency/api/cache/languages" +// } +``` + ## Known Limitations -- The browser plugin for Grammarly conflicts with Fluency and is a known issue for many web apps. The solution is to either disable Grammarly while using Fluency in the ProcessWire admin, or log into the admin in a private browser window where Grammarly may not be running. Consider disabling Grammarly for the website you are editing content on when in the admin. Instructions [here](https://support.grammarly.com/hc/en-us/articles/115000091612-Turn-off-Grammarly-on-one-or-more-websites). +- The browser plugin for Grammarly may conflict with Fluency and is a known issue for many web apps. If you encounter issues, the solution is to either disable Grammarly while using Fluency in the ProcessWire admin, or log into the admin in a private browser window where Grammarly may not be running. Consider disabling Grammarly for the website you are editing content on when in the admin. Instructions provided by Grammarly [here](https://support.grammarly.com/hc/en-us/articles/115000091612-Turn-off-Grammarly-on-one-or-more-websites). ## Cost diff --git a/app/FluencyLocalization.php b/app/FluencyLocalization.php index d127e2c..10bde44 100644 --- a/app/FluencyLocalization.php +++ b/app/FluencyLocalization.php @@ -46,6 +46,9 @@ public static function getAll(): object { 'clickToCopy' => __('Click to Copy'), 'copied' => __('Copied!') ], + 'languageTranslator' => [ + 'translateAllButton' => __('Click To Translate All'), + ], 'usage' => [ 'title' => __('Translation Service Usage Information'), 'description' => __('Click Refresh to get usage information'), diff --git a/app/FluencyMarkup.php b/app/FluencyMarkup.php index e894b3f..852bc6b 100644 --- a/app/FluencyMarkup.php +++ b/app/FluencyMarkup.php @@ -57,7 +57,7 @@ public static function p(string|array $values, string|array $classes = []): stri public static function a( string $href, string $content, - string|array $classes = [], + string|array|null $classes = [], string $target = '_self', string|array $rel = [] ): string { diff --git a/assets/scripts/fluency.bundle.js b/assets/scripts/fluency.bundle.js index f6ed680..b58e470 100644 --- a/assets/scripts/fluency.bundle.js +++ b/assets/scripts/fluency.bundle.js @@ -1,2 +1,2 @@ -!function n(i,s,l){function r(e,t){if(!s[e]){if(!i[e]){var a="function"==typeof require&&require;if(!t&&a)return a(e,!0);if(u)return u(e,!0);throw(t=new Error("Cannot find module '"+e+"'")).code="MODULE_NOT_FOUND",t}a=s[e]={exports:{}},i[e][0].call(a.exports,function(t){return r(i[e][1][t]||t)},a,a.exports,n,i,s,l)}return s[e].exports}for(var u="function"==typeof require&&require,t=0;t{s.default.moduleShouldInitialize()&&(i.default.init(),n.default.init())})},{"./global/FtConfig":3,"./inputfields/FtInputfields":13,"./ui/FtAdminMenu":15}],2:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var o=(t=t("./FtConfig"))&&t.__esModule?t:{default:t};t=function(){const a=o.default.getUiTextFor("errors");const l=t=>{var e={"X-Requested-With":"XMLHttpRequest"};return"GET"===t&&(e.Accept="application/json"),"POST"===t&&(e["Content-Type"]="application/json"),e},t=(t,e)=>fetch(t,{method:"GET",cache:"no-store",headers:l("GET")}).then(r).then(e).catch(u),e=(t,e)=>fetch(t,{method:"DELETE",headers:l("GET")}).then(r).then(e).catch(u),r=t=>{if(204===t.status)return t;if(t.ok)return t.json();throw new Error},u=t=>{console.error("[Fluency module API failure]",t.message);var e={error:null,message:null};return"NetworkError"===t.message.split(" ")[0]?(e.error="FLUENCY_CLIENT_DISCONNECTED",e.message=a.FLUENCY_CLIENT_DISCONNECTED):(e.error="UNKNOWN_ERROR",e.message=a.UNKNOWN_ERROR),e};return{deleteTranslatableLanguagesCache:()=>e(o.default.getApiEndpointFor("translatableLanguagesCache"),t=>t),deleteTranslationCache:()=>e(o.default.getApiEndpointFor("translationCache"),t=>t),getAvailableLanguages:()=>t(o.default.getApiEndpointFor("languages"),t=>t),getTranslation:function(t,e,a){var n,i=3t,fetch(n,{method:"POST",cache:"no-store",headers:l,body:JSON.stringify(t)}).then(r).then(e).catch(u)},getUsage:()=>t(o.default.getApiEndpointFor("usage"),t=>t)}}();a.default=t},{"./FtConfig":3}],3:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=function(){const t=ProcessWire.config.fluency;var e=t.localization;const a={activityOverlay:e.activityOverlay,languageSelect:e.languageSelect,inputfieldTranslateButtons:e.inputfieldTranslateButtons,standaloneTranslator:e.standaloneTranslator,usage:e.usage,errors:e.errors},n={languages:t.apiEndpoints.languages,translatableLanguagesCache:t.apiEndpoints.translatableLanguagesCache,test:t.apiEndpoints.test,translation:t.apiEndpoints.translation,translationCache:t.apiEndpoints.translationCache,usage:t.apiEndpoints.usage},i=t.configuredLanguages,s=t.unconfiguredLanguages;const l=()=>i;const r=()=>s;const u=()=>t.engine;return{fieldInitializedAttr:"data-ft-initialized",getApiEndpointFor:t=>n[t],getConfiguredLanguages:l,getDefaultLanguage:()=>i.reduce((t,e)=>e.default?e:t,null),getEngineInfo:u,getEngineProvidesUsageData:()=>u().providesUsageData,getTranslationAction:()=>t.interface.inputfieldTranslationAction,getLanguageCount:()=>i.length+s.length,getLanguageForId:a=>(a=parseInt(a,10),i.reduce((t,e)=>e.id===a?e:t,null)),getUiTextFor:t=>a[t],getUnconfiguredLanguages:r,languageIsTranslatable:t=>!s.includes(parseInt(t,10)),moduleShouldInitialize:()=>1Math.random().toString(36)[2]).join("")}()),n.innerText=e,t.appendChild(n)},getPageId:n,pageIdIs:t=>n()===t}},{}],5:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldCKEditor=a.FtInputfieldCKEditor=void 0;var d=n(t("../ui/FtActivityOverlay")),c=n(t("../global/FtConfig")),f=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldCKEditor=t=>!!t.querySelector(".InputfieldCKEditorNormal");a.FtInputfieldCKEditor=function(t){const e={},a={},n={},i={},s={};let l=null,r;if(this.getActivityOverlay=()=>r,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(c.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getEditorInstanceForLanguage(t).getData(),this.setValueForLanguage=(t,e)=>{var a=this.getEditorInstanceForLanguage(t);return a.setData(e),a.fire("change"),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>{var e;return Object.hasOwn(s,t)&&s[t]||(e=this.createCKEditorSelector(t),s[t]=CKEDITOR.instances[e]),s[t]},this.createCKEditorSelector=t=>t==c.default.getDefaultLanguage().id?l:l+"__"+t,this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{i[t.dataset.language]=t}),i),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.registerInputEventListener=e=>{this.getEditorInstanceForLanguage(e).on("change",t=>{a[e]=this.getValueForLanguage(e),n[e].setModifiedState(this.contentHasChanged(e))})},void 0===CKEDITOR)console.error("CKEditor was not found by Fluency, translation unavailable");else{var u,o=this.getInputContainers();for(u in l=Object.values(o)[0].id.replace("langTab_",""),o){var g=o[u];s[u]=this.getEditorInstanceForLanguage(u),n[u]=new h.default(g),this.registerInputEventListener(u)}r=new d.default(this),new f.default(this,o)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],6:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldCKEditorInline=a.FtInputfieldCKEditorInline=void 0;var c=n(t("../ui/FtActivityOverlay")),f=n(t("../global/FtConfig")),h=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),v=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldCKEditorInline=t=>!!t.querySelector(".InputfieldCKEditorInline");a.FtInputfieldCKEditorInline=function(e){const a={},n={},i={},s={},l={},r={};let u=null,t;if(this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(f.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getEditorInstanceForLanguage(t);return e?e.getData():this.getContentElementForLanguage(t).innerHTML},this.setValueForLanguage=(t,e)=>{var a=this.getEditorInstanceForLanguage(t),n=this.getContentElementForLanguage(t);return a?a.setValue(e):n.innerHTML=e,n.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=CKEDITOR.instances[this.createCKEditorSelector(t)]),l[t]),this.getContentElementForLanguage=t=>(Object.hasOwn(r,t)||(r[t]=this.getInputContainerForLanguage(t).querySelector(".InputfieldCKEditorInlineEditor")),r[t]),this.createCKEditorSelector=t=>t==f.default.getDefaultLanguage().id?u:u+"__"+t,this.getInputContainers=()=>(Object.keys(s).length!==f.default.getLanguageCount()&&this.getSelf().querySelectorAll("[data-language]").forEach(t=>{s[t.dataset.language]=t}),s),this.getInputContainerForLanguage=t=>(Object.hasOwn(s,t)||(s[t]=e.querySelector(`[data-language="${t}"]`)),s[t]),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t],this.registerUpdateEvent=t=>{t=this.getContentElementForLanguage(t);new MutationObserver((t,e)=>{for(var a of t)a.target.dispatchEvent(new Event("input"))}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{this.getContentElementForLanguage(e).addEventListener("input",t=>{n[e]=this.getValueForLanguage(e),i[e].setModifiedState(this.contentHasChanged(e))})},void 0===CKEDITOR)console.error("CKEditor was not found by Fluency, translation unavailable");else{var o,g=this.getInputContainers();for(o in u=Object.values(g)[0].id.replace("langTab_",""),g){var d=g[o];l[o]=this.getEditorInstanceForLanguage(o),i[o]=new v.default(d),this.registerInputEventListener(o)}t=new c.default(this),new h.default(this,g)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],7:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=i(t("../ui/FtActivityOverlay")),g=i(t("../global/FtConfig")),d=i(t("./FtInputfields")),c=i(t("../ui/FtInputfieldTranslateButton")),f=i(t("../ui/FtLanguageTab"));function i(t){return t&&t.__esModule?t:{default:t}}function h(t){let e;this.getSelf=()=>t,this.getActivityOverlay=()=>e,e=new n.default(this)}a.default=function(t){const e={},a={};const n={},i={};let s=(new f.default).getContentModifiedClass(),l={};this.getActivityOverlay=t=>t?l[t].getActivityOverlay():null,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(g.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return d.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(i,t)&&i[t]||(i[t]=this.getInputContainerForLanguage(t).querySelector("input")),i[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(n,t)||n[t]||this.getInputContainers(),n[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll(".LanguageSupport").forEach(t=>{var e=t.querySelector("input[type=text]").name.replace("_pw_page_name","")||g.default.getDefaultLanguage().id;n[e]=t}),n),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.setModifiedState=(t,e)=>{t=this.getInputContainerForLanguage(t);e&&t.classList.add(s),e||t.classList.remove(s)},this.registerInputEventListener=e=>{this.getFieldForLanguage(e).addEventListener("input",t=>{a[e]=t.target.value,this.setModifiedState(e,this.contentHasChanged(e))})};var r,u=this.getInputContainers();for(r in u){var o=u[r];e[r]=this.getValueForLanguage(r),l[r]=new h(o),this.registerInputEventListener(r)}new c.default(this,u,!0)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],8:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTable=void 0;a.FtIsInputfieldTable=t=>n(t)||i(t);const n=t=>!!t.classList.contains("InputfieldTable"),i=t=>"TBODY"===!!t.tagName&&t.querySelectorAll(".InputfieldTable_hasLangTabs").length},{}],9:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldText=a.FtInputfieldText=void 0;var g=n(t("../ui/FtActivityOverlay")),d=n(t("../global/FtConfig")),c=n(t("./FtInputfields")),f=n(t("../ui/FtInputfieldTranslateButton")),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldText=t=>!!t.querySelector("input[type='text']");a.FtInputfieldText=function(e){const a={},n={},i={},s={},l={};let t;this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(d.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return c.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=this.getInputContainerForLanguage(t).querySelector("input")),l[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(s,t)&&s[t]||(s[t]=e.querySelector(`[data-language="${t}"]`)),s[t]),this.getInputContainers=()=>(e.querySelectorAll("[data-language]").forEach(t=>s[t.dataset.language]=t),s),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t],this.registerInputEventListener=e=>{this.getFieldForLanguage(e).addEventListener("input",t=>{n[e]=t.target.value,i[e].setModifiedState(this.contentHasChanged(e))})};var r,u=this.getInputContainers();for(r in u){var o=u[r];a[r]=this.getValueForLanguage(r),i[r]=new h.default(o),this.registerInputEventListener(r)}t=new g.default(this),new f.default(this,u)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],10:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTextarea=a.FtInputfieldTextarea=void 0;var o=n(t("../ui/FtActivityOverlay")),g=n(t("../global/FtConfig")),d=n(t("./FtInputfields")),c=n(t("../ui/FtInputfieldTranslateButton")),f=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTextarea=t=>!!t.querySelector("textarea:not(.InputfieldCKEditorNormal,.InputfieldTinyMCEEditor)");a.FtInputfieldTextarea=function(e){const a={},n={},i={},s={},l={};let t;this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(g.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return d.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(l,t)||(l[t]=e.querySelector(`[data-language="${t}"] textarea`)),l[t]),this.getInputContainers=()=>(e.querySelectorAll("[data-language]").forEach(t=>{s[t.dataset.language]=t}),s),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t];var r=this.getInputContainers();for(let e in r){var u=r[e];a[e]=this.getValueForLanguage(e),i[e]=new f.default(u),u.querySelector("textarea").addEventListener("input",t=>{n[e]=t.target.value,i[e].setModifiedState(this.contentHasChanged(e))})}t=new o.default(this),new c.default(this,r)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],11:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTinyMCE=a.FtInputfieldTinyMCE=void 0;var g=n(t("../ui/FtActivityOverlay")),d=n(t("../global/FtConfig")),c=n(t("./FtInputfields")),f=n(t("../ui/FtInputfieldTranslateButton")),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTinyMCE=t=>!!t.querySelector(".InputfieldTinyMCENormal");a.FtInputfieldTinyMCE=function(t){const i={},a={},s={},e={},l={},r={};let u=null,n;this.getActivityOverlay=()=>n,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(d.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getTinymceInstanceForLanguage(t);return e?e.getContent():this.getTextareaForLanguage(t).value},this.setValueForLanguage=(t,e)=>{var a=this.getTinymceInstanceForLanguage(t),a=(a&&(a.setContent(e),a.fire("input")),this.getTextareaForLanguage(t));return c.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getTinymceInstanceForLanguage=t=>{var e;return Object.hasOwn(r,t)&&r[t]||(e=this.createTinymceSelector(t),r[t]=tinymce.get(e)),r[t]},this.getTextareaForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=this.getSelf().querySelector(`[data-language="${t}"] textarea`)),l[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{e[t.dataset.language]=t}),e),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==i[t],this.createTinymceSelector=t=>t==d.default.getDefaultLanguage().id?u:u+"__"+t,this.bindTinymceEvents=(e,t)=>{t.on("keyup",t=>this.getTextareaForLanguage(e).dispatchEvent(new Event("input")))},this.initTinymceInstanceOnCreation=(n,t)=>{new MutationObserver((t,e)=>{for(var a of t)a.target.dataset.language==n&&(r[n]=this.getTinymceInstanceForLanguage(n),this.bindTinymceEvents(n,r[n]),r[n])&&e.disconnect()}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{l[e].addEventListener("input",t=>{a[e]=this.getValueForLanguage(e),s[e].setModifiedState(this.contentHasChanged(e))})},this.initAll=t=>{for(var e in u=Object.values(t)[0].id.replace("langTab_",""),t){var a=t[e];i[e]=this.getValueForLanguage(e),s[e]=new h.default(a),r[e]=this.getTinymceInstanceForLanguage(e),l[e]=this.getTextareaForLanguage(e),this.registerInputEventListener(e),r[e]||this.initTinymceInstanceOnCreation(e,a)}for(var n in r)Object.hasOwn(r,n)&&r[n]&&this.bindTinymceEvents(n,r[n])};{const o=this.getInputContainers();setTimeout(()=>{this.initAll(o)},50),n=new g.default(this),new f.default(this,o)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],12:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTinyMCEInline=a.FtInputfieldTinyMCEInline=void 0;var c=n(t("../ui/FtActivityOverlay")),f=n(t("../global/FtConfig")),h=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),v=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTinyMCEInline=t=>!!t.querySelector(".InputfieldTinyMCEInline");a.FtInputfieldTinyMCEInline=function(t){const e={},a={},n={},i={},s={},l={};let r=null,u;if(this.getActivityOverlay=()=>u,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(f.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getEditorInstanceForLanguage(t);return e?e.getContent():this.getContentElementForLanguage(t).innerHTML},this.setValueForLanguage=(t,e)=>{var a=this.getContentElementForLanguage(t);return a.innerHTML=e,a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>{var e;return Object.hasOwn(l,t)&&l[t]||(e=this.createTinymceSelector(t),l[t]=tinymce.get(e)),l[t]},this.getContentElementForLanguage=t=>(Object.hasOwn(s,t)||(s[t]=this.getInputContainerForLanguage(t).querySelector(".mce-content-body")),s[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(i,t)&&i[t]||(i[t]=this.getSelf().querySelector(`[data-language="${t}"]`)),i[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{i[t.dataset.language]=t}),i),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.createTinymceSelector=t=>t==f.default.getDefaultLanguage().id?r:r+"__"+t,this.registerUpdateEvent=t=>{t=this.getContentElementForLanguage(t);new MutationObserver((t,e)=>{for(var a of t)a.target.dispatchEvent(new Event("input"))}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{this.getContentElementForLanguage(e).addEventListener("input",t=>{a[e]=this.getValueForLanguage(e),n[e].setModifiedState(this.contentHasChanged(e))})},void 0===tinymce)console.error("TinyMCE was not found by Fluency, translation unavailable");else{var o,g=this.getInputContainers();for(o in r=Object.values(g)[0].id.replace("langTab_",""),g){var d=g[o];e[o]=this.getValueForLanguage(o),n[o]=new v.default(d),this.registerUpdateEvent(o),this.registerInputEventListener(o)}u=new c.default(this),new h.default(this,g)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],13:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var l=n(t("../global/FtConfig")),r=(n(t("../global/FtTools")),t("./FtInputfieldCKEditor")),u=t("./FtInputfieldCKEditorInline"),o=t("./FtInputfieldTable"),g=t("./FtInputfieldText"),d=t("./FtInputfieldTextarea"),c=t("./FtInputfieldTinyMCE"),f=t("./FtInputfieldTinyMCEInline"),h=n(t("./FtInputfieldPageName"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){const n="[class*='hasLangTabs']";const i=t=>{for(var e of t)a(e)},a=t=>{e(t)||t.classList.contains("InputfieldItemList")||t.closest("[class*='Template']")||((t=>{switch(true){case(0,o.FtIsInputfieldTable)(t):i(t.querySelectorAll(".langTabs"));break;case(0,r.FtIsInputfieldCKEditor)(t):return new r.FtInputfieldCKEditor(t);case(0,u.FtIsInputfieldCKEditorInline)(t):return new u.FtInputfieldCKEditorInline(t);case(0,c.FtIsInputfieldTinyMCE)(t):return new c.FtInputfieldTinyMCE(t);case(0,f.FtIsInputfieldTinyMCEInline)(t):return new f.FtInputfieldTinyMCEInline(t);case(0,d.FtIsInputfieldTextarea)(t):return new d.FtInputfieldTextarea(t);case(0,g.FtIsInputfieldText)(t):return new g.FtInputfieldText(t);default:console.warn("Fluency does not recognize this inputfield, translation is not available",t)}})(t),s(t))},e=t=>t.hasAttribute(l.default.fieldInitializedAttr)||!!t.querySelector(".ft-translate-button"),s=t=>t.setAttribute(l.default.fieldInitializedAttr,"");return{init:function(){var t=document.querySelectorAll(n);t.length&&(i(t),t=document.getElementById("pw-content-body"),new MutationObserver((t,e)=>{for(var a of t){a=a.target.querySelectorAll(n);a.length&&i(a)}}).observe(t,{childList:!0,subtree:!0}),[...document.querySelectorAll(".InputfieldPageName")].forEach(t=>{t&&!e(t)&&(new h.default(t),s(t))}))},updateValue:(t,e)=>{t.focus(),t.value=e,t.blur()},fieldIsInitialized:e}}();a.default=t},{"../global/FtConfig":3,"../global/FtTools":4,"./FtInputfieldCKEditor":5,"./FtInputfieldCKEditorInline":6,"./FtInputfieldPageName":7,"./FtInputfieldTable":8,"./FtInputfieldText":9,"./FtInputfieldTextarea":10,"./FtInputfieldTinyMCE":11,"./FtInputfieldTinyMCEInline":12}],14:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var r=(t=t("../global/FtConfig"))&&t.__esModule?t:{default:t};a.default=function(t){var a=this;let n=1{this.setActivityActive(),this.setOverlayVisible()},this.showMessage=function(t){var e=1{a.setOverlayInvisible()},t),setTimeout(()=>{a.setActivityInactive(),a.setMessageInactive(),a.setErrorInactive(),a.setFlashInactive(),a.setMessageContent("")},t+500)},this.setActivityActive=()=>{e.classList.add(i.activity)},this.setActivityInactive=()=>{e.classList.remove(i.activity)},this.setMessageActive=()=>{e.classList.add(i.message)},this.setMessageInactive=()=>{e.classList.remove(i.message)},this.setMessageContent=t=>{s.innerText=t},this.setFlashActive=t=>{e.classList.add(i.flash)},this.setFlashInactive=t=>{e.classList.remove(i.flash)},this.setSuccessActive=()=>{e.classList.add(i.success)},this.setSuccessInactive=()=>{e.classList.remove(i.success)},this.setErrorActive=()=>{e.classList.add(i.error)},this.setErrorInactive=()=>{e.classList.remove(i.error)},this.setOverlayVisible=()=>{e.classList.add(i.visible)},this.setOverlayInvisible=()=>{e.classList.remove(i.visible)},this.create=()=>(e=this.buildOverlayEl(),l=this.buildActivityEl(),s=this.buildMessageEl(),e.appendChild(l),e.appendChild(s),e),this.buildOverlayEl=()=>{var t=document.createElement("div");return t.setAttribute("class",i.overlay),t},this.buildActivityEl=()=>{var t=r.default.getUiTextFor("activityOverlay")[n];let e=document.createElement("div");e.setAttribute("class",i.activityAnimationContainer),e=t.animated.reduce((t,e)=>{var a=document.createElement("span");return a.setAttribute("class",i.activityAnimationItem),a.innerHTML=e,t.appendChild(a),t},e);var a=document.createElement("div");return a.setAttribute("class",i.activityStaticText),a.innerText=t.static,(l=document.createElement("div")).setAttribute("class",i.activityContainer),l.appendChild(a),l.appendChild(e),l},this.buildMessageEl=()=>((s=document.createElement("div")).setAttribute("class",i.messageContainer),s),t=t.getSelf(),e=this.create(),t.classList.add(i.parent),t.appendChild(e)}},{"../global/FtConfig":3}],15:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0,a.default={init:()=>{{var t=document.querySelectorAll(".pw-masthead .pw-primary-nav > li > a"),e;"Fluency"!==new URLSearchParams(window.location.search).get("name")&&t.forEach((t,e)=>{var a=t.href.split("/").filter(Boolean);a[a.length-1].includes("fluency")&&(t.href=t.href+"?modal=1",t.classList.add("pw-modal-large"),t.classList.add("pw-modal"))})}}}},{}],16:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var o=n(t("../global/FtConfig")),g=(n(t("../global/FtTools")),n(t("../global/Fluency"))),r=n(t("./FtUiElements"));function n(t){return t&&t.__esModule?t:{default:t}}a.default=function(u,t){let e=2{var a,n,i=o.default.languageIsTranslatable(t),s=t==o.default.getDefaultLanguage().id;i&&!s&&({button:a,container:n}=r.default.createTranslateButton(l.translateButton),this.bindButton(a,o.default.getLanguageForId(t)),e.appendChild(n)),i&&s&&e.appendChild(r.default.createStatusElement(l.translationAvailable)),i||e.appendChild(r.default.createStatusElement(l.languageNotAvailable))},this.bindButton=(t,a)=>{t.addEventListener("click",t=>{t.preventDefault();t=u.getValueForDefaultLanguage();if(t){const e=u.getActivityOverlay()??u.getActivityOverlay(a.id);e.showActivity(),g.default.getTranslation(o.default.getDefaultLanguage().engineLanguage.sourceCode,a.engineLanguage.targetCode,t).then(t=>{t.error?u.getActivityOverlay().showError(t.message):(u.setValueForLanguage(a.id,t.translations[0]),e.hide())})}})},this.addTranslateToAllButton=(t,e)=>{var a=e[t],{button:n,container:i}=r.default.createTranslateButton(l.translateToAllButton);this.bindTranslateToAllButton(n,o.default.getLanguageForId(t),e),a.appendChild(i)},this.bindTranslateToAllButton=(t,r,e)=>{t.addEventListener("click",t=>{t.preventDefault();var s=u.getValueForLanguage(r.id);if(s){let a=Object.keys(e).length,n=!1,i=u.getActivityOverlay();for(var l in i.showActivity(),e)if(l!==r.id){let e=o.default.getLanguageForId(l);g.default.getTranslation(r.engineLanguage.sourceCode,e.engineLanguage.targetCode,s).then(t=>{t.error?(n||u.getActivityOverlay().showError(t.message),n=!0):u.setValueForLanguage(e.id,t.translations[0])}).then(t=>{0!==--a||n||i.hide()})}}})},t)o.default.getTranslationAction()!==o.default.translationActionTypes.all||e||this.addTranslateToAllButton(a,t),o.default.getTranslationAction()!==o.default.translationActionTypes.each&&!e||this.addTranslateElements(a,t[a])}},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4,"./FtUiElements":18}],17:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;a.default=function(t){const e="ft-content-changed";let a=null;this.getContentModifiedClass=()=>e,this.setModifiedState=t=>t?this.setTabModified():this.setTabUnmodified(),this.setTabModified=()=>this.getLanguageTab().classList.add(e),this.setTabUnmodified=()=>this.getLanguageTab().classList.remove(e),this.getLanguageTab=()=>a??t.closest(".langTabs").querySelector(`.langTabLink[data-lang="${t.dataset.language}"`),t&&(a=this.getLanguageTab())}},{}],18:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var s=n(t("../global/FtConfig"));n(t("../global/FtTools")),n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){const a={translateButton:{container:"ft-translate-button-container",button:"ft-translate-button"},statusPlaceholder:{container:"ft-translation-status-container",label:"ft-translation-status"},icon:"ft-icon"},n=s.default.getUiTextFor("inputfieldTranslateButtons"),i=()=>{var t=document.createElement("a"),e=(t.setAttribute("href",ProcessWire.config.urls.admin+"fluency/?modal=1"),t.setAttribute("class","pw-modal pw-modal-large"),document.createElement("i"));return e.setAttribute("class",a.icon+" fa fa-language"),e.setAttribute("uk-tooltip",n.showTranslator),t.appendChild(e),t};return{createStatusElement:t=>{var e=document.createElement("span"),t=(e.setAttribute("class",a.statusPlaceholder.label),e.innerText=t,document.createElement("div"));return t.setAttribute("class",a.statusPlaceholder.container),t.appendChild(i()),t.appendChild(e),t},createTranslateButton:t=>{var e=document.createElement("a"),t=(e.innerText=t,e.setAttribute("class",a.translateButton.button),e.setAttribute("href",""),document.createElement("div"));return t.setAttribute("class",a.translateButton.container),t.appendChild(i()),t.appendChild(e),{button:e,container:t}},createIcon:i,elementClasses:a}}();a.default=t},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4}]},{},[1]); +!function n(i,s,l){function r(e,t){if(!s[e]){if(!i[e]){var a="function"==typeof require&&require;if(!t&&a)return a(e,!0);if(u)return u(e,!0);throw(t=new Error("Cannot find module '"+e+"'")).code="MODULE_NOT_FOUND",t}a=s[e]={exports:{}},i[e][0].call(a.exports,function(t){return r(i[e][1][t]||t)},a,a.exports,n,i,s,l)}return s[e].exports}for(var u="function"==typeof require&&require,t=0;t{s.default.moduleShouldInitialize()&&(i.default.init(),n.default.init())})},{"./global/FtConfig":3,"./inputfields/FtInputfields":13,"./ui/FtAdminMenu":15}],2:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var o=(t=t("./FtConfig"))&&t.__esModule?t:{default:t};t=function(){const a=o.default.getUiTextFor("errors");const l=t=>{var e={"X-Requested-With":"XMLHttpRequest"};return"GET"===t&&(e.Accept="application/json"),"POST"===t&&(e["Content-Type"]="application/json"),e},t=(t,e)=>fetch(t,{method:"GET",cache:"no-store",headers:l("GET")}).then(r).then(e).catch(u),e=(t,e)=>fetch(t,{method:"DELETE",headers:l("GET")}).then(r).then(e).catch(u),r=t=>{if(204===t.status)return t;if(t.ok)return t.json();throw new Error},u=t=>{console.error("[Fluency module API failure]",t.message);var e={error:null,message:null};return"NetworkError"===t.message.split(" ")[0]?(e.error="FLUENCY_CLIENT_DISCONNECTED",e.message=a.FLUENCY_CLIENT_DISCONNECTED):(e.error="UNKNOWN_ERROR",e.message=a.UNKNOWN_ERROR),e};return{deleteTranslatableLanguagesCache:()=>e(o.default.getApiEndpointFor("translatableLanguagesCache"),t=>t),deleteTranslationCache:()=>e(o.default.getApiEndpointFor("translationCache"),t=>t),getAvailableLanguages:()=>t(o.default.getApiEndpointFor("languages"),t=>t),getTranslation:function(t,e,a){var n,i=3t,fetch(n,{method:"POST",cache:"no-store",headers:l,body:JSON.stringify(t)}).then(r).then(e).catch(u)},getUsage:()=>t(o.default.getApiEndpointFor("usage"),t=>t)}}();a.default=t},{"./FtConfig":3}],3:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=function(){const t=ProcessWire.config.fluency;var e=t.localization;const a={translateButton:{container:"ft-translate-button-container",button:"ft-translate-button"},translateAllButton:{container:"Inputfield InputfieldHeaderHidden",content:"InputfieldContent",button:"ft-translate-all-button"},statusPlaceholder:{container:"ft-translation-status-container",label:"ft-translation-status"},icon:"ft-icon"},n={activityOverlay:e.activityOverlay,languageSelect:e.languageSelect,inputfieldTranslateButtons:e.inputfieldTranslateButtons,standaloneTranslator:e.standaloneTranslator,usage:e.usage,errors:e.errors,languageTranslator:e.languageTranslator},i={languages:t.apiEndpoints.languages,translatableLanguagesCache:t.apiEndpoints.translatableLanguagesCache,test:t.apiEndpoints.test,translation:t.apiEndpoints.translation,translationCache:t.apiEndpoints.translationCache,usage:t.apiEndpoints.usage},s=t.configuredLanguages,l=t.unconfiguredLanguages;const r=()=>s;const u=()=>l;const o=()=>t.engine;return{fieldInitializedAttr:"data-ft-initialized",getApiEndpointFor:t=>i[t],getConfiguredLanguages:r,getDefaultLanguage:()=>s.reduce((t,e)=>e.default?e:t,null),getElementClassesFor:t=>a[t],getEngineInfo:o,getEngineProvidesUsageData:()=>o().providesUsageData,getLanguageCount:()=>s.length+l.length,getLanguageForId:a=>(a=parseInt(a,10),s.reduce((t,e)=>e.id===a?e:t,null)),getTranslationAction:()=>t.interface.inputfieldTranslationAction,getUiTextFor:t=>n[t],getUnconfiguredLanguages:u,languageIsTranslatable:t=>!l.includes(parseInt(t,10)),moduleShouldInitialize:()=>1Math.random().toString(36)[2]).join("")}()),n.innerText=e,t.appendChild(n)},getPageId:n,pageIdIs:t=>n()===t}},{}],5:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldCKEditor=a.FtInputfieldCKEditor=void 0;var d=n(t("../ui/FtActivityOverlay")),c=n(t("../global/FtConfig")),f=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldCKEditor=t=>!!t.querySelector(".InputfieldCKEditorNormal");a.FtInputfieldCKEditor=function(t){const e={},a={},n={},i={},s={};let l=null,r;if(this.getActivityOverlay=()=>r,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(c.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getEditorInstanceForLanguage(t).getData(),this.setValueForLanguage=(t,e)=>{var a=this.getEditorInstanceForLanguage(t);return a.setData(e),a.fire("change"),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>{var e;return Object.hasOwn(s,t)&&s[t]||(e=this.createCKEditorSelector(t),s[t]=CKEDITOR.instances[e]),s[t]},this.createCKEditorSelector=t=>t==c.default.getDefaultLanguage().id?l:l+"__"+t,this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{i[t.dataset.language]=t}),i),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.registerInputEventListener=e=>{this.getEditorInstanceForLanguage(e).on("change",t=>{a[e]=this.getValueForLanguage(e),n[e].setModifiedState(this.contentHasChanged(e))})},void 0===CKEDITOR)console.error("CKEditor was not found by Fluency, translation unavailable");else{var u,o=this.getInputContainers();for(u in l=Object.values(o)[0].id.replace("langTab_",""),o){var g=o[u];s[u]=this.getEditorInstanceForLanguage(u),n[u]=new h.default(g),this.registerInputEventListener(u)}r=new d.default(this),new f.default(this,o)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],6:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldCKEditorInline=a.FtInputfieldCKEditorInline=void 0;var c=n(t("../ui/FtActivityOverlay")),f=n(t("../global/FtConfig")),h=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),v=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldCKEditorInline=t=>!!t.querySelector(".InputfieldCKEditorInline");a.FtInputfieldCKEditorInline=function(e){const a={},n={},i={},s={},l={},r={};let u=null,t;if(this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(f.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getEditorInstanceForLanguage(t);return e?e.getData():this.getContentElementForLanguage(t).innerHTML},this.setValueForLanguage=(t,e)=>{var a=this.getEditorInstanceForLanguage(t),n=this.getContentElementForLanguage(t);return a?a.setValue(e):n.innerHTML=e,n.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=CKEDITOR.instances[this.createCKEditorSelector(t)]),l[t]),this.getContentElementForLanguage=t=>(Object.hasOwn(r,t)||(r[t]=this.getInputContainerForLanguage(t).querySelector(".InputfieldCKEditorInlineEditor")),r[t]),this.createCKEditorSelector=t=>t==f.default.getDefaultLanguage().id?u:u+"__"+t,this.getInputContainers=()=>(Object.keys(s).length!==f.default.getLanguageCount()&&this.getSelf().querySelectorAll("[data-language]").forEach(t=>{s[t.dataset.language]=t}),s),this.getInputContainerForLanguage=t=>(Object.hasOwn(s,t)||(s[t]=e.querySelector(`[data-language="${t}"]`)),s[t]),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t],this.registerUpdateEvent=t=>{t=this.getContentElementForLanguage(t);new MutationObserver((t,e)=>{for(var a of t)a.target.dispatchEvent(new Event("input"))}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{this.getContentElementForLanguage(e).addEventListener("input",t=>{n[e]=this.getValueForLanguage(e),i[e].setModifiedState(this.contentHasChanged(e))})},void 0===CKEDITOR)console.error("CKEditor was not found by Fluency, translation unavailable");else{var o,g=this.getInputContainers();for(o in u=Object.values(g)[0].id.replace("langTab_",""),g){var d=g[o];l[o]=this.getEditorInstanceForLanguage(o),i[o]=new v.default(d),this.registerInputEventListener(o)}t=new c.default(this),new h.default(this,g)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],7:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=i(t("../ui/FtActivityOverlay")),g=i(t("../global/FtConfig")),d=i(t("./FtInputfields")),c=i(t("../ui/FtInputfieldTranslateButton")),f=i(t("../ui/FtLanguageTab"));function i(t){return t&&t.__esModule?t:{default:t}}function h(t){let e;this.getSelf=()=>t,this.getActivityOverlay=()=>e,e=new n.default(this)}a.default=function(t){const e={},a={};const n={},i={};let s=(new f.default).getContentModifiedClass(),l={};this.getActivityOverlay=t=>t?l[t].getActivityOverlay():null,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(g.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return d.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(i,t)&&i[t]||(i[t]=this.getInputContainerForLanguage(t).querySelector("input")),i[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(n,t)||n[t]||this.getInputContainers(),n[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll(".LanguageSupport").forEach(t=>{var e=t.querySelector("input[type=text]").name.replace("_pw_page_name","")||g.default.getDefaultLanguage().id;n[e]=t}),n),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.setModifiedState=(t,e)=>{t=this.getInputContainerForLanguage(t);e&&t.classList.add(s),e||t.classList.remove(s)},this.registerInputEventListener=e=>{this.getFieldForLanguage(e).addEventListener("input",t=>{a[e]=t.target.value,this.setModifiedState(e,this.contentHasChanged(e))})};var r,u=this.getInputContainers();for(r in u){var o=u[r];e[r]=this.getValueForLanguage(r),l[r]=new h(o),this.registerInputEventListener(r)}new c.default(this,u,!0)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],8:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTable=void 0;a.FtIsInputfieldTable=t=>n(t)||i(t);const n=t=>!!t.classList.contains("InputfieldTable"),i=t=>"TBODY"===!!t.tagName&&t.querySelectorAll(".InputfieldTable_hasLangTabs").length},{}],9:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldText=a.FtInputfieldText=void 0;var g=n(t("../ui/FtActivityOverlay")),d=n(t("../global/FtConfig")),c=n(t("./FtInputfields")),f=n(t("../ui/FtInputfieldTranslateButton")),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldText=t=>!!t.querySelector("input[type='text']");a.FtInputfieldText=function(e){const a={},n={},i={},s={},l={};let t;this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(d.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return c.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=this.getInputContainerForLanguage(t).querySelector("input")),l[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(s,t)&&s[t]||(s[t]=e.querySelector(`[data-language="${t}"]`)),s[t]),this.getInputContainers=()=>(e.querySelectorAll("[data-language]").forEach(t=>s[t.dataset.language]=t),s),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t],this.registerInputEventListener=e=>{this.getFieldForLanguage(e).addEventListener("input",t=>{n[e]=t.target.value,i[e].setModifiedState(this.contentHasChanged(e))})};var r,u=this.getInputContainers();for(r in u){var o=u[r];a[r]=this.getValueForLanguage(r),i[r]=new h.default(o),this.registerInputEventListener(r)}t=new g.default(this),new f.default(this,u)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],10:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTextarea=a.FtInputfieldTextarea=void 0;var o=n(t("../ui/FtActivityOverlay")),g=n(t("../global/FtConfig")),d=n(t("./FtInputfields")),c=n(t("../ui/FtInputfieldTranslateButton")),f=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTextarea=t=>!!t.querySelector("textarea:not(.InputfieldCKEditorNormal,.InputfieldTinyMCEEditor)");a.FtInputfieldTextarea=function(e){const a={},n={},i={},s={},l={};let t;this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(g.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return d.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(l,t)||(l[t]=e.querySelector(`[data-language="${t}"] textarea`)),l[t]),this.getInputContainers=()=>(e.querySelectorAll("[data-language]").forEach(t=>{s[t.dataset.language]=t}),s),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t];var r=this.getInputContainers();for(let e in r){var u=r[e];a[e]=this.getValueForLanguage(e),i[e]=new f.default(u),u.querySelector("textarea").addEventListener("input",t=>{n[e]=t.target.value,i[e].setModifiedState(this.contentHasChanged(e))})}t=new o.default(this),new c.default(this,r)}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],11:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTinyMCE=a.FtInputfieldTinyMCE=void 0;var g=n(t("../ui/FtActivityOverlay")),d=n(t("../global/FtConfig")),c=n(t("./FtInputfields")),f=n(t("../ui/FtInputfieldTranslateButton")),h=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTinyMCE=t=>!!t.querySelector(".InputfieldTinyMCENormal");a.FtInputfieldTinyMCE=function(t){const i={},a={},s={},e={},l={},r={};let u=null,n;this.getActivityOverlay=()=>n,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(d.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getTinymceInstanceForLanguage(t);return e?e.getContent():this.getTextareaForLanguage(t).value},this.setValueForLanguage=(t,e)=>{var a=this.getTinymceInstanceForLanguage(t),a=(a&&(a.setContent(e),a.fire("input")),this.getTextareaForLanguage(t));return c.default.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getTinymceInstanceForLanguage=t=>{var e;return Object.hasOwn(r,t)&&r[t]||(e=this.createTinymceSelector(t),r[t]=tinymce.get(e)),r[t]},this.getTextareaForLanguage=t=>(Object.hasOwn(l,t)&&l[t]||(l[t]=this.getSelf().querySelector(`[data-language="${t}"] textarea`)),l[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{e[t.dataset.language]=t}),e),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==i[t],this.createTinymceSelector=t=>t==d.default.getDefaultLanguage().id?u:u+"__"+t,this.bindTinymceEvents=(e,t)=>{t.on("keyup",t=>this.getTextareaForLanguage(e).dispatchEvent(new Event("input")))},this.initTinymceInstanceOnCreation=(n,t)=>{new MutationObserver((t,e)=>{for(var a of t)a.target.dataset.language==n&&(r[n]=this.getTinymceInstanceForLanguage(n),this.bindTinymceEvents(n,r[n]),r[n])&&e.disconnect()}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{l[e].addEventListener("input",t=>{a[e]=this.getValueForLanguage(e),s[e].setModifiedState(this.contentHasChanged(e))})},this.initAll=t=>{for(var e in u=Object.values(t)[0].id.replace("langTab_",""),t){var a=t[e];i[e]=this.getValueForLanguage(e),s[e]=new h.default(a),r[e]=this.getTinymceInstanceForLanguage(e),l[e]=this.getTextareaForLanguage(e),this.registerInputEventListener(e),r[e]||this.initTinymceInstanceOnCreation(e,a)}for(var n in r)Object.hasOwn(r,n)&&r[n]&&this.bindTinymceEvents(n,r[n])};{const o=this.getInputContainers();setTimeout(()=>{this.initAll(o)},50),n=new g.default(this),new f.default(this,o)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],12:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.FtIsInputfieldTinyMCEInline=a.FtInputfieldTinyMCEInline=void 0;var c=n(t("../ui/FtActivityOverlay")),f=n(t("../global/FtConfig")),h=(n(t("./FtInputfields")),n(t("../ui/FtInputfieldTranslateButton"))),v=n(t("../ui/FtLanguageTab"));function n(t){return t&&t.__esModule?t:{default:t}}a.FtIsInputfieldTinyMCEInline=t=>!!t.querySelector(".InputfieldTinyMCEInline");a.FtInputfieldTinyMCEInline=function(t){const e={},a={},n={},i={},s={},l={};let r=null,u;if(this.getActivityOverlay=()=>u,this.getSelf=()=>t,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(f.default.getDefaultLanguage().id),this.getValueForLanguage=t=>{var e=this.getEditorInstanceForLanguage(t);return e?e.getContent():this.getContentElementForLanguage(t).innerHTML},this.setValueForLanguage=(t,e)=>{var a=this.getContentElementForLanguage(t);return a.innerHTML=e,a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getEditorInstanceForLanguage=t=>{var e;return Object.hasOwn(l,t)&&l[t]||(e=this.createTinymceSelector(t),l[t]=tinymce.get(e)),l[t]},this.getContentElementForLanguage=t=>(Object.hasOwn(s,t)||(s[t]=this.getInputContainerForLanguage(t).querySelector(".mce-content-body")),s[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(i,t)&&i[t]||(i[t]=this.getSelf().querySelector(`[data-language="${t}"]`)),i[t]),this.getInputContainers=()=>(this.getSelf().querySelectorAll("[data-language]").forEach(t=>{i[t.dataset.language]=t}),i),this.contentHasChanged=t=>Object.hasOwn(a,t)&&a[t]!==e[t],this.createTinymceSelector=t=>t==f.default.getDefaultLanguage().id?r:r+"__"+t,this.registerUpdateEvent=t=>{t=this.getContentElementForLanguage(t);new MutationObserver((t,e)=>{for(var a of t)a.target.dispatchEvent(new Event("input"))}).observe(t,{childList:!0})},this.registerInputEventListener=e=>{this.getContentElementForLanguage(e).addEventListener("input",t=>{a[e]=this.getValueForLanguage(e),n[e].setModifiedState(this.contentHasChanged(e))})},void 0===tinymce)console.error("TinyMCE was not found by Fluency, translation unavailable");else{var o,g=this.getInputContainers();for(o in r=Object.values(g)[0].id.replace("langTab_",""),g){var d=g[o];e[o]=this.getValueForLanguage(o),n[o]=new v.default(d),this.registerUpdateEvent(o),this.registerInputEventListener(o)}u=new c.default(this),new h.default(this,g)}}},{"../global/FtConfig":3,"../ui/FtActivityOverlay":14,"../ui/FtInputfieldTranslateButton":16,"../ui/FtLanguageTab":17,"./FtInputfields":13}],13:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var l=n(t("../global/FtConfig")),r=(n(t("../global/FtTools")),t("./FtInputfieldCKEditor")),u=t("./FtInputfieldCKEditorInline"),o=t("./FtInputfieldTable"),g=t("./FtInputfieldText"),d=t("./FtInputfieldTextarea"),c=t("./FtInputfieldTinyMCE"),f=t("./FtInputfieldTinyMCEInline"),h=n(t("./FtInputfieldPageName"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){const n="[class*='hasLangTabs']";const i=t=>{for(var e of t)a(e)},a=t=>{e(t)||t.classList.contains("InputfieldItemList")||t.closest("[class*='Template']")||((t=>{switch(true){case(0,o.FtIsInputfieldTable)(t):i(t.querySelectorAll(".langTabs"));break;case(0,r.FtIsInputfieldCKEditor)(t):return new r.FtInputfieldCKEditor(t);case(0,u.FtIsInputfieldCKEditorInline)(t):return new u.FtInputfieldCKEditorInline(t);case(0,c.FtIsInputfieldTinyMCE)(t):return new c.FtInputfieldTinyMCE(t);case(0,f.FtIsInputfieldTinyMCEInline)(t):return new f.FtInputfieldTinyMCEInline(t);case(0,d.FtIsInputfieldTextarea)(t):return new d.FtInputfieldTextarea(t);case(0,g.FtIsInputfieldText)(t):return new g.FtInputfieldText(t);default:console.warn("Fluency does not recognize this inputfield, translation is not available",t)}})(t),s(t))},e=t=>t.hasAttribute(l.default.fieldInitializedAttr)||!!t.querySelector(".ft-translate-button"),s=t=>t.setAttribute(l.default.fieldInitializedAttr,"");return{init:function(){var t=document.querySelectorAll(n);t.length&&(i(t),t=document.getElementById("pw-content-body"),new MutationObserver((t,e)=>{for(var a of t){a=a.target.querySelectorAll(n);a.length&&i(a)}}).observe(t,{childList:!0,subtree:!0}),[...document.querySelectorAll(".InputfieldPageName")].forEach(t=>{t&&!e(t)&&(new h.default(t),s(t))}))},updateValue:(t,e)=>{t.focus(),t.value=e,t.blur()},fieldIsInitialized:e}}();a.default=t},{"../global/FtConfig":3,"../global/FtTools":4,"./FtInputfieldCKEditor":5,"./FtInputfieldCKEditorInline":6,"./FtInputfieldPageName":7,"./FtInputfieldTable":8,"./FtInputfieldText":9,"./FtInputfieldTextarea":10,"./FtInputfieldTinyMCE":11,"./FtInputfieldTinyMCEInline":12}],14:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var r=(t=t("../global/FtConfig"))&&t.__esModule?t:{default:t};a.default=function(t){var a=this;let n=1{this.setActivityActive(),this.setOverlayVisible()},this.showMessage=function(t){var e=1{a.setOverlayInvisible()},t),setTimeout(()=>{a.setActivityInactive(),a.setMessageInactive(),a.setErrorInactive(),a.setFlashInactive(),a.setMessageContent("")},t+500)},this.setActivityActive=()=>{e.classList.add(i.activity)},this.setActivityInactive=()=>{e.classList.remove(i.activity)},this.setMessageActive=()=>{e.classList.add(i.message)},this.setMessageInactive=()=>{e.classList.remove(i.message)},this.setMessageContent=t=>{s.innerText=t},this.setFlashActive=t=>{e.classList.add(i.flash)},this.setFlashInactive=t=>{e.classList.remove(i.flash)},this.setSuccessActive=()=>{e.classList.add(i.success)},this.setSuccessInactive=()=>{e.classList.remove(i.success)},this.setErrorActive=()=>{e.classList.add(i.error)},this.setErrorInactive=()=>{e.classList.remove(i.error)},this.setOverlayVisible=()=>{e.classList.add(i.visible)},this.setOverlayInvisible=()=>{e.classList.remove(i.visible)},this.create=()=>(e=this.buildOverlayEl(),l=this.buildActivityEl(),s=this.buildMessageEl(),e.appendChild(l),e.appendChild(s),e),this.buildOverlayEl=()=>{var t=document.createElement("div");return t.setAttribute("class",i.overlay),t},this.buildActivityEl=()=>{var t=r.default.getUiTextFor("activityOverlay")[n];let e=document.createElement("div");e.setAttribute("class",i.activityAnimationContainer),e=t.animated.reduce((t,e)=>{var a=document.createElement("span");return a.setAttribute("class",i.activityAnimationItem),a.innerHTML=e,t.appendChild(a),t},e);var a=document.createElement("div");return a.setAttribute("class",i.activityStaticText),a.innerText=t.static,(l=document.createElement("div")).setAttribute("class",i.activityContainer),l.appendChild(a),l.appendChild(e),l},this.buildMessageEl=()=>((s=document.createElement("div")).setAttribute("class",i.messageContainer),s),t=t.getSelf(),e=this.create(),t.classList.add(i.parent),t.appendChild(e)}},{"../global/FtConfig":3}],15:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0,a.default={init:()=>{{var t=document.querySelectorAll(".pw-masthead .pw-primary-nav > li > a"),e;"Fluency"!==new URLSearchParams(window.location.search).get("name")&&t.forEach((t,e)=>{var a=t.href.split("/").filter(Boolean);a[a.length-1].includes("fluency")&&(t.href=t.href+"?modal=1",t.classList.add("pw-modal-large"),t.classList.add("pw-modal"))})}}}},{}],16:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var o=n(t("../global/FtConfig")),g=(n(t("../global/FtTools")),n(t("../global/Fluency"))),r=n(t("./FtUiElements"));function n(t){return t&&t.__esModule?t:{default:t}}a.default=function(u,t){let e=2{var a,n,i=o.default.languageIsTranslatable(t),s=t==o.default.getDefaultLanguage().id;i&&!s&&({button:a,container:n}=r.default.createTranslateButton(l.translateButton),this.bindButton(a,o.default.getLanguageForId(t)),e.appendChild(n)),i&&s&&e.appendChild(r.default.createStatusElement(l.translationAvailable)),i||e.appendChild(r.default.createStatusElement(l.languageNotAvailable))},this.bindButton=(t,a)=>{t.addEventListener("click",t=>{t.preventDefault();t=u.getValueForDefaultLanguage();if(t){const e=u.getActivityOverlay()??u.getActivityOverlay(a.id);e.showActivity(),g.default.getTranslation(o.default.getDefaultLanguage().engineLanguage.sourceCode,a.engineLanguage.targetCode,t).then(t=>{t.error?u.getActivityOverlay().showError(t.message):(u.setValueForLanguage(a.id,t.translations[0]),e.hide())})}})},this.addTranslateToAllButton=(t,e)=>{var a=e[t],{button:n,container:i}=r.default.createTranslateButton(l.translateToAllButton);this.bindTranslateToAllButton(n,o.default.getLanguageForId(t),e),a.appendChild(i)},this.bindTranslateToAllButton=(t,r,e)=>{t.addEventListener("click",t=>{t.preventDefault();var s=u.getValueForLanguage(r.id);if(s){let a=Object.keys(e).length,n=!1,i=u.getActivityOverlay();for(var l in i.showActivity(),e)if(l!==r.id){let e=o.default.getLanguageForId(l);g.default.getTranslation(r.engineLanguage.sourceCode,e.engineLanguage.targetCode,s).then(t=>{t.error?(n||u.getActivityOverlay().showError(t.message),n=!0):u.setValueForLanguage(e.id,t.translations[0])}).then(t=>{0!==--a||n||i.hide()})}}})},t)o.default.getTranslationAction()!==o.default.translationActionTypes.all||e||this.addTranslateToAllButton(a,t),o.default.getTranslationAction()!==o.default.translationActionTypes.each&&!e||this.addTranslateElements(a,t[a])}},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4,"./FtUiElements":18}],17:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;a.default=function(t){const e="ft-content-changed";let a=null;this.getContentModifiedClass=()=>e,this.setModifiedState=t=>t?this.setTabModified():this.setTabUnmodified(),this.setTabModified=()=>this.getLanguageTab().classList.add(e),this.setTabUnmodified=()=>this.getLanguageTab().classList.remove(e),this.getLanguageTab=()=>a??t.closest(".langTabs").querySelector(`.langTabLink[data-lang="${t.dataset.language}"`),t&&(a=this.getLanguageTab())}},{}],18:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var s=n(t("../global/FtConfig"));n(t("../global/FtTools")),n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){var t=s.default.elementClasses;const a=s.default.getUiTextFor("inputfieldTranslateButtons"),n=()=>{var t=document.createElement("a"),e=(t.setAttribute("href",ProcessWire.config.urls.admin+"fluency/?modal=1"),t.setAttribute("class","pw-modal pw-modal-large"),document.createElement("i"));return e.setAttribute("class",s.default.getElementClassesFor("icon")+" fa fa-language"),e.setAttribute("uk-tooltip",a.showTranslator),t.appendChild(e),t};return{createStatusElement:t=>{var e=s.default.getElementClassesFor("statusPlaceholder"),a=document.createElement("span"),t=(a.setAttribute("class",e.label),a.innerText=t,document.createElement("div"));return t.setAttribute("class",e.container),t.appendChild(n()),t.appendChild(a),t},createTranslateButton:t=>{var e=s.default.getElementClassesFor("translateButton"),a=document.createElement("a"),t=(a.innerText=t,a.setAttribute("class",e.button),a.setAttribute("href",""),document.createElement("div"));return t.setAttribute("class",e.container),t.appendChild(n()),t.appendChild(a),{button:a,container:t}},createTranslateAllButton:t=>{var e=s.default.getElementClassesFor("translateAllButton"),a=document.createElement("a"),n=(a.innerText=s.default.getUiTextFor("languageTranslator").translateAllButton,a.setAttribute("class",e.button),a.setAttribute("href",""),document.createElement("div")),i=(n.setAttribute("class",e.content),n.appendChild(a),document.createElement("li"));return i.setAttribute("class",e.container),i.appendChild(n),{button:a,container:i}},createIcon:n,elementClasses:t}}();a.default=t},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4}]},{},[1]); //# sourceMappingURL=maps/fluency.bundle.js.map diff --git a/assets/scripts/fluency_language_translator.bundle.js b/assets/scripts/fluency_language_translator.bundle.js index fff1329..2b75774 100644 --- a/assets/scripts/fluency_language_translator.bundle.js +++ b/assets/scripts/fluency_language_translator.bundle.js @@ -1,2 +1,2 @@ -!function n(i,s,r){function l(e,t){if(!s[e]){if(!i[e]){var a="function"==typeof require&&require;if(!t&&a)return a(e,!0);if(o)return o(e,!0);throw(t=new Error("Cannot find module '"+e+"'")).code="MODULE_NOT_FOUND",t}a=s[e]={exports:{}},i[e][0].call(a.exports,function(t){return l(i[e][1][t]||t)},a,a.exports,n,i,s,r)}return s[e].exports}for(var o="function"==typeof require&&require,t=0;t{i.default.moduleShouldInitialize()&&n.default.init()})},{"./global/FtConfig":3,"./inputfields/FtLanguageTranslatorInputfields":5}],2:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var u=(t=t("./FtConfig"))&&t.__esModule?t:{default:t};t=function(){const a=u.default.getUiTextFor("errors");const r=t=>{var e={"X-Requested-With":"XMLHttpRequest"};return"GET"===t&&(e.Accept="application/json"),"POST"===t&&(e["Content-Type"]="application/json"),e},t=(t,e)=>fetch(t,{method:"GET",cache:"no-store",headers:r("GET")}).then(l).then(e).catch(o),e=(t,e)=>fetch(t,{method:"DELETE",headers:r("GET")}).then(l).then(e).catch(o),l=t=>{if(204===t.status)return t;if(t.ok)return t.json();throw new Error},o=t=>{console.error("[Fluency module API failure]",t.message);var e={error:null,message:null};return"NetworkError"===t.message.split(" ")[0]?(e.error="FLUENCY_CLIENT_DISCONNECTED",e.message=a.FLUENCY_CLIENT_DISCONNECTED):(e.error="UNKNOWN_ERROR",e.message=a.UNKNOWN_ERROR),e};return{deleteTranslatableLanguagesCache:()=>e(u.default.getApiEndpointFor("translatableLanguagesCache"),t=>t),deleteTranslationCache:()=>e(u.default.getApiEndpointFor("translationCache"),t=>t),getAvailableLanguages:()=>t(u.default.getApiEndpointFor("languages"),t=>t),getTranslation:function(t,e,a){var n,i=3t,fetch(n,{method:"POST",cache:"no-store",headers:r,body:JSON.stringify(t)}).then(l).then(e).catch(o)},getUsage:()=>t(u.default.getApiEndpointFor("usage"),t=>t)}}();a.default=t},{"./FtConfig":3}],3:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=function(){const t=ProcessWire.config.fluency;var e=t.localization;const a={activityOverlay:e.activityOverlay,languageSelect:e.languageSelect,inputfieldTranslateButtons:e.inputfieldTranslateButtons,standaloneTranslator:e.standaloneTranslator,usage:e.usage,errors:e.errors},n={languages:t.apiEndpoints.languages,translatableLanguagesCache:t.apiEndpoints.translatableLanguagesCache,test:t.apiEndpoints.test,translation:t.apiEndpoints.translation,translationCache:t.apiEndpoints.translationCache,usage:t.apiEndpoints.usage},i=t.configuredLanguages,s=t.unconfiguredLanguages;const r=()=>i;const l=()=>s;const o=()=>t.engine;return{fieldInitializedAttr:"data-ft-initialized",getApiEndpointFor:t=>n[t],getConfiguredLanguages:r,getDefaultLanguage:()=>i.reduce((t,e)=>e.default?e:t,null),getEngineInfo:o,getEngineProvidesUsageData:()=>o().providesUsageData,getInputfieldTranslationAction:()=>t.interface.inputfieldTranslationAction,getLanguageCount:()=>i.length+s.length,getLanguageForId:a=>(a=parseInt(a,10),i.reduce((t,e)=>e.id===a?e:t,null)),getUiTextFor:t=>a[t],getUnconfiguredLanguages:l,languageIsTranslatable:t=>!s.includes(parseInt(t,10)),moduleShouldInitialize:()=>1Math.random().toString(36)[2]).join("")}()),n.innerText=e,t.appendChild(n)},getPageId:n,pageIdIs:t=>n()===t}},{}],5:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=a.LanguageTranslatorInputfield=a.FtInputfieldText=void 0;var c=n(t("../ui/FtActivityOverlay")),r=n(t("../ui/FtUiElements")),d=n(t("../global/FtConfig")),l=n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}t={init:()=>{var t=document.querySelectorAll(".InputfieldContent");t&&[...t].forEach(t=>{t.querySelector("input.translatable")&&new i(t)})}};const i=function(a){const n=d.default.getUiTextFor("inputfieldTranslateButtons");let e,i=a.querySelector(".description").innerText,s=a.querySelector("input");this.getSelf=()=>a,this.getActivityOverlay=()=>e,this.addTranslateButton=()=>{var{button:t,container:e}=r.default.createTranslateButton(n.translate);this.bindTranslateButton(t),a.appendChild(e)},this.bindTranslateButton=t=>{t.addEventListener("click",t=>{t.preventDefault(),this.translateContent()})},this.translateContent=()=>{var t=new URLSearchParams(window.location.search),t=parseInt(t.get("language_id"));e.showActivity(),l.default.getTranslation(d.default.getDefaultLanguage().engineLanguage.sourceCode,d.default.getLanguageForId(t).engineLanguage.targetCode,i).then(t=>{t.error?e.showError(t.message):(s.value=t.translations[0],e.hide())})},e=new c.default(this),this.addTranslateButton()};a.LanguageTranslatorInputfield=i;a.default=t;a.FtInputfieldText=function(e){const a={},n={},i={},s={},r={};let t;this.getActivityOverlay=()=>t,this.getSelf=()=>e,this.getValueForDefaultLanguage=()=>this.getValueForLanguage(d.default.getDefaultLanguage().id),this.getValueForLanguage=t=>this.getFieldForLanguage(t).value,this.setValueForLanguage=(t,e)=>{var a=this.getFieldForLanguage(t);return FtInputfields.updateValue(a,e),a.dispatchEvent(new Event("input")),this.contentHasChanged(t)},this.getFieldForLanguage=t=>(Object.hasOwn(r,t)&&r[t]||(r[t]=this.getInputContainerForLanguage(t).querySelector("input")),r[t]),this.getInputContainerForLanguage=t=>(Object.hasOwn(s,t)&&s[t]||(s[t]=e.querySelector(`[data-language="${t}"]`)),s[t]),this.getInputContainers=()=>(e.querySelectorAll("[data-language]").forEach(t=>s[t.dataset.language]=t),s),this.contentHasChanged=t=>Object.hasOwn(n,t)&&n[t]!==a[t],this.registerInputEventListener=e=>{this.getFieldForLanguage(e).addEventListener("input",t=>{n[e]=t.target.value,i[e].setModifiedState(this.contentHasChanged(e))})};var l,o=this.getInputContainers();for(l in o){var u=o[l];a[l]=this.getValueForLanguage(l),i[l]=new FtLanguageTab(u),this.registerInputEventListener(l)}t=new c.default(this),new FtInputfieldTranslateButton(this,o)}},{"../global/Fluency":2,"../global/FtConfig":3,"../ui/FtActivityOverlay":6,"../ui/FtUiElements":7}],6:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var l=(t=t("../global/FtConfig"))&&t.__esModule?t:{default:t};a.default=function(t){var a=this;let n=1{this.setActivityActive(),this.setOverlayVisible()},this.showMessage=function(t){var e=1{a.setOverlayInvisible()},t),setTimeout(()=>{a.setActivityInactive(),a.setMessageInactive(),a.setErrorInactive(),a.setFlashInactive(),a.setMessageContent("")},t+500)},this.setActivityActive=()=>{e.classList.add(i.activity)},this.setActivityInactive=()=>{e.classList.remove(i.activity)},this.setMessageActive=()=>{e.classList.add(i.message)},this.setMessageInactive=()=>{e.classList.remove(i.message)},this.setMessageContent=t=>{s.innerText=t},this.setFlashActive=t=>{e.classList.add(i.flash)},this.setFlashInactive=t=>{e.classList.remove(i.flash)},this.setSuccessActive=()=>{e.classList.add(i.success)},this.setSuccessInactive=()=>{e.classList.remove(i.success)},this.setErrorActive=()=>{e.classList.add(i.error)},this.setErrorInactive=()=>{e.classList.remove(i.error)},this.setOverlayVisible=()=>{e.classList.add(i.visible)},this.setOverlayInvisible=()=>{e.classList.remove(i.visible)},this.create=()=>(e=this.buildOverlayEl(),r=this.buildActivityEl(),s=this.buildMessageEl(),e.appendChild(r),e.appendChild(s),e),this.buildOverlayEl=()=>{var t=document.createElement("div");return t.setAttribute("class",i.overlay),t},this.buildActivityEl=()=>{var t=l.default.getUiTextFor("activityOverlay")[n];let e=document.createElement("div");e.setAttribute("class",i.activityAnimationContainer),e=t.animated.reduce((t,e)=>{var a=document.createElement("span");return a.setAttribute("class",i.activityAnimationItem),a.innerHTML=e,t.appendChild(a),t},e);var a=document.createElement("div");return a.setAttribute("class",i.activityStaticText),a.innerText=t.static,(r=document.createElement("div")).setAttribute("class",i.activityContainer),r.appendChild(a),r.appendChild(e),r},this.buildMessageEl=()=>((s=document.createElement("div")).setAttribute("class",i.messageContainer),s),t=t.getSelf(),e=this.create(),t.classList.add(i.parent),t.appendChild(e)}},{"../global/FtConfig":3}],7:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var s=n(t("../global/FtConfig"));n(t("../global/FtTools")),n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){const a={translateButton:{container:"ft-translate-button-container",button:"ft-translate-button"},statusPlaceholder:{container:"ft-translation-status-container",label:"ft-translation-status"},icon:"ft-icon"},n=s.default.getUiTextFor("inputfieldTranslateButtons"),i=()=>{var t=document.createElement("a"),e=(t.setAttribute("href",ProcessWire.config.urls.admin+"fluency/?modal=1"),t.setAttribute("class","pw-modal pw-modal-large"),document.createElement("i"));return e.setAttribute("class",a.icon+" fa fa-language"),e.setAttribute("uk-tooltip",n.showTranslator),t.appendChild(e),t};return{createStatusElement:t=>{var e=document.createElement("span"),t=(e.setAttribute("class",a.statusPlaceholder.label),e.innerText=t,document.createElement("div"));return t.setAttribute("class",a.statusPlaceholder.container),t.appendChild(i()),t.appendChild(e),t},createTranslateButton:t=>{var e=document.createElement("a"),t=(e.innerText=t,e.setAttribute("class",a.translateButton.button),e.setAttribute("href","noaction"),document.createElement("div"));return t.setAttribute("class",a.translateButton.container),t.appendChild(i()),t.appendChild(e),{button:e,container:t}},createIcon:i,elementClasses:a}}();a.default=t},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4}]},{},[1]); +!function n(i,s,r){function l(e,t){if(!s[e]){if(!i[e]){var a="function"==typeof require&&require;if(!t&&a)return a(e,!0);if(o)return o(e,!0);throw(t=new Error("Cannot find module '"+e+"'")).code="MODULE_NOT_FOUND",t}a=s[e]={exports:{}},i[e][0].call(a.exports,function(t){return l(i[e][1][t]||t)},a,a.exports,n,i,s,r)}return s[e].exports}for(var o="function"==typeof require&&require,t=0;t{i.default.moduleShouldInitialize()&&n.default.init()})},{"./global/FtConfig":3,"./inputfields/FtLanguageTranslatorInputfields":5}],2:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var u=(t=t("./FtConfig"))&&t.__esModule?t:{default:t};t=function(){const a=u.default.getUiTextFor("errors");const r=t=>{var e={"X-Requested-With":"XMLHttpRequest"};return"GET"===t&&(e.Accept="application/json"),"POST"===t&&(e["Content-Type"]="application/json"),e},t=(t,e)=>fetch(t,{method:"GET",cache:"no-store",headers:r("GET")}).then(l).then(e).catch(o),e=(t,e)=>fetch(t,{method:"DELETE",headers:r("GET")}).then(l).then(e).catch(o),l=t=>{if(204===t.status)return t;if(t.ok)return t.json();throw new Error},o=t=>{console.error("[Fluency module API failure]",t.message);var e={error:null,message:null};return"NetworkError"===t.message.split(" ")[0]?(e.error="FLUENCY_CLIENT_DISCONNECTED",e.message=a.FLUENCY_CLIENT_DISCONNECTED):(e.error="UNKNOWN_ERROR",e.message=a.UNKNOWN_ERROR),e};return{deleteTranslatableLanguagesCache:()=>e(u.default.getApiEndpointFor("translatableLanguagesCache"),t=>t),deleteTranslationCache:()=>e(u.default.getApiEndpointFor("translationCache"),t=>t),getAvailableLanguages:()=>t(u.default.getApiEndpointFor("languages"),t=>t),getTranslation:function(t,e,a){var n,i=3t,fetch(n,{method:"POST",cache:"no-store",headers:r,body:JSON.stringify(t)}).then(l).then(e).catch(o)},getUsage:()=>t(u.default.getApiEndpointFor("usage"),t=>t)}}();a.default=t},{"./FtConfig":3}],3:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var n=function(){const t=ProcessWire.config.fluency;var e=t.localization;const a={translateButton:{container:"ft-translate-button-container",button:"ft-translate-button"},translateAllButton:{container:"Inputfield InputfieldHeaderHidden",content:"InputfieldContent",button:"ft-translate-all-button"},statusPlaceholder:{container:"ft-translation-status-container",label:"ft-translation-status"},icon:"ft-icon"},n={activityOverlay:e.activityOverlay,languageSelect:e.languageSelect,inputfieldTranslateButtons:e.inputfieldTranslateButtons,standaloneTranslator:e.standaloneTranslator,usage:e.usage,errors:e.errors,languageTranslator:e.languageTranslator},i={languages:t.apiEndpoints.languages,translatableLanguagesCache:t.apiEndpoints.translatableLanguagesCache,test:t.apiEndpoints.test,translation:t.apiEndpoints.translation,translationCache:t.apiEndpoints.translationCache,usage:t.apiEndpoints.usage},s=t.configuredLanguages,r=t.unconfiguredLanguages;const l=()=>s;const o=()=>r;const u=()=>t.engine;return{fieldInitializedAttr:"data-ft-initialized",getApiEndpointFor:t=>i[t],getConfiguredLanguages:l,getDefaultLanguage:()=>s.reduce((t,e)=>e.default?e:t,null),getElementClassesFor:t=>a[t],getEngineInfo:u,getEngineProvidesUsageData:()=>u().providesUsageData,getLanguageCount:()=>s.length+r.length,getLanguageForId:a=>(a=parseInt(a,10),s.reduce((t,e)=>e.id===a?e:t,null)),getTranslationAction:()=>t.interface.inputfieldTranslationAction,getUiTextFor:t=>n[t],getUnconfiguredLanguages:o,languageIsTranslatable:t=>!r.includes(parseInt(t,10)),moduleShouldInitialize:()=>1Math.random().toString(36)[2]).join("")}()),n.innerText=e,t.appendChild(n)},getPageId:n,pageIdIs:t=>n()===t}},{}],5:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var r=n(t("../ui/FtActivityOverlay")),l=n(t("../ui/FtUiElements")),o=n(t("../global/FtConfig")),u=n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}const i=function(t){let s,a=[];this.getSelf=()=>t,this.getActivityOverlay=()=>s,this.addTranslateButton=()=>{var{button:t,container:e}=l.default.createTranslateAllButton();this.bindTranslateButton(t),document.querySelector(".Inputfields").insertAdjacentElement("afterbegin",e)},this.bindTranslateButton=t=>{t.addEventListener("click",t=>{t.preventDefault(),this.translateContent()})},this.getGroupedContentForTranslation=()=>{return a.reduce((t,e,a)=>{a=Math.floor(a/40);return t[a]||(t[a]=[]),t[a].push(e),t},[])},this.translateContent=()=>{var t=this.getGroupedContentForTranslation();s.showActivity();let e=t.length;var a=new URLSearchParams(window.location.search);const n=parseInt(a.get("language_id"));let i=!1;t.forEach((a,t)=>{i||u.default.getTranslation(o.default.getDefaultLanguage().engineLanguage.sourceCode,o.default.getLanguageForId(n).engineLanguage.targetCode,a.map(t=>t.text)).then(t=>{if(t.error)i||(s.showError(t.message),i=!0);else{var e=t.translations;if(a.length!==e.length)s.showError("Error"),i=!0;else for(let t=0;t{0!==--e||i||s.hide()})})},this.mapSourceTargetElements=()=>{[...document.querySelectorAll(".InputfieldContent")].forEach(t=>{var e=t.querySelector(".description"),t=t.querySelector("input.translatable, textarea.translatable");t&&e&&e.innerText&&a.push({text:e.innerText,input:t})})},s=new r.default(this),this.mapSourceTargetElements(),this.addTranslateButton()},s=function(a){const n=o.default.getUiTextFor("inputfieldTranslateButtons");let e,i=a.querySelector(".description").innerText,s=a.querySelector("input, textarea");this.getSelf=()=>a,this.getActivityOverlay=()=>e,this.addTranslateButton=()=>{var{button:t,container:e}=l.default.createTranslateButton(n.translate);this.bindTranslateButton(t),a.appendChild(e)},this.bindTranslateButton=t=>{t.addEventListener("click",t=>{t.preventDefault(),this.translateContent()})},this.translateContent=()=>{var t=new URLSearchParams(window.location.search),t=parseInt(t.get("language_id"));e.showActivity(),u.default.getTranslation(o.default.getDefaultLanguage().engineLanguage.sourceCode,o.default.getLanguageForId(t).engineLanguage.targetCode,i).then(t=>{t.error?e.showError(t.message):(s.value=t.translations[0],e.hide())})},e=new r.default(this),this.addTranslateButton()};a.default={init:()=>{{var t=document.querySelectorAll(".InputfieldContent");t&&[...t].forEach(t=>{t.querySelector("input.translatable, textarea.translatable")&&new s(t)})}{var e=document.querySelector(".Inputfields");new i(e)}}}},{"../global/Fluency":2,"../global/FtConfig":3,"../ui/FtActivityOverlay":6,"../ui/FtUiElements":7}],6:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var l=(t=t("../global/FtConfig"))&&t.__esModule?t:{default:t};a.default=function(t){var a=this;let n=1{this.setActivityActive(),this.setOverlayVisible()},this.showMessage=function(t){var e=1{a.setOverlayInvisible()},t),setTimeout(()=>{a.setActivityInactive(),a.setMessageInactive(),a.setErrorInactive(),a.setFlashInactive(),a.setMessageContent("")},t+500)},this.setActivityActive=()=>{e.classList.add(i.activity)},this.setActivityInactive=()=>{e.classList.remove(i.activity)},this.setMessageActive=()=>{e.classList.add(i.message)},this.setMessageInactive=()=>{e.classList.remove(i.message)},this.setMessageContent=t=>{s.innerText=t},this.setFlashActive=t=>{e.classList.add(i.flash)},this.setFlashInactive=t=>{e.classList.remove(i.flash)},this.setSuccessActive=()=>{e.classList.add(i.success)},this.setSuccessInactive=()=>{e.classList.remove(i.success)},this.setErrorActive=()=>{e.classList.add(i.error)},this.setErrorInactive=()=>{e.classList.remove(i.error)},this.setOverlayVisible=()=>{e.classList.add(i.visible)},this.setOverlayInvisible=()=>{e.classList.remove(i.visible)},this.create=()=>(e=this.buildOverlayEl(),r=this.buildActivityEl(),s=this.buildMessageEl(),e.appendChild(r),e.appendChild(s),e),this.buildOverlayEl=()=>{var t=document.createElement("div");return t.setAttribute("class",i.overlay),t},this.buildActivityEl=()=>{var t=l.default.getUiTextFor("activityOverlay")[n];let e=document.createElement("div");e.setAttribute("class",i.activityAnimationContainer),e=t.animated.reduce((t,e)=>{var a=document.createElement("span");return a.setAttribute("class",i.activityAnimationItem),a.innerHTML=e,t.appendChild(a),t},e);var a=document.createElement("div");return a.setAttribute("class",i.activityStaticText),a.innerText=t.static,(r=document.createElement("div")).setAttribute("class",i.activityContainer),r.appendChild(a),r.appendChild(e),r},this.buildMessageEl=()=>((s=document.createElement("div")).setAttribute("class",i.messageContainer),s),t=t.getSelf(),e=this.create(),t.classList.add(i.parent),t.appendChild(e)}},{"../global/FtConfig":3}],7:[function(t,e,a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var s=n(t("../global/FtConfig"));n(t("../global/FtTools")),n(t("../global/Fluency"));function n(t){return t&&t.__esModule?t:{default:t}}t=function(){var t=s.default.elementClasses;const a=s.default.getUiTextFor("inputfieldTranslateButtons"),n=()=>{var t=document.createElement("a"),e=(t.setAttribute("href",ProcessWire.config.urls.admin+"fluency/?modal=1"),t.setAttribute("class","pw-modal pw-modal-large"),document.createElement("i"));return e.setAttribute("class",s.default.getElementClassesFor("icon")+" fa fa-language"),e.setAttribute("uk-tooltip",a.showTranslator),t.appendChild(e),t};return{createStatusElement:t=>{var e=s.default.getElementClassesFor("statusPlaceholder"),a=document.createElement("span"),t=(a.setAttribute("class",e.label),a.innerText=t,document.createElement("div"));return t.setAttribute("class",e.container),t.appendChild(n()),t.appendChild(a),t},createTranslateButton:t=>{var e=s.default.getElementClassesFor("translateButton"),a=document.createElement("a"),t=(a.innerText=t,a.setAttribute("class",e.button),a.setAttribute("href",""),document.createElement("div"));return t.setAttribute("class",e.container),t.appendChild(n()),t.appendChild(a),{button:a,container:t}},createTranslateAllButton:t=>{var e=s.default.getElementClassesFor("translateAllButton"),a=document.createElement("a"),n=(a.innerText=s.default.getUiTextFor("languageTranslator").translateAllButton,a.setAttribute("class",e.button),a.setAttribute("href",""),document.createElement("div")),i=(n.setAttribute("class",e.content),n.appendChild(a),document.createElement("li"));return i.setAttribute("class",e.container),i.appendChild(n),{button:a,container:i}},createIcon:n,elementClasses:t}}();a.default=t},{"../global/Fluency":2,"../global/FtConfig":3,"../global/FtTools":4}]},{},[1]); //# sourceMappingURL=maps/fluency_language_translator.bundle.js.map diff --git a/assets/scripts/maps/fluency.bundle.js.map b/assets/scripts/maps/fluency.bundle.js.map index 9fb1a15..102274b 100644 --- a/assets/scripts/maps/fluency.bundle.js.map +++ b/assets/scripts/maps/fluency.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"../fluency.bundle.js","sources":["fluency.bundle.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i {\n if (_FtConfig.default.moduleShouldInitialize()) {\n _FtAdminMenu.default.init();\n _FtInputfields.default.init();\n }\n});\n\n},{\"./global/FtConfig\":3,\"./inputfields/FtInputfields\":13,\"./ui/FtAdminMenu\":15}],2:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"./FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Core module interface\n * Handles all interaction with the ProcessWire module backend\n * @return {object} Public interfaces\n */\n\nconst Fluency = function () {\n /**\n * Localized error strings\n * @type {Object}\n */\n const errors = _FtConfig.default.getUiTextFor('errors');\n\n /**\n * Data Request Methods\n */\n\n /**\n * Gets a translation from the Fluency module\n * @param {String} sourceLanguage ISO language code\n * @param {String} targetLanguage ISO langauge code\n * @param {String|Array} content Content to translate\n * @param {Array} options Additional options\n * @param {Bool|null} caching Enable/disable caching\n * @return {Promise}\n */\n const getTranslation = function (sourceLanguage, targetLanguage, content) {\n let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];\n let caching = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;\n return postRequest(_FtConfig.default.getApiEndpointFor('translation'), {\n sourceLanguage: sourceLanguage,\n targetLanguage: targetLanguage,\n content: content,\n options: options,\n caching: caching\n }, response => {\n return response;\n });\n };\n\n /**\n * Gets the current translation service API usage\n * @return {Promise}\n */\n const getUsage = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('usage'), response => {\n return response;\n });\n };\n\n /**\n * Get all language available for translation. Provides source/target lists from the translation\n * service API\n * @return {Promise}\n */\n const getAvailableLanguages = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('languages'), response => {\n return response;\n });\n };\n\n /**\n * Clear all cached translations\n * @return {Promise}\n */\n const deleteTranslationCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translationCache'), response => {\n return response;\n });\n };\n\n /**\n * Clear cached list of translatable languages\n * @return {Promise}\n */\n const deleteTranslatableLanguagesCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translatableLanguagesCache'), response => {\n return response;\n });\n };\n\n /**\n * HTTP Requests\n */\n\n /**\n * Create headers for AJAX requests\n * @return {Object}\n */\n const requestHeaders = requestType => {\n const requestHeaders = {\n 'X-Requested-With': 'XMLHttpRequest'\n };\n if (requestType === 'GET') {\n requestHeaders['Accept'] = 'application/json';\n }\n if (requestType === 'POST') {\n requestHeaders['Content-Type'] = 'application/json';\n }\n return requestHeaders;\n };\n\n /**\n * Executes a POST request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Object} data Data for request\n * @param {Callable} data Function to handle response body\n * @return {Promise}\n */\n const postRequest = (endpoint, data, responseHandler) => {\n return fetch(endpoint, {\n method: 'POST',\n cache: 'no-store',\n headers: requestHeaders,\n body: JSON.stringify(data)\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a GET request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const getRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'GET',\n cache: 'no-store',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a DELETE request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const deleteRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'DELETE',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Parses response\n * @param {Object} response Fluency API response\n * @return {Object|Void}\n * @throws Error\n */\n const parseResponse = response => {\n if (response.status === 204) {\n return response;\n }\n if (response.ok) {\n return response.json();\n }\n throw new Error();\n };\n\n /**\n * Parses and returns results for a fetch error\n * These are network level errors that occur between ProcessWire and the hosting server\n * Any translation or service errors will be located within the response body itself\n * @param {Error} error Fetch API error object\n * @return {Object}\n */\n const handleFetchError = error => {\n console.error('[Fluency module API failure]', error.message);\n const returnObject = {\n error: null,\n message: null\n };\n switch (error.message.split(' ')[0]) {\n case 'NetworkError':\n returnObject.error = 'FLUENCY_CLIENT_DISCONNECTED';\n returnObject.message = errors['FLUENCY_CLIENT_DISCONNECTED'];\n break;\n default:\n returnObject.error = 'UNKNOWN_ERROR';\n returnObject.message = errors['UNKNOWN_ERROR'];\n break;\n }\n return returnObject;\n };\n return {\n deleteTranslatableLanguagesCache,\n deleteTranslationCache,\n getAvailableLanguages,\n getTranslation,\n getUsage\n };\n}();\nvar _default = Fluency;\nexports.default = _default;\n\n},{\"./FtConfig\":3}],3:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * This provides access methods to get module configuration values\n * @return {Object} Public methods\n */\nconst FtConfig = function () {\n // Public properties\n\n const fieldInitializedAttr = 'data-ft-initialized';\n\n // Private properties\n\n /**\n * Holds the data passed from the Fluency module\n * @access Private\n * @type {Object}\n */\n const config = ProcessWire.config.fluency;\n\n /**\n * All UI strings\n * @type {Object}\n */\n const localizedStrings = config.localization;\n\n /**\n * Objects interface with the Fluency config object so that changes to the object\n * structure from the back end do not break the UI. Use the public methods below\n * to access ProcessWire.config.fluency properties and data\n */\n\n /**\n * Localized strings keyed sets\n * @type {Object}\n */\n const strings = {\n activityOverlay: localizedStrings.activityOverlay,\n languageSelect: localizedStrings.languageSelect,\n inputfieldTranslateButtons: localizedStrings.inputfieldTranslateButtons,\n standaloneTranslator: localizedStrings.standaloneTranslator,\n usage: localizedStrings.usage,\n errors: localizedStrings.errors\n };\n\n /**\n * Fluency API keyed URLs\n * @type {Object}\n */\n const endpoints = {\n languages: config.apiEndpoints.languages,\n translatableLanguagesCache: config.apiEndpoints.translatableLanguagesCache,\n test: config.apiEndpoints.test,\n translation: config.apiEndpoints.translation,\n translationCache: config.apiEndpoints.translationCache,\n usage: config.apiEndpoints.usage\n };\n\n /**\n * Contains all of the Fluency configured langauges from the module\n * @type {Array}\n */\n const configuredLanguages = config.configuredLanguages;\n\n /**\n * Contains an array of ProcessWire language IDs not configured in Fluency\n * @type {Array}\n */\n const unconfiguredLanguages = config.unconfiguredLanguages;\n\n // Public methods\n\n /**\n * Fluency REST API\n */\n const getApiEndpointFor = key => endpoints[key];\n\n /**\n * Languages\n */\n\n const getConfiguredLanguages = () => configuredLanguages;\n const getDefaultLanguage = () => getConfiguredLanguages().reduce((defaultLang, lang) => lang.default ? lang : defaultLang, null);\n const languageIsTranslatable = languageId => !getUnconfiguredLanguages().includes(parseInt(languageId, 10));\n const getUnconfiguredLanguages = () => unconfiguredLanguages;\n const getLanguageCount = () => getConfiguredLanguages().length + getUnconfiguredLanguages().length;\n const getLanguageForId = pwLanguageId => {\n pwLanguageId = parseInt(pwLanguageId, 10);\n return getConfiguredLanguages().reduce((match, language) => language.id === pwLanguageId ? language : match, null);\n };\n\n /**\n * Localization\n */\n\n const getUiTextFor = key => strings[key];\n\n /**\n * Module Configuration/State\n */\n\n const moduleShouldInitialize = () => getConfiguredLanguages().length > 1;\n const getEngineInfo = () => config.engine;\n const getEngineProvidesUsageData = () => getEngineInfo().providesUsageData;\n const getTranslationAction = () => config.interface.inputfieldTranslationAction;\n\n /**\n * Translation types. No magic strings.\n */\n const translationActionTypes = {\n each: 'translate_each_language',\n all: 'translate_to_all_languages'\n };\n return {\n fieldInitializedAttr,\n getApiEndpointFor,\n getConfiguredLanguages,\n getDefaultLanguage,\n getEngineInfo,\n getEngineProvidesUsageData,\n getTranslationAction,\n getLanguageCount,\n getLanguageForId,\n getUiTextFor,\n getUnconfiguredLanguages,\n languageIsTranslatable,\n moduleShouldInitialize,\n translationActionTypes\n };\n}();\nvar _default = FtConfig;\nexports.default = _default;\n\n},{}],4:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * These are common tools the Fluency translation module uses\n * It is loaded first in order of scripts added to the page so that the module\n * is available to all subsequent scripts\n *\n * @return {Object} Public methods\n */\nconst FtTools = function () {\n /**\n * Create a random string of hex characters\n * @param {Number} length\n * @return {String}\n */\n const randomHex = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6;\n const chars = '0123456789ABCDEF'.split('');\n [...Array(length)].reduce((hex, i) => hex = chars[Math.floor(Math.random() * chars.length)], '');\n };\n\n /**\n * Generate random string of upper/lower/ints\n * @param length\n * @return string\n */\n const createRandomString = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5;\n return [...Array(length)].map(() => Math.random().toString(36)[2]).join('');\n };\n\n /**\n * Appends a div to a given element with a defined string, optionally adds a unique\n * string in case differentiating between more than one with the same text is\n * needed\n * @param {Element} element Element to tag\n * @param {String} text Text for tag\n * @param {Boolean} addRandomId Add random ID string to tag\n * @return {Void}\n */\n const tagElement = function (element, text) {\n let addRandomId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n const tagDiv = document.createElement('div');\n tagDiv.setAttribute('class', 'ft-element-tag');\n if (addRandomId) {\n text += ' | ' + createRandomString();\n }\n tagDiv.innerText = text;\n element.appendChild(tagDiv);\n };\n\n /**\n * Creates a random HTML hex code\n * @return {String} [description]\n */\n const randomHexColor = () => `#${randomHex()}`;\n\n /**\n * Gets the page ID from the current URL\n * @return {int|null} Page ID number, null if not present\n */\n var getPageId = function () {\n var urlParams = new URLSearchParams(window.location.search);\n return urlParams ? parseInt(urlParams.get('id')) : null;\n };\n\n /**\n * Checks page ID against page ID passed\n * @param {int} id ID to check against\n * @return {bool} True/false whether is current page ID\n */\n const pageIdIs = id => getPageId() === id;\n return {\n tagElement,\n getPageId,\n pageIdIs\n };\n}();\nvar _default = FtTools;\nexports.default = _default;\n\n},{}],5:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldCKEditor = exports.FtInputfieldCKEditor = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains a regular CKEditor instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldCKEditor = inputfield => !!inputfield.querySelector('.InputfieldCKEditorNormal');\n\n/**\n * Handles translations for CKEditor Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldCKEditor = FtIsInputfieldCKEditor;\nconst FtInputfieldCKEditor = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n *\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all CKEditor instances\n * @property {String} ProcessWire Language ID\n * @value {CKEditor|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the base CKEditor instance ID that can be used to get the default CKEditor instance\n * using the CKEditor API, or another instance by modifying this one.\n * Set on FtInputfieldCKEditor instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /**\n * Gets existing or instantiates a new activity overlay\n *\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getEditorInstanceForLanguage(languageId).getData();\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const instance = this.getEditorInstanceForLanguage(languageId);\n instance.setData(value);\n instance.fire('change');\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the CKEditor instance for a given language ID. This method should\n * be used exclusively to get instances as it also sets event listeners for content\n * changes if they have been instantiated after FtInputfieldCKEditor has loaded\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?CKEditor}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const ckeditorSelector = this.createCKEditorSelector(languageId);\n editorInstances[languageId] = CKEDITOR.instances[ckeditorSelector];\n return editorInstances[languageId];\n };\n\n /**\n * Creates a CKEditor ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createCKEditorSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Registers the event listener that watches for content changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {void}\n */\n this.registerInputEventListener = languageId => {\n this.getEditorInstanceForLanguage(languageId).on('change', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init on object instantiation\n * @access private\n * @return {Void}\n */\n (() => {\n if (CKEDITOR === undefined) {\n console.error('CKEditor was not found by Fluency, translation unavailable');\n return;\n }\n const allInputContainers = this.getInputContainers();\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n editorInstances[languageId] = this.getEditorInstanceForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldCKEditor = FtInputfieldCKEditor;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],6:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldCKEditorInline = exports.FtInputfieldCKEditorInline = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains an inline CKEditor instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldCKEditorInline = inputfield => !!inputfield.querySelector('.InputfieldCKEditorInline');\n\n/**\n * Handles translations for CKEditor Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldCKEditorInline = FtIsInputfieldCKEditorInline;\nconst FtInputfieldCKEditorInline = function (inputfield) {\n /**\n * Contains values for all fields/languages\n * Populated on FtInputfieldCKEditorInline instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all CKEditor instances\n * @property {String} ProcessWire Language ID\n * @value {CKEditor|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain all elements that the inline editor uses for content\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const contentElements = {};\n\n /**\n * Will contain the base CKEditor instance ID that can be used to get the default CKEditor instance\n * using the CKEditor API, or another instance by modifying this one.\n * Set on FtInputfieldCKEditor instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /**\n * Gets existing or instantiates a new activity overlay\n *\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * Attempts to get the value for a language via the CKEditor API, falls back to directly getting\n * the content of the content element\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const ckeditorInstance = this.getEditorInstanceForLanguage(languageId);\n if (ckeditorInstance) {\n return ckeditorInstance.getData();\n }\n return this.getContentElementForLanguage(languageId).innerHTML;\n };\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const instance = this.getEditorInstanceForLanguage(languageId);\n const contentElement = this.getContentElementForLanguage(languageId);\n instance ? instance.setValue(value) : contentElement.innerHTML = value;\n contentElement.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the CKEditor instance for a given language ID. This method should\n * be used exclusively to get instances as it also sets event listeners for content\n * changes if they have been instantiated after FtInputfieldCKEditor has loaded\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?CKEditor}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n editorInstances[languageId] = CKEDITOR.instances[this.createCKEditorSelector(languageId)];\n return editorInstances[languageId];\n };\n\n /**\n * Gets the content element that CKEditor uses to store the field content\n * Ensures memoization\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getContentElementForLanguage = languageId => {\n if (Object.hasOwn(contentElements, languageId)) {\n return contentElements[languageId];\n }\n contentElements[languageId] = this.getInputContainerForLanguage(languageId).querySelector('.InputfieldCKEditorInlineEditor');\n return contentElements[languageId];\n };\n\n /**\n * Creates a CKEditor ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createCKEditorSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n if (Object.keys(inputContainers).length === _FtConfig.default.getLanguageCount()) {\n return inputContainers;\n }\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId)) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a MutationObserver that will detect when the content has changed for a given content\n * element. When content is changed, is will mock an 'input' even that an eventListener will\n * respond to\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerUpdateEvent = languageId => {\n const contentElement = this.getContentElementForLanguage(languageId);\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n mutation.target.dispatchEvent(new Event('input'));\n }\n }).observe(contentElement, {\n childList: true\n });\n };\n\n /**\n * Registers an event listener that will respond to any 'input' changes in a\n * content element\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getContentElementForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init on object instantiation\n * @access private\n * @return {Void}\n */\n (() => {\n if (CKEDITOR === undefined) {\n console.error('CKEditor was not found by Fluency, translation unavailable');\n return null;\n }\n const allInputContainers = this.getInputContainers();\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n editorInstances[languageId] = this.getEditorInstanceForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldCKEditorInline = FtInputfieldCKEditorInline;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],7:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Handles IO operations for a multilanguage InputfieldPageName element\n * The InputfieldPageName element has special considerations compared to other fields as they do not\n * have the same markup structure.\n * Some actions are internalized here, such as\n * @param {Element} inputfield The Inputfield .InputfieldPageName container\n */\nconst FtInputfieldPageName = function (inputfield) {\n /**\n * Page-load values for all fields/languages\n * Populated on object instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when content is modified\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * FtLanguageTab objects for each language\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all elements containing language inputs\n * @property {String} ProcessWire Language ID\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Text input fields\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageFields = {};\n let contentModifiedClass = new _FtLanguageTab.default().getContentModifiedClass();\n\n /**\n * Activity overlays by language IDs\n * @access public\n * @type {Object}\n */\n let activityOverlays = {};\n\n /*\n * Return null to signal that the overlay should be by language ID\n *\n * @access public\n * @return {Object|Null}\n */\n this.getActivityOverlay = languageId => {\n if (!languageId) {\n return null;\n }\n return activityOverlays[languageId].getActivityOverlay();\n };\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) {\n return languageFields[languageId];\n }\n languageFields[languageId] = this.getInputContainerForLanguage(languageId).querySelector('input');\n return languageFields[languageId];\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (!Object.hasOwn(inputContainers, languageId) && !inputContainers[languageId]) {\n this.getInputContainers();\n }\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n // Page name fields require querying the child input and determining the language by analyzing\n // the name attribute of the text input itself\n this.getSelf().querySelectorAll('.LanguageSupport').forEach(el => {\n // The default language input has no language ID, it's the default language, so fallback\n const languageId = el.querySelector('input[type=text]').name.replace('_pw_page_name', '') || _FtConfig.default.getDefaultLanguage().id;\n inputContainers[languageId] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n this.setModifiedState = (languageId, contentHasChanged) => {\n const inputContainer = this.getInputContainerForLanguage(languageId);\n if (contentHasChanged) {\n inputContainer.classList.add(contentModifiedClass);\n }\n if (!contentHasChanged) {\n inputContainer.classList.remove(contentModifiedClass);\n }\n };\n\n /**\n * Registers the event listener that watches for changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getFieldForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n this.setModifiedState(languageId, this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n activityOverlays[languageId] = new createActivityOverlay(inputContainer);\n this.registerInputEventListener(languageId);\n }\n new _FtInputfieldTranslateButton.default(this, allInputContainers, true);\n })();\n};\nconst createActivityOverlay = function (languageInput) {\n let activityOverlay;\n this.getSelf = () => languageInput;\n this.getActivityOverlay = () => activityOverlay;\n (() => {\n activityOverlay = new _FtActivityOverlay.default(this);\n })();\n};\nvar _default = FtInputfieldPageName;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],8:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTable = void 0;\n/**\n * Determines if a given inputfield contains a Table instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTable = inputfield => isInputfieldTable(inputfield) || isInputfieldTableRow(inputfield);\n\n/**\n * Handles table inputfields on load\n * @param {Element} inputfield\n * @return {Bool}\n */\nexports.FtIsInputfieldTable = FtIsInputfieldTable;\nconst isInputfieldTable = inputfield => !!inputfield.classList.contains('InputfieldTable');\nconst isInputfieldTableRow = inputfield => !!inputfield.tagName === 'TBODY' && inputfield.querySelectorAll('.InputfieldTable_hasLangTabs').length;\n\n},{}],9:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldText = exports.FtInputfieldText = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if the current inputfield is an InputfieldText\n * @param {Element} inputfield Element containing the multilanguage fields\n * @return {Bool}\n */\nconst FtIsInputfieldText = inputfield => !!inputfield.querySelector(\"input[type='text']\");\n\n/**\n * Handles IO operations for a multilanguage InputfieldText element\n * Language IDs are always converted to int to accept values from all sources since some may be\n * retrieved from various sources as a string\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldText = FtIsInputfieldText;\nconst FtInputfieldText = function (inputfield) {\n /**\n * Page-load values for all fields/languages\n * Populated on object instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when content is modified\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * FtLanguageTab objects for each language\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all elements containing language inputs\n * @property {String} ProcessWire Language ID\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Text input fields\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageFields = {};\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) {\n return languageFields[languageId];\n }\n languageFields[languageId] = this.getInputContainerForLanguage(languageId).querySelector('input');\n return languageFields[languageId];\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n inputfield.querySelectorAll('[data-language]').forEach(el => inputContainers[el.dataset.language] = el);\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Registers the event listener that watches for changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getFieldForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldText = FtInputfieldText;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],10:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTextarea = exports.FtInputfieldTextarea = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if the current inputfield is an InputfieldText\n * @param {Element} inputfield Element containing the multilanguage fields\n * @return {Bool}\n */\nconst FtIsInputfieldTextarea = inputfield => !!inputfield.querySelector('textarea:not(.InputfieldCKEditorNormal,.InputfieldTinyMCEEditor)');\n\n/**\n * Handles IO operations for a multilanguage InputfieldText element\n * Language IDs are always converted to int to accept values from all sources since some may be\n * retrieved from various sources as a string\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldTextarea = FtIsInputfieldTextarea;\nconst FtInputfieldTextarea = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * Language ID keys are integers\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * Language ID keys are integers\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Will contain all language input text fields keyed by language ID\n * @type {Object}\n */\n const languageFields = {};\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId)) {\n return languageFields[languageId];\n }\n languageFields[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"] textarea`);\n return languageFields[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n inputfield.querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n inputContainer.querySelector('textarea').addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTextarea = FtInputfieldTextarea;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],11:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTinyMCE = exports.FtInputfieldTinyMCE = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains a regular TinyMCE instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTinyMCE = inputfield => !!inputfield.querySelector('.InputfieldTinyMCENormal');\n\n/**\n * Handles IO operations for a multilanguage InputfieldTinyMCE elements\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldTinyMCE = FtIsInputfieldTinyMCE;\nconst FtInputfieldTinyMCE = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n *\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all language input textarea fields that hold Inputfield data before TinyMCE\n * instances are initialized.\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const textareas = {};\n\n /**\n * Will contain all TinyMCE instances as they become available (are initialized). Most TinyMCE\n * instances are lazy loaded or loaded on demand. Keyed by language ID\n * This is populated on FtInputfieldTinyMCE on instantiation and language ID properties will either\n * have a TinyMCE object or null\n * @property {String} ProcessWire Language ID\n * @value {TinyMCE|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the base TinyMCE instance ID that can be used to get the default TinyMCE instance\n * using the TinyMCE API, or another instance by modifying this one.\n * Set on FtInputfieldTinyMCE instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const tinymceInstance = this.getTinymceInstanceForLanguage(languageId);\n if (tinymceInstance) {\n return tinymceInstance.getContent();\n }\n return this.getTextareaForLanguage(languageId).value;\n };\n\n /**\n * Sets content for a language, will set the value for TinyMCE if it exists, and always set the\n * value for the textarea\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const tinymceInstance = this.getTinymceInstanceForLanguage(languageId);\n if (tinymceInstance) {\n tinymceInstance.setContent(value);\n tinymceInstance.fire('input');\n }\n const field = this.getTextareaForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the TinyMCE instance for a given language ID if it exists\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?TinyMCE}\n */\n this.getTinymceInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const tinymceSelector = this.createTinymceSelector(languageId);\n editorInstances[languageId] = tinymce.get(tinymceSelector);\n return editorInstances[languageId];\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getTextareaForLanguage = languageId => {\n if (Object.hasOwn(textareas, languageId) && !!textareas[languageId]) {\n return textareas[languageId];\n }\n textareas[languageId] = this.getSelf().querySelector(`[data-language=\"${languageId}\"] textarea`);\n return textareas[languageId];\n };\n\n /**\n * Get all input containers holding TinyMCE instances, memoizes. Keyed by ID\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a TinyMCE ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createTinymceSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Bind Inputfield required events to a TinyMCE instance\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Object} tinymceInstance TinyMCE object\n * @return {Void}\n */\n this.bindTinymceEvents = (languageId, tinymceInstance) => {\n tinymceInstance.on('keyup', e => this.getTextareaForLanguage(languageId).dispatchEvent(new Event('input')));\n };\n\n /**\n * Creates an observer that looks for new TinyMCE instances within this Inputfield\n * @access private\n * @return {void}\n */\n this.initTinymceInstanceOnCreation = (languageId, inputContainer) => {\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n let targetEl = mutation.target;\n if (targetEl.dataset.language == languageId) {\n editorInstances[languageId] = this.getTinymceInstanceForLanguage(languageId);\n this.bindTinymceEvents(languageId, editorInstances[languageId]);\n if (editorInstances[languageId]) {\n observer.disconnect();\n }\n }\n }\n }).observe(inputContainer, {\n childList: true\n });\n };\n\n /**\n * Registers the event listener that watches for content changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {void}\n */\n this.registerInputEventListener = languageId => {\n textareas[languageId].addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Initializes FtInputfieldTinyMCE Inputfield\n * @access private\n * @param {Array} allInputContainers All elements containing TinyMCE fields\n * @return {Void}\n */\n this.initAll = allInputContainers => {\n // TinyMCE instances are initialzied using a field ID. The default language element contains\n // an ID substring that can be modified to create a TinyMCE ID string that can be used to get\n // TinyMCE instances\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n\n // At runtime/initialization only the TinyMCE instance will load for the default language, others\n // will be loaded when switched to the tab. Still attempt to get all TinyMCE instances for all\n // tabs in case they are available\n for (let languageId in allInputContainers) {\n const inputContainer = allInputContainers[languageId];\n\n // Get initial content on page load\n // Call this first to ensure getValueForLanguage() pulls from the textarea element rather than\n // attempting to use the TinyMCE API on object instantiation\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n editorInstances[languageId] = this.getTinymceInstanceForLanguage(languageId);\n textareas[languageId] = this.getTextareaForLanguage(languageId);\n this.registerInputEventListener(languageId);\n\n // If there was no editor found at initialization, register when created\n if (!editorInstances[languageId]) {\n this.initTinymceInstanceOnCreation(languageId, inputContainer);\n }\n }\n\n // Bind TinyMCE event listeners to any TinyMCE input fields found on initialization\n for (let languageId in editorInstances) {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n this.bindTinymceEvents(languageId, editorInstances[languageId]);\n }\n }\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n\n // Set a micro timeout to allow TinyMCE instances to instantiate.\n // This is especially important when new fields are dynamically added after page load\n setTimeout(() => {\n this.initAll(allInputContainers);\n }, 50);\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTinyMCE = FtInputfieldTinyMCE;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],12:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTinyMCEInline = exports.FtInputfieldTinyMCEInline = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains an inline TinyMCE instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTinyMCEInline = inputfield => !!inputfield.querySelector('.InputfieldTinyMCEInline');\n\n/**\n * Handles translations for TinyMCE Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldTinyMCEInline = FtIsInputfieldTinyMCEInline;\nconst FtInputfieldTinyMCEInline = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * Language ID keys are integers\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * Language ID keys are integers\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Will contain all the HTML elements that the inline TinyMCE editor stores/modifies content\n * keyed by language ID\n * @type {Object}\n */\n const contentElements = {};\n\n /**\n * Will contain all TinyMCE instances as they become available\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the TinyMCE instance name for the default language.\n * Used to get the TinyMCE instance\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const tinymceInstance = this.getEditorInstanceForLanguage(languageId);\n if (tinymceInstance) {\n return tinymceInstance.getContent();\n }\n return this.getContentElementForLanguage(languageId).innerHTML;\n };\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const contentElement = this.getContentElementForLanguage(languageId);\n contentElement.innerHTML = value;\n\n // Required to programmatically trigger the event listener for this field\n contentElement.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the TinyMCE instance for a given language ID if it exists\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?TinyMCE}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const tinymceSelector = this.createTinymceSelector(languageId);\n editorInstances[languageId] = tinymce.get(tinymceSelector);\n return editorInstances[languageId];\n };\n\n /**\n * Gets the content element that TinyMCE uses to store the field content\n * Ensures memoization\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getContentElementForLanguage = languageId => {\n if (Object.hasOwn(contentElements, languageId)) {\n return contentElements[languageId];\n }\n contentElements[languageId] = this.getInputContainerForLanguage(languageId).querySelector('.mce-content-body');\n return contentElements[languageId];\n };\n\n /**\n * Gets a specific input container. Memoizes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = this.getSelf().querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * This determines if the content for a given langauge has changed. In some instancesTinyMCE\n * inserts unwanted elements into empty fields that will always register content as having been\n * changed. This includes adding elements to fields that may be returned to their original content\n * matching content at page load. These \"phantom elements\" must me checked for.\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a TinyMCE ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createTinymceSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Creates a MutationObserver that will detect when the innerHTML content has changed for a given\n * content element. When content is changed, it will mock an 'input' event that an eventListener\n * can respond to\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerUpdateEvent = languageId => {\n const contentElement = this.getContentElementForLanguage(languageId);\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n mutation.target.dispatchEvent(new Event('input'));\n }\n }).observe(contentElement, {\n childList: true\n });\n };\n\n /**\n * Register an input observer\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getContentElementForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n if (tinymce === undefined) {\n console.error('TinyMCE was not found by Fluency, translation unavailable');\n return null;\n }\n const allInputContainers = this.getInputContainers();\n\n // TinyMCE instances are initialzied using a field ID. The default language element contains\n // an ID substring that can be modified to create a TinyMCE ID string that can be used to get\n // TinyMCE instances\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerUpdateEvent(languageId);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTinyMCEInline = FtInputfieldTinyMCEInline;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],13:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _FtInputfieldCKEditor = require(\"./FtInputfieldCKEditor\");\nvar _FtInputfieldCKEditorInline = require(\"./FtInputfieldCKEditorInline\");\nvar _FtInputfieldTable = require(\"./FtInputfieldTable\");\nvar _FtInputfieldText = require(\"./FtInputfieldText\");\nvar _FtInputfieldTextarea = require(\"./FtInputfieldTextarea\");\nvar _FtInputfieldTinyMCE = require(\"./FtInputfieldTinyMCE\");\nvar _FtInputfieldTinyMCEInline = require(\"./FtInputfieldTinyMCEInline\");\nvar _FtInputfieldPageName = _interopRequireDefault(require(\"./FtInputfieldPageName\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Orchestration for initializing all multilanguage inputfields on a page\n * @return {Object} Public interface methods\n */\nconst FtInputfields = function () {\n /**\n * Selector used to find translatable Inputfields\n * All inputfield containers on the page that are multilanguage have this class\n * @type {String}\n */\n const langInputfieldClass = \"[class*='hasLangTabs']\";\n // const langInputfieldClass = '.hasLangTabs';\n\n /**\n * Initializes multilanguage fields if present on page\n * @return {void}\n */\n const init = function () {\n const langInputfieldContainers = document.querySelectorAll(langInputfieldClass);\n\n // Only init if there are multi-language Inputfields on the page\n if (langInputfieldContainers.length) {\n initInputfields(langInputfieldContainers);\n initInputfieldsOnInsertion();\n initPageNameInputfields();\n }\n };\n\n /**\n * Initializes multiple multilanguage fields in a collection of elelents\n * @param {NodeList} langInputfieldContainers\n * @return {Void}\n */\n const initInputfields = langInputfieldContainers => {\n for (let langInputfieldContainer of langInputfieldContainers) {\n initInputfield(langInputfieldContainer);\n }\n };\n\n /**\n * Initializes the field within a container\n * @param {Element} langInputfieldContainer Element containing inputfield\n * @return {void}\n */\n const initInputfield = langInputfieldContainer => {\n // Do not initialize fields that have already been initialized\n // Do not initialized fields that are a list element and not an Inputfield themselves\n if (!fieldIsInitialized(langInputfieldContainer) && !langInputfieldContainer.classList.contains('InputfieldItemList') && !isInputfieldTemplate(langInputfieldContainer)) {\n let inputfield = getFtInputfieldObject(langInputfieldContainer);\n setFieldIsInitialized(langInputfieldContainer);\n if (!inputfield) {\n return;\n }\n }\n };\n\n /**\n * Detect if Inputfield container is a hidden template element used to dynamically create new\n * Inputfields on demand\n * @param {Element} langInputfieldContainer\n * @return {Bool}\n */\n const isInputfieldTemplate = langInputfieldContainer => !!langInputfieldContainer.closest(\"[class*='Template']\");\n\n /**\n * Initializes a FtInputfield object instance by type\n * Order of checks is important Complex fields should be cased higher\n * Fields with lower complexity should be cased last to prevent catching simple elements in\n * complex fields that use simple inputs\n * @param {Element} langInputfieldContainers\n * @return {?Object}\n */\n const getFtInputfieldObject = langInputfieldContainer => {\n switch (true) {\n case (0, _FtInputfieldTable.FtIsInputfieldTable)(langInputfieldContainer):\n // Initialize all new fields which have a different class than top-level fields\n initInputfields(langInputfieldContainer.querySelectorAll('.langTabs'));\n break;\n case (0, _FtInputfieldCKEditor.FtIsInputfieldCKEditor)(langInputfieldContainer):\n return new _FtInputfieldCKEditor.FtInputfieldCKEditor(langInputfieldContainer);\n case (0, _FtInputfieldCKEditorInline.FtIsInputfieldCKEditorInline)(langInputfieldContainer):\n return new _FtInputfieldCKEditorInline.FtInputfieldCKEditorInline(langInputfieldContainer);\n case (0, _FtInputfieldTinyMCE.FtIsInputfieldTinyMCE)(langInputfieldContainer):\n return new _FtInputfieldTinyMCE.FtInputfieldTinyMCE(langInputfieldContainer);\n case (0, _FtInputfieldTinyMCEInline.FtIsInputfieldTinyMCEInline)(langInputfieldContainer):\n return new _FtInputfieldTinyMCEInline.FtInputfieldTinyMCEInline(langInputfieldContainer);\n case (0, _FtInputfieldTextarea.FtIsInputfieldTextarea)(langInputfieldContainer):\n return new _FtInputfieldTextarea.FtInputfieldTextarea(langInputfieldContainer);\n case (0, _FtInputfieldText.FtIsInputfieldText)(langInputfieldContainer):\n return new _FtInputfieldText.FtInputfieldText(langInputfieldContainer);\n default:\n console.warn('Fluency does not recognize this inputfield, translation is not available', langInputfieldContainer);\n return null;\n }\n };\n\n /**\n * This sets a mutation observer on the main content area of the edit page that will initialize\n * new fields that may be added on focus or triggered by AJAX actions\n *\n * @return {void}\n */\n const initInputfieldsOnInsertion = () => {\n const parentNode = document.getElementById('pw-content-body');\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n let targetEl = mutation.target;\n const foundEls = targetEl.querySelectorAll(langInputfieldClass);\n if (foundEls.length) {\n initInputfields(foundEls);\n }\n }\n }).observe(parentNode, {\n childList: true,\n subtree: true\n });\n };\n\n /**\n * Initializes page name fields. Must be initialized separately since they do not\n * follow the structure of other inputfields\n * @return {void}\n */\n const initPageNameInputfields = () => {\n const pageNameInputfields = document.querySelectorAll('.InputfieldPageName');\n [...pageNameInputfields].forEach(pageNameInputfield => {\n if (pageNameInputfield && !fieldIsInitialized(pageNameInputfield)) {\n let inputfield = new _FtInputfieldPageName.default(pageNameInputfield);\n setFieldIsInitialized(pageNameInputfield);\n if (!inputfield) {\n return;\n }\n }\n });\n };\n\n /**\n * Checks if a given field has been initialized\n * @param {DOMNode} langInputfieldContainer Container element for multi-language field\n * @return {bool}\n */\n const fieldIsInitialized = langTabContainer => langTabContainer.hasAttribute(_FtConfig.default.fieldInitializedAttr) || !!langTabContainer.querySelector('.ft-translate-button');\n\n /**\n * Marks a field as initialized by adding a data attribute to the container\n * @param {DOMNode} langTabContainer Container element for multi-language field\n * @return {void}\n */\n const setFieldIsInitialized = langTabContainer => langTabContainer.setAttribute(_FtConfig.default.fieldInitializedAttr, '');\n\n /**\n * This updates the value of an input element such as text or textarea\n * When a field is updated it must be blurred so that it is recognized as having been changed and\n * the \"unsaved changes\" alert will be shown if navigating away from a page without saving\n * @param {HTMLElement} inputEl Element\n * @param {string} value\n * @return {void}\n */\n const updateValue = (inputEl, value) => {\n inputEl.focus();\n inputEl.value = value;\n inputEl.blur();\n };\n return {\n init,\n updateValue,\n fieldIsInitialized\n };\n}();\nvar _default = FtInputfields;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3,\"../global/FtTools\":4,\"./FtInputfieldCKEditor\":5,\"./FtInputfieldCKEditorInline\":6,\"./FtInputfieldPageName\":7,\"./FtInputfieldTable\":8,\"./FtInputfieldText\":9,\"./FtInputfieldTextarea\":10,\"./FtInputfieldTinyMCE\":11,\"./FtInputfieldTinyMCEInline\":12}],14:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates, inserts, and controls the actions the activity overlay for the provided\n * targetContainer\n * @param {object} targetContainer An instantiated object for an inputfield or fieldset\n * @param {string} type The type of activity for this overlay. 'translate' or 'update'\n */\nconst FtActivityOverlay = function (targetContainer) {\n var _this = this;\n let activityType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'translating';\n const elClasses = {\n parent: 'ft-activity-overlay-container',\n overlay: 'ft-activity-overlay',\n error: 'error',\n message: 'message',\n flash: 'flash',\n success: 'success',\n activity: 'activity',\n visible: 'visible',\n activityContainer: 'ft-activity',\n activityStaticText: 'ft-activity-text',\n activityAnimationContainer: 'ft-activity-animation-container',\n activityAnimationItem: 'ft-activity-animation-item',\n messageContainer: 'ft-activity-message'\n };\n\n /**\n * Will contain the activityOverlay Element for this targetContainer\n * @type {Element}\n */\n let activityOverlay;\n\n /**\n * Will contain the message Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let messageContainer;\n\n /**\n * Will contain the animation container Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let activityContainer;\n\n /**\n * Control Methods\n */\n\n /**\n * This shows the overlay's activity animation that was created at instantiation\n * Must be manually hidden with the hide() method\n *\n * @return {void}\n */\n this.showActivity = () => {\n this.setActivityActive();\n this.setOverlayVisible();\n };\n\n /**\n * Shows a message in the overlay (neutral background)\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showMessage = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;\n _this.setMessageContent(message);\n _this.setActivityInactive();\n _this.setMessageActive();\n _this.setOverlayVisible();\n _this.hide(displayTime);\n };\n\n /**\n * Shows a success message (success color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashSuccess = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setSuccessActive();\n _this.setFlashActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows a success message (error color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setFlashActive();\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows an error message in a visible overlay (error background)\n *\n * @param {String} message Message to show in overlay error\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 7000;\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Hide an overlay immediately or after a preset amount of time\n *\n * @param {Number} delay Length of time in ms before hiding overlay\n */\n this.hide = function () {\n let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n setTimeout(() => {\n _this.setOverlayInvisible();\n }, delay);\n\n // Ensures the animation is finished before modifying content\n setTimeout(() => {\n _this.setActivityInactive();\n _this.setMessageInactive();\n _this.setErrorInactive();\n _this.setFlashInactive();\n _this.setMessageContent('');\n }, delay + 500);\n };\n\n /**\n * Private Methods\n */\n\n /**\n * Shows the activity element\n *\n * @access Private\n */\n this.setActivityActive = () => {\n activityOverlay.classList.add(elClasses.activity);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setActivityInactive = () => {\n activityOverlay.classList.remove(elClasses.activity);\n };\n\n /**\n * Shows the message element\n *\n * @access Private\n */\n this.setMessageActive = () => {\n activityOverlay.classList.add(elClasses.message);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setMessageInactive = () => {\n activityOverlay.classList.remove(elClasses.message);\n };\n\n /**\n * Sets the content of the overlay message\n *\n * @access Private\n */\n this.setMessageContent = content => {\n messageContainer.innerText = content;\n };\n\n /**\n * Adds flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashActive = content => {\n activityOverlay.classList.add(elClasses.flash);\n };\n\n /**\n * removes flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashInactive = content => {\n activityOverlay.classList.remove(elClasses.flash);\n };\n\n /**\n * Sets message to success\n *\n * @access Private\n */\n this.setSuccessActive = () => {\n activityOverlay.classList.add(elClasses.success);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setSuccessInactive = () => {\n activityOverlay.classList.remove(elClasses.success);\n };\n\n /**\n * Sets message to error\n *\n * @access Private\n */\n this.setErrorActive = () => {\n activityOverlay.classList.add(elClasses.error);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setErrorInactive = () => {\n activityOverlay.classList.remove(elClasses.error);\n };\n\n /**\n * Shows this activity overlay\n *\n * @access Private\n */\n this.setOverlayVisible = () => {\n activityOverlay.classList.add(elClasses.visible);\n };\n this.setOverlayInvisible = () => {\n activityOverlay.classList.remove(elClasses.visible);\n };\n\n /**\n * Creates and returns an activity overlay element\n *\n * @return {HTMLElement}\n */\n this.create = () => {\n activityOverlay = this.buildOverlayEl();\n activityContainer = this.buildActivityEl();\n messageContainer = this.buildMessageEl();\n activityOverlay.appendChild(activityContainer);\n activityOverlay.appendChild(messageContainer);\n return activityOverlay;\n };\n\n /**\n * Creates the parent overlay element\n *\n * @return {Element}\n * @access Private\n */\n this.buildOverlayEl = () => {\n const overlay = document.createElement('div');\n\n // overlay.setAttribute('data-gradient-1', 'rgba(62, 185, 152, .85)');\n overlay.setAttribute('class', elClasses.overlay);\n return overlay;\n };\n\n /**\n * Creates container for animation and contents of animation\n *\n * @return {Element}\n * @access Private\n */\n this.buildActivityEl = () => {\n let text = _FtConfig.default.getUiTextFor('activityOverlay')[activityType];\n let activityAnimationContainer = document.createElement('div');\n activityAnimationContainer.setAttribute('class', elClasses.activityAnimationContainer);\n\n // Add all animation items to the animation container\n activityAnimationContainer = text.animated.reduce((el, string) => {\n let activityText = document.createElement('span');\n\n // Add text items\n activityText.setAttribute('class', elClasses.activityAnimationItem);\n activityText.innerHTML = string;\n el.appendChild(activityText);\n return el;\n }, activityAnimationContainer);\n\n // Create static text element\n let staticText = document.createElement('div');\n staticText.setAttribute('class', elClasses.activityStaticText);\n staticText.innerText = text.static;\n\n // Create activity container and append children\n activityContainer = document.createElement('div');\n activityContainer.setAttribute('class', elClasses.activityContainer);\n activityContainer.appendChild(staticText);\n activityContainer.appendChild(activityAnimationContainer);\n return activityContainer;\n };\n\n /**\n * Builds the element that will hold messages in the overlay\n *\n * @return {Element}\n * @access Private\n */\n this.buildMessageEl = () => {\n messageContainer = document.createElement('div');\n messageContainer.setAttribute('class', elClasses.messageContainer);\n return messageContainer;\n };\n (() => {\n const targetContainerContainer = targetContainer.getSelf();\n activityOverlay = this.create();\n targetContainerContainer.classList.add(elClasses.parent);\n targetContainerContainer.appendChild(activityOverlay);\n })();\n};\nvar _default = FtActivityOverlay;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3}],15:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * Handles modifying the Fluency menu item\n * @return {object} Public methods\n */\nconst FtAdminMenu = function () {\n /**\n * Initializes module\n * @return {void}\n */\n const init = () => {\n convertFtAdminMenuToModal();\n };\n\n /**\n * Finds and converts the Translation admin menu item to open in a modal\n * rather than navigating to the page.\n * @return {void}\n */\n const convertFtAdminMenuToModal = () => {\n const adminNavItems = document.querySelectorAll('.pw-masthead .pw-primary-nav > li > a'),\n urlParams = new URLSearchParams(window.location.search);\n\n // We don't want to modify this menu item if we are on the Fluency config page\n // because the modal behavior is not available\n if (urlParams.get('name') === 'Fluency') {\n return false;\n }\n adminNavItems.forEach((el, i) => {\n let hrefSegments = el.href.split('/').filter(Boolean);\n if (hrefSegments[hrefSegments.length - 1].includes('fluency')) {\n el.href = el.href + '?modal=1';\n el.classList.add('pw-modal-large');\n el.classList.add('pw-modal');\n }\n });\n };\n return {\n init: init\n };\n}();\nvar _default = FtAdminMenu;\nexports.default = _default;\n\n},{}],16:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nvar _FtUiElements = _interopRequireDefault(require(\"./FtUiElements\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * The translate button establishes the UI element used to trigger translations\n * by the user. It manages the translation process by displaying/hiding the\n * activity overlay, showing messages and errors, getting translations from\n * the Fluency API, and modifying content. This is done by manipulating the\n * inputfield and activityOverlay objects passed.\n */\n\nconst FtInputfieldTranslateButton = function (inputfield, inputContainers) {\n let forceEachTranslationAction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n /**\n * Gets all localized strings from the FluencyConfig object\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Adds translate elements to inputfield containers\n * @param {string|int} languageId ProcessWire language ID\n * @param {Element} inputContainer Inputcontainer for this language\n * @return {void}\n */\n this.addTranslateElements = (languageId, inputContainer) => {\n const isTranslatable = _FtConfig.default.languageIsTranslatable(languageId);\n const isDefaultLanguage = languageId == _FtConfig.default.getDefaultLanguage().id;\n\n // Translatable, not default language\n if (isTranslatable && !isDefaultLanguage) {\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translateButton);\n this.bindButton(button, _FtConfig.default.getLanguageForId(languageId));\n inputContainer.appendChild(container);\n }\n\n // Translatable, default language\n if (isTranslatable && isDefaultLanguage) {\n inputContainer.appendChild(_FtUiElements.default.createStatusElement(uiText.translationAvailable));\n }\n\n // Not translatable\n if (!isTranslatable) {\n inputContainer.appendChild(_FtUiElements.default.createStatusElement(uiText.languageNotAvailable));\n }\n };\n\n /**\n * Binds a button for translation\n * @param {Element} buttonElement Element to bind translation action to\n * @param {Object} languageConfig Fluency language configuration object\n * @return {Void}\n */\n this.bindButton = (buttonElement, languageConfig) => {\n buttonElement.addEventListener('click', e => {\n e.preventDefault();\n const translationSourceContent = inputfield.getValueForDefaultLanguage();\n if (!translationSourceContent) {\n return;\n }\n\n // Try to get the inputfield activity overlay, fall back to retrieving by language ID where\n // the inputfield element can delegate to a specific activity overlay located within it\n const activityOverlay = inputfield.getActivityOverlay() ?? inputfield.getActivityOverlay(languageConfig.id);\n activityOverlay.showActivity();\n _Fluency.default.getTranslation(_FtConfig.default.getDefaultLanguage().engineLanguage.sourceCode, languageConfig.engineLanguage.targetCode, translationSourceContent).then(result => {\n if (result.error) {\n inputfield.getActivityOverlay().showError(result.message);\n return;\n }\n inputfield.setValueForLanguage(languageConfig.id, result.translations[0]);\n activityOverlay.hide();\n });\n });\n };\n\n /**\n * Creates the \"Translate to all\" button and adds it to the inputfield\n *\n * @param {int} sourceLanguageId ProcessWire language ID\n * @param {HTMLElements} inputContainers All language input containers for this inputfield\n * @return {void}\n */\n this.addTranslateToAllButton = (sourceLanguageId, inputContainers) => {\n const sourceInputContainer = inputContainers[sourceLanguageId];\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translateToAllButton);\n this.bindTranslateToAllButton(button, _FtConfig.default.getLanguageForId(sourceLanguageId), inputContainers);\n sourceInputContainer.appendChild(container);\n };\n\n /**\n * Binds translation action to button that translates to all other languages\n *\n * @param {Element} buttonElement [description]\n * @param {object} sourceLanguageConfig The FtConfig object for the source language\n * @param {HTMLElements} inputContainers All language input containers for this inputfield\n * @return {void}\n */\n this.bindTranslateToAllButton = (buttonElement, sourceLanguageConfig, inputContainers) => {\n buttonElement.addEventListener('click', e => {\n e.preventDefault();\n const translationSourceContent = inputfield.getValueForLanguage(sourceLanguageConfig.id);\n\n // Do not translate if there's no source content or risk content in other languages to\n // be removed\n if (!translationSourceContent) {\n return;\n }\n\n // Used to count the number of languages left when translating to all\n let translationLanguageCount = Object.keys(inputContainers).length;\n let errorOccurred = false;\n let activityOverlay = inputfield.getActivityOverlay();\n activityOverlay.showActivity();\n for (let targetLanguageId in inputContainers) {\n // No need to translate self\n if (targetLanguageId === sourceLanguageConfig.id) {\n continue;\n }\n let targetLanguageConfig = _FtConfig.default.getLanguageForId(targetLanguageId);\n _Fluency.default.getTranslation(sourceLanguageConfig.engineLanguage.sourceCode, targetLanguageConfig.engineLanguage.targetCode, translationSourceContent).then(result => {\n if (result.error) {\n // Only show the error overlay if an error has not already occurred\n if (!errorOccurred) {\n inputfield.getActivityOverlay().showError(result.message);\n }\n errorOccurred = true;\n return;\n }\n inputfield.setValueForLanguage(targetLanguageConfig.id, result.translations[0]);\n }).then(result => {\n translationLanguageCount--;\n\n // If an error occurred, messaging/overlay will be handled by the error process\n if (translationLanguageCount === 0 && !errorOccurred) {\n activityOverlay.hide();\n }\n });\n }\n });\n };\n\n /**\n * Init on object instantiation\n */\n (() => {\n for (let languageId in inputContainers) {\n if (_FtConfig.default.getTranslationAction() === _FtConfig.default.translationActionTypes.all && !forceEachTranslationAction) {\n this.addTranslateToAllButton(languageId, inputContainers);\n }\n if (_FtConfig.default.getTranslationAction() === _FtConfig.default.translationActionTypes.each || forceEachTranslationAction) {\n this.addTranslateElements(languageId, inputContainers[languageId]);\n }\n }\n })();\n};\nvar _default = FtInputfieldTranslateButton;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4,\"./FtUiElements\":18}],17:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * A stateful function handling behaviors for a language tab associated with a input container\n * contained within an Inputfield. An \"input container\" is the div that contains the label and\n * input/textarea/element (depending on Inputfield type) for a language\n * @param {Element} inputContainer Language\n */\nconst FtLanguageTab = function (inputContainer) {\n /**\n * Note\n * @type {String}\n */\n const contentModifiedClass = 'ft-content-changed';\n\n /**\n * Cached associated tab for this input container\n * @type {Element}\n */\n let languageTab = null;\n this.getContentModifiedClass = () => contentModifiedClass;\n\n /**\n * Sets state of tab\n * @param {bool} modified Determines state of tab display\n * @return {void}\n */\n this.setModifiedState = modified => modified ? this.setTabModified() : this.setTabUnmodified();\n this.setTabModified = () => this.getLanguageTab().classList.add(contentModifiedClass);\n this.setTabUnmodified = () => this.getLanguageTab().classList.remove(contentModifiedClass);\n this.getLanguageTab = () => {\n return languageTab ?? inputContainer.closest('.langTabs').querySelector(`.langTabLink[data-lang=\"${inputContainer.dataset.language}\"`);\n };\n\n /**\n * Init method executed on object instantiation\n * @return {void}\n */\n (() => {\n if (!inputContainer) {\n return false;\n }\n languageTab = this.getLanguageTab();\n })();\n};\nvar _default = FtLanguageTab;\nexports.default = _default;\n\n},{}],18:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates common HTML elements\n *\n * @return {Object} Public methods\n */\nconst FtUiElements = function () {\n /**\n * @type {Object}\n */\n const elementClasses = {\n translateButton: {\n container: 'ft-translate-button-container',\n button: 'ft-translate-button'\n },\n statusPlaceholder: {\n container: 'ft-translation-status-container',\n label: 'ft-translation-status'\n },\n icon: 'ft-icon'\n };\n\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Creates a language fontawesome icon element\n *\n * @return {Element}\n */\n const createIcon = () => {\n const iconLink = document.createElement('a');\n iconLink.setAttribute('href', `${ProcessWire.config.urls.admin}fluency/?modal=1`);\n iconLink.setAttribute('class', 'pw-modal pw-modal-large');\n const icon = document.createElement('i');\n icon.setAttribute('class', `${elementClasses.icon} fa fa-language`);\n icon.setAttribute('uk-tooltip', uiText.showTranslator);\n iconLink.appendChild(icon);\n return iconLink;\n };\n\n /**\n * Creates a status placeholder\n *\n * @return {Element}\n */\n const createStatusElement = text => {\n const label = document.createElement('span');\n label.setAttribute('class', elementClasses.statusPlaceholder.label);\n label.innerText = text;\n const container = document.createElement('div');\n container.setAttribute('class', elementClasses.statusPlaceholder.container);\n container.appendChild(createIcon());\n container.appendChild(label);\n return container;\n };\n\n /**\n * Creates a translate button element\n *\n * @return {Object} Container element and Button element\n */\n const createTranslateButton = text => {\n const button = document.createElement('a');\n button.innerText = text;\n button.setAttribute('class', elementClasses.translateButton.button);\n button.setAttribute('href', '');\n const container = document.createElement('div');\n container.setAttribute('class', elementClasses.translateButton.container);\n container.appendChild(createIcon());\n container.appendChild(button);\n return {\n button,\n container\n };\n };\n return {\n createStatusElement,\n createTranslateButton,\n createIcon,\n elementClasses\n };\n}();\nvar _default = FtUiElements;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4}]},{},[1]);\n"],"names":["r","e","n","t","o","i","f","c","require","u","a","Error","code","p","exports","call","length","1","module","_FtInputfields","_interopRequireDefault","_FtAdminMenu","_FtConfig","obj","__esModule","default","window","addEventListener","moduleShouldInitialize","init","./global/FtConfig","./inputfields/FtInputfields","./ui/FtAdminMenu","2","Object","defineProperty","value","Fluency","errors","getUiTextFor","requestHeaders","requestType","X-Requested-With","getRequest","endpoint","responseHandler","fetch","method","cache","headers","then","parseResponse","catch","handleFetchError","deleteRequest","response","status","ok","json","error","console","message","returnObject","split","deleteTranslatableLanguagesCache","getApiEndpointFor","deleteTranslationCache","getAvailableLanguages","getTranslation","sourceLanguage","targetLanguage","content","let","options","arguments","undefined","caching","data","body","JSON","stringify","getUsage","./FtConfig","3","FtConfig","config","ProcessWire","fluency","localizedStrings","localization","strings","activityOverlay","languageSelect","inputfieldTranslateButtons","standaloneTranslator","usage","endpoints","languages","apiEndpoints","translatableLanguagesCache","test","translation","translationCache","configuredLanguages","unconfiguredLanguages","getConfiguredLanguages","getUnconfiguredLanguages","getEngineInfo","engine","fieldInitializedAttr","key","getDefaultLanguage","reduce","defaultLang","lang","getEngineProvidesUsageData","providesUsageData","getTranslationAction","interface","inputfieldTranslationAction","getLanguageCount","getLanguageForId","pwLanguageId","parseInt","match","language","id","languageIsTranslatable","languageId","includes","translationActionTypes","each","all","4","getPageId","urlParams","URLSearchParams","location","search","get","tagElement","element","text","addRandomId","tagDiv","document","createElement","setAttribute","Array","map","Math","random","toString","join","innerText","appendChild","pageIdIs","5","FtIsInputfieldCKEditor","FtInputfieldCKEditor","_FtActivityOverlay","_FtInputfieldTranslateButton","_FtLanguageTab","inputfield","querySelector","initValues","changedValues","languageTabs","inputContainers","editorInstances","defaultLanguageInstanceId","this","getActivityOverlay","getSelf","getValueForDefaultLanguage","getValueForLanguage","getEditorInstanceForLanguage","getData","setValueForLanguage","instance","setData","fire","contentHasChanged","ckeditorSelector","hasOwn","createCKEditorSelector","CKEDITOR","instances","getInputContainers","querySelectorAll","forEach","el","dataset","registerInputEventListener","on","setModifiedState","allInputContainers","values","replace","inputContainer","../global/FtConfig","../ui/FtActivityOverlay","../ui/FtInputfieldTranslateButton","../ui/FtLanguageTab","./FtInputfields","6","FtIsInputfieldCKEditorInline","FtInputfieldCKEditorInline","contentElements","ckeditorInstance","getContentElementForLanguage","innerHTML","contentElement","setValue","dispatchEvent","Event","getInputContainerForLanguage","keys","registerUpdateEvent","MutationObserver","mutations","observer","mutation","target","observe","childList","7","createActivityOverlay","languageInput","languageFields","contentModifiedClass","getContentModifiedClass","activityOverlays","getFieldForLanguage","field","updateValue","name","classList","add","remove","8","FtIsInputfieldTable","isInputfieldTable","isInputfieldTableRow","contains","tagName","9","FtIsInputfieldText","FtInputfieldText","10","FtIsInputfieldTextarea","FtInputfieldTextarea","11","FtIsInputfieldTinyMCE","FtInputfieldTinyMCE","textareas","tinymceInstance","getTinymceInstanceForLanguage","getContent","getTextareaForLanguage","setContent","tinymceSelector","createTinymceSelector","tinymce","bindTinymceEvents","initTinymceInstanceOnCreation","disconnect","initAll","setTimeout","12","FtIsInputfieldTinyMCEInline","FtInputfieldTinyMCEInline","13","_FtInputfieldCKEditor","_FtInputfieldCKEditorInline","_FtInputfieldTable","_FtInputfieldText","_FtInputfieldTextarea","_FtInputfieldTinyMCE","_FtInputfieldTinyMCEInline","_FtInputfieldPageName","FtInputfields","langInputfieldClass","initInputfields","langInputfieldContainers","langInputfieldContainer","initInputfield","fieldIsInitialized","closest","warn","setFieldIsInitialized","langTabContainer","hasAttribute","parentNode","getElementById","foundEls","subtree","pageNameInputfield","inputEl","focus","blur","../global/FtTools","./FtInputfieldCKEditor","./FtInputfieldCKEditorInline","./FtInputfieldPageName","./FtInputfieldTable","./FtInputfieldText","./FtInputfieldTextarea","./FtInputfieldTinyMCE","./FtInputfieldTinyMCEInline","14","targetContainer","_this","activityType","elClasses","parent","overlay","flash","success","activity","visible","activityContainer","activityStaticText","activityAnimationContainer","activityAnimationItem","messageContainer","showActivity","setActivityActive","setOverlayVisible","showMessage","displayTime","setMessageContent","setActivityInactive","setMessageActive","hide","flashSuccess","setSuccessActive","setFlashActive","flashError","setErrorActive","showError","delay","setOverlayInvisible","setMessageInactive","setErrorInactive","setFlashInactive","setSuccessInactive","create","buildOverlayEl","buildActivityEl","buildMessageEl","animated","string","activityText","staticText","static","targetContainerContainer","15","convertFtAdminMenuToModal","adminNavItems","hrefSegments","href","filter","Boolean","16","_Fluency","_FtUiElements","forceEachTranslationAction","uiText","addTranslateElements","button","container","isTranslatable","isDefaultLanguage","createTranslateButton","translateButton","bindButton","createStatusElement","translationAvailable","languageNotAvailable","buttonElement","languageConfig","preventDefault","translationSourceContent","engineLanguage","sourceCode","targetCode","result","translations","addTranslateToAllButton","sourceLanguageId","sourceInputContainer","translateToAllButton","bindTranslateToAllButton","sourceLanguageConfig","translationLanguageCount","errorOccurred","targetLanguageId","targetLanguageConfig","../global/Fluency","./FtUiElements","17","languageTab","modified","setTabModified","setTabUnmodified","getLanguageTab","18","FtUiElements","elementClasses","statusPlaceholder","label","icon","createIcon","iconLink","urls","admin","showTranslator"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"../fluency.bundle.js","sources":["fluency.bundle.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i {\n if (_FtConfig.default.moduleShouldInitialize()) {\n _FtAdminMenu.default.init();\n _FtInputfields.default.init();\n }\n});\n\n},{\"./global/FtConfig\":3,\"./inputfields/FtInputfields\":13,\"./ui/FtAdminMenu\":15}],2:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"./FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Core module interface\n * Handles all interaction with the ProcessWire module backend\n * @return {object} Public interfaces\n */\n\nconst Fluency = function () {\n /**\n * Localized error strings\n * @type {Object}\n */\n const errors = _FtConfig.default.getUiTextFor('errors');\n\n /**\n * Data Request Methods\n */\n\n /**\n * Gets a translation from the Fluency module\n * @param {String} sourceLanguage ISO language code\n * @param {String} targetLanguage ISO langauge code\n * @param {String|Array} content Content to translate\n * @param {Array} options Additional options\n * @param {Bool|null} caching Enable/disable caching\n * @return {Promise}\n */\n const getTranslation = function (sourceLanguage, targetLanguage, content) {\n let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];\n let caching = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;\n return postRequest(_FtConfig.default.getApiEndpointFor('translation'), {\n sourceLanguage: sourceLanguage,\n targetLanguage: targetLanguage,\n content: content,\n options: options,\n caching: caching\n }, response => {\n return response;\n });\n };\n\n /**\n * Gets the current translation service API usage\n * @return {Promise}\n */\n const getUsage = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('usage'), response => {\n return response;\n });\n };\n\n /**\n * Get all language available for translation. Provides source/target lists from the translation\n * service API\n * @return {Promise}\n */\n const getAvailableLanguages = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('languages'), response => {\n return response;\n });\n };\n\n /**\n * Clear all cached translations\n * @return {Promise}\n */\n const deleteTranslationCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translationCache'), response => {\n return response;\n });\n };\n\n /**\n * Clear cached list of translatable languages\n * @return {Promise}\n */\n const deleteTranslatableLanguagesCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translatableLanguagesCache'), response => {\n return response;\n });\n };\n\n /**\n * HTTP Requests\n */\n\n /**\n * Create headers for AJAX requests\n * @return {Object}\n */\n const requestHeaders = requestType => {\n const requestHeaders = {\n 'X-Requested-With': 'XMLHttpRequest'\n };\n if (requestType === 'GET') {\n requestHeaders['Accept'] = 'application/json';\n }\n if (requestType === 'POST') {\n requestHeaders['Content-Type'] = 'application/json';\n }\n return requestHeaders;\n };\n\n /**\n * Executes a POST request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Object} data Data for request\n * @param {Callable} data Function to handle response body\n * @return {Promise}\n */\n const postRequest = (endpoint, data, responseHandler) => {\n return fetch(endpoint, {\n method: 'POST',\n cache: 'no-store',\n headers: requestHeaders,\n body: JSON.stringify(data)\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a GET request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const getRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'GET',\n cache: 'no-store',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a DELETE request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const deleteRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'DELETE',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Parses response\n * @param {Object} response Fluency API response\n * @return {Object|Void}\n * @throws Error\n */\n const parseResponse = response => {\n if (response.status === 204) {\n return response;\n }\n if (response.ok) {\n return response.json();\n }\n throw new Error();\n };\n\n /**\n * Parses and returns results for a fetch error\n * These are network level errors that occur between ProcessWire and the hosting server\n * Any translation or service errors will be located within the response body itself\n * @param {Error} error Fetch API error object\n * @return {Object}\n */\n const handleFetchError = error => {\n console.error('[Fluency module API failure]', error.message);\n const returnObject = {\n error: null,\n message: null\n };\n switch (error.message.split(' ')[0]) {\n case 'NetworkError':\n returnObject.error = 'FLUENCY_CLIENT_DISCONNECTED';\n returnObject.message = errors['FLUENCY_CLIENT_DISCONNECTED'];\n break;\n default:\n returnObject.error = 'UNKNOWN_ERROR';\n returnObject.message = errors['UNKNOWN_ERROR'];\n break;\n }\n return returnObject;\n };\n return {\n deleteTranslatableLanguagesCache,\n deleteTranslationCache,\n getAvailableLanguages,\n getTranslation,\n getUsage\n };\n}();\nvar _default = Fluency;\nexports.default = _default;\n\n},{\"./FtConfig\":3}],3:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * This provides access methods to get module configuration values\n * @return {Object} Public methods\n */\nconst FtConfig = function () {\n // Public properties\n\n const fieldInitializedAttr = 'data-ft-initialized';\n const translationActionTypes = {\n each: 'translate_each_language',\n all: 'translate_to_all_languages'\n };\n\n // Private properties\n\n /**\n * Holds the data passed from the Fluency module\n * @access Private\n * @type {Object}\n */\n const config = ProcessWire.config.fluency;\n\n /**\n * All UI strings\n * @type {Object}\n */\n const localizedStrings = config.localization;\n\n /**\n * Classes for elements created in UI\n * @type {Object}\n */\n const elementClasses = {\n translateButton: {\n container: 'ft-translate-button-container',\n button: 'ft-translate-button'\n },\n translateAllButton: {\n container: 'Inputfield InputfieldHeaderHidden',\n content: 'InputfieldContent',\n button: 'ft-translate-all-button'\n },\n statusPlaceholder: {\n container: 'ft-translation-status-container',\n label: 'ft-translation-status'\n },\n icon: 'ft-icon'\n };\n\n /**\n * Objects interface with the Fluency config object so that changes to the object\n * structure from the back end do not break the UI. Use the public methods below\n * to access ProcessWire.config.fluency properties and data\n */\n\n /**\n * Localized strings keyed sets\n * @type {Object}\n */\n const strings = {\n activityOverlay: localizedStrings.activityOverlay,\n languageSelect: localizedStrings.languageSelect,\n inputfieldTranslateButtons: localizedStrings.inputfieldTranslateButtons,\n standaloneTranslator: localizedStrings.standaloneTranslator,\n usage: localizedStrings.usage,\n errors: localizedStrings.errors,\n languageTranslator: localizedStrings.languageTranslator\n };\n\n /**\n * Fluency API keyed URLs\n * @type {Object}\n */\n const endpoints = {\n languages: config.apiEndpoints.languages,\n translatableLanguagesCache: config.apiEndpoints.translatableLanguagesCache,\n test: config.apiEndpoints.test,\n translation: config.apiEndpoints.translation,\n translationCache: config.apiEndpoints.translationCache,\n usage: config.apiEndpoints.usage\n };\n\n /**\n * Contains all of the Fluency configured langauges from the module\n * @type {Array}\n */\n const configuredLanguages = config.configuredLanguages;\n\n /**\n * Contains an array of ProcessWire language IDs not configured in Fluency\n * @type {Array}\n */\n const unconfiguredLanguages = config.unconfiguredLanguages;\n\n // Public methods\n\n /**\n * Fluency REST API\n */\n const getApiEndpointFor = key => endpoints[key];\n\n /**\n * Languages\n */\n\n /**\n * Get all configured languages\n * @return {object}\n */\n const getConfiguredLanguages = () => configuredLanguages;\n\n /**\n * Returns ProcessWire's default language\n * @return {object}\n */\n const getDefaultLanguage = () => getConfiguredLanguages().reduce((defaultLang, lang) => lang.default ? lang : defaultLang, null);\n\n /**\n * Determines if the language with a given ProcessWire ID can be translated\n * @param {int|string} languageId ProcessWire language ID\n * @return {bool}\n */\n const languageIsTranslatable = languageId => !getUnconfiguredLanguages().includes(parseInt(languageId, 10));\n\n /**\n * Get all languages not configured in Fluency\n * @return {object}\n */\n const getUnconfiguredLanguages = () => unconfiguredLanguages;\n\n /**\n * Gets total count of configured and unconfigured languages\n * @return {int}\n */\n const getLanguageCount = () => getConfiguredLanguages().length + getUnconfiguredLanguages().length;\n\n /**\n * Get a configured language by it's ProcessWire ID\n * @param {string|int} pwLanguageId ProcessWire language ID\n * @return {object}\n */\n const getLanguageForId = pwLanguageId => {\n pwLanguageId = parseInt(pwLanguageId, 10);\n return getConfiguredLanguages().reduce((match, language) => language.id === pwLanguageId ? language : match, null);\n };\n\n /**\n * Localization\n */\n\n /**\n * Accessor method for localized UI strings\n * @param {string} key Object key\n * @return {string}\n */\n const getUiTextFor = key => strings[key];\n\n /**\n * Module Configuration/State\n */\n\n /**\n * Determines if Fluency JS should initialize based on whether languages have\n * been configured\n * @return {bool}\n */\n const moduleShouldInitialize = () => getConfiguredLanguages().length > 1;\n\n /**\n * Returns the translation engine config object for the engine configured in Fluency\n * @return {object|null}\n */\n const getEngineInfo = () => config.engine;\n\n /**\n * Does this engine provide usage data?\n * @return {bool}\n */\n const getEngineProvidesUsageData = () => getEngineInfo().providesUsageData;\n\n /**\n * Gets the type of translation action chosen in the Flunecy module config\n * @return {string}\n */\n const getTranslationAction = () => config.interface.inputfieldTranslationAction;\n const getElementClassesFor = element => elementClasses[element];\n return {\n fieldInitializedAttr,\n getApiEndpointFor,\n getConfiguredLanguages,\n getDefaultLanguage,\n getElementClassesFor,\n getEngineInfo,\n getEngineProvidesUsageData,\n getLanguageCount,\n getLanguageForId,\n getTranslationAction,\n getUiTextFor,\n getUnconfiguredLanguages,\n languageIsTranslatable,\n moduleShouldInitialize,\n translationActionTypes\n };\n}();\nvar _default = FtConfig;\nexports.default = _default;\n\n},{}],4:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * These are common tools the Fluency translation module uses\n * It is loaded first in order of scripts added to the page so that the module\n * is available to all subsequent scripts\n *\n * @return {Object} Public methods\n */\nconst FtTools = function () {\n /**\n * Create a random string of hex characters\n * @param {Number} length\n * @return {String}\n */\n const randomHex = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6;\n const chars = '0123456789ABCDEF'.split('');\n [...Array(length)].reduce((hex, i) => hex = chars[Math.floor(Math.random() * chars.length)], '');\n };\n\n /**\n * Generate random string of upper/lower/ints\n * @param length\n * @return string\n */\n const createRandomString = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5;\n return [...Array(length)].map(() => Math.random().toString(36)[2]).join('');\n };\n\n /**\n * Appends a div to a given element with a defined string, optionally adds a unique\n * string in case differentiating between more than one with the same text is\n * needed\n * @param {Element} element Element to tag\n * @param {String} text Text for tag\n * @param {Boolean} addRandomId Add random ID string to tag\n * @return {Void}\n */\n const tagElement = function (element, text) {\n let addRandomId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n const tagDiv = document.createElement('div');\n tagDiv.setAttribute('class', 'ft-element-tag');\n if (addRandomId) {\n text += ' | ' + createRandomString();\n }\n tagDiv.innerText = text;\n element.appendChild(tagDiv);\n };\n\n /**\n * Creates a random HTML hex code\n * @return {String} [description]\n */\n const randomHexColor = () => `#${randomHex()}`;\n\n /**\n * Gets the page ID from the current URL\n * @return {int|null} Page ID number, null if not present\n */\n var getPageId = function () {\n var urlParams = new URLSearchParams(window.location.search);\n return urlParams ? parseInt(urlParams.get('id')) : null;\n };\n\n /**\n * Checks page ID against page ID passed\n * @param {int} id ID to check against\n * @return {bool} True/false whether is current page ID\n */\n const pageIdIs = id => getPageId() === id;\n return {\n tagElement,\n getPageId,\n pageIdIs\n };\n}();\nvar _default = FtTools;\nexports.default = _default;\n\n},{}],5:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldCKEditor = exports.FtInputfieldCKEditor = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains a regular CKEditor instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldCKEditor = inputfield => !!inputfield.querySelector('.InputfieldCKEditorNormal');\n\n/**\n * Handles translations for CKEditor Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldCKEditor = FtIsInputfieldCKEditor;\nconst FtInputfieldCKEditor = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n *\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all CKEditor instances\n * @property {String} ProcessWire Language ID\n * @value {CKEditor|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the base CKEditor instance ID that can be used to get the default CKEditor instance\n * using the CKEditor API, or another instance by modifying this one.\n * Set on FtInputfieldCKEditor instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /**\n * Gets existing or instantiates a new activity overlay\n *\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getEditorInstanceForLanguage(languageId).getData();\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const instance = this.getEditorInstanceForLanguage(languageId);\n instance.setData(value);\n instance.fire('change');\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the CKEditor instance for a given language ID. This method should\n * be used exclusively to get instances as it also sets event listeners for content\n * changes if they have been instantiated after FtInputfieldCKEditor has loaded\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?CKEditor}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const ckeditorSelector = this.createCKEditorSelector(languageId);\n editorInstances[languageId] = CKEDITOR.instances[ckeditorSelector];\n return editorInstances[languageId];\n };\n\n /**\n * Creates a CKEditor ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createCKEditorSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Registers the event listener that watches for content changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {void}\n */\n this.registerInputEventListener = languageId => {\n this.getEditorInstanceForLanguage(languageId).on('change', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init on object instantiation\n * @access private\n * @return {Void}\n */\n (() => {\n if (CKEDITOR === undefined) {\n console.error('CKEditor was not found by Fluency, translation unavailable');\n return;\n }\n const allInputContainers = this.getInputContainers();\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n editorInstances[languageId] = this.getEditorInstanceForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldCKEditor = FtInputfieldCKEditor;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],6:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldCKEditorInline = exports.FtInputfieldCKEditorInline = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains an inline CKEditor instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldCKEditorInline = inputfield => !!inputfield.querySelector('.InputfieldCKEditorInline');\n\n/**\n * Handles translations for CKEditor Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldCKEditorInline = FtIsInputfieldCKEditorInline;\nconst FtInputfieldCKEditorInline = function (inputfield) {\n /**\n * Contains values for all fields/languages\n * Populated on FtInputfieldCKEditorInline instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all CKEditor instances\n * @property {String} ProcessWire Language ID\n * @value {CKEditor|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain all elements that the inline editor uses for content\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const contentElements = {};\n\n /**\n * Will contain the base CKEditor instance ID that can be used to get the default CKEditor instance\n * using the CKEditor API, or another instance by modifying this one.\n * Set on FtInputfieldCKEditor instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /**\n * Gets existing or instantiates a new activity overlay\n *\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * Attempts to get the value for a language via the CKEditor API, falls back to directly getting\n * the content of the content element\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const ckeditorInstance = this.getEditorInstanceForLanguage(languageId);\n if (ckeditorInstance) {\n return ckeditorInstance.getData();\n }\n return this.getContentElementForLanguage(languageId).innerHTML;\n };\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const instance = this.getEditorInstanceForLanguage(languageId);\n const contentElement = this.getContentElementForLanguage(languageId);\n instance ? instance.setValue(value) : contentElement.innerHTML = value;\n contentElement.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the CKEditor instance for a given language ID. This method should\n * be used exclusively to get instances as it also sets event listeners for content\n * changes if they have been instantiated after FtInputfieldCKEditor has loaded\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?CKEditor}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n editorInstances[languageId] = CKEDITOR.instances[this.createCKEditorSelector(languageId)];\n return editorInstances[languageId];\n };\n\n /**\n * Gets the content element that CKEditor uses to store the field content\n * Ensures memoization\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getContentElementForLanguage = languageId => {\n if (Object.hasOwn(contentElements, languageId)) {\n return contentElements[languageId];\n }\n contentElements[languageId] = this.getInputContainerForLanguage(languageId).querySelector('.InputfieldCKEditorInlineEditor');\n return contentElements[languageId];\n };\n\n /**\n * Creates a CKEditor ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createCKEditorSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n if (Object.keys(inputContainers).length === _FtConfig.default.getLanguageCount()) {\n return inputContainers;\n }\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId)) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a MutationObserver that will detect when the content has changed for a given content\n * element. When content is changed, is will mock an 'input' even that an eventListener will\n * respond to\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerUpdateEvent = languageId => {\n const contentElement = this.getContentElementForLanguage(languageId);\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n mutation.target.dispatchEvent(new Event('input'));\n }\n }).observe(contentElement, {\n childList: true\n });\n };\n\n /**\n * Registers an event listener that will respond to any 'input' changes in a\n * content element\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getContentElementForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init on object instantiation\n * @access private\n * @return {Void}\n */\n (() => {\n if (CKEDITOR === undefined) {\n console.error('CKEditor was not found by Fluency, translation unavailable');\n return null;\n }\n const allInputContainers = this.getInputContainers();\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n editorInstances[languageId] = this.getEditorInstanceForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldCKEditorInline = FtInputfieldCKEditorInline;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],7:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Handles IO operations for a multilanguage InputfieldPageName element\n * The InputfieldPageName element has special considerations compared to other fields as they do not\n * have the same markup structure.\n * Some actions are internalized here, such as\n * @param {Element} inputfield The Inputfield .InputfieldPageName container\n */\nconst FtInputfieldPageName = function (inputfield) {\n /**\n * Page-load values for all fields/languages\n * Populated on object instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when content is modified\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * FtLanguageTab objects for each language\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all elements containing language inputs\n * @property {String} ProcessWire Language ID\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Text input fields\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageFields = {};\n let contentModifiedClass = new _FtLanguageTab.default().getContentModifiedClass();\n\n /**\n * Activity overlays by language IDs\n * @access public\n * @type {Object}\n */\n let activityOverlays = {};\n\n /*\n * Return null to signal that the overlay should be by language ID\n *\n * @access public\n * @return {Object|Null}\n */\n this.getActivityOverlay = languageId => {\n if (!languageId) {\n return null;\n }\n return activityOverlays[languageId].getActivityOverlay();\n };\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) {\n return languageFields[languageId];\n }\n languageFields[languageId] = this.getInputContainerForLanguage(languageId).querySelector('input');\n return languageFields[languageId];\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (!Object.hasOwn(inputContainers, languageId) && !inputContainers[languageId]) {\n this.getInputContainers();\n }\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n // Page name fields require querying the child input and determining the language by analyzing\n // the name attribute of the text input itself\n this.getSelf().querySelectorAll('.LanguageSupport').forEach(el => {\n // The default language input has no language ID, it's the default language, so fallback\n const languageId = el.querySelector('input[type=text]').name.replace('_pw_page_name', '') || _FtConfig.default.getDefaultLanguage().id;\n inputContainers[languageId] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n this.setModifiedState = (languageId, contentHasChanged) => {\n const inputContainer = this.getInputContainerForLanguage(languageId);\n if (contentHasChanged) {\n inputContainer.classList.add(contentModifiedClass);\n }\n if (!contentHasChanged) {\n inputContainer.classList.remove(contentModifiedClass);\n }\n };\n\n /**\n * Registers the event listener that watches for changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getFieldForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n this.setModifiedState(languageId, this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n activityOverlays[languageId] = new createActivityOverlay(inputContainer);\n this.registerInputEventListener(languageId);\n }\n new _FtInputfieldTranslateButton.default(this, allInputContainers, true);\n })();\n};\nconst createActivityOverlay = function (languageInput) {\n let activityOverlay;\n this.getSelf = () => languageInput;\n this.getActivityOverlay = () => activityOverlay;\n (() => {\n activityOverlay = new _FtActivityOverlay.default(this);\n })();\n};\nvar _default = FtInputfieldPageName;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],8:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTable = void 0;\n/**\n * Determines if a given inputfield contains a Table instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTable = inputfield => isInputfieldTable(inputfield) || isInputfieldTableRow(inputfield);\n\n/**\n * Handles table inputfields on load\n * @param {Element} inputfield\n * @return {Bool}\n */\nexports.FtIsInputfieldTable = FtIsInputfieldTable;\nconst isInputfieldTable = inputfield => !!inputfield.classList.contains('InputfieldTable');\nconst isInputfieldTableRow = inputfield => !!inputfield.tagName === 'TBODY' && inputfield.querySelectorAll('.InputfieldTable_hasLangTabs').length;\n\n},{}],9:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldText = exports.FtInputfieldText = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if the current inputfield is an InputfieldText\n * @param {Element} inputfield Element containing the multilanguage fields\n * @return {Bool}\n */\nconst FtIsInputfieldText = inputfield => !!inputfield.querySelector(\"input[type='text']\");\n\n/**\n * Handles IO operations for a multilanguage InputfieldText element\n * Language IDs are always converted to int to accept values from all sources since some may be\n * retrieved from various sources as a string\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldText = FtIsInputfieldText;\nconst FtInputfieldText = function (inputfield) {\n /**\n * Page-load values for all fields/languages\n * Populated on object instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when content is modified\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * FtLanguageTab objects for each language\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all elements containing language inputs\n * @property {String} ProcessWire Language ID\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Text input fields\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageFields = {};\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) {\n return languageFields[languageId];\n }\n languageFields[languageId] = this.getInputContainerForLanguage(languageId).querySelector('input');\n return languageFields[languageId];\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n inputfield.querySelectorAll('[data-language]').forEach(el => inputContainers[el.dataset.language] = el);\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Registers the event listener that watches for changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getFieldForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldText = FtInputfieldText;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],10:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTextarea = exports.FtInputfieldTextarea = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if the current inputfield is an InputfieldText\n * @param {Element} inputfield Element containing the multilanguage fields\n * @return {Bool}\n */\nconst FtIsInputfieldTextarea = inputfield => !!inputfield.querySelector('textarea:not(.InputfieldCKEditorNormal,.InputfieldTinyMCEEditor)');\n\n/**\n * Handles IO operations for a multilanguage InputfieldText element\n * Language IDs are always converted to int to accept values from all sources since some may be\n * retrieved from various sources as a string\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldTextarea = FtIsInputfieldTextarea;\nconst FtInputfieldTextarea = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * Language ID keys are integers\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * Language ID keys are integers\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Will contain all language input text fields keyed by language ID\n * @type {Object}\n */\n const languageFields = {};\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId)) {\n return languageFields[languageId];\n }\n languageFields[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"] textarea`);\n return languageFields[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n inputfield.querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n inputContainer.querySelector('textarea').addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTextarea = FtInputfieldTextarea;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],11:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTinyMCE = exports.FtInputfieldTinyMCE = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains a regular TinyMCE instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTinyMCE = inputfield => !!inputfield.querySelector('.InputfieldTinyMCENormal');\n\n/**\n * Handles IO operations for a multilanguage InputfieldTinyMCE elements\n * @param {Element} inputfield The Inputfield .hasLangTabs container\n */\nexports.FtIsInputfieldTinyMCE = FtIsInputfieldTinyMCE;\nconst FtInputfieldTinyMCE = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n *\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {String} Inputfield content\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const inputContainers = {};\n\n /**\n * Will contain all language input textarea fields that hold Inputfield data before TinyMCE\n * instances are initialized.\n * @property {String} ProcessWire Language ID\n * @value {Element}\n * @type {Object}\n */\n const textareas = {};\n\n /**\n * Will contain all TinyMCE instances as they become available (are initialized). Most TinyMCE\n * instances are lazy loaded or loaded on demand. Keyed by language ID\n * This is populated on FtInputfieldTinyMCE on instantiation and language ID properties will either\n * have a TinyMCE object or null\n * @property {String} ProcessWire Language ID\n * @value {TinyMCE|null}\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the base TinyMCE instance ID that can be used to get the default TinyMCE instance\n * using the TinyMCE API, or another instance by modifying this one.\n * Set on FtInputfieldTinyMCE instantiation\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const tinymceInstance = this.getTinymceInstanceForLanguage(languageId);\n if (tinymceInstance) {\n return tinymceInstance.getContent();\n }\n return this.getTextareaForLanguage(languageId).value;\n };\n\n /**\n * Sets content for a language, will set the value for TinyMCE if it exists, and always set the\n * value for the textarea\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const tinymceInstance = this.getTinymceInstanceForLanguage(languageId);\n if (tinymceInstance) {\n tinymceInstance.setContent(value);\n tinymceInstance.fire('input');\n }\n const field = this.getTextareaForLanguage(languageId);\n _FtInputfields.default.updateValue(field, value);\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the TinyMCE instance for a given language ID if it exists\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?TinyMCE}\n */\n this.getTinymceInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const tinymceSelector = this.createTinymceSelector(languageId);\n editorInstances[languageId] = tinymce.get(tinymceSelector);\n return editorInstances[languageId];\n };\n\n /**\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getTextareaForLanguage = languageId => {\n if (Object.hasOwn(textareas, languageId) && !!textareas[languageId]) {\n return textareas[languageId];\n }\n textareas[languageId] = this.getSelf().querySelector(`[data-language=\"${languageId}\"] textarea`);\n return textareas[languageId];\n };\n\n /**\n * Get all input containers holding TinyMCE instances, memoizes. Keyed by ID\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a TinyMCE ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createTinymceSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Bind Inputfield required events to a TinyMCE instance\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Object} tinymceInstance TinyMCE object\n * @return {Void}\n */\n this.bindTinymceEvents = (languageId, tinymceInstance) => {\n tinymceInstance.on('keyup', e => this.getTextareaForLanguage(languageId).dispatchEvent(new Event('input')));\n };\n\n /**\n * Creates an observer that looks for new TinyMCE instances within this Inputfield\n * @access private\n * @return {void}\n */\n this.initTinymceInstanceOnCreation = (languageId, inputContainer) => {\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n let targetEl = mutation.target;\n if (targetEl.dataset.language == languageId) {\n editorInstances[languageId] = this.getTinymceInstanceForLanguage(languageId);\n this.bindTinymceEvents(languageId, editorInstances[languageId]);\n if (editorInstances[languageId]) {\n observer.disconnect();\n }\n }\n }\n }).observe(inputContainer, {\n childList: true\n });\n };\n\n /**\n * Registers the event listener that watches for content changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {void}\n */\n this.registerInputEventListener = languageId => {\n textareas[languageId].addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Initializes FtInputfieldTinyMCE Inputfield\n * @access private\n * @param {Array} allInputContainers All elements containing TinyMCE fields\n * @return {Void}\n */\n this.initAll = allInputContainers => {\n // TinyMCE instances are initialzied using a field ID. The default language element contains\n // an ID substring that can be modified to create a TinyMCE ID string that can be used to get\n // TinyMCE instances\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n\n // At runtime/initialization only the TinyMCE instance will load for the default language, others\n // will be loaded when switched to the tab. Still attempt to get all TinyMCE instances for all\n // tabs in case they are available\n for (let languageId in allInputContainers) {\n const inputContainer = allInputContainers[languageId];\n\n // Get initial content on page load\n // Call this first to ensure getValueForLanguage() pulls from the textarea element rather than\n // attempting to use the TinyMCE API on object instantiation\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n editorInstances[languageId] = this.getTinymceInstanceForLanguage(languageId);\n textareas[languageId] = this.getTextareaForLanguage(languageId);\n this.registerInputEventListener(languageId);\n\n // If there was no editor found at initialization, register when created\n if (!editorInstances[languageId]) {\n this.initTinymceInstanceOnCreation(languageId, inputContainer);\n }\n }\n\n // Bind TinyMCE event listeners to any TinyMCE input fields found on initialization\n for (let languageId in editorInstances) {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n this.bindTinymceEvents(languageId, editorInstances[languageId]);\n }\n }\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n\n // Set a micro timeout to allow TinyMCE instances to instantiate.\n // This is especially important when new fields are dynamically added after page load\n setTimeout(() => {\n this.initAll(allInputContainers);\n }, 50);\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTinyMCE = FtInputfieldTinyMCE;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],12:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.FtIsInputfieldTinyMCEInline = exports.FtInputfieldTinyMCEInline = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtInputfields = _interopRequireDefault(require(\"./FtInputfields\"));\nvar _FtInputfieldTranslateButton = _interopRequireDefault(require(\"../ui/FtInputfieldTranslateButton\"));\nvar _FtLanguageTab = _interopRequireDefault(require(\"../ui/FtLanguageTab\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Determines if a given inputfield contains an inline TinyMCE instance\n * @param {Element} inputfield Inputfield (.langTabs) element\n * @return {Bool}\n */\nconst FtIsInputfieldTinyMCEInline = inputfield => !!inputfield.querySelector('.InputfieldTinyMCEInline');\n\n/**\n * Handles translations for TinyMCE Inputfields\n * @return {object} Public methods\n */\nexports.FtIsInputfieldTinyMCEInline = FtIsInputfieldTinyMCEInline;\nconst FtInputfieldTinyMCEInline = function (inputfield) {\n /**\n * Contains values for all fields/languages keyed by ProcessWire language ID.\n * Populated on object instantiation\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when they change keyed by language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * Will contain FtLanguageTab object for each language keyed by language ID\n * Language ID keys are integers\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all language input containers keyed by language ID\n * Language ID keys are integers\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Will contain all the HTML elements that the inline TinyMCE editor stores/modifies content\n * keyed by language ID\n * @type {Object}\n */\n const contentElements = {};\n\n /**\n * Will contain all TinyMCE instances as they become available\n * @type {Object}\n */\n const editorInstances = {};\n\n /**\n * Will contain the TinyMCE instance name for the default language.\n * Used to get the TinyMCE instance\n * @type {?String}\n */\n let defaultLanguageInstanceId = null;\n\n /**\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => {\n const tinymceInstance = this.getEditorInstanceForLanguage(languageId);\n if (tinymceInstance) {\n return tinymceInstance.getContent();\n }\n return this.getContentElementForLanguage(languageId).innerHTML;\n };\n\n /**\n * @access public\n * @param {Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const contentElement = this.getContentElementForLanguage(languageId);\n contentElement.innerHTML = value;\n\n // Required to programmatically trigger the event listener for this field\n contentElement.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * Attempts to get the TinyMCE instance for a given language ID if it exists\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {?TinyMCE}\n */\n this.getEditorInstanceForLanguage = languageId => {\n if (Object.hasOwn(editorInstances, languageId) && !!editorInstances[languageId]) {\n return editorInstances[languageId];\n }\n const tinymceSelector = this.createTinymceSelector(languageId);\n editorInstances[languageId] = tinymce.get(tinymceSelector);\n return editorInstances[languageId];\n };\n\n /**\n * Gets the content element that TinyMCE uses to store the field content\n * Ensures memoization\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getContentElementForLanguage = languageId => {\n if (Object.hasOwn(contentElements, languageId)) {\n return contentElements[languageId];\n }\n contentElements[languageId] = this.getInputContainerForLanguage(languageId).querySelector('.mce-content-body');\n return contentElements[languageId];\n };\n\n /**\n * Gets a specific input container. Memoizes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = this.getSelf().querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n this.getSelf().querySelectorAll('[data-language]').forEach(el => {\n inputContainers[el.dataset.language] = el;\n });\n return inputContainers;\n };\n\n /**\n * This determines if the content for a given langauge has changed. In some instancesTinyMCE\n * inserts unwanted elements into empty fields that will always register content as having been\n * changed. This includes adding elements to fields that may be returned to their original content\n * matching content at page load. These \"phantom elements\" must me checked for.\n * @access private\n * @param {Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Creates a TinyMCE ID used to get instances by language\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {String}\n */\n this.createTinymceSelector = languageId => {\n if (languageId == _FtConfig.default.getDefaultLanguage().id) {\n return defaultLanguageInstanceId;\n }\n return `${defaultLanguageInstanceId}__${languageId}`;\n };\n\n /**\n * Creates a MutationObserver that will detect when the innerHTML content has changed for a given\n * content element. When content is changed, it will mock an 'input' event that an eventListener\n * can respond to\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerUpdateEvent = languageId => {\n const contentElement = this.getContentElementForLanguage(languageId);\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n mutation.target.dispatchEvent(new Event('input'));\n }\n }).observe(contentElement, {\n childList: true\n });\n };\n\n /**\n * Register an input observer\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getContentElementForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n if (tinymce === undefined) {\n console.error('TinyMCE was not found by Fluency, translation unavailable');\n return null;\n }\n const allInputContainers = this.getInputContainers();\n\n // TinyMCE instances are initialzied using a field ID. The default language element contains\n // an ID substring that can be modified to create a TinyMCE ID string that can be used to get\n // TinyMCE instances\n defaultLanguageInstanceId = Object.values(allInputContainers)[0].id.replace('langTab_', '');\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new _FtLanguageTab.default(inputContainer);\n this.registerUpdateEvent(languageId);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new _FtInputfieldTranslateButton.default(this, allInputContainers);\n })();\n};\nexports.FtInputfieldTinyMCEInline = FtInputfieldTinyMCEInline;\n\n},{\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":14,\"../ui/FtInputfieldTranslateButton\":16,\"../ui/FtLanguageTab\":17,\"./FtInputfields\":13}],13:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _FtInputfieldCKEditor = require(\"./FtInputfieldCKEditor\");\nvar _FtInputfieldCKEditorInline = require(\"./FtInputfieldCKEditorInline\");\nvar _FtInputfieldTable = require(\"./FtInputfieldTable\");\nvar _FtInputfieldText = require(\"./FtInputfieldText\");\nvar _FtInputfieldTextarea = require(\"./FtInputfieldTextarea\");\nvar _FtInputfieldTinyMCE = require(\"./FtInputfieldTinyMCE\");\nvar _FtInputfieldTinyMCEInline = require(\"./FtInputfieldTinyMCEInline\");\nvar _FtInputfieldPageName = _interopRequireDefault(require(\"./FtInputfieldPageName\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Orchestration for initializing all multilanguage inputfields on a page\n * @return {Object} Public interface methods\n */\nconst FtInputfields = function () {\n /**\n * Selector used to find translatable Inputfields\n * All inputfield containers on the page that are multilanguage have this class\n * @type {String}\n */\n const langInputfieldClass = \"[class*='hasLangTabs']\";\n // const langInputfieldClass = '.hasLangTabs';\n\n /**\n * Initializes multilanguage fields if present on page\n * @return {void}\n */\n const init = function () {\n const langInputfieldContainers = document.querySelectorAll(langInputfieldClass);\n\n // Only init if there are multi-language Inputfields on the page\n if (langInputfieldContainers.length) {\n initInputfields(langInputfieldContainers);\n initInputfieldsOnInsertion();\n initPageNameInputfields();\n }\n };\n\n /**\n * Initializes multiple multilanguage fields in a collection of elelents\n * @param {NodeList} langInputfieldContainers\n * @return {Void}\n */\n const initInputfields = langInputfieldContainers => {\n for (let langInputfieldContainer of langInputfieldContainers) {\n initInputfield(langInputfieldContainer);\n }\n };\n\n /**\n * Initializes the field within a container\n * @param {Element} langInputfieldContainer Element containing inputfield\n * @return {void}\n */\n const initInputfield = langInputfieldContainer => {\n // Do not initialize fields that have already been initialized\n // Do not initialized fields that are a list element and not an Inputfield themselves\n if (!fieldIsInitialized(langInputfieldContainer) && !langInputfieldContainer.classList.contains('InputfieldItemList') && !isInputfieldTemplate(langInputfieldContainer)) {\n let inputfield = getFtInputfieldObject(langInputfieldContainer);\n setFieldIsInitialized(langInputfieldContainer);\n if (!inputfield) {\n return;\n }\n }\n };\n\n /**\n * Detect if Inputfield container is a hidden template element used to dynamically create new\n * Inputfields on demand\n * @param {Element} langInputfieldContainer\n * @return {Bool}\n */\n const isInputfieldTemplate = langInputfieldContainer => !!langInputfieldContainer.closest(\"[class*='Template']\");\n\n /**\n * Initializes a FtInputfield object instance by type\n * Order of checks is important Complex fields should be cased higher\n * Fields with lower complexity should be cased last to prevent catching simple elements in\n * complex fields that use simple inputs\n * @param {Element} langInputfieldContainers\n * @return {?Object}\n */\n const getFtInputfieldObject = langInputfieldContainer => {\n switch (true) {\n case (0, _FtInputfieldTable.FtIsInputfieldTable)(langInputfieldContainer):\n // Initialize all new fields which have a different class than top-level fields\n initInputfields(langInputfieldContainer.querySelectorAll('.langTabs'));\n break;\n case (0, _FtInputfieldCKEditor.FtIsInputfieldCKEditor)(langInputfieldContainer):\n return new _FtInputfieldCKEditor.FtInputfieldCKEditor(langInputfieldContainer);\n case (0, _FtInputfieldCKEditorInline.FtIsInputfieldCKEditorInline)(langInputfieldContainer):\n return new _FtInputfieldCKEditorInline.FtInputfieldCKEditorInline(langInputfieldContainer);\n case (0, _FtInputfieldTinyMCE.FtIsInputfieldTinyMCE)(langInputfieldContainer):\n return new _FtInputfieldTinyMCE.FtInputfieldTinyMCE(langInputfieldContainer);\n case (0, _FtInputfieldTinyMCEInline.FtIsInputfieldTinyMCEInline)(langInputfieldContainer):\n return new _FtInputfieldTinyMCEInline.FtInputfieldTinyMCEInline(langInputfieldContainer);\n case (0, _FtInputfieldTextarea.FtIsInputfieldTextarea)(langInputfieldContainer):\n return new _FtInputfieldTextarea.FtInputfieldTextarea(langInputfieldContainer);\n case (0, _FtInputfieldText.FtIsInputfieldText)(langInputfieldContainer):\n return new _FtInputfieldText.FtInputfieldText(langInputfieldContainer);\n default:\n console.warn('Fluency does not recognize this inputfield, translation is not available', langInputfieldContainer);\n return null;\n }\n };\n\n /**\n * This sets a mutation observer on the main content area of the edit page that will initialize\n * new fields that may be added on focus or triggered by AJAX actions\n *\n * @return {void}\n */\n const initInputfieldsOnInsertion = () => {\n const parentNode = document.getElementById('pw-content-body');\n new MutationObserver((mutations, observer) => {\n for (let mutation of mutations) {\n let targetEl = mutation.target;\n const foundEls = targetEl.querySelectorAll(langInputfieldClass);\n if (foundEls.length) {\n initInputfields(foundEls);\n }\n }\n }).observe(parentNode, {\n childList: true,\n subtree: true\n });\n };\n\n /**\n * Initializes page name fields. Must be initialized separately since they do not\n * follow the structure of other inputfields\n * @return {void}\n */\n const initPageNameInputfields = () => {\n const pageNameInputfields = document.querySelectorAll('.InputfieldPageName');\n [...pageNameInputfields].forEach(pageNameInputfield => {\n if (pageNameInputfield && !fieldIsInitialized(pageNameInputfield)) {\n let inputfield = new _FtInputfieldPageName.default(pageNameInputfield);\n setFieldIsInitialized(pageNameInputfield);\n if (!inputfield) {\n return;\n }\n }\n });\n };\n\n /**\n * Checks if a given field has been initialized\n * @param {DOMNode} langInputfieldContainer Container element for multi-language field\n * @return {bool}\n */\n const fieldIsInitialized = langTabContainer => langTabContainer.hasAttribute(_FtConfig.default.fieldInitializedAttr) || !!langTabContainer.querySelector('.ft-translate-button');\n\n /**\n * Marks a field as initialized by adding a data attribute to the container\n * @param {DOMNode} langTabContainer Container element for multi-language field\n * @return {void}\n */\n const setFieldIsInitialized = langTabContainer => langTabContainer.setAttribute(_FtConfig.default.fieldInitializedAttr, '');\n\n /**\n * This updates the value of an input element such as text or textarea\n * When a field is updated it must be blurred so that it is recognized as having been changed and\n * the \"unsaved changes\" alert will be shown if navigating away from a page without saving\n * @param {HTMLElement} inputEl Element\n * @param {string} value\n * @return {void}\n */\n const updateValue = (inputEl, value) => {\n inputEl.focus();\n inputEl.value = value;\n inputEl.blur();\n };\n return {\n init,\n updateValue,\n fieldIsInitialized\n };\n}();\nvar _default = FtInputfields;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3,\"../global/FtTools\":4,\"./FtInputfieldCKEditor\":5,\"./FtInputfieldCKEditorInline\":6,\"./FtInputfieldPageName\":7,\"./FtInputfieldTable\":8,\"./FtInputfieldText\":9,\"./FtInputfieldTextarea\":10,\"./FtInputfieldTinyMCE\":11,\"./FtInputfieldTinyMCEInline\":12}],14:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates, inserts, and controls the actions the activity overlay for the provided\n * targetContainer\n * @param {object} targetContainer An instantiated object for an inputfield or fieldset\n * @param {string} type The type of activity for this overlay. 'translate' or 'update'\n */\nconst FtActivityOverlay = function (targetContainer) {\n var _this = this;\n let activityType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'translating';\n const elClasses = {\n parent: 'ft-activity-overlay-container',\n overlay: 'ft-activity-overlay',\n error: 'error',\n message: 'message',\n flash: 'flash',\n success: 'success',\n activity: 'activity',\n visible: 'visible',\n activityContainer: 'ft-activity',\n activityStaticText: 'ft-activity-text',\n activityAnimationContainer: 'ft-activity-animation-container',\n activityAnimationItem: 'ft-activity-animation-item',\n messageContainer: 'ft-activity-message'\n };\n\n /**\n * Will contain the activityOverlay Element for this targetContainer\n * @type {Element}\n */\n let activityOverlay;\n\n /**\n * Will contain the message Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let messageContainer;\n\n /**\n * Will contain the animation container Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let activityContainer;\n\n /**\n * Control Methods\n */\n\n /**\n * This shows the overlay's activity animation that was created at instantiation\n * Must be manually hidden with the hide() method\n *\n * @return {void}\n */\n this.showActivity = () => {\n this.setActivityActive();\n this.setOverlayVisible();\n };\n\n /**\n * Shows a message in the overlay (neutral background)\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showMessage = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;\n _this.setMessageContent(message);\n _this.setActivityInactive();\n _this.setMessageActive();\n _this.setOverlayVisible();\n _this.hide(displayTime);\n };\n\n /**\n * Shows a success message (success color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashSuccess = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setSuccessActive();\n _this.setFlashActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows a success message (error color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setFlashActive();\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows an error message in a visible overlay (error background)\n *\n * @param {String} message Message to show in overlay error\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 7000;\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Hide an overlay immediately or after a preset amount of time\n *\n * @param {Number} delay Length of time in ms before hiding overlay\n */\n this.hide = function () {\n let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n setTimeout(() => {\n _this.setOverlayInvisible();\n }, delay);\n\n // Ensures the animation is finished before modifying content\n setTimeout(() => {\n _this.setActivityInactive();\n _this.setMessageInactive();\n _this.setErrorInactive();\n _this.setFlashInactive();\n _this.setMessageContent('');\n }, delay + 500);\n };\n\n /**\n * Private Methods\n */\n\n /**\n * Shows the activity element\n *\n * @access Private\n */\n this.setActivityActive = () => {\n activityOverlay.classList.add(elClasses.activity);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setActivityInactive = () => {\n activityOverlay.classList.remove(elClasses.activity);\n };\n\n /**\n * Shows the message element\n *\n * @access Private\n */\n this.setMessageActive = () => {\n activityOverlay.classList.add(elClasses.message);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setMessageInactive = () => {\n activityOverlay.classList.remove(elClasses.message);\n };\n\n /**\n * Sets the content of the overlay message\n *\n * @access Private\n */\n this.setMessageContent = content => {\n messageContainer.innerText = content;\n };\n\n /**\n * Adds flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashActive = content => {\n activityOverlay.classList.add(elClasses.flash);\n };\n\n /**\n * removes flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashInactive = content => {\n activityOverlay.classList.remove(elClasses.flash);\n };\n\n /**\n * Sets message to success\n *\n * @access Private\n */\n this.setSuccessActive = () => {\n activityOverlay.classList.add(elClasses.success);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setSuccessInactive = () => {\n activityOverlay.classList.remove(elClasses.success);\n };\n\n /**\n * Sets message to error\n *\n * @access Private\n */\n this.setErrorActive = () => {\n activityOverlay.classList.add(elClasses.error);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setErrorInactive = () => {\n activityOverlay.classList.remove(elClasses.error);\n };\n\n /**\n * Shows this activity overlay\n *\n * @access Private\n */\n this.setOverlayVisible = () => {\n activityOverlay.classList.add(elClasses.visible);\n };\n this.setOverlayInvisible = () => {\n activityOverlay.classList.remove(elClasses.visible);\n };\n\n /**\n * Creates and returns an activity overlay element\n *\n * @return {HTMLElement}\n */\n this.create = () => {\n activityOverlay = this.buildOverlayEl();\n activityContainer = this.buildActivityEl();\n messageContainer = this.buildMessageEl();\n activityOverlay.appendChild(activityContainer);\n activityOverlay.appendChild(messageContainer);\n return activityOverlay;\n };\n\n /**\n * Creates the parent overlay element\n *\n * @return {Element}\n * @access Private\n */\n this.buildOverlayEl = () => {\n const overlay = document.createElement('div');\n\n // overlay.setAttribute('data-gradient-1', 'rgba(62, 185, 152, .85)');\n overlay.setAttribute('class', elClasses.overlay);\n return overlay;\n };\n\n /**\n * Creates container for animation and contents of animation\n *\n * @return {Element}\n * @access Private\n */\n this.buildActivityEl = () => {\n let text = _FtConfig.default.getUiTextFor('activityOverlay')[activityType];\n let activityAnimationContainer = document.createElement('div');\n activityAnimationContainer.setAttribute('class', elClasses.activityAnimationContainer);\n\n // Add all animation items to the animation container\n activityAnimationContainer = text.animated.reduce((el, string) => {\n let activityText = document.createElement('span');\n\n // Add text items\n activityText.setAttribute('class', elClasses.activityAnimationItem);\n activityText.innerHTML = string;\n el.appendChild(activityText);\n return el;\n }, activityAnimationContainer);\n\n // Create static text element\n let staticText = document.createElement('div');\n staticText.setAttribute('class', elClasses.activityStaticText);\n staticText.innerText = text.static;\n\n // Create activity container and append children\n activityContainer = document.createElement('div');\n activityContainer.setAttribute('class', elClasses.activityContainer);\n activityContainer.appendChild(staticText);\n activityContainer.appendChild(activityAnimationContainer);\n return activityContainer;\n };\n\n /**\n * Builds the element that will hold messages in the overlay\n *\n * @return {Element}\n * @access Private\n */\n this.buildMessageEl = () => {\n messageContainer = document.createElement('div');\n messageContainer.setAttribute('class', elClasses.messageContainer);\n return messageContainer;\n };\n (() => {\n const targetContainerContainer = targetContainer.getSelf();\n activityOverlay = this.create();\n targetContainerContainer.classList.add(elClasses.parent);\n targetContainerContainer.appendChild(activityOverlay);\n })();\n};\nvar _default = FtActivityOverlay;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3}],15:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * Handles modifying the Fluency menu item\n * @return {object} Public methods\n */\nconst FtAdminMenu = function () {\n /**\n * Initializes module\n * @return {void}\n */\n const init = () => {\n convertFtAdminMenuToModal();\n };\n\n /**\n * Finds and converts the Translation admin menu item to open in a modal\n * rather than navigating to the page.\n * @return {void}\n */\n const convertFtAdminMenuToModal = () => {\n const adminNavItems = document.querySelectorAll('.pw-masthead .pw-primary-nav > li > a'),\n urlParams = new URLSearchParams(window.location.search);\n\n // We don't want to modify this menu item if we are on the Fluency config page\n // because the modal behavior is not available\n if (urlParams.get('name') === 'Fluency') {\n return false;\n }\n adminNavItems.forEach((el, i) => {\n let hrefSegments = el.href.split('/').filter(Boolean);\n if (hrefSegments[hrefSegments.length - 1].includes('fluency')) {\n el.href = el.href + '?modal=1';\n el.classList.add('pw-modal-large');\n el.classList.add('pw-modal');\n }\n });\n };\n return {\n init: init\n };\n}();\nvar _default = FtAdminMenu;\nexports.default = _default;\n\n},{}],16:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nvar _FtUiElements = _interopRequireDefault(require(\"./FtUiElements\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * The translate button establishes the UI element used to trigger translations\n * by the user. It manages the translation process by displaying/hiding the\n * activity overlay, showing messages and errors, getting translations from\n * the Fluency API, and modifying content. This is done by manipulating the\n * inputfield and activityOverlay objects passed.\n */\n\nconst FtInputfieldTranslateButton = function (inputfield, inputContainers) {\n let forceEachTranslationAction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n /**\n * Gets all localized strings from the FluencyConfig object\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Adds translate elements to inputfield containers\n * @param {string|int} languageId ProcessWire language ID\n * @param {Element} inputContainer Inputcontainer for this language\n * @return {void}\n */\n this.addTranslateElements = (languageId, inputContainer) => {\n const isTranslatable = _FtConfig.default.languageIsTranslatable(languageId);\n const isDefaultLanguage = languageId == _FtConfig.default.getDefaultLanguage().id;\n\n // Translatable, not default language\n if (isTranslatable && !isDefaultLanguage) {\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translateButton);\n this.bindButton(button, _FtConfig.default.getLanguageForId(languageId));\n inputContainer.appendChild(container);\n }\n\n // Translatable, default language\n if (isTranslatable && isDefaultLanguage) {\n inputContainer.appendChild(_FtUiElements.default.createStatusElement(uiText.translationAvailable));\n }\n\n // Not translatable\n if (!isTranslatable) {\n inputContainer.appendChild(_FtUiElements.default.createStatusElement(uiText.languageNotAvailable));\n }\n };\n\n /**\n * Binds a button for translation\n * @param {Element} buttonElement Element to bind translation action to\n * @param {Object} languageConfig Fluency language configuration object\n * @return {Void}\n */\n this.bindButton = (buttonElement, languageConfig) => {\n buttonElement.addEventListener('click', e => {\n e.preventDefault();\n const translationSourceContent = inputfield.getValueForDefaultLanguage();\n if (!translationSourceContent) {\n return;\n }\n\n // Try to get the inputfield activity overlay, fall back to retrieving by language ID where\n // the inputfield element can delegate to a specific activity overlay located within it\n const activityOverlay = inputfield.getActivityOverlay() ?? inputfield.getActivityOverlay(languageConfig.id);\n activityOverlay.showActivity();\n _Fluency.default.getTranslation(_FtConfig.default.getDefaultLanguage().engineLanguage.sourceCode, languageConfig.engineLanguage.targetCode, translationSourceContent).then(result => {\n if (result.error) {\n inputfield.getActivityOverlay().showError(result.message);\n return;\n }\n inputfield.setValueForLanguage(languageConfig.id, result.translations[0]);\n activityOverlay.hide();\n });\n });\n };\n\n /**\n * Creates the \"Translate to all\" button and adds it to the inputfield\n *\n * @param {int} sourceLanguageId ProcessWire language ID\n * @param {HTMLElements} inputContainers All language input containers for this inputfield\n * @return {void}\n */\n this.addTranslateToAllButton = (sourceLanguageId, inputContainers) => {\n const sourceInputContainer = inputContainers[sourceLanguageId];\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translateToAllButton);\n this.bindTranslateToAllButton(button, _FtConfig.default.getLanguageForId(sourceLanguageId), inputContainers);\n sourceInputContainer.appendChild(container);\n };\n\n /**\n * Binds translation action to button that translates to all other languages\n *\n * @param {Element} buttonElement [description]\n * @param {object} sourceLanguageConfig The FtConfig object for the source language\n * @param {HTMLElements} inputContainers All language input containers for this inputfield\n * @return {void}\n */\n this.bindTranslateToAllButton = (buttonElement, sourceLanguageConfig, inputContainers) => {\n buttonElement.addEventListener('click', e => {\n e.preventDefault();\n const translationSourceContent = inputfield.getValueForLanguage(sourceLanguageConfig.id);\n\n // Do not translate if there's no source content or risk content in other languages to\n // be removed\n if (!translationSourceContent) {\n return;\n }\n\n // Used to count the number of languages left when translating to all\n let translationLanguageCount = Object.keys(inputContainers).length;\n let errorOccurred = false;\n let activityOverlay = inputfield.getActivityOverlay();\n activityOverlay.showActivity();\n for (let targetLanguageId in inputContainers) {\n // No need to translate self\n if (targetLanguageId === sourceLanguageConfig.id) {\n continue;\n }\n let targetLanguageConfig = _FtConfig.default.getLanguageForId(targetLanguageId);\n _Fluency.default.getTranslation(sourceLanguageConfig.engineLanguage.sourceCode, targetLanguageConfig.engineLanguage.targetCode, translationSourceContent).then(result => {\n if (result.error) {\n // Only show the error overlay if an error has not already occurred\n if (!errorOccurred) {\n inputfield.getActivityOverlay().showError(result.message);\n }\n errorOccurred = true;\n return;\n }\n inputfield.setValueForLanguage(targetLanguageConfig.id, result.translations[0]);\n }).then(result => {\n translationLanguageCount--;\n\n // If an error occurred, messaging/overlay will be handled by the error process\n if (translationLanguageCount === 0 && !errorOccurred) {\n activityOverlay.hide();\n }\n });\n }\n });\n };\n\n /**\n * Init on object instantiation\n */\n (() => {\n for (let languageId in inputContainers) {\n if (_FtConfig.default.getTranslationAction() === _FtConfig.default.translationActionTypes.all && !forceEachTranslationAction) {\n this.addTranslateToAllButton(languageId, inputContainers);\n }\n if (_FtConfig.default.getTranslationAction() === _FtConfig.default.translationActionTypes.each || forceEachTranslationAction) {\n this.addTranslateElements(languageId, inputContainers[languageId]);\n }\n }\n })();\n};\nvar _default = FtInputfieldTranslateButton;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4,\"./FtUiElements\":18}],17:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * A stateful function handling behaviors for a language tab associated with a input container\n * contained within an Inputfield. An \"input container\" is the div that contains the label and\n * input/textarea/element (depending on Inputfield type) for a language\n * @param {Element} inputContainer Language\n */\nconst FtLanguageTab = function (inputContainer) {\n /**\n * Note\n * @type {String}\n */\n const contentModifiedClass = 'ft-content-changed';\n\n /**\n * Cached associated tab for this input container\n * @type {Element}\n */\n let languageTab = null;\n this.getContentModifiedClass = () => contentModifiedClass;\n\n /**\n * Sets state of tab\n * @param {bool} modified Determines state of tab display\n * @return {void}\n */\n this.setModifiedState = modified => modified ? this.setTabModified() : this.setTabUnmodified();\n this.setTabModified = () => this.getLanguageTab().classList.add(contentModifiedClass);\n this.setTabUnmodified = () => this.getLanguageTab().classList.remove(contentModifiedClass);\n this.getLanguageTab = () => {\n return languageTab ?? inputContainer.closest('.langTabs').querySelector(`.langTabLink[data-lang=\"${inputContainer.dataset.language}\"`);\n };\n\n /**\n * Init method executed on object instantiation\n * @return {void}\n */\n (() => {\n if (!inputContainer) {\n return false;\n }\n languageTab = this.getLanguageTab();\n })();\n};\nvar _default = FtLanguageTab;\nexports.default = _default;\n\n},{}],18:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates common HTML elements\n *\n * @return {Object} Public methods\n */\nconst FtUiElements = function () {\n /**\n * @type {Object}\n */\n const elementClasses = _FtConfig.default.elementClasses;\n\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Creates a language fontawesome icon element\n *\n * @return {Element}\n */\n const createIcon = () => {\n const iconLink = document.createElement('a');\n iconLink.setAttribute('href', `${ProcessWire.config.urls.admin}fluency/?modal=1`);\n iconLink.setAttribute('class', 'pw-modal pw-modal-large');\n const icon = document.createElement('i');\n icon.setAttribute('class', `${_FtConfig.default.getElementClassesFor('icon')} fa fa-language`);\n icon.setAttribute('uk-tooltip', uiText.showTranslator);\n iconLink.appendChild(icon);\n return iconLink;\n };\n\n /**\n * Creates a status placeholder\n *\n * @return {Element}\n */\n const createStatusElement = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('statusPlaceholder');\n const label = document.createElement('span');\n label.setAttribute('class', elClasses.label);\n label.innerText = text;\n const container = document.createElement('div');\n container.setAttribute('class', elClasses.container);\n container.appendChild(createIcon());\n container.appendChild(label);\n return container;\n };\n\n /**\n * Creates a translate button element\n *\n * @return {Object} Container element and Button element\n */\n const createTranslateButton = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('translateButton');\n const button = document.createElement('a');\n button.innerText = text;\n button.setAttribute('class', elClasses.button);\n button.setAttribute('href', '');\n const container = document.createElement('div');\n container.setAttribute('class', elClasses.container);\n container.appendChild(createIcon());\n container.appendChild(button);\n return {\n button,\n container\n };\n };\n const createTranslateAllButton = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('translateAllButton');\n const button = document.createElement('a');\n button.innerText = _FtConfig.default.getUiTextFor('languageTranslator').translateAllButton;\n button.setAttribute('class', elClasses.button);\n button.setAttribute('href', '');\n const content = document.createElement('div');\n content.setAttribute('class', elClasses.content);\n content.appendChild(button);\n const container = document.createElement('li');\n container.setAttribute('class', elClasses.container);\n container.appendChild(content);\n return {\n button,\n container\n };\n };\n return {\n createStatusElement,\n createTranslateButton,\n createTranslateAllButton,\n createIcon,\n elementClasses\n };\n}();\nvar _default = FtUiElements;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4}]},{},[1]);\n"],"names":["r","e","n","t","o","i","f","c","require","u","a","Error","code","p","exports","call","length","1","module","_FtInputfields","_interopRequireDefault","_FtAdminMenu","_FtConfig","obj","__esModule","default","window","addEventListener","moduleShouldInitialize","init","./global/FtConfig","./inputfields/FtInputfields","./ui/FtAdminMenu","2","Object","defineProperty","value","Fluency","errors","getUiTextFor","requestHeaders","requestType","X-Requested-With","getRequest","endpoint","responseHandler","fetch","method","cache","headers","then","parseResponse","catch","handleFetchError","deleteRequest","response","status","ok","json","error","console","message","returnObject","split","deleteTranslatableLanguagesCache","getApiEndpointFor","deleteTranslationCache","getAvailableLanguages","getTranslation","sourceLanguage","targetLanguage","content","let","options","arguments","undefined","caching","data","body","JSON","stringify","getUsage","./FtConfig","3","FtConfig","config","ProcessWire","fluency","localizedStrings","localization","elementClasses","translateButton","container","button","translateAllButton","statusPlaceholder","label","icon","strings","activityOverlay","languageSelect","inputfieldTranslateButtons","standaloneTranslator","usage","languageTranslator","endpoints","languages","apiEndpoints","translatableLanguagesCache","test","translation","translationCache","configuredLanguages","unconfiguredLanguages","getConfiguredLanguages","getUnconfiguredLanguages","getEngineInfo","engine","fieldInitializedAttr","key","getDefaultLanguage","reduce","defaultLang","lang","getElementClassesFor","element","getEngineProvidesUsageData","providesUsageData","getLanguageCount","getLanguageForId","pwLanguageId","parseInt","match","language","id","getTranslationAction","interface","inputfieldTranslationAction","languageIsTranslatable","languageId","includes","translationActionTypes","each","all","4","getPageId","urlParams","URLSearchParams","location","search","get","tagElement","text","addRandomId","tagDiv","document","createElement","setAttribute","Array","map","Math","random","toString","join","innerText","appendChild","pageIdIs","5","FtIsInputfieldCKEditor","FtInputfieldCKEditor","_FtActivityOverlay","_FtInputfieldTranslateButton","_FtLanguageTab","inputfield","querySelector","initValues","changedValues","languageTabs","inputContainers","editorInstances","defaultLanguageInstanceId","this","getActivityOverlay","getSelf","getValueForDefaultLanguage","getValueForLanguage","getEditorInstanceForLanguage","getData","setValueForLanguage","instance","setData","fire","contentHasChanged","ckeditorSelector","hasOwn","createCKEditorSelector","CKEDITOR","instances","getInputContainers","querySelectorAll","forEach","el","dataset","registerInputEventListener","on","setModifiedState","allInputContainers","values","replace","inputContainer","../global/FtConfig","../ui/FtActivityOverlay","../ui/FtInputfieldTranslateButton","../ui/FtLanguageTab","./FtInputfields","6","FtIsInputfieldCKEditorInline","FtInputfieldCKEditorInline","contentElements","ckeditorInstance","getContentElementForLanguage","innerHTML","contentElement","setValue","dispatchEvent","Event","getInputContainerForLanguage","keys","registerUpdateEvent","MutationObserver","mutations","observer","mutation","target","observe","childList","7","createActivityOverlay","languageInput","languageFields","contentModifiedClass","getContentModifiedClass","activityOverlays","getFieldForLanguage","field","updateValue","name","classList","add","remove","8","FtIsInputfieldTable","isInputfieldTable","isInputfieldTableRow","contains","tagName","9","FtIsInputfieldText","FtInputfieldText","10","FtIsInputfieldTextarea","FtInputfieldTextarea","11","FtIsInputfieldTinyMCE","FtInputfieldTinyMCE","textareas","tinymceInstance","getTinymceInstanceForLanguage","getContent","getTextareaForLanguage","setContent","tinymceSelector","createTinymceSelector","tinymce","bindTinymceEvents","initTinymceInstanceOnCreation","disconnect","initAll","setTimeout","12","FtIsInputfieldTinyMCEInline","FtInputfieldTinyMCEInline","13","_FtInputfieldCKEditor","_FtInputfieldCKEditorInline","_FtInputfieldTable","_FtInputfieldText","_FtInputfieldTextarea","_FtInputfieldTinyMCE","_FtInputfieldTinyMCEInline","_FtInputfieldPageName","FtInputfields","langInputfieldClass","initInputfields","langInputfieldContainers","langInputfieldContainer","initInputfield","fieldIsInitialized","closest","warn","setFieldIsInitialized","langTabContainer","hasAttribute","parentNode","getElementById","foundEls","subtree","pageNameInputfield","inputEl","focus","blur","../global/FtTools","./FtInputfieldCKEditor","./FtInputfieldCKEditorInline","./FtInputfieldPageName","./FtInputfieldTable","./FtInputfieldText","./FtInputfieldTextarea","./FtInputfieldTinyMCE","./FtInputfieldTinyMCEInline","14","targetContainer","_this","activityType","elClasses","parent","overlay","flash","success","activity","visible","activityContainer","activityStaticText","activityAnimationContainer","activityAnimationItem","messageContainer","showActivity","setActivityActive","setOverlayVisible","showMessage","displayTime","setMessageContent","setActivityInactive","setMessageActive","hide","flashSuccess","setSuccessActive","setFlashActive","flashError","setErrorActive","showError","delay","setOverlayInvisible","setMessageInactive","setErrorInactive","setFlashInactive","setSuccessInactive","create","buildOverlayEl","buildActivityEl","buildMessageEl","animated","string","activityText","staticText","static","targetContainerContainer","15","convertFtAdminMenuToModal","adminNavItems","hrefSegments","href","filter","Boolean","16","_Fluency","_FtUiElements","forceEachTranslationAction","uiText","addTranslateElements","isTranslatable","isDefaultLanguage","createTranslateButton","bindButton","createStatusElement","translationAvailable","languageNotAvailable","buttonElement","languageConfig","preventDefault","translationSourceContent","engineLanguage","sourceCode","targetCode","result","translations","addTranslateToAllButton","sourceLanguageId","sourceInputContainer","translateToAllButton","bindTranslateToAllButton","sourceLanguageConfig","translationLanguageCount","errorOccurred","targetLanguageId","targetLanguageConfig","../global/Fluency","./FtUiElements","17","languageTab","modified","setTabModified","setTabUnmodified","getLanguageTab","18","FtUiElements","createIcon","iconLink","urls","admin","showTranslator","createTranslateAllButton"],"mappings":"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"} \ No newline at end of file diff --git a/assets/scripts/maps/fluency_language_translator.bundle.js.map b/assets/scripts/maps/fluency_language_translator.bundle.js.map index 75ca709..2b60ab0 100644 --- a/assets/scripts/maps/fluency_language_translator.bundle.js.map +++ b/assets/scripts/maps/fluency_language_translator.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"../fluency_language_translator.bundle.js","sources":["fluency_language_translator.bundle.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i {\n if (_FtConfig.default.moduleShouldInitialize()) {\n _FtLanguageTranslatorInputfields.default.init();\n }\n});\n\n},{\"./global/FtConfig\":3,\"./inputfields/FtLanguageTranslatorInputfields\":5}],2:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"./FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Core module interface\n * Handles all interaction with the ProcessWire module backend\n * @return {object} Public interfaces\n */\n\nconst Fluency = function () {\n /**\n * Localized error strings\n * @type {Object}\n */\n const errors = _FtConfig.default.getUiTextFor('errors');\n\n /**\n * Data Request Methods\n */\n\n /**\n * Gets a translation from the Fluency module\n * @param {String} sourceLanguage ISO language code\n * @param {String} targetLanguage ISO langauge code\n * @param {String|Array} content Content to translate\n * @param {Array} options Additional options\n * @param {Bool|null} caching Enable/disable caching\n * @return {Promise}\n */\n const getTranslation = function (sourceLanguage, targetLanguage, content) {\n let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];\n let caching = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;\n return postRequest(_FtConfig.default.getApiEndpointFor('translation'), {\n sourceLanguage: sourceLanguage,\n targetLanguage: targetLanguage,\n content: content,\n options: options,\n caching: caching\n }, response => {\n return response;\n });\n };\n\n /**\n * Gets the current translation service API usage\n * @return {Promise}\n */\n const getUsage = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('usage'), response => {\n return response;\n });\n };\n\n /**\n * Get all language available for translation. Provides source/target lists from the translation\n * service API\n * @return {Promise}\n */\n const getAvailableLanguages = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('languages'), response => {\n return response;\n });\n };\n\n /**\n * Clear all cached translations\n * @return {Promise}\n */\n const deleteTranslationCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translationCache'), response => {\n return response;\n });\n };\n\n /**\n * Clear cached list of translatable languages\n * @return {Promise}\n */\n const deleteTranslatableLanguagesCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translatableLanguagesCache'), response => {\n return response;\n });\n };\n\n /**\n * HTTP Requests\n */\n\n /**\n * Create headers for AJAX requests\n * @return {Object}\n */\n const requestHeaders = requestType => {\n const requestHeaders = {\n 'X-Requested-With': 'XMLHttpRequest'\n };\n if (requestType === 'GET') {\n requestHeaders['Accept'] = 'application/json';\n }\n if (requestType === 'POST') {\n requestHeaders['Content-Type'] = 'application/json';\n }\n return requestHeaders;\n };\n\n /**\n * Executes a POST request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Object} data Data for request\n * @param {Callable} data Function to handle response body\n * @return {Promise}\n */\n const postRequest = (endpoint, data, responseHandler) => {\n return fetch(endpoint, {\n method: 'POST',\n cache: 'no-store',\n headers: requestHeaders,\n body: JSON.stringify(data)\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a GET request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const getRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'GET',\n cache: 'no-store',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a DELETE request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const deleteRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'DELETE',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Parses response\n * @param {Object} response Fluency API response\n * @return {Object|Void}\n * @throws Error\n */\n const parseResponse = response => {\n if (response.status === 204) {\n return response;\n }\n if (response.ok) {\n return response.json();\n }\n throw new Error();\n };\n\n /**\n * Parses and returns results for a fetch error\n * These are network level errors that occur between ProcessWire and the hosting server\n * Any translation or service errors will be located within the response body itself\n * @param {Error} error Fetch API error object\n * @return {Object}\n */\n const handleFetchError = error => {\n console.error('[Fluency module API failure]', error.message);\n const returnObject = {\n error: null,\n message: null\n };\n switch (error.message.split(' ')[0]) {\n case 'NetworkError':\n returnObject.error = 'FLUENCY_CLIENT_DISCONNECTED';\n returnObject.message = errors['FLUENCY_CLIENT_DISCONNECTED'];\n break;\n default:\n returnObject.error = 'UNKNOWN_ERROR';\n returnObject.message = errors['UNKNOWN_ERROR'];\n break;\n }\n return returnObject;\n };\n return {\n deleteTranslatableLanguagesCache,\n deleteTranslationCache,\n getAvailableLanguages,\n getTranslation,\n getUsage\n };\n}();\nvar _default = Fluency;\nexports.default = _default;\n\n},{\"./FtConfig\":3}],3:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * This provides access methods to get module configuration values\n * @return {Object} Public methods\n */\nconst FtConfig = function () {\n // Public properties\n\n const fieldInitializedAttr = 'data-ft-initialized';\n\n // Private properties\n\n /**\n * Holds the data passed from the Fluency module\n * @access Private\n * @type {Object}\n */\n const config = ProcessWire.config.fluency;\n\n /**\n * All UI strings\n * @type {Object}\n */\n const localizedStrings = config.localization;\n\n /**\n * Objects interface with the Fluency config object so that changes to the object\n * structure from the back end do not break the UI. Use the public methods below\n * to access ProcessWire.config.fluency properties and data\n */\n\n /**\n * Localized strings keyed sets\n * @type {Object}\n */\n const strings = {\n activityOverlay: localizedStrings.activityOverlay,\n languageSelect: localizedStrings.languageSelect,\n inputfieldTranslateButtons: localizedStrings.inputfieldTranslateButtons,\n standaloneTranslator: localizedStrings.standaloneTranslator,\n usage: localizedStrings.usage,\n errors: localizedStrings.errors\n };\n\n /**\n * Fluency API keyed URLs\n * @type {Object}\n */\n const endpoints = {\n languages: config.apiEndpoints.languages,\n translatableLanguagesCache: config.apiEndpoints.translatableLanguagesCache,\n test: config.apiEndpoints.test,\n translation: config.apiEndpoints.translation,\n translationCache: config.apiEndpoints.translationCache,\n usage: config.apiEndpoints.usage\n };\n\n /**\n * Contains all of the Fluency configured langauges from the module\n * @type {Array}\n */\n const configuredLanguages = config.configuredLanguages;\n\n /**\n * Contains an array of ProcessWire language IDs not configured in Fluency\n * @type {Array}\n */\n const unconfiguredLanguages = config.unconfiguredLanguages;\n\n // Public methods\n\n /**\n * Fluency REST API\n */\n const getApiEndpointFor = key => endpoints[key];\n\n /**\n * Languages\n */\n\n const getConfiguredLanguages = () => configuredLanguages;\n const getDefaultLanguage = () => getConfiguredLanguages().reduce((defaultLang, lang) => lang.default ? lang : defaultLang, null);\n const languageIsTranslatable = languageId => !getUnconfiguredLanguages().includes(parseInt(languageId, 10));\n const getUnconfiguredLanguages = () => unconfiguredLanguages;\n const getLanguageCount = () => getConfiguredLanguages().length + getUnconfiguredLanguages().length;\n const getLanguageForId = pwLanguageId => {\n pwLanguageId = parseInt(pwLanguageId, 10);\n return getConfiguredLanguages().reduce((match, language) => language.id === pwLanguageId ? language : match, null);\n };\n\n /**\n * Localization\n */\n\n const getUiTextFor = key => strings[key];\n\n /**\n * Module Configuration/State\n */\n\n const moduleShouldInitialize = () => getConfiguredLanguages().length > 1;\n const getEngineInfo = () => config.engine;\n const getEngineProvidesUsageData = () => getEngineInfo().providesUsageData;\n const getInputfieldTranslationAction = () => config.interface.inputfieldTranslationAction;\n return {\n fieldInitializedAttr,\n getApiEndpointFor,\n getConfiguredLanguages,\n getDefaultLanguage,\n getEngineInfo,\n getEngineProvidesUsageData,\n getInputfieldTranslationAction,\n getLanguageCount,\n getLanguageForId,\n getUiTextFor,\n getUnconfiguredLanguages,\n languageIsTranslatable,\n moduleShouldInitialize\n };\n}();\nvar _default = FtConfig;\nexports.default = _default;\n\n},{}],4:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * These are common tools the Fluency translation module uses\n * It is loaded first in order of scripts added to the page so that the module\n * is available to all subsequent scripts\n *\n * @return {Object} Public methods\n */\nconst FtTools = function () {\n /**\n * Create a random string of hex characters\n * @param {Number} length\n * @return {String}\n */\n const randomHex = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6;\n const chars = '0123456789ABCDEF'.split('');\n [...Array(length)].reduce((hex, i) => hex = chars[Math.floor(Math.random() * chars.length)], '');\n };\n\n /**\n * Generate random string of upper/lower/ints\n * @param length\n * @return string\n */\n const createRandomString = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5;\n return [...Array(length)].map(() => Math.random().toString(36)[2]).join('');\n };\n\n /**\n * Appends a div to a given element with a defined string, optionally adds a unique\n * string in case differentiating between more than one with the same text is\n * needed\n * @param {Element} element Element to tag\n * @param {String} text Text for tag\n * @param {Boolean} addRandomId Add random ID string to tag\n * @return {Void}\n */\n const tagElement = function (element, text) {\n let addRandomId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n const tagDiv = document.createElement('div');\n tagDiv.setAttribute('class', 'ft-element-tag');\n if (addRandomId) {\n text += ' | ' + createRandomString();\n }\n tagDiv.innerText = text;\n element.appendChild(tagDiv);\n };\n\n /**\n * Creates a random HTML hex code\n * @return {String} [description]\n */\n const randomHexColor = () => `#${randomHex()}`;\n\n /**\n * Gets the page ID from the current URL\n * @return {int|null} Page ID number, null if not present\n */\n var getPageId = function () {\n var urlParams = new URLSearchParams(window.location.search);\n return urlParams ? parseInt(urlParams.get('id')) : null;\n };\n\n /**\n * Checks page ID against page ID passed\n * @param {int} id ID to check against\n * @return {bool} True/false whether is current page ID\n */\n const pageIdIs = id => getPageId() === id;\n return {\n tagElement,\n getPageId,\n pageIdIs\n };\n}();\nvar _default = FtTools;\nexports.default = _default;\n\n},{}],5:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.LanguageTranslatorInputfield = exports.FtInputfieldText = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtUiElements = _interopRequireDefault(require(\"../ui/FtUiElements\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Used for creating translation function for ProcessWire's core language translation pages\n *\n * @return {Object} Public methods\n */\nconst FtLanguageTranslatorInputfields = function () {\n const init = () => {\n const translationInputfields = document.querySelectorAll('.InputfieldContent');\n if (!translationInputfields) {\n return;\n }\n [...translationInputfields].forEach(inputfield => {\n if (inputfield.querySelector('input.translatable')) {\n new LanguageTranslatorInputfield(inputfield);\n }\n });\n };\n return {\n init\n };\n}();\nconst LanguageTranslatorInputfield = function (inputfieldContainer) {\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n let activityOverlay;\n let sourceText = inputfieldContainer.querySelector('.description').innerText;\n let targetInput = inputfieldContainer.querySelector('input');\n this.getSelf = () => inputfieldContainer;\n this.getActivityOverlay = () => activityOverlay;\n this.addTranslateButton = () => {\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translate);\n this.bindTranslateButton(button);\n inputfieldContainer.appendChild(container);\n };\n this.bindTranslateButton = button => {\n button.addEventListener('click', e => {\n e.preventDefault();\n this.translateContent();\n });\n };\n this.translateContent = () => {\n const urlParams = new URLSearchParams(window.location.search);\n const id = parseInt(urlParams.get('language_id'));\n activityOverlay.showActivity();\n _Fluency.default.getTranslation(_FtConfig.default.getDefaultLanguage().engineLanguage.sourceCode, _FtConfig.default.getLanguageForId(id).engineLanguage.targetCode, sourceText).then(result => {\n if (result.error) {\n activityOverlay.showError(result.message);\n return;\n }\n targetInput.value = result.translations[0];\n activityOverlay.hide();\n });\n };\n (() => {\n activityOverlay = new _FtActivityOverlay.default(this);\n this.addTranslateButton();\n })();\n};\nexports.LanguageTranslatorInputfield = LanguageTranslatorInputfield;\nvar _default = FtLanguageTranslatorInputfields;\n/**\n * Handles IO operations for a multilanguage InputfieldText element\n * Language IDs are always converted to int to accept values from all sources since some may be\n * retrieved from various sources as a string\n *\n * NOTE: This is not a standard inputfield object and should not be instantiated in FtInputfields\n * and only in specific locations of the PW Admin\n *\n * @param {Element}\n */\nexports.default = _default;\nconst FtInputfieldText = function (inputfield) {\n /**\n * Page-load values for all fields/languages\n * Populated on object instantiation\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const initValues = {};\n\n /**\n * Will contain new values for fields/languages when content is modified\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const changedValues = {};\n\n /**\n * FtLanguageTab objects for each language\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageTabs = {};\n\n /**\n * Will contain all elements containing language inputs\n * @property {String} ProcessWire Language ID\n * @type {NodeList}\n */\n const inputContainers = {};\n\n /**\n * Text input fields\n * @property {String} ProcessWire Language ID\n * @type {Object}\n */\n const languageFields = {};\n\n /**\n * Activity overlay object, set on instantiation\n *\n * @access public\n * @type {Object}\n */\n let activityOverlay;\n\n /*\n * @access public\n * @return {Object}\n */\n this.getActivityOverlay = () => activityOverlay;\n\n /**\n * @access public\n * @return {Element} Inputfield element passed to this object on creation\n */\n this.getSelf = () => inputfield;\n\n /**\n * @access public\n * @return {Mixed}\n */\n this.getValueForDefaultLanguage = () => this.getValueForLanguage(_FtConfig.default.getDefaultLanguage().id);\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Mixed}\n */\n this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value;\n\n /**\n * @access public\n * @param {String|Int} languageId ProcessWire language ID\n * @param {Mixed} value Value to insert into field\n * @return {Bool} Content is different from page load value\n */\n this.setValueForLanguage = (languageId, value) => {\n const field = this.getFieldForLanguage(languageId);\n FtInputfields.updateValue(field, value);\n\n // Required to programmatically trigger the event listener for this field\n field.dispatchEvent(new Event('input'));\n return this.contentHasChanged(languageId);\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element} Text field\n */\n this.getFieldForLanguage = languageId => {\n if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) {\n return languageFields[languageId];\n }\n languageFields[languageId] = this.getInputContainerForLanguage(languageId).querySelector('input');\n return languageFields[languageId];\n };\n\n /**\n * Gets a specific input container\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Element}\n */\n this.getInputContainerForLanguage = languageId => {\n if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) {\n return inputContainers[languageId];\n }\n inputContainers[languageId] = inputfield.querySelector(`[data-language=\"${languageId}\"]`);\n return inputContainers[languageId];\n };\n\n /**\n * Get all input containers where content is entered, memoizes\n * @access private\n * @return {Object} All languages keyed by (int) language ID\n */\n this.getInputContainers = () => {\n inputfield.querySelectorAll('[data-language]').forEach(el => inputContainers[el.dataset.language] = el);\n return inputContainers;\n };\n\n /**\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Bool}\n */\n this.contentHasChanged = languageId => Object.hasOwn(changedValues, languageId) && changedValues[languageId] !== initValues[languageId];\n\n /**\n * Registers the event listener that watches for changes\n * @access private\n * @param {String|Int} languageId ProcessWire language ID\n * @return {Void}\n */\n this.registerInputEventListener = languageId => {\n this.getFieldForLanguage(languageId).addEventListener('input', e => {\n changedValues[languageId] = e.target.value;\n languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId));\n });\n };\n\n /**\n * Init method executed on object instantiation\n * - Stores initial field values for each langauge\n * - Creates/stores an FtLanguageTab object for each language\n * - Binds an event that detects changes on input\n * @return {Void}\n */\n (() => {\n const allInputContainers = this.getInputContainers();\n for (let languageId in allInputContainers) {\n let inputContainer = allInputContainers[languageId];\n initValues[languageId] = this.getValueForLanguage(languageId);\n languageTabs[languageId] = new FtLanguageTab(inputContainer);\n this.registerInputEventListener(languageId);\n }\n activityOverlay = new _FtActivityOverlay.default(this);\n new FtInputfieldTranslateButton(this, allInputContainers);\n })();\n};\nexports.FtInputfieldText = FtInputfieldText;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":6,\"../ui/FtUiElements\":7}],6:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates, inserts, and controls the actions the activity overlay for the provided\n * targetContainer\n * @param {object} targetContainer An instantiated object for an inputfield or fieldset\n * @param {string} type The type of activity for this overlay. 'translate' or 'update'\n */\nconst FtActivityOverlay = function (targetContainer) {\n var _this = this;\n let activityType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'translating';\n const elClasses = {\n parent: 'ft-activity-overlay-container',\n overlay: 'ft-activity-overlay',\n error: 'error',\n message: 'message',\n flash: 'flash',\n success: 'success',\n activity: 'activity',\n visible: 'visible',\n activityContainer: 'ft-activity',\n activityStaticText: 'ft-activity-text',\n activityAnimationContainer: 'ft-activity-animation-container',\n activityAnimationItem: 'ft-activity-animation-item',\n messageContainer: 'ft-activity-message'\n };\n\n /**\n * Will contain the activityOverlay Element for this targetContainer\n * @type {Element}\n */\n let activityOverlay;\n\n /**\n * Will contain the message Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let messageContainer;\n\n /**\n * Will contain the animation container Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let activityContainer;\n\n /**\n * Control Methods\n */\n\n /**\n * This shows the overlay's activity animation that was created at instantiation\n * Must be manually hidden with the hide() method\n *\n * @return {void}\n */\n this.showActivity = () => {\n this.setActivityActive();\n this.setOverlayVisible();\n };\n\n /**\n * Shows a message in the overlay (neutral background)\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showMessage = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;\n _this.setMessageContent(message);\n _this.setActivityInactive();\n _this.setMessageActive();\n _this.setOverlayVisible();\n _this.hide(displayTime);\n };\n\n /**\n * Shows a success message (success color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashSuccess = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setSuccessActive();\n _this.setFlashActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows a success message (error color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setFlashActive();\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows an error message in a visible overlay (error background)\n *\n * @param {String} message Message to show in overlay error\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 7000;\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Hide an overlay immediately or after a preset amount of time\n *\n * @param {Number} delay Length of time in ms before hiding overlay\n */\n this.hide = function () {\n let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n setTimeout(() => {\n _this.setOverlayInvisible();\n }, delay);\n\n // Ensures the animation is finished before modifying content\n setTimeout(() => {\n _this.setActivityInactive();\n _this.setMessageInactive();\n _this.setErrorInactive();\n _this.setFlashInactive();\n _this.setMessageContent('');\n }, delay + 500);\n };\n\n /**\n * Private Methods\n */\n\n /**\n * Shows the activity element\n *\n * @access Private\n */\n this.setActivityActive = () => {\n activityOverlay.classList.add(elClasses.activity);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setActivityInactive = () => {\n activityOverlay.classList.remove(elClasses.activity);\n };\n\n /**\n * Shows the message element\n *\n * @access Private\n */\n this.setMessageActive = () => {\n activityOverlay.classList.add(elClasses.message);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setMessageInactive = () => {\n activityOverlay.classList.remove(elClasses.message);\n };\n\n /**\n * Sets the content of the overlay message\n *\n * @access Private\n */\n this.setMessageContent = content => {\n messageContainer.innerText = content;\n };\n\n /**\n * Adds flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashActive = content => {\n activityOverlay.classList.add(elClasses.flash);\n };\n\n /**\n * removes flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashInactive = content => {\n activityOverlay.classList.remove(elClasses.flash);\n };\n\n /**\n * Sets message to success\n *\n * @access Private\n */\n this.setSuccessActive = () => {\n activityOverlay.classList.add(elClasses.success);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setSuccessInactive = () => {\n activityOverlay.classList.remove(elClasses.success);\n };\n\n /**\n * Sets message to error\n *\n * @access Private\n */\n this.setErrorActive = () => {\n activityOverlay.classList.add(elClasses.error);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setErrorInactive = () => {\n activityOverlay.classList.remove(elClasses.error);\n };\n\n /**\n * Shows this activity overlay\n *\n * @access Private\n */\n this.setOverlayVisible = () => {\n activityOverlay.classList.add(elClasses.visible);\n };\n this.setOverlayInvisible = () => {\n activityOverlay.classList.remove(elClasses.visible);\n };\n\n /**\n * Creates and returns an activity overlay element\n *\n * @return {HTMLElement}\n */\n this.create = () => {\n activityOverlay = this.buildOverlayEl();\n activityContainer = this.buildActivityEl();\n messageContainer = this.buildMessageEl();\n activityOverlay.appendChild(activityContainer);\n activityOverlay.appendChild(messageContainer);\n return activityOverlay;\n };\n\n /**\n * Creates the parent overlay element\n *\n * @return {Element}\n * @access Private\n */\n this.buildOverlayEl = () => {\n const overlay = document.createElement('div');\n\n // overlay.setAttribute('data-gradient-1', 'rgba(62, 185, 152, .85)');\n overlay.setAttribute('class', elClasses.overlay);\n return overlay;\n };\n\n /**\n * Creates container for animation and contents of animation\n *\n * @return {Element}\n * @access Private\n */\n this.buildActivityEl = () => {\n let text = _FtConfig.default.getUiTextFor('activityOverlay')[activityType];\n let activityAnimationContainer = document.createElement('div');\n activityAnimationContainer.setAttribute('class', elClasses.activityAnimationContainer);\n\n // Add all animation items to the animation container\n activityAnimationContainer = text.animated.reduce((el, string) => {\n let activityText = document.createElement('span');\n\n // Add text items\n activityText.setAttribute('class', elClasses.activityAnimationItem);\n activityText.innerHTML = string;\n el.appendChild(activityText);\n return el;\n }, activityAnimationContainer);\n\n // Create static text element\n let staticText = document.createElement('div');\n staticText.setAttribute('class', elClasses.activityStaticText);\n staticText.innerText = text.static;\n\n // Create activity container and append children\n activityContainer = document.createElement('div');\n activityContainer.setAttribute('class', elClasses.activityContainer);\n activityContainer.appendChild(staticText);\n activityContainer.appendChild(activityAnimationContainer);\n return activityContainer;\n };\n\n /**\n * Builds the element that will hold messages in the overlay\n *\n * @return {Element}\n * @access Private\n */\n this.buildMessageEl = () => {\n messageContainer = document.createElement('div');\n messageContainer.setAttribute('class', elClasses.messageContainer);\n return messageContainer;\n };\n (() => {\n const targetContainerContainer = targetContainer.getSelf();\n activityOverlay = this.create();\n targetContainerContainer.classList.add(elClasses.parent);\n targetContainerContainer.appendChild(activityOverlay);\n })();\n};\nvar _default = FtActivityOverlay;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3}],7:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates common HTML elements\n *\n * @return {Object} Public methods\n */\nconst FtUiElements = function () {\n /**\n * @type {Object}\n */\n const elementClasses = {\n translateButton: {\n container: 'ft-translate-button-container',\n button: 'ft-translate-button'\n },\n statusPlaceholder: {\n container: 'ft-translation-status-container',\n label: 'ft-translation-status'\n },\n icon: 'ft-icon'\n };\n\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Creates a language fontawesome icon element\n *\n * @return {Element}\n */\n const createIcon = () => {\n const iconLink = document.createElement('a');\n iconLink.setAttribute('href', `${ProcessWire.config.urls.admin}fluency/?modal=1`);\n iconLink.setAttribute('class', 'pw-modal pw-modal-large');\n const icon = document.createElement('i');\n icon.setAttribute('class', `${elementClasses.icon} fa fa-language`);\n icon.setAttribute('uk-tooltip', uiText.showTranslator);\n iconLink.appendChild(icon);\n return iconLink;\n };\n\n /**\n * Creates a status placeholder\n *\n * @return {Element}\n */\n const createStatusElement = text => {\n const label = document.createElement('span');\n label.setAttribute('class', elementClasses.statusPlaceholder.label);\n label.innerText = text;\n const container = document.createElement('div');\n container.setAttribute('class', elementClasses.statusPlaceholder.container);\n container.appendChild(createIcon());\n container.appendChild(label);\n return container;\n };\n\n /**\n * Creates a translate button element\n *\n * @return {Object} Container element and Button element\n */\n const createTranslateButton = text => {\n const button = document.createElement('a');\n button.innerText = text;\n button.setAttribute('class', elementClasses.translateButton.button);\n button.setAttribute('href', 'noaction');\n const container = document.createElement('div');\n container.setAttribute('class', elementClasses.translateButton.container);\n container.appendChild(createIcon());\n container.appendChild(button);\n return {\n button,\n container\n };\n };\n return {\n createStatusElement,\n createTranslateButton,\n createIcon,\n elementClasses\n };\n}();\nvar _default = FtUiElements;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4}]},{},[1]);\n"],"names":["r","e","n","t","o","i","f","c","require","u","a","Error","code","p","exports","call","length","1","module","_FtLanguageTranslatorInputfields","_interopRequireDefault","_FtConfig","obj","__esModule","default","window","addEventListener","moduleShouldInitialize","init","./global/FtConfig","./inputfields/FtLanguageTranslatorInputfields","2","Object","defineProperty","value","Fluency","errors","getUiTextFor","requestHeaders","requestType","X-Requested-With","getRequest","endpoint","responseHandler","fetch","method","cache","headers","then","parseResponse","catch","handleFetchError","deleteRequest","response","status","ok","json","error","console","message","returnObject","split","deleteTranslatableLanguagesCache","getApiEndpointFor","deleteTranslationCache","getAvailableLanguages","getTranslation","sourceLanguage","targetLanguage","content","let","options","arguments","undefined","caching","data","body","JSON","stringify","getUsage","./FtConfig","3","FtConfig","config","ProcessWire","fluency","localizedStrings","localization","strings","activityOverlay","languageSelect","inputfieldTranslateButtons","standaloneTranslator","usage","endpoints","languages","apiEndpoints","translatableLanguagesCache","test","translation","translationCache","configuredLanguages","unconfiguredLanguages","getConfiguredLanguages","getUnconfiguredLanguages","getEngineInfo","engine","fieldInitializedAttr","key","getDefaultLanguage","reduce","defaultLang","lang","getEngineProvidesUsageData","providesUsageData","getInputfieldTranslationAction","interface","inputfieldTranslationAction","getLanguageCount","getLanguageForId","pwLanguageId","parseInt","match","language","id","languageIsTranslatable","languageId","includes","4","getPageId","urlParams","URLSearchParams","location","search","get","tagElement","element","text","addRandomId","tagDiv","document","createElement","setAttribute","Array","map","Math","random","toString","join","innerText","appendChild","pageIdIs","5","LanguageTranslatorInputfield","FtInputfieldText","_FtActivityOverlay","_FtUiElements","_Fluency","FtLanguageTranslatorInputfields","translationInputfields","querySelectorAll","forEach","inputfield","querySelector","inputfieldContainer","uiText","sourceText","targetInput","this","getSelf","getActivityOverlay","addTranslateButton","button","container","createTranslateButton","translate","bindTranslateButton","preventDefault","translateContent","showActivity","engineLanguage","sourceCode","targetCode","result","showError","translations","hide","initValues","changedValues","languageTabs","inputContainers","languageFields","getValueForDefaultLanguage","getValueForLanguage","getFieldForLanguage","setValueForLanguage","field","FtInputfields","updateValue","dispatchEvent","Event","contentHasChanged","hasOwn","getInputContainerForLanguage","getInputContainers","el","dataset","registerInputEventListener","target","setModifiedState","allInputContainers","inputContainer","FtLanguageTab","FtInputfieldTranslateButton","../global/Fluency","../global/FtConfig","../ui/FtActivityOverlay","../ui/FtUiElements","6","targetContainer","_this","activityType","elClasses","parent","overlay","flash","success","activity","visible","activityContainer","activityStaticText","activityAnimationContainer","activityAnimationItem","messageContainer","setActivityActive","setOverlayVisible","showMessage","displayTime","setMessageContent","setActivityInactive","setMessageActive","flashSuccess","setSuccessActive","setFlashActive","flashError","setErrorActive","delay","setTimeout","setOverlayInvisible","setMessageInactive","setErrorInactive","setFlashInactive","classList","add","remove","setSuccessInactive","create","buildOverlayEl","buildActivityEl","buildMessageEl","animated","string","activityText","innerHTML","staticText","static","targetContainerContainer","7","FtUiElements","elementClasses","translateButton","statusPlaceholder","label","icon","createIcon","iconLink","urls","admin","showTranslator","createStatusElement","../global/FtTools"],"mappings":"AAAA,CAAY,SAASA,EAAEC,EAAEC,EAAEC,GAAG,SAASC,EAAEC,EAAEC,GAAG,GAAG,CAACJ,EAAEG,GAAG,CAAC,GAAG,CAACJ,EAAEI,GAAG,CAAC,IAAIE,EAAE,YAAY,OAAOC,SAASA,QAAQ,GAAG,CAACF,GAAGC,EAAE,OAAOA,EAAEF,EAAE,CAAA,CAAE,EAAE,GAAGI,EAAE,OAAOA,EAAEJ,EAAE,CAAA,CAAE,EAAgD,MAA1CK,EAAE,IAAIC,MAAM,uBAAuBN,EAAE,GAAG,GAAUO,KAAK,mBAAmBF,CAAC,CAAKG,EAAEX,EAAEG,GAAG,CAACS,QAAQ,EAAE,EAAEb,EAAEI,GAAG,GAAGU,KAAKF,EAAEC,QAAQ,SAASd,GAAoB,OAAOI,EAAlBH,EAAEI,GAAG,GAAGL,IAAeA,CAAC,CAAC,EAAEa,EAAEA,EAAEC,QAAQd,EAAEC,EAAEC,EAAEC,CAAC,CAAC,CAAC,OAAOD,EAAEG,GAAGS,OAAO,CAAC,IAAI,IAAIL,EAAE,YAAY,OAAOD,SAASA,QAAQH,EAAE,EAAEA,EAAEF,EAAEa,OAAOX,CAAC,GAAGD,EAAED,EAAEE,EAAE,EAAE,OAAOD,CAAC,EAAc,CAACa,EAAE,CAAC,SAAST,EAAQU,EAAOJ,GACxe,aAEA,IAAIK,EAAmCC,EAAuBZ,EAAQ,+CAA+C,CAAC,EAClHa,EAAYD,EAAuBZ,EAAQ,mBAAmB,CAAC,EACnE,SAASY,EAAuBE,GAAO,OAAOA,GAAOA,EAAIC,WAAaD,EAAM,CAAEE,QAASF,CAAI,CAAG,CAC9FG,OAAOC,iBAAiB,OAAQzB,IAC1BoB,EAAUG,QAAQG,uBAAuB,GAC3CR,EAAiCK,QAAQI,KAAK,CAElD,CAAC,CAED,EAAE,CAACC,oBAAoB,EAAEC,gDAAgD,CAAC,GAAGC,EAAE,CAAC,SAASvB,EAAQU,EAAOJ,GACxG,aAEAkB,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAU,KAAA,EAClB,IAAIH,GAC4BC,EADOd,EAAQ,YAAY,IACNc,EAAIC,WAAaD,EAAM,CAAEE,QAASF,CAAI,EAOrFa,EAAU,WAKd,MAAMC,EAASf,EAAUG,QAAQa,aAAa,QAAQ,EA8EtD,MAAMC,EAAiBC,IACrB,IAAMD,EAAiB,CACrBE,mBAAoB,gBACtB,EAOA,MANoB,QAAhBD,IACFD,EAAuB,OAAI,oBAET,SAAhBC,IACFD,EAAe,gBAAkB,oBAE5BA,CACT,EAwBMG,EAAa,CAACC,EAAUC,IACrBC,MAAMF,EAAU,CACrBG,OAAQ,MACRC,MAAO,WACPC,QAAST,EAAe,KAAK,CAC/B,CAAC,EAAEU,KAAKC,CAAa,EAAED,KAAKL,CAAe,EAAEO,MAAMC,CAAgB,EAS/DC,EAAgB,CAACV,EAAUC,IACxBC,MAAMF,EAAU,CACrBG,OAAQ,SACRE,QAAST,EAAe,KAAK,CAC/B,CAAC,EAAEU,KAAKC,CAAa,EAAED,KAAKL,CAAe,EAAEO,MAAMC,CAAgB,EAS/DF,EAAgBI,IACpB,GAAwB,MAApBA,EAASC,OACX,OAAOD,EAET,GAAIA,EAASE,GACX,OAAOF,EAASG,KAAK,EAEvB,MAAM,IAAI7C,KACZ,EASMwC,EAAmBM,IACvBC,QAAQD,MAAM,+BAAgCA,EAAME,OAAO,EAC3D,IAAMC,EAAe,CACnBH,MAAO,KACPE,QAAS,IACX,EAWA,MATO,iBADCF,EAAME,QAAQE,MAAM,GAAG,EAAE,IAE7BD,EAAaH,MAAQ,8BACrBG,EAAaD,QAAUvB,EAAoC,8BAG3DwB,EAAaH,MAAQ,gBACrBG,EAAaD,QAAUvB,EAAsB,eAG1CwB,CACT,EACA,MAAO,CACLE,iCAhHuC,IAChCV,EAAc/B,EAAUG,QAAQuC,kBAAkB,4BAA4B,EAAGV,GAC/EA,CACR,EA8GDW,uBA3H6B,IACtBZ,EAAc/B,EAAUG,QAAQuC,kBAAkB,kBAAkB,EAAGV,GACrEA,CACR,EAyHDY,sBAtI4B,IACrBxB,EAAWpB,EAAUG,QAAQuC,kBAAkB,WAAW,EAAGV,GAC3DA,CACR,EAoIDa,eApKqB,SAAUC,EAAgBC,EAAgBC,GAC/DC,IAkFmB5B,EAlFf6B,EAA6B,EAAnBC,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,GAC9EE,EAA6B,EAAnBF,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,KAClF,OAgFmB9B,EAhFArB,EAAUG,QAAQuC,kBAAkB,aAAa,EAgFvCY,EAhF0C,CACrER,eAAgBA,EAChBC,eAAgBA,EAChBC,QAASA,EACTE,QAASA,EACTG,QAASA,CACX,EA0EmC/B,EA1EhCU,GACMA,EA0EFT,MAAMF,EAAU,CACrBG,OAAQ,OACRC,MAAO,WACPC,QAAST,EACTsC,KAAMC,KAAKC,UAAUH,CAAI,CAC3B,CAAC,EAAE3B,KAAKC,CAAa,EAAED,KAAKL,CAAe,EAAEO,MAAMC,CAAgB,CA7ErE,EAyJE4B,SAnJe,IACRtC,EAAWpB,EAAUG,QAAQuC,kBAAkB,OAAO,EAAGV,GACvDA,CACR,CAiJH,CACF,EAAE,EAEFvC,EAAQU,QADOW,CAGf,EAAE,CAAC6C,aAAa,CAAC,GAAGC,EAAE,CAAC,SAASzE,EAAQU,EAAOJ,GAC/C,aAEAkB,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAU,KAAA,EAKlB,IAAM0D,EAAW,WAYf,MAAMC,EAASC,YAAYD,OAAOE,QAMlC,IAAMC,EAAmBH,EAAOI,aAYhC,MAAMC,EAAU,CACdC,gBAAiBH,EAAiBG,gBAClCC,eAAgBJ,EAAiBI,eACjCC,2BAA4BL,EAAiBK,2BAC7CC,qBAAsBN,EAAiBM,qBACvCC,MAAOP,EAAiBO,MACxBzD,OAAQkD,EAAiBlD,MAC3B,EAMM0D,EAAY,CAChBC,UAAWZ,EAAOa,aAAaD,UAC/BE,2BAA4Bd,EAAOa,aAAaC,2BAChDC,KAAMf,EAAOa,aAAaE,KAC1BC,YAAahB,EAAOa,aAAaG,YACjCC,iBAAkBjB,EAAOa,aAAaI,iBACtCP,MAAOV,EAAOa,aAAaH,KAC7B,EAMMQ,EAAsBlB,EAAOkB,oBAM7BC,EAAwBnB,EAAOmB,sBAarC,MAAMC,EAAyB,IAAMF,EAGrC,MAAMG,EAA2B,IAAMF,EAkBvC,MAAMG,EAAgB,IAAMtB,EAAOuB,OAGnC,MAAO,CACLC,qBAjG2B,sBAkG3B5C,kBAhCwB6C,GAAOd,EAAUc,GAiCzCL,uBAAAA,EACAM,mBA3ByB,IADUR,EACqBS,OAAO,CAACC,EAAaC,IAASA,EAAKxF,QAAUwF,EAAOD,EAAa,IAAI,EA4B7HN,cAAAA,EACAQ,2BARiC,IAAMR,EAAc,EAAES,kBASvDC,+BARqC,IAAMhC,EAAOiC,UAAUC,4BAS5DC,iBA5BuB,IAJYjB,EAImBrF,OADjBsF,EACqDtF,OA6B1FuG,iBA5BuBC,IACvBA,EAAeC,SAASD,EAAc,EAAE,EANLnB,EAOHS,OAAO,CAACY,EAAOC,IAAaA,EAASC,KAAOJ,EAAeG,EAAWD,EAAO,IAAI,GA2BjHrF,aApBmBuE,GAAOpB,EAAQoB,GAqBlCJ,yBAAAA,EACAqB,uBAlC6BC,GAAc,CACNxB,EADkCyB,SAASN,SAASK,EAAY,EAAE,CAAC,EAmCxGnG,uBAjB6B,IAAwC,EApBlC0E,EAoByBrF,MAkB9D,CACF,EAAE,EAEFF,EAAQU,QADO0D,CAGf,EAAE,IAAI8C,EAAE,CAAC,SAASxH,EAAQU,EAAOJ,GACjC,aAiEkB,SAAZmH,IACF,IAAIC,EAAY,IAAIC,gBAAgB1G,OAAO2G,SAASC,MAAM,EAC1D,OAAOH,EAAYT,SAASS,EAAUI,IAAI,IAAI,CAAC,EAAI,IACrD,CAlEFtG,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAU,KAAA,EA8ElBV,EAAQU,QAPC,CACL+G,WAjCiB,SAAUC,EAASC,GACpCnE,IAAIoE,EAAclE,EAAmB,EAAnBA,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,KAAmBA,UAAU,GAC3EmE,EAASC,SAASC,cAAc,KAAK,EAC3CF,EAAOG,aAAa,QAAS,gBAAgB,EACzCJ,IACFD,GAAQ,MAnBe,WAEzB,MAAO,CAAC,GAAGM,MADqB,EAAnBvE,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,CAC1D,GAAGwE,IAAI,IAAMC,KAAKC,OAAO,EAAEC,SAAS,EAAE,EAAE,EAAE,EAAEC,KAAK,EAAE,CAC5E,EAgBuC,GAErCT,EAAOU,UAAYZ,EACnBD,EAAQc,YAAYX,CAAM,CAC5B,EAyBEV,UAAAA,EACAsB,SAJe3B,GAAMK,EAAU,IAAML,CAKvC,CAKF,EAAE,IAAI4B,EAAE,CAAC,SAAShJ,EAAQU,EAAOJ,GACjC,aAEAkB,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAUV,EAAQ2I,6BAA+B3I,EAAQ4I,iBAAmB,KAAA,EACpF,IAAIC,EAAqBvI,EAAuBZ,EAAQ,yBAAyB,CAAC,EAC9EoJ,EAAgBxI,EAAuBZ,EAAQ,oBAAoB,CAAC,EACpEa,EAAYD,EAAuBZ,EAAQ,oBAAoB,CAAC,EAChEqJ,EAAWzI,EAAuBZ,EAAQ,mBAAmB,CAAC,EAClE,SAASY,EAAuBE,GAAO,OAAOA,GAAOA,EAAIC,WAAaD,EAAM,CAAEE,QAASF,CAAI,CAAG,CAMxFwI,EAYG,CACLlI,KAZW,KACX,IAAMmI,EAAyBnB,SAASoB,iBAAiB,oBAAoB,EACxED,GAGL,CAAC,GAAGA,GAAwBE,QAAQC,IAC9BA,EAAWC,cAAc,oBAAoB,GAC/C,IAAIV,EAA6BS,CAAU,CAE/C,CAAC,CACH,CAGA,EAEF,MAAMT,EAA+B,SAAUW,GAO7C,MAAMC,EAAShJ,EAAUG,QAAQa,aAAa,4BAA4B,EAC1EiC,IAAImB,EACA6E,EAAaF,EAAoBD,cAAc,cAAc,EAAEd,UAC/DkB,EAAcH,EAAoBD,cAAc,OAAO,EAC3DK,KAAKC,QAAU,IAAML,EACrBI,KAAKE,mBAAqB,IAAMjF,EAChC+E,KAAKG,mBAAqB,KACxB,GAAM,CACJC,OAAAA,EACAC,UAAAA,CACF,EAAIjB,EAAcpI,QAAQsJ,sBAAsBT,EAAOU,SAAS,EAChEP,KAAKQ,oBAAoBJ,CAAM,EAC/BR,EAAoBd,YAAYuB,CAAS,CAC3C,EACAL,KAAKQ,oBAAsBJ,IACzBA,EAAOlJ,iBAAiB,QAASzB,IAC/BA,EAAEgL,eAAe,EACjBT,KAAKU,iBAAiB,CACxB,CAAC,CACH,EACAV,KAAKU,iBAAmB,KACtB,IAAMhD,EAAY,IAAIC,gBAAgB1G,OAAO2G,SAASC,MAAM,EACtDT,EAAKH,SAASS,EAAUI,IAAI,aAAa,CAAC,EAChD7C,EAAgB0F,aAAa,EAC7BtB,EAASrI,QAAQ0C,eAAe7C,EAAUG,QAAQqF,mBAAmB,EAAEuE,eAAeC,WAAYhK,EAAUG,QAAQ+F,iBAAiBK,CAAE,EAAEwD,eAAeE,WAAYhB,CAAU,EAAEtH,KAAKuI,IAC/KA,EAAO9H,MACTgC,EAAgB+F,UAAUD,EAAO5H,OAAO,GAG1C4G,EAAYrI,MAAQqJ,EAAOE,aAAa,GACxChG,EAAgBiG,KAAK,EACvB,CAAC,CACH,EAEEjG,EAAkB,IAAIkE,EAAmBnI,QAAQgJ,IAAI,EACrDA,KAAKG,mBAAmB,CAE5B,EACA7J,EAAQ2I,6BAA+BA,EAYvC3I,EAAQU,QAXOsI,EA6KfhJ,EAAQ4I,iBAjKiB,SAAUQ,GAOjC,MAAMyB,EAAa,GAObC,EAAgB,GAOhBC,EAAe,GAOfC,EAAkB,GAOlBC,EAAiB,GAQvBzH,IAAImB,EAMJ+E,KAAKE,mBAAqB,IAAMjF,EAMhC+E,KAAKC,QAAU,IAAMP,EAMrBM,KAAKwB,2BAA6B,IAAMxB,KAAKyB,oBAAoB5K,EAAUG,QAAQqF,mBAAmB,EAAEe,EAAE,EAO1G4C,KAAKyB,oBAAsBnE,GAAc0C,KAAK0B,oBAAoBpE,CAAU,EAAE5F,MAQ9EsI,KAAK2B,oBAAsB,CAACrE,EAAY5F,KACtC,IAAMkK,EAAQ5B,KAAK0B,oBAAoBpE,CAAU,EAKjD,OAJAuE,cAAcC,YAAYF,EAAOlK,CAAK,EAGtCkK,EAAMG,cAAc,IAAIC,MAAM,OAAO,CAAC,EAC/BhC,KAAKiC,kBAAkB3E,CAAU,CAC1C,EAOA0C,KAAK0B,oBAAsBpE,IACrB9F,OAAO0K,OAAOX,EAAgBjE,CAAU,GAAOiE,EAAejE,KAGlEiE,EAAejE,GAAc0C,KAAKmC,6BAA6B7E,CAAU,EAAEqC,cAAc,OAAO,GACzF4B,EAAejE,IASxB0C,KAAKmC,6BAA+B7E,IAC9B9F,OAAO0K,OAAOZ,EAAiBhE,CAAU,GAAOgE,EAAgBhE,KAGpEgE,EAAgBhE,GAAcoC,EAAWC,iCAAiCrC,KAAc,GACjFgE,EAAgBhE,IAQzB0C,KAAKoC,mBAAqB,KACxB1C,EAAWF,iBAAiB,iBAAiB,EAAEC,QAAQ4C,GAAMf,EAAgBe,EAAGC,QAAQnF,UAAYkF,CAAE,EAC/Ff,GAQTtB,KAAKiC,kBAAoB3E,GAAc9F,OAAO0K,OAAOd,EAAe9D,CAAU,GAAK8D,EAAc9D,KAAgB6D,EAAW7D,GAQ5H0C,KAAKuC,2BAA6BjF,IAChC0C,KAAK0B,oBAAoBpE,CAAU,EAAEpG,iBAAiB,QAASzB,IAC7D2L,EAAc9D,GAAc7H,EAAE+M,OAAO9K,MACrC2J,EAAa/D,GAAYmF,iBAAiBzC,KAAKiC,kBAAkB3E,CAAU,CAAC,CAC9E,CAAC,CACH,EAUE,IACSA,EADHoF,EAAqB1C,KAAKoC,mBAAmB,EACnD,IAAS9E,KAAcoF,EAAoB,CACzC5I,IAAI6I,EAAiBD,EAAmBpF,GACxC6D,EAAW7D,GAAc0C,KAAKyB,oBAAoBnE,CAAU,EAC5D+D,EAAa/D,GAAc,IAAIsF,cAAcD,CAAc,EAC3D3C,KAAKuC,2BAA2BjF,CAAU,CAC5C,CACArC,EAAkB,IAAIkE,EAAmBnI,QAAQgJ,IAAI,EACrD,IAAI6C,4BAA4B7C,KAAM0C,CAAkB,CAE5D,CAGA,EAAE,CAACI,oBAAoB,EAAEC,qBAAqB,EAAEC,0BAA0B,EAAEC,qBAAqB,CAAC,GAAGC,EAAE,CAAC,SAASlN,EAAQU,EAAOJ,GAChI,aAEAkB,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAU,KAAA,EAClB,IAAIH,GAC4BC,EADOd,EAAQ,oBAAoB,IACdc,EAAIC,WAAaD,EAAM,CAAEE,QAASF,CAAI,EA6U3FR,EAAQU,QAtUkB,SAAUmM,GAClC,IAAIC,EAAQpD,KACZlG,IAAIuJ,EAAkC,EAAnBrJ,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,cACvF,MAAMsJ,EAAY,CAChBC,OAAQ,gCACRC,QAAS,sBACTvK,MAAO,QACPE,QAAS,UACTsK,MAAO,QACPC,QAAS,UACTC,SAAU,WACVC,QAAS,UACTC,kBAAmB,cACnBC,mBAAoB,mBACpBC,2BAA4B,kCAC5BC,sBAAuB,6BACvBC,iBAAkB,qBACpB,EAMAnK,IAAImB,EAMAgJ,EAMAJ,EAYJ7D,KAAKW,aAAe,KAClBX,KAAKkE,kBAAkB,EACvBlE,KAAKmE,kBAAkB,CACzB,EAQAnE,KAAKoE,YAAc,SAAUjL,GAC3BW,IAAIuK,EAAiC,EAAnBrK,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,IACtFoJ,EAAMkB,kBAAkBnL,CAAO,EAC/BiK,EAAMmB,oBAAoB,EAC1BnB,EAAMoB,iBAAiB,EACvBpB,EAAMe,kBAAkB,EACxBf,EAAMlC,KAAKmD,CAAW,CACxB,EASArE,KAAKyE,aAAe,SAAUtL,GAC5BW,IAAIuK,EAAiC,EAAnBrK,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,IACtFoJ,EAAMsB,iBAAiB,EACvBtB,EAAMuB,eAAe,EACrBvB,EAAMgB,YAAYjL,EAASkL,CAAW,CACxC,EASArE,KAAK4E,WAAa,SAAUzL,GAC1BW,IAAIuK,EAAiC,EAAnBrK,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,IACtFoJ,EAAMuB,eAAe,EACrBvB,EAAMyB,eAAe,EACrBzB,EAAMgB,YAAYjL,EAASkL,CAAW,CACxC,EASArE,KAAKgB,UAAY,SAAU7H,GACzBW,IAAIuK,EAAiC,EAAnBrK,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,IACtFoJ,EAAMyB,eAAe,EACrBzB,EAAMgB,YAAYjL,EAASkL,CAAW,CACxC,EAOArE,KAAKkB,KAAO,WACVpH,IAAIgL,EAA2B,EAAnB9K,UAAUxD,QAA+ByD,KAAAA,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,EAChF+K,WAAW,KACT3B,EAAM4B,oBAAoB,CAC5B,EAAGF,CAAK,EAGRC,WAAW,KACT3B,EAAMmB,oBAAoB,EAC1BnB,EAAM6B,mBAAmB,EACzB7B,EAAM8B,iBAAiB,EACvB9B,EAAM+B,iBAAiB,EACvB/B,EAAMkB,kBAAkB,EAAE,CAC5B,EAAGQ,EAAQ,GAAG,CAChB,EAWA9E,KAAKkE,kBAAoB,KACvBjJ,EAAgBmK,UAAUC,IAAI/B,EAAUK,QAAQ,CAClD,EAOA3D,KAAKuE,oBAAsB,KACzBtJ,EAAgBmK,UAAUE,OAAOhC,EAAUK,QAAQ,CACrD,EAOA3D,KAAKwE,iBAAmB,KACtBvJ,EAAgBmK,UAAUC,IAAI/B,EAAUnK,OAAO,CACjD,EAOA6G,KAAKiF,mBAAqB,KACxBhK,EAAgBmK,UAAUE,OAAOhC,EAAUnK,OAAO,CACpD,EAOA6G,KAAKsE,kBAAoBzK,IACvBoK,EAAiBpF,UAAYhF,CAC/B,EAOAmG,KAAK2E,eAAiB9K,IACpBoB,EAAgBmK,UAAUC,IAAI/B,EAAUG,KAAK,CAC/C,EAOAzD,KAAKmF,iBAAmBtL,IACtBoB,EAAgBmK,UAAUE,OAAOhC,EAAUG,KAAK,CAClD,EAOAzD,KAAK0E,iBAAmB,KACtBzJ,EAAgBmK,UAAUC,IAAI/B,EAAUI,OAAO,CACjD,EAOA1D,KAAKuF,mBAAqB,KACxBtK,EAAgBmK,UAAUE,OAAOhC,EAAUI,OAAO,CACpD,EAOA1D,KAAK6E,eAAiB,KACpB5J,EAAgBmK,UAAUC,IAAI/B,EAAUrK,KAAK,CAC/C,EAOA+G,KAAKkF,iBAAmB,KACtBjK,EAAgBmK,UAAUE,OAAOhC,EAAUrK,KAAK,CAClD,EAOA+G,KAAKmE,kBAAoB,KACvBlJ,EAAgBmK,UAAUC,IAAI/B,EAAUM,OAAO,CACjD,EACA5D,KAAKgF,oBAAsB,KACzB/J,EAAgBmK,UAAUE,OAAOhC,EAAUM,OAAO,CACpD,EAOA5D,KAAKwF,OAAS,KACZvK,EAAkB+E,KAAKyF,eAAe,EACtC5B,EAAoB7D,KAAK0F,gBAAgB,EACzCzB,EAAmBjE,KAAK2F,eAAe,EACvC1K,EAAgB6D,YAAY+E,CAAiB,EAC7C5I,EAAgB6D,YAAYmF,CAAgB,EACrChJ,GAST+E,KAAKyF,eAAiB,KACpB,IAAMjC,EAAUpF,SAASC,cAAc,KAAK,EAI5C,OADAmF,EAAQlF,aAAa,QAASgF,EAAUE,OAAO,EACxCA,CACT,EAQAxD,KAAK0F,gBAAkB,KACrB5L,IAAImE,EAAOpH,EAAUG,QAAQa,aAAa,iBAAiB,EAAEwL,GAC7DvJ,IAAIiK,EAA6B3F,SAASC,cAAc,KAAK,EAC7D0F,EAA2BzF,aAAa,QAASgF,EAAUS,0BAA0B,EAGrFA,EAA6B9F,EAAK2H,SAAStJ,OAAO,CAAC+F,EAAIwD,KACrD/L,IAAIgM,EAAe1H,SAASC,cAAc,MAAM,EAMhD,OAHAyH,EAAaxH,aAAa,QAASgF,EAAUU,qBAAqB,EAClE8B,EAAaC,UAAYF,EACzBxD,EAAGvD,YAAYgH,CAAY,EACpBzD,CACT,EAAG0B,CAA0B,EAG7BjK,IAAIkM,EAAa5H,SAASC,cAAc,KAAK,EAS7C,OARA2H,EAAW1H,aAAa,QAASgF,EAAUQ,kBAAkB,EAC7DkC,EAAWnH,UAAYZ,EAAKgI,QAG5BpC,EAAoBzF,SAASC,cAAc,KAAK,GAC9BC,aAAa,QAASgF,EAAUO,iBAAiB,EACnEA,EAAkB/E,YAAYkH,CAAU,EACxCnC,EAAkB/E,YAAYiF,CAA0B,EACjDF,CACT,EAQA7D,KAAK2F,eAAiB,MACpB1B,EAAmB7F,SAASC,cAAc,KAAK,GAC9BC,aAAa,QAASgF,EAAUW,gBAAgB,EAC1DA,GAGDiC,EAA2B/C,EAAgBlD,QAAQ,EACzDhF,EAAkB+E,KAAKwF,OAAO,EAC9BU,EAAyBd,UAAUC,IAAI/B,EAAUC,MAAM,EACvD2C,EAAyBpH,YAAY7D,CAAe,CAExD,CAIA,EAAE,CAAC8H,qBAAqB,CAAC,GAAGoD,EAAE,CAAC,SAASnQ,EAAQU,EAAOJ,GACvD,aAEAkB,OAAOC,eAAenB,EAAS,aAAc,CAC3CoB,MAAO,CAAA,CACT,CAAC,EACDpB,EAAQU,QAAU,KAAA,EAClB,IAAIH,EAAYD,EAAuBZ,EAAQ,oBAAoB,CAAC,EACrDY,EAAuBZ,EAAQ,mBAAmB,CAAC,EACnDY,EAAuBZ,EAAQ,mBAAmB,CAAC,EAClE,SAASY,EAAuBE,GAAO,OAAOA,GAAOA,EAAIC,WAAaD,EAAM,CAAEE,QAASF,CAAI,CAAG,CAMxFsP,EAAe,WAInB,MAAMC,EAAiB,CACrBC,gBAAiB,CACfjG,UAAW,gCACXD,OAAQ,qBACV,EACAmG,kBAAmB,CACjBlG,UAAW,kCACXmG,MAAO,uBACT,EACAC,KAAM,SACR,EAQM5G,EAAShJ,EAAUG,QAAQa,aAAa,4BAA4B,EAOpE6O,EAAa,KACjB,IAAMC,EAAWvI,SAASC,cAAc,GAAG,EAGrCoI,GAFNE,EAASrI,aAAa,OAAW1D,YAAYD,OAAOiM,KAAKC,MAA3B,kBAAkD,EAChFF,EAASrI,aAAa,QAAS,yBAAyB,EAC3CF,SAASC,cAAc,GAAG,GAIvC,OAHAoI,EAAKnI,aAAa,QAAY+H,EAAeI,KAAlB,iBAAuC,EAClEA,EAAKnI,aAAa,aAAcuB,EAAOiH,cAAc,EACrDH,EAAS7H,YAAY2H,CAAI,EAClBE,CACT,EAqCA,MAAO,CACLI,oBA/B0B9I,IAC1B,IAAMuI,EAAQpI,SAASC,cAAc,MAAM,EAGrCgC,GAFNmG,EAAMlI,aAAa,QAAS+H,EAAeE,kBAAkBC,KAAK,EAClEA,EAAM3H,UAAYZ,EACAG,SAASC,cAAc,KAAK,GAI9C,OAHAgC,EAAU/B,aAAa,QAAS+H,EAAeE,kBAAkBlG,SAAS,EAC1EA,EAAUvB,YAAY4H,EAAW,CAAC,EAClCrG,EAAUvB,YAAY0H,CAAK,EACpBnG,CACT,EAuBEC,sBAhB4BrC,IAC5B,IAAMmC,EAAShC,SAASC,cAAc,GAAG,EAInCgC,GAHND,EAAOvB,UAAYZ,EACnBmC,EAAO9B,aAAa,QAAS+H,EAAeC,gBAAgBlG,MAAM,EAClEA,EAAO9B,aAAa,OAAQ,UAAU,EACpBF,SAASC,cAAc,KAAK,GAI9C,OAHAgC,EAAU/B,aAAa,QAAS+H,EAAeC,gBAAgBjG,SAAS,EACxEA,EAAUvB,YAAY4H,EAAW,CAAC,EAClCrG,EAAUvB,YAAYsB,CAAM,EACrB,CACLA,OAAAA,EACAC,UAAAA,CACF,CACF,EAIEqG,WAAAA,EACAL,eAAAA,CACF,CACF,EAAE,EAEF/P,EAAQU,QADOoP,CAGf,EAAE,CAACtD,oBAAoB,EAAEC,qBAAqB,EAAEiE,oBAAoB,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE"} \ No newline at end of file +{"version":3,"file":"../fluency_language_translator.bundle.js","sources":["fluency_language_translator.bundle.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i {\n if (_FtConfig.default.moduleShouldInitialize()) {\n _FtLanguageTranslatorInputfields.default.init();\n }\n});\n\n},{\"./global/FtConfig\":3,\"./inputfields/FtLanguageTranslatorInputfields\":5}],2:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"./FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Core module interface\n * Handles all interaction with the ProcessWire module backend\n * @return {object} Public interfaces\n */\n\nconst Fluency = function () {\n /**\n * Localized error strings\n * @type {Object}\n */\n const errors = _FtConfig.default.getUiTextFor('errors');\n\n /**\n * Data Request Methods\n */\n\n /**\n * Gets a translation from the Fluency module\n * @param {String} sourceLanguage ISO language code\n * @param {String} targetLanguage ISO langauge code\n * @param {String|Array} content Content to translate\n * @param {Array} options Additional options\n * @param {Bool|null} caching Enable/disable caching\n * @return {Promise}\n */\n const getTranslation = function (sourceLanguage, targetLanguage, content) {\n let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];\n let caching = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;\n return postRequest(_FtConfig.default.getApiEndpointFor('translation'), {\n sourceLanguage: sourceLanguage,\n targetLanguage: targetLanguage,\n content: content,\n options: options,\n caching: caching\n }, response => {\n return response;\n });\n };\n\n /**\n * Gets the current translation service API usage\n * @return {Promise}\n */\n const getUsage = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('usage'), response => {\n return response;\n });\n };\n\n /**\n * Get all language available for translation. Provides source/target lists from the translation\n * service API\n * @return {Promise}\n */\n const getAvailableLanguages = () => {\n return getRequest(_FtConfig.default.getApiEndpointFor('languages'), response => {\n return response;\n });\n };\n\n /**\n * Clear all cached translations\n * @return {Promise}\n */\n const deleteTranslationCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translationCache'), response => {\n return response;\n });\n };\n\n /**\n * Clear cached list of translatable languages\n * @return {Promise}\n */\n const deleteTranslatableLanguagesCache = () => {\n return deleteRequest(_FtConfig.default.getApiEndpointFor('translatableLanguagesCache'), response => {\n return response;\n });\n };\n\n /**\n * HTTP Requests\n */\n\n /**\n * Create headers for AJAX requests\n * @return {Object}\n */\n const requestHeaders = requestType => {\n const requestHeaders = {\n 'X-Requested-With': 'XMLHttpRequest'\n };\n if (requestType === 'GET') {\n requestHeaders['Accept'] = 'application/json';\n }\n if (requestType === 'POST') {\n requestHeaders['Content-Type'] = 'application/json';\n }\n return requestHeaders;\n };\n\n /**\n * Executes a POST request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Object} data Data for request\n * @param {Callable} data Function to handle response body\n * @return {Promise}\n */\n const postRequest = (endpoint, data, responseHandler) => {\n return fetch(endpoint, {\n method: 'POST',\n cache: 'no-store',\n headers: requestHeaders,\n body: JSON.stringify(data)\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a GET request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const getRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'GET',\n cache: 'no-store',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Executes a DELETE request to a given endpoint\n * @param {String} endpoint URL for AJAX request\n * @param {Callable} responseHandler Function to handle response body\n * @return {Promise}\n */\n const deleteRequest = (endpoint, responseHandler) => {\n return fetch(endpoint, {\n method: 'DELETE',\n headers: requestHeaders('GET')\n }).then(parseResponse).then(responseHandler).catch(handleFetchError);\n };\n\n /**\n * Parses response\n * @param {Object} response Fluency API response\n * @return {Object|Void}\n * @throws Error\n */\n const parseResponse = response => {\n if (response.status === 204) {\n return response;\n }\n if (response.ok) {\n return response.json();\n }\n throw new Error();\n };\n\n /**\n * Parses and returns results for a fetch error\n * These are network level errors that occur between ProcessWire and the hosting server\n * Any translation or service errors will be located within the response body itself\n * @param {Error} error Fetch API error object\n * @return {Object}\n */\n const handleFetchError = error => {\n console.error('[Fluency module API failure]', error.message);\n const returnObject = {\n error: null,\n message: null\n };\n switch (error.message.split(' ')[0]) {\n case 'NetworkError':\n returnObject.error = 'FLUENCY_CLIENT_DISCONNECTED';\n returnObject.message = errors['FLUENCY_CLIENT_DISCONNECTED'];\n break;\n default:\n returnObject.error = 'UNKNOWN_ERROR';\n returnObject.message = errors['UNKNOWN_ERROR'];\n break;\n }\n return returnObject;\n };\n return {\n deleteTranslatableLanguagesCache,\n deleteTranslationCache,\n getAvailableLanguages,\n getTranslation,\n getUsage\n };\n}();\nvar _default = Fluency;\nexports.default = _default;\n\n},{\"./FtConfig\":3}],3:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * This provides access methods to get module configuration values\n * @return {Object} Public methods\n */\nconst FtConfig = function () {\n // Public properties\n\n const fieldInitializedAttr = 'data-ft-initialized';\n const translationActionTypes = {\n each: 'translate_each_language',\n all: 'translate_to_all_languages'\n };\n\n // Private properties\n\n /**\n * Holds the data passed from the Fluency module\n * @access Private\n * @type {Object}\n */\n const config = ProcessWire.config.fluency;\n\n /**\n * All UI strings\n * @type {Object}\n */\n const localizedStrings = config.localization;\n\n /**\n * Classes for elements created in UI\n * @type {Object}\n */\n const elementClasses = {\n translateButton: {\n container: 'ft-translate-button-container',\n button: 'ft-translate-button'\n },\n translateAllButton: {\n container: 'Inputfield InputfieldHeaderHidden',\n content: 'InputfieldContent',\n button: 'ft-translate-all-button'\n },\n statusPlaceholder: {\n container: 'ft-translation-status-container',\n label: 'ft-translation-status'\n },\n icon: 'ft-icon'\n };\n\n /**\n * Objects interface with the Fluency config object so that changes to the object\n * structure from the back end do not break the UI. Use the public methods below\n * to access ProcessWire.config.fluency properties and data\n */\n\n /**\n * Localized strings keyed sets\n * @type {Object}\n */\n const strings = {\n activityOverlay: localizedStrings.activityOverlay,\n languageSelect: localizedStrings.languageSelect,\n inputfieldTranslateButtons: localizedStrings.inputfieldTranslateButtons,\n standaloneTranslator: localizedStrings.standaloneTranslator,\n usage: localizedStrings.usage,\n errors: localizedStrings.errors,\n languageTranslator: localizedStrings.languageTranslator\n };\n\n /**\n * Fluency API keyed URLs\n * @type {Object}\n */\n const endpoints = {\n languages: config.apiEndpoints.languages,\n translatableLanguagesCache: config.apiEndpoints.translatableLanguagesCache,\n test: config.apiEndpoints.test,\n translation: config.apiEndpoints.translation,\n translationCache: config.apiEndpoints.translationCache,\n usage: config.apiEndpoints.usage\n };\n\n /**\n * Contains all of the Fluency configured langauges from the module\n * @type {Array}\n */\n const configuredLanguages = config.configuredLanguages;\n\n /**\n * Contains an array of ProcessWire language IDs not configured in Fluency\n * @type {Array}\n */\n const unconfiguredLanguages = config.unconfiguredLanguages;\n\n // Public methods\n\n /**\n * Fluency REST API\n */\n const getApiEndpointFor = key => endpoints[key];\n\n /**\n * Languages\n */\n\n /**\n * Get all configured languages\n * @return {object}\n */\n const getConfiguredLanguages = () => configuredLanguages;\n\n /**\n * Returns ProcessWire's default language\n * @return {object}\n */\n const getDefaultLanguage = () => getConfiguredLanguages().reduce((defaultLang, lang) => lang.default ? lang : defaultLang, null);\n\n /**\n * Determines if the language with a given ProcessWire ID can be translated\n * @param {int|string} languageId ProcessWire language ID\n * @return {bool}\n */\n const languageIsTranslatable = languageId => !getUnconfiguredLanguages().includes(parseInt(languageId, 10));\n\n /**\n * Get all languages not configured in Fluency\n * @return {object}\n */\n const getUnconfiguredLanguages = () => unconfiguredLanguages;\n\n /**\n * Gets total count of configured and unconfigured languages\n * @return {int}\n */\n const getLanguageCount = () => getConfiguredLanguages().length + getUnconfiguredLanguages().length;\n\n /**\n * Get a configured language by it's ProcessWire ID\n * @param {string|int} pwLanguageId ProcessWire language ID\n * @return {object}\n */\n const getLanguageForId = pwLanguageId => {\n pwLanguageId = parseInt(pwLanguageId, 10);\n return getConfiguredLanguages().reduce((match, language) => language.id === pwLanguageId ? language : match, null);\n };\n\n /**\n * Localization\n */\n\n /**\n * Accessor method for localized UI strings\n * @param {string} key Object key\n * @return {string}\n */\n const getUiTextFor = key => strings[key];\n\n /**\n * Module Configuration/State\n */\n\n /**\n * Determines if Fluency JS should initialize based on whether languages have\n * been configured\n * @return {bool}\n */\n const moduleShouldInitialize = () => getConfiguredLanguages().length > 1;\n\n /**\n * Returns the translation engine config object for the engine configured in Fluency\n * @return {object|null}\n */\n const getEngineInfo = () => config.engine;\n\n /**\n * Does this engine provide usage data?\n * @return {bool}\n */\n const getEngineProvidesUsageData = () => getEngineInfo().providesUsageData;\n\n /**\n * Gets the type of translation action chosen in the Flunecy module config\n * @return {string}\n */\n const getTranslationAction = () => config.interface.inputfieldTranslationAction;\n const getElementClassesFor = element => elementClasses[element];\n return {\n fieldInitializedAttr,\n getApiEndpointFor,\n getConfiguredLanguages,\n getDefaultLanguage,\n getElementClassesFor,\n getEngineInfo,\n getEngineProvidesUsageData,\n getLanguageCount,\n getLanguageForId,\n getTranslationAction,\n getUiTextFor,\n getUnconfiguredLanguages,\n languageIsTranslatable,\n moduleShouldInitialize,\n translationActionTypes\n };\n}();\nvar _default = FtConfig;\nexports.default = _default;\n\n},{}],4:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n/**\n * These are common tools the Fluency translation module uses\n * It is loaded first in order of scripts added to the page so that the module\n * is available to all subsequent scripts\n *\n * @return {Object} Public methods\n */\nconst FtTools = function () {\n /**\n * Create a random string of hex characters\n * @param {Number} length\n * @return {String}\n */\n const randomHex = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6;\n const chars = '0123456789ABCDEF'.split('');\n [...Array(length)].reduce((hex, i) => hex = chars[Math.floor(Math.random() * chars.length)], '');\n };\n\n /**\n * Generate random string of upper/lower/ints\n * @param length\n * @return string\n */\n const createRandomString = function () {\n let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5;\n return [...Array(length)].map(() => Math.random().toString(36)[2]).join('');\n };\n\n /**\n * Appends a div to a given element with a defined string, optionally adds a unique\n * string in case differentiating between more than one with the same text is\n * needed\n * @param {Element} element Element to tag\n * @param {String} text Text for tag\n * @param {Boolean} addRandomId Add random ID string to tag\n * @return {Void}\n */\n const tagElement = function (element, text) {\n let addRandomId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n const tagDiv = document.createElement('div');\n tagDiv.setAttribute('class', 'ft-element-tag');\n if (addRandomId) {\n text += ' | ' + createRandomString();\n }\n tagDiv.innerText = text;\n element.appendChild(tagDiv);\n };\n\n /**\n * Creates a random HTML hex code\n * @return {String} [description]\n */\n const randomHexColor = () => `#${randomHex()}`;\n\n /**\n * Gets the page ID from the current URL\n * @return {int|null} Page ID number, null if not present\n */\n var getPageId = function () {\n var urlParams = new URLSearchParams(window.location.search);\n return urlParams ? parseInt(urlParams.get('id')) : null;\n };\n\n /**\n * Checks page ID against page ID passed\n * @param {int} id ID to check against\n * @return {bool} True/false whether is current page ID\n */\n const pageIdIs = id => getPageId() === id;\n return {\n tagElement,\n getPageId,\n pageIdIs\n };\n}();\nvar _default = FtTools;\nexports.default = _default;\n\n},{}],5:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtActivityOverlay = _interopRequireDefault(require(\"../ui/FtActivityOverlay\"));\nvar _FtUiElements = _interopRequireDefault(require(\"../ui/FtUiElements\"));\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Used for creating translation function for ProcessWire's core language translation pages\n *\n * @return {Object} Public methods\n */\nconst FtLanguageTranslatorInputfields = function () {\n /**\n * Initialize\n * @return {void}\n */\n const init = () => {\n initFields();\n initTranslateAllButton();\n };\n\n /**\n * Initializes per-field translation triggers\n * @return {void}\n */\n const initFields = () => {\n const translationInputfields = document.querySelectorAll('.InputfieldContent');\n if (!translationInputfields) {\n return;\n }\n [...translationInputfields].forEach(inputfield => {\n if (inputfield.querySelector('input.translatable, textarea.translatable')) {\n new LanguageTranslatorInputfield(inputfield);\n }\n });\n };\n const initTranslateAllButton = () => {\n const container = document.querySelector('.Inputfields');\n new AllInputfieldTranslator(container);\n };\n return {\n init\n };\n}();\n\n/**\n * Creates and binds the translate all button\n */\nconst AllInputfieldTranslator = function (inputfields) {\n let activityOverlay;\n let sourceTargetMap = [];\n this.getSelf = () => inputfields;\n this.getActivityOverlay = () => activityOverlay;\n this.addTranslateButton = () => {\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateAllButton();\n this.bindTranslateButton(button);\n document.querySelector('.Inputfields').insertAdjacentElement('afterbegin', container);\n };\n this.bindTranslateButton = button => {\n button.addEventListener('click', e => {\n e.preventDefault();\n this.translateContent();\n });\n };\n\n /**\n * This chunks the sourceTargetElement array into an array of smaller arrays that can be\n * handled by the translation service\n * @return {array} Array of arrays containing content/inputs\n */\n this.getGroupedContentForTranslation = () => {\n const perChunk = 40; // groups per chunk\n\n return sourceTargetMap.reduce((chunks, item, index) => {\n const chunkIndex = Math.floor(index / perChunk);\n if (!chunks[chunkIndex]) {\n chunks[chunkIndex] = []; // start a new chunk\n }\n\n chunks[chunkIndex].push(item);\n return chunks;\n }, []);\n };\n\n /**\n * Translates all fields in chunks\n * @return {void}\n */\n this.translateContent = () => {\n const translationGroups = this.getGroupedContentForTranslation();\n activityOverlay.showActivity();\n let groupsToTranslate = translationGroups.length;\n const urlParams = new URLSearchParams(window.location.search);\n const id = parseInt(urlParams.get('language_id'));\n let errorOccurred = false;\n translationGroups.forEach((translationGroup, i) => {\n // Stop trying if something went wrong\n if (errorOccurred) {\n return;\n }\n _Fluency.default.getTranslation(_FtConfig.default.getDefaultLanguage().engineLanguage.sourceCode, _FtConfig.default.getLanguageForId(id).engineLanguage.targetCode, translationGroup.map(sourceTarget => sourceTarget.text)).then(result => {\n // Handle an error\n if (result.error) {\n if (!errorOccurred) {\n activityOverlay.showError(result.message);\n errorOccurred = true;\n }\n return;\n }\n const translations = result.translations;\n if (translationGroup.length !== translations.length) {\n activityOverlay.showError('Error');\n errorOccurred = true;\n return;\n }\n for (let i = 0; i < translations.length; i++) {\n translationGroup[i].input.value = translations[i];\n }\n }).then(result => {\n groupsToTranslate--;\n if (groupsToTranslate === 0 && !errorOccurred) {\n activityOverlay.hide();\n }\n });\n });\n };\n\n /**\n * Push all source text and target inputs to array that can be translated in bulk\n * @return {void}\n */\n this.mapSourceTargetElements = () => {\n [...document.querySelectorAll('.InputfieldContent')].forEach(inputfield => {\n const description = inputfield.querySelector('.description');\n const targetInput = inputfield.querySelector('input.translatable, textarea.translatable');\n if (targetInput && description && description.innerText) {\n sourceTargetMap.push({\n text: description.innerText,\n input: targetInput\n });\n }\n });\n };\n (() => {\n activityOverlay = new _FtActivityOverlay.default(this);\n this.mapSourceTargetElements();\n this.addTranslateButton();\n })();\n};\nconst LanguageTranslatorInputfield = function (inputfieldContainer) {\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n let activityOverlay;\n let sourceText = inputfieldContainer.querySelector('.description').innerText;\n let targetInput = inputfieldContainer.querySelector('input, textarea');\n this.getSelf = () => inputfieldContainer;\n this.getActivityOverlay = () => activityOverlay;\n this.addTranslateButton = () => {\n const {\n button,\n container\n } = _FtUiElements.default.createTranslateButton(uiText.translate);\n this.bindTranslateButton(button);\n inputfieldContainer.appendChild(container);\n };\n this.bindTranslateButton = button => {\n button.addEventListener('click', e => {\n e.preventDefault();\n this.translateContent();\n });\n };\n this.translateContent = () => {\n const urlParams = new URLSearchParams(window.location.search);\n const id = parseInt(urlParams.get('language_id'));\n activityOverlay.showActivity();\n _Fluency.default.getTranslation(_FtConfig.default.getDefaultLanguage().engineLanguage.sourceCode, _FtConfig.default.getLanguageForId(id).engineLanguage.targetCode, sourceText).then(result => {\n if (result.error) {\n activityOverlay.showError(result.message);\n return;\n }\n targetInput.value = result.translations[0];\n activityOverlay.hide();\n });\n };\n (() => {\n activityOverlay = new _FtActivityOverlay.default(this);\n this.addTranslateButton();\n })();\n};\nvar _default = FtLanguageTranslatorInputfields;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../ui/FtActivityOverlay\":6,\"../ui/FtUiElements\":7}],6:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates, inserts, and controls the actions the activity overlay for the provided\n * targetContainer\n * @param {object} targetContainer An instantiated object for an inputfield or fieldset\n * @param {string} type The type of activity for this overlay. 'translate' or 'update'\n */\nconst FtActivityOverlay = function (targetContainer) {\n var _this = this;\n let activityType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'translating';\n const elClasses = {\n parent: 'ft-activity-overlay-container',\n overlay: 'ft-activity-overlay',\n error: 'error',\n message: 'message',\n flash: 'flash',\n success: 'success',\n activity: 'activity',\n visible: 'visible',\n activityContainer: 'ft-activity',\n activityStaticText: 'ft-activity-text',\n activityAnimationContainer: 'ft-activity-animation-container',\n activityAnimationItem: 'ft-activity-animation-item',\n messageContainer: 'ft-activity-message'\n };\n\n /**\n * Will contain the activityOverlay Element for this targetContainer\n * @type {Element}\n */\n let activityOverlay;\n\n /**\n * Will contain the message Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let messageContainer;\n\n /**\n * Will contain the animation container Element for this targetContainer's activityOverlay\n * @type {Element}\n */\n let activityContainer;\n\n /**\n * Control Methods\n */\n\n /**\n * This shows the overlay's activity animation that was created at instantiation\n * Must be manually hidden with the hide() method\n *\n * @return {void}\n */\n this.showActivity = () => {\n this.setActivityActive();\n this.setOverlayVisible();\n };\n\n /**\n * Shows a message in the overlay (neutral background)\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showMessage = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5000;\n _this.setMessageContent(message);\n _this.setActivityInactive();\n _this.setMessageActive();\n _this.setOverlayVisible();\n _this.hide(displayTime);\n };\n\n /**\n * Shows a success message (success color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashSuccess = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setSuccessActive();\n _this.setFlashActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows a success message (error color background)\n *\n * @param {String} message Text to display\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {[type]} [description]\n */\n this.flashError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n _this.setFlashActive();\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Shows an error message in a visible overlay (error background)\n *\n * @param {String} message Message to show in overlay error\n * @param {Number} displayTime Length of time in ms before hiding overlay after shown\n * @return {void}\n */\n this.showError = function (message) {\n let displayTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 7000;\n _this.setErrorActive();\n _this.showMessage(message, displayTime);\n };\n\n /**\n * Hide an overlay immediately or after a preset amount of time\n *\n * @param {Number} delay Length of time in ms before hiding overlay\n */\n this.hide = function () {\n let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n setTimeout(() => {\n _this.setOverlayInvisible();\n }, delay);\n\n // Ensures the animation is finished before modifying content\n setTimeout(() => {\n _this.setActivityInactive();\n _this.setMessageInactive();\n _this.setErrorInactive();\n _this.setFlashInactive();\n _this.setMessageContent('');\n }, delay + 500);\n };\n\n /**\n * Private Methods\n */\n\n /**\n * Shows the activity element\n *\n * @access Private\n */\n this.setActivityActive = () => {\n activityOverlay.classList.add(elClasses.activity);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setActivityInactive = () => {\n activityOverlay.classList.remove(elClasses.activity);\n };\n\n /**\n * Shows the message element\n *\n * @access Private\n */\n this.setMessageActive = () => {\n activityOverlay.classList.add(elClasses.message);\n };\n\n /**\n * Hides the activity element\n *\n * @access Private\n */\n this.setMessageInactive = () => {\n activityOverlay.classList.remove(elClasses.message);\n };\n\n /**\n * Sets the content of the overlay message\n *\n * @access Private\n */\n this.setMessageContent = content => {\n messageContainer.innerText = content;\n };\n\n /**\n * Adds flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashActive = content => {\n activityOverlay.classList.add(elClasses.flash);\n };\n\n /**\n * removes flashing overlay behavior\n *\n * @access Private\n */\n this.setFlashInactive = content => {\n activityOverlay.classList.remove(elClasses.flash);\n };\n\n /**\n * Sets message to success\n *\n * @access Private\n */\n this.setSuccessActive = () => {\n activityOverlay.classList.add(elClasses.success);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setSuccessInactive = () => {\n activityOverlay.classList.remove(elClasses.success);\n };\n\n /**\n * Sets message to error\n *\n * @access Private\n */\n this.setErrorActive = () => {\n activityOverlay.classList.add(elClasses.error);\n };\n\n /**\n * Unsets message error\n *\n * @access Private\n */\n this.setErrorInactive = () => {\n activityOverlay.classList.remove(elClasses.error);\n };\n\n /**\n * Shows this activity overlay\n *\n * @access Private\n */\n this.setOverlayVisible = () => {\n activityOverlay.classList.add(elClasses.visible);\n };\n this.setOverlayInvisible = () => {\n activityOverlay.classList.remove(elClasses.visible);\n };\n\n /**\n * Creates and returns an activity overlay element\n *\n * @return {HTMLElement}\n */\n this.create = () => {\n activityOverlay = this.buildOverlayEl();\n activityContainer = this.buildActivityEl();\n messageContainer = this.buildMessageEl();\n activityOverlay.appendChild(activityContainer);\n activityOverlay.appendChild(messageContainer);\n return activityOverlay;\n };\n\n /**\n * Creates the parent overlay element\n *\n * @return {Element}\n * @access Private\n */\n this.buildOverlayEl = () => {\n const overlay = document.createElement('div');\n\n // overlay.setAttribute('data-gradient-1', 'rgba(62, 185, 152, .85)');\n overlay.setAttribute('class', elClasses.overlay);\n return overlay;\n };\n\n /**\n * Creates container for animation and contents of animation\n *\n * @return {Element}\n * @access Private\n */\n this.buildActivityEl = () => {\n let text = _FtConfig.default.getUiTextFor('activityOverlay')[activityType];\n let activityAnimationContainer = document.createElement('div');\n activityAnimationContainer.setAttribute('class', elClasses.activityAnimationContainer);\n\n // Add all animation items to the animation container\n activityAnimationContainer = text.animated.reduce((el, string) => {\n let activityText = document.createElement('span');\n\n // Add text items\n activityText.setAttribute('class', elClasses.activityAnimationItem);\n activityText.innerHTML = string;\n el.appendChild(activityText);\n return el;\n }, activityAnimationContainer);\n\n // Create static text element\n let staticText = document.createElement('div');\n staticText.setAttribute('class', elClasses.activityStaticText);\n staticText.innerText = text.static;\n\n // Create activity container and append children\n activityContainer = document.createElement('div');\n activityContainer.setAttribute('class', elClasses.activityContainer);\n activityContainer.appendChild(staticText);\n activityContainer.appendChild(activityAnimationContainer);\n return activityContainer;\n };\n\n /**\n * Builds the element that will hold messages in the overlay\n *\n * @return {Element}\n * @access Private\n */\n this.buildMessageEl = () => {\n messageContainer = document.createElement('div');\n messageContainer.setAttribute('class', elClasses.messageContainer);\n return messageContainer;\n };\n (() => {\n const targetContainerContainer = targetContainer.getSelf();\n activityOverlay = this.create();\n targetContainerContainer.classList.add(elClasses.parent);\n targetContainerContainer.appendChild(activityOverlay);\n })();\n};\nvar _default = FtActivityOverlay;\nexports.default = _default;\n\n},{\"../global/FtConfig\":3}],7:[function(require,module,exports){\n\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar _FtConfig = _interopRequireDefault(require(\"../global/FtConfig\"));\nvar _FtTools = _interopRequireDefault(require(\"../global/FtTools\"));\nvar _Fluency = _interopRequireDefault(require(\"../global/Fluency\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n/**\n * Creates common HTML elements\n *\n * @return {Object} Public methods\n */\nconst FtUiElements = function () {\n /**\n * @type {Object}\n */\n const elementClasses = _FtConfig.default.elementClasses;\n\n /**\n * Gets all localized strings from the FluencyConfig object\n * These do nothing on their own and must be bound with any behavior after creation\n *\n * @type {object}\n */\n const uiText = _FtConfig.default.getUiTextFor('inputfieldTranslateButtons');\n\n /**\n * Creates a language fontawesome icon element\n *\n * @return {Element}\n */\n const createIcon = () => {\n const iconLink = document.createElement('a');\n iconLink.setAttribute('href', `${ProcessWire.config.urls.admin}fluency/?modal=1`);\n iconLink.setAttribute('class', 'pw-modal pw-modal-large');\n const icon = document.createElement('i');\n icon.setAttribute('class', `${_FtConfig.default.getElementClassesFor('icon')} fa fa-language`);\n icon.setAttribute('uk-tooltip', uiText.showTranslator);\n iconLink.appendChild(icon);\n return iconLink;\n };\n\n /**\n * Creates a status placeholder\n *\n * @return {Element}\n */\n const createStatusElement = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('statusPlaceholder');\n const label = document.createElement('span');\n label.setAttribute('class', elClasses.label);\n label.innerText = text;\n const container = document.createElement('div');\n container.setAttribute('class', elClasses.container);\n container.appendChild(createIcon());\n container.appendChild(label);\n return container;\n };\n\n /**\n * Creates a translate button element\n *\n * @return {Object} Container element and Button element\n */\n const createTranslateButton = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('translateButton');\n const button = document.createElement('a');\n button.innerText = text;\n button.setAttribute('class', elClasses.button);\n button.setAttribute('href', '');\n const container = document.createElement('div');\n container.setAttribute('class', elClasses.container);\n container.appendChild(createIcon());\n container.appendChild(button);\n return {\n button,\n container\n };\n };\n const createTranslateAllButton = text => {\n const elClasses = _FtConfig.default.getElementClassesFor('translateAllButton');\n const button = document.createElement('a');\n button.innerText = _FtConfig.default.getUiTextFor('languageTranslator').translateAllButton;\n button.setAttribute('class', elClasses.button);\n button.setAttribute('href', '');\n const content = document.createElement('div');\n content.setAttribute('class', elClasses.content);\n content.appendChild(button);\n const container = document.createElement('li');\n container.setAttribute('class', elClasses.container);\n container.appendChild(content);\n return {\n button,\n container\n };\n };\n return {\n createStatusElement,\n createTranslateButton,\n createTranslateAllButton,\n createIcon,\n elementClasses\n };\n}();\nvar _default = FtUiElements;\nexports.default = _default;\n\n},{\"../global/Fluency\":2,\"../global/FtConfig\":3,\"../global/FtTools\":4}]},{},[1]);\n"],"names":["r","e","n","t","o","i","f","c","require","u","a","Error","code","p","exports","call","length","1","module","_FtLanguageTranslatorInputfields","_interopRequireDefault","_FtConfig","obj","__esModule","default","window","addEventListener","moduleShouldInitialize","init","./global/FtConfig","./inputfields/FtLanguageTranslatorInputfields","2","Object","defineProperty","value","Fluency","errors","getUiTextFor","requestHeaders","requestType","X-Requested-With","getRequest","endpoint","responseHandler","fetch","method","cache","headers","then","parseResponse","catch","handleFetchError","deleteRequest","response","status","ok","json","error","console","message","returnObject","split","deleteTranslatableLanguagesCache","getApiEndpointFor","deleteTranslationCache","getAvailableLanguages","getTranslation","sourceLanguage","targetLanguage","content","let","options","arguments","undefined","caching","data","body","JSON","stringify","getUsage","./FtConfig","3","FtConfig","config","ProcessWire","fluency","localizedStrings","localization","elementClasses","translateButton","container","button","translateAllButton","statusPlaceholder","label","icon","strings","activityOverlay","languageSelect","inputfieldTranslateButtons","standaloneTranslator","usage","languageTranslator","endpoints","languages","apiEndpoints","translatableLanguagesCache","test","translation","translationCache","configuredLanguages","unconfiguredLanguages","getConfiguredLanguages","getUnconfiguredLanguages","getEngineInfo","engine","fieldInitializedAttr","key","getDefaultLanguage","reduce","defaultLang","lang","getElementClassesFor","element","getEngineProvidesUsageData","providesUsageData","getLanguageCount","getLanguageForId","pwLanguageId","parseInt","match","language","id","getTranslationAction","interface","inputfieldTranslationAction","languageIsTranslatable","languageId","includes","translationActionTypes","each","all","4","getPageId","urlParams","URLSearchParams","location","search","get","tagElement","text","addRandomId","tagDiv","document","createElement","setAttribute","Array","map","Math","random","toString","join","innerText","appendChild","pageIdIs","5","_FtActivityOverlay","_FtUiElements","_Fluency","AllInputfieldTranslator","inputfields","sourceTargetMap","this","getSelf","getActivityOverlay","addTranslateButton","createTranslateAllButton","bindTranslateButton","querySelector","insertAdjacentElement","preventDefault","translateContent","getGroupedContentForTranslation","chunks","item","index","chunkIndex","floor","push","translationGroups","showActivity","groupsToTranslate","errorOccurred","forEach","translationGroup","engineLanguage","sourceCode","targetCode","sourceTarget","result","showError","translations","input","hide","mapSourceTargetElements","querySelectorAll","inputfield","description","targetInput","LanguageTranslatorInputfield","inputfieldContainer","uiText","sourceText","createTranslateButton","translate","initFields","translationInputfields","initTranslateAllButton","../global/Fluency","../global/FtConfig","../ui/FtActivityOverlay","../ui/FtUiElements","6","targetContainer","_this","activityType","elClasses","parent","overlay","flash","success","activity","visible","activityContainer","activityStaticText","activityAnimationContainer","activityAnimationItem","messageContainer","setActivityActive","setOverlayVisible","showMessage","displayTime","setMessageContent","setActivityInactive","setMessageActive","flashSuccess","setSuccessActive","setFlashActive","flashError","setErrorActive","delay","setTimeout","setOverlayInvisible","setMessageInactive","setErrorInactive","setFlashInactive","classList","add","remove","setSuccessInactive","create","buildOverlayEl","buildActivityEl","buildMessageEl","animated","el","string","activityText","innerHTML","staticText","static","targetContainerContainer","7","FtUiElements","createIcon","iconLink","urls","admin","showTranslator","createStatusElement","../global/FtTools"],"mappings":"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"} \ No newline at end of file diff --git a/gulpfile.babel.js b/gulpfile.babel.js index b21753d..f714540 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -145,7 +145,7 @@ const watch = async function () { Scripts.compileFluency, // Scripts.compileStandaloneTranslator, // Scripts.compileApiUsage, - // Scripts.compileLanguageTranslator, + Scripts.compileLanguageTranslator, // Scripts.compileModuleConfig, ), ); diff --git a/src/scripts/global/FtConfig.js b/src/scripts/global/FtConfig.js index 240f578..cfce2bc 100644 --- a/src/scripts/global/FtConfig.js +++ b/src/scripts/global/FtConfig.js @@ -7,6 +7,11 @@ const FtConfig = (function () { const fieldInitializedAttr = 'data-ft-initialized'; + const translationActionTypes = { + each: 'translate_each_language', + all: 'translate_to_all_languages', + }; + // Private properties /** @@ -22,6 +27,27 @@ const FtConfig = (function () { */ const localizedStrings = config.localization; + /** + * Classes for elements created in UI + * @type {Object} + */ + const elementClasses = { + translateButton: { + container: 'ft-translate-button-container', + button: 'ft-translate-button', + }, + translateAllButton: { + container: 'Inputfield InputfieldHeaderHidden', + content: 'InputfieldContent', + button: 'ft-translate-all-button', + }, + statusPlaceholder: { + container: 'ft-translation-status-container', + label: 'ft-translation-status', + }, + icon: 'ft-icon', + }; + /** * Objects interface with the Fluency config object so that changes to the object * structure from the back end do not break the UI. Use the public methods below @@ -39,6 +65,7 @@ const FtConfig = (function () { standaloneTranslator: localizedStrings.standaloneTranslator, usage: localizedStrings.usage, errors: localizedStrings.errors, + languageTranslator: localizedStrings.languageTranslator, }; /** @@ -77,22 +104,48 @@ const FtConfig = (function () { * Languages */ + /** + * Get all configured languages + * @return {object} + */ const getConfiguredLanguages = () => configuredLanguages; + /** + * Returns ProcessWire's default language + * @return {object} + */ const getDefaultLanguage = () => getConfiguredLanguages().reduce( (defaultLang, lang) => (lang.default ? lang : defaultLang), null, ); + /** + * Determines if the language with a given ProcessWire ID can be translated + * @param {int|string} languageId ProcessWire language ID + * @return {bool} + */ const languageIsTranslatable = languageId => !getUnconfiguredLanguages().includes(parseInt(languageId, 10)); + /** + * Get all languages not configured in Fluency + * @return {object} + */ const getUnconfiguredLanguages = () => unconfiguredLanguages; + /** + * Gets total count of configured and unconfigured languages + * @return {int} + */ const getLanguageCount = () => getConfiguredLanguages().length + getUnconfiguredLanguages().length; + /** + * Get a configured language by it's ProcessWire ID + * @param {string|int} pwLanguageId ProcessWire language ID + * @return {object} + */ const getLanguageForId = pwLanguageId => { pwLanguageId = parseInt(pwLanguageId, 10); @@ -106,38 +159,55 @@ const FtConfig = (function () { * Localization */ + /** + * Accessor method for localized UI strings + * @param {string} key Object key + * @return {string} + */ const getUiTextFor = key => strings[key]; /** * Module Configuration/State */ + /** + * Determines if Fluency JS should initialize based on whether languages have + * been configured + * @return {bool} + */ const moduleShouldInitialize = () => getConfiguredLanguages().length > 1; + /** + * Returns the translation engine config object for the engine configured in Fluency + * @return {object|null} + */ const getEngineInfo = () => config.engine; + /** + * Does this engine provide usage data? + * @return {bool} + */ const getEngineProvidesUsageData = () => getEngineInfo().providesUsageData; - const getTranslationAction = () => config.interface.inputfieldTranslationAction; - /** - * Translation types. No magic strings. + * Gets the type of translation action chosen in the Flunecy module config + * @return {string} */ - const translationActionTypes = { - each: 'translate_each_language', - all: 'translate_to_all_languages', - }; + const getTranslationAction = () => config.interface.inputfieldTranslationAction; + + const getElementClassesFor = element => elementClasses[element]; return { fieldInitializedAttr, getApiEndpointFor, getConfiguredLanguages, getDefaultLanguage, + getElementClassesFor, getEngineInfo, getEngineProvidesUsageData, - getTranslationAction, getLanguageCount, getLanguageForId, + getTranslationAction, getUiTextFor, getUnconfiguredLanguages, languageIsTranslatable, diff --git a/src/scripts/inputfields/FtLanguageTranslatorInputfields.js b/src/scripts/inputfields/FtLanguageTranslatorInputfields.js index 67dc43d..8367c48 100644 --- a/src/scripts/inputfields/FtLanguageTranslatorInputfields.js +++ b/src/scripts/inputfields/FtLanguageTranslatorInputfields.js @@ -9,7 +9,20 @@ import Fluency from '../global/Fluency'; * @return {Object} Public methods */ const FtLanguageTranslatorInputfields = (function () { + /** + * Initialize + * @return {void} + */ const init = () => { + initFields(); + initTranslateAllButton(); + }; + + /** + * Initializes per-field translation triggers + * @return {void} + */ + const initFields = () => { const translationInputfields = document.querySelectorAll('.InputfieldContent'); if (!translationInputfields) { @@ -17,42 +30,41 @@ const FtLanguageTranslatorInputfields = (function () { } [...translationInputfields].forEach(inputfield => { - if (inputfield.querySelector('input.translatable')) { + if (inputfield.querySelector('input.translatable, textarea.translatable')) { new LanguageTranslatorInputfield(inputfield); } }); }; + const initTranslateAllButton = () => { + const container = document.querySelector('.Inputfields'); + + new AllInputfieldTranslator(container); + }; + return { init, }; })(); -const LanguageTranslatorInputfield = function (inputfieldContainer) { - /** - * Gets all localized strings from the FluencyConfig object - * These do nothing on their own and must be bound with any behavior after creation - * - * @type {object} - */ - const uiText = FtConfig.getUiTextFor('inputfieldTranslateButtons'); - +/** + * Creates and binds the translate all button + */ +const AllInputfieldTranslator = function (inputfields) { let activityOverlay; - let sourceText = inputfieldContainer.querySelector('.description').innerText; + let sourceTargetMap = []; - let targetInput = inputfieldContainer.querySelector('input'); - - this.getSelf = () => inputfieldContainer; + this.getSelf = () => inputfields; this.getActivityOverlay = () => activityOverlay; this.addTranslateButton = () => { - const { button, container } = FtUiElements.createTranslateButton(uiText.translate); + const { button, container } = FtUiElements.createTranslateAllButton(); this.bindTranslateButton(button); - inputfieldContainer.appendChild(container); + document.querySelector('.Inputfields').insertAdjacentElement('afterbegin', container); }; this.bindTranslateButton = button => { @@ -63,226 +75,177 @@ const LanguageTranslatorInputfield = function (inputfieldContainer) { }); }; - this.translateContent = () => { - const urlParams = new URLSearchParams(window.location.search); - const id = parseInt(urlParams.get('language_id')); - - activityOverlay.showActivity(); + /** + * This chunks the sourceTargetElement array into an array of smaller arrays that can be + * handled by the translation service + * @return {array} Array of arrays containing content/inputs + */ + this.getGroupedContentForTranslation = () => { + const perChunk = 40; // groups per chunk - Fluency.getTranslation( - FtConfig.getDefaultLanguage().engineLanguage.sourceCode, - FtConfig.getLanguageForId(id).engineLanguage.targetCode, - sourceText - ).then(result => { - if (result.error) { - activityOverlay.showError(result.message); + return sourceTargetMap.reduce((chunks, item, index) => { + const chunkIndex = Math.floor(index / perChunk); - return; + if (!chunks[chunkIndex]) { + chunks[chunkIndex] = []; // start a new chunk } - targetInput.value = result.translations[0]; + chunks[chunkIndex].push(item); - activityOverlay.hide(); - }); + return chunks; + }, []); }; - (() => { - activityOverlay = new FtActivityOverlay(this); - - this.addTranslateButton(); - })(); -}; - -export default FtLanguageTranslatorInputfields; - -/** - * Handles IO operations for a multilanguage InputfieldText element - * Language IDs are always converted to int to accept values from all sources since some may be - * retrieved from various sources as a string - * - * NOTE: This is not a standard inputfield object and should not be instantiated in FtInputfields - * and only in specific locations of the PW Admin - * - * @param {Element} - */ -const FtInputfieldText = function (inputfield) { /** - * Page-load values for all fields/languages - * Populated on object instantiation - * @property {String} ProcessWire Language ID - * @type {Object} + * Translates all fields in chunks + * @return {void} */ - const initValues = {}; + this.translateContent = () => { + const translationGroups = this.getGroupedContentForTranslation(); - /** - * Will contain new values for fields/languages when content is modified - * @property {String} ProcessWire Language ID - * @type {Object} - */ - const changedValues = {}; + activityOverlay.showActivity(); - /** - * FtLanguageTab objects for each language - * @property {String} ProcessWire Language ID - * @type {Object} - */ - const languageTabs = {}; + let groupsToTranslate = translationGroups.length; - /** - * Will contain all elements containing language inputs - * @property {String} ProcessWire Language ID - * @type {NodeList} - */ - const inputContainers = {}; + const urlParams = new URLSearchParams(window.location.search); + const id = parseInt(urlParams.get('language_id')); - /** - * Text input fields - * @property {String} ProcessWire Language ID - * @type {Object} - */ - const languageFields = {}; + let errorOccurred = false; - /** - * Activity overlay object, set on instantiation - * - * @access public - * @type {Object} - */ - let activityOverlay; + translationGroups.forEach((translationGroup, i) => { + // Stop trying if something went wrong + if (errorOccurred) { + return; + } - /* - * @access public - * @return {Object} - */ - this.getActivityOverlay = () => activityOverlay; + Fluency.getTranslation( + FtConfig.getDefaultLanguage().engineLanguage.sourceCode, + FtConfig.getLanguageForId(id).engineLanguage.targetCode, + translationGroup.map(sourceTarget => sourceTarget.text), + ) + .then(result => { + // Handle an error + if (result.error) { + if (!errorOccurred) { + activityOverlay.showError(result.message); - /** - * @access public - * @return {Element} Inputfield element passed to this object on creation - */ - this.getSelf = () => inputfield; + errorOccurred = true; + } - /** - * @access public - * @return {Mixed} - */ - this.getValueForDefaultLanguage = () => - this.getValueForLanguage(FtConfig.getDefaultLanguage().id); + return; + } - /** - * @access public - * @param {String|Int} languageId ProcessWire language ID - * @return {Mixed} - */ - this.getValueForLanguage = languageId => this.getFieldForLanguage(languageId).value; + const translations = result.translations; - /** - * @access public - * @param {String|Int} languageId ProcessWire language ID - * @param {Mixed} value Value to insert into field - * @return {Bool} Content is different from page load value - */ - this.setValueForLanguage = (languageId, value) => { - const field = this.getFieldForLanguage(languageId); + if (translationGroup.length !== translations.length) { + activityOverlay.showError('Error'); + + errorOccurred = true; - FtInputfields.updateValue(field, value); + return; + } - // Required to programmatically trigger the event listener for this field - field.dispatchEvent(new Event('input')); + for (let i = 0; i < translations.length; i++) { + translationGroup[i].input.value = translations[i]; + } + }) + .then(result => { + groupsToTranslate--; - return this.contentHasChanged(languageId); + if (groupsToTranslate === 0 && !errorOccurred) { + activityOverlay.hide(); + } + }); + }); }; /** - * @access private - * @param {String|Int} languageId ProcessWire language ID - * @return {Element} Text field + * Push all source text and target inputs to array that can be translated in bulk + * @return {void} */ - this.getFieldForLanguage = languageId => { - if (Object.hasOwn(languageFields, languageId) && !!languageFields[languageId]) { - return languageFields[languageId]; - } + this.mapSourceTargetElements = () => { + [...document.querySelectorAll('.InputfieldContent')].forEach(inputfield => { + const description = inputfield.querySelector('.description'); + const targetInput = inputfield.querySelector('input.translatable, textarea.translatable'); - languageFields[languageId] = - this.getInputContainerForLanguage(languageId).querySelector('input'); - - return languageFields[languageId]; + if (targetInput && description && description.innerText) { + sourceTargetMap.push({ text: description.innerText, input: targetInput }); + } + }); }; - /** - * Gets a specific input container - * @access private - * @param {String|Int} languageId ProcessWire language ID - * @return {Element} - */ - this.getInputContainerForLanguage = languageId => { - if (Object.hasOwn(inputContainers, languageId) && !!inputContainers[languageId]) { - return inputContainers[languageId]; - } + (() => { + activityOverlay = new FtActivityOverlay(this); - inputContainers[languageId] = inputfield.querySelector(`[data-language="${languageId}"]`); + this.mapSourceTargetElements(); - return inputContainers[languageId]; - }; + this.addTranslateButton(); + })(); +}; +const LanguageTranslatorInputfield = function (inputfieldContainer) { /** - * Get all input containers where content is entered, memoizes - * @access private - * @return {Object} All languages keyed by (int) language ID + * Gets all localized strings from the FluencyConfig object + * These do nothing on their own and must be bound with any behavior after creation + * + * @type {object} */ - this.getInputContainers = () => { - inputfield - .querySelectorAll('[data-language]') - .forEach(el => (inputContainers[el.dataset.language] = el)); + const uiText = FtConfig.getUiTextFor('inputfieldTranslateButtons'); + + let activityOverlay; + + let sourceText = inputfieldContainer.querySelector('.description').innerText; + + let targetInput = inputfieldContainer.querySelector('input, textarea'); + + this.getSelf = () => inputfieldContainer; + + this.getActivityOverlay = () => activityOverlay; + + this.addTranslateButton = () => { + const { button, container } = FtUiElements.createTranslateButton(uiText.translate); - return inputContainers; + this.bindTranslateButton(button); + + inputfieldContainer.appendChild(container); }; - /** - * @access private - * @param {String|Int} languageId ProcessWire language ID - * @return {Bool} - */ - this.contentHasChanged = languageId => - Object.hasOwn(changedValues, languageId) && - changedValues[languageId] !== initValues[languageId]; + this.bindTranslateButton = button => { + button.addEventListener('click', e => { + e.preventDefault(); - /** - * Registers the event listener that watches for changes - * @access private - * @param {String|Int} languageId ProcessWire language ID - * @return {Void} - */ - this.registerInputEventListener = languageId => { - this.getFieldForLanguage(languageId).addEventListener('input', e => { - changedValues[languageId] = e.target.value; - languageTabs[languageId].setModifiedState(this.contentHasChanged(languageId)); + this.translateContent(); }); }; - /** - * Init method executed on object instantiation - * - Stores initial field values for each langauge - * - Creates/stores an FtLanguageTab object for each language - * - Binds an event that detects changes on input - * @return {Void} - */ - (() => { - const allInputContainers = this.getInputContainers(); + this.translateContent = () => { + const urlParams = new URLSearchParams(window.location.search); + const id = parseInt(urlParams.get('language_id')); - for (let languageId in allInputContainers) { - let inputContainer = allInputContainers[languageId]; + activityOverlay.showActivity(); - initValues[languageId] = this.getValueForLanguage(languageId); - languageTabs[languageId] = new FtLanguageTab(inputContainer); + Fluency.getTranslation( + FtConfig.getDefaultLanguage().engineLanguage.sourceCode, + FtConfig.getLanguageForId(id).engineLanguage.targetCode, + sourceText, + ).then(result => { + if (result.error) { + activityOverlay.showError(result.message); - this.registerInputEventListener(languageId); - } + return; + } + targetInput.value = result.translations[0]; + + activityOverlay.hide(); + }); + }; + + (() => { activityOverlay = new FtActivityOverlay(this); - new FtInputfieldTranslateButton(this, allInputContainers); + this.addTranslateButton(); })(); }; -export { LanguageTranslatorInputfield, FtInputfieldText }; +export default FtLanguageTranslatorInputfields; diff --git a/src/scripts/ui/FtUiElements.js b/src/scripts/ui/FtUiElements.js index b48447a..94d97e0 100644 --- a/src/scripts/ui/FtUiElements.js +++ b/src/scripts/ui/FtUiElements.js @@ -11,17 +11,7 @@ const FtUiElements = (function () { /** * @type {Object} */ - const elementClasses = { - translateButton: { - container: 'ft-translate-button-container', - button: 'ft-translate-button', - }, - statusPlaceholder: { - container: 'ft-translation-status-container', - label: 'ft-translation-status', - }, - icon: 'ft-icon', - }; + const elementClasses = FtConfig.elementClasses; /** * Gets all localized strings from the FluencyConfig object @@ -42,7 +32,7 @@ const FtUiElements = (function () { iconLink.setAttribute('class', 'pw-modal pw-modal-large'); const icon = document.createElement('i'); - icon.setAttribute('class', `${elementClasses.icon} fa fa-language`); + icon.setAttribute('class', `${FtConfig.getElementClassesFor('icon')} fa fa-language`); icon.setAttribute('uk-tooltip', uiText.showTranslator); iconLink.appendChild(icon); @@ -56,12 +46,14 @@ const FtUiElements = (function () { * @return {Element} */ const createStatusElement = text => { + const elClasses = FtConfig.getElementClassesFor('statusPlaceholder'); + const label = document.createElement('span'); - label.setAttribute('class', elementClasses.statusPlaceholder.label); + label.setAttribute('class', elClasses.label); label.innerText = text; const container = document.createElement('div'); - container.setAttribute('class', elementClasses.statusPlaceholder.container); + container.setAttribute('class', elClasses.container); container.appendChild(createIcon()); container.appendChild(label); @@ -75,13 +67,15 @@ const FtUiElements = (function () { * @return {Object} Container element and Button element */ const createTranslateButton = text => { + const elClasses = FtConfig.getElementClassesFor('translateButton'); + const button = document.createElement('a'); button.innerText = text; - button.setAttribute('class', elementClasses.translateButton.button); + button.setAttribute('class', elClasses.button); button.setAttribute('href', ''); const container = document.createElement('div'); - container.setAttribute('class', elementClasses.translateButton.container); + container.setAttribute('class', elClasses.container); container.appendChild(createIcon()); container.appendChild(button); @@ -92,9 +86,32 @@ const FtUiElements = (function () { }; }; + const createTranslateAllButton = text => { + const elClasses = FtConfig.getElementClassesFor('translateAllButton'); + + const button = document.createElement('a'); + button.innerText = FtConfig.getUiTextFor('languageTranslator').translateAllButton; + button.setAttribute('class', elClasses.button); + button.setAttribute('href', ''); + + const content = document.createElement('div'); + content.setAttribute('class', elClasses.content); + content.appendChild(button); + + const container = document.createElement('li'); + container.setAttribute('class', elClasses.container); + container.appendChild(content); + + return { + button, + container, + }; + }; + return { createStatusElement, createTranslateButton, + createTranslateAllButton, createIcon, elementClasses, };