From 88f87eb85ac8127c72379fe5b90dde1eced3219a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 5 Apr 2023 15:27:32 +0200 Subject: [PATCH 001/240] chore(github): release workflow pointed to correct branch for 4.x --- .github/workflows/create-zip-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-zip-release.yml b/.github/workflows/create-zip-release.yml index 870e544071f..d4c6d8eedff 100644 --- a/.github/workflows/create-zip-release.yml +++ b/.github/workflows/create-zip-release.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v2 with: repository: Elgg/starter-project - ref: master + ref: 4.x path: ${{ steps.branch.outputs.ZIP_FOLDER }} - name: Composer Install From 58b1ae7d12eae286a48fde8afb1bd6e16704e26b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 19 Jun 2023 10:23:18 +0200 Subject: [PATCH 002/240] feat(html): added a scroll to top button --- engine/theme.php | 1 - languages/en.php | 2 ++ views/default/core.css.php | 1 + views/default/elements/misc/scroll_to_top.css | 19 +++++++++++++++++++ views/default/elements/reset.css.php | 8 ++++++++ views/default/elgg.js.php | 8 ++++++++ views/default/page/elements/foot.php | 11 +++++++---- views/default/page/layouts/elements/body.php | 12 +++++------- .../default/page/layouts/elements/footer.php | 6 ++---- .../default/page/layouts/elements/header.php | 6 ++---- 10 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 views/default/elements/misc/scroll_to_top.css diff --git a/engine/theme.php b/engine/theme.php index 371a1a3502a..4cb1f89a4e4 100644 --- a/engine/theme.php +++ b/engine/theme.php @@ -25,7 +25,6 @@ 'h5-font-size' => '0.9rem', 'h6-font-size' => '0.8rem', - // element colors 'text-color-soft' => '#969696', 'text-color-mild' => '#7d7d7d', diff --git a/languages/en.php b/languages/en.php index 40ba21d6037..c9b00250222 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1197,6 +1197,8 @@ 'list:error:getter:admin' => "The getter '%s' returned a(n) '%s', however the viewer '%s' requires an array", 'link:text' => 'view link', + + 'scroll_to_top' => 'Scroll to top', /** * Generic questions diff --git a/views/default/core.css.php b/views/default/core.css.php index aa1234e2427..babc2569122 100644 --- a/views/default/core.css.php +++ b/views/default/core.css.php @@ -11,6 +11,7 @@ echo elgg_view('elements/widgets.css', $vars); echo elgg_view('elements/components.css', $vars); echo elgg_view('elements/layout.css', $vars); +echo elgg_view('elements/misc/scroll_to_top.css', $vars); echo elgg_view('elements/misc/spinner.css', $vars); echo elgg_view('elements/helpers.css', $vars); echo elgg_view('elements/z-index.css', $vars); diff --git a/views/default/elements/misc/scroll_to_top.css b/views/default/elements/misc/scroll_to_top.css new file mode 100644 index 00000000000..1dc82f6a7b3 --- /dev/null +++ b/views/default/elements/misc/scroll_to_top.css @@ -0,0 +1,19 @@ +#elgg-scroll-to-top { + display: none; + font-size: 1.5rem; + padding: 0.5rem 1rem; + border-radius: 4px; + background: $(background-color-soft); + color: $(text-color-highlight); + border: 1px solid $(border-color-highlight); + position: fixed; + right: 2rem; + bottom: 2rem; + + text-decoration: none; + opacity: 0.8; + + &:hover { + opacity: 1; + } +} diff --git a/views/default/elements/reset.css.php b/views/default/elements/reset.css.php index 505d0b23e8d..11ea68f4987 100644 --- a/views/default/elements/reset.css.php +++ b/views/default/elements/reset.css.php @@ -100,6 +100,13 @@ text-size-adjust: 100%; } +/* Smooth scrolling IF user doesn't have a preference due to motion sensitivities */ +@media screen and (prefers-reduced-motion: no-preference) { + html { + scroll-behavior: smooth; + } +} + article, aside, figure, @@ -127,6 +134,7 @@ } body { + position: relative; color: $(text-color-strong); background: $(body-background-color); font-size: 1rem; diff --git a/views/default/elgg.js.php b/views/default/elgg.js.php index df31cbc08b7..a675d9702f0 100644 --- a/views/default/elgg.js.php +++ b/views/default/elgg.js.php @@ -47,6 +47,14 @@ function requiresConfirmation(e) { }; $(document).on('click', '*[data-confirm]', requiresConfirmation); + + document.addEventListener('scroll', function() { + if ($(document).scrollTop() > 1000) { + $('#elgg-scroll-to-top').show(); + } else { + $('#elgg-scroll-to-top').hide(); + } + }, { passive: true }); return elgg; }); diff --git a/views/default/page/elements/foot.php b/views/default/page/elements/foot.php index 04fda9c9794..18102fc3ead 100644 --- a/views/default/page/elements/foot.php +++ b/views/default/page/elements/foot.php @@ -17,7 +17,10 @@ } $deps = _elgg_services()->amdConfig->getDependencies(); -?> - + +echo elgg_format_element('script', [], 'require(' . json_encode($deps, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . ');'); + +echo elgg_view_url('#top', elgg_view_icon('chevron-up'), [ + 'id' => 'elgg-scroll-to-top', + 'title' => elgg_echo('scroll_to_top'), +]); diff --git a/views/default/page/layouts/elements/body.php b/views/default/page/layouts/elements/body.php index f72e5da6e5e..4e9ad310da2 100644 --- a/views/default/page/layouts/elements/body.php +++ b/views/default/page/layouts/elements/body.php @@ -2,17 +2,15 @@ /** * Layout body * - * @uses $vars['breadcrumbs'] Breadcrumbs - * Will no be rendered if the value is 'false' - * Will render 'navigation/breadcrumbs' view if - * not set or is an array of breadcrumbs - * Will override breadcrumbs view if set to a string + * @uses $vars['breadcrumbs'] Breadcrumbs + * Will no be rendered if the value is 'false' + * Will render 'navigation/breadcrumbs' view if + * not set or is an array of breadcrumbs + * Will override breadcrumbs view if set to a string * * @uses $vars['title'] Optional title for main content area * @uses $vars['header'] Optional override for the header - * * @uses $vars['content'] Content - * @uses $vars['footer'] Optional footer */ $filter = elgg_view('page/layouts/elements/filter', $vars); diff --git a/views/default/page/layouts/elements/footer.php b/views/default/page/layouts/elements/footer.php index 8a025021fac..f93f174063c 100644 --- a/views/default/page/layouts/elements/footer.php +++ b/views/default/page/layouts/elements/footer.php @@ -9,7 +9,5 @@ if (empty($footer)) { return; } -?> - + +echo elgg_format_element('div', ['class' => ['elgg-foot', 'elgg-layout-footer']], $footer); diff --git a/views/default/page/layouts/elements/header.php b/views/default/page/layouts/elements/header.php index 15329d3461e..29b5d796790 100644 --- a/views/default/page/layouts/elements/header.php +++ b/views/default/page/layouts/elements/header.php @@ -30,7 +30,5 @@ if (empty($header)) { return; } -?> -
- -
+ +echo elgg_format_element('div', ['class' => ['elgg-head', 'elgg-layout-header']], $header); From f86aa5a8f06fa9d12218ab23a30402255c86487a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 20 Jun 2023 15:33:40 +0200 Subject: [PATCH 003/240] chore(core): changelog is now written by PHP fixes #14376 --- .scripts/release.php | 27 +- .scripts/write-changelog.js | 32 - docs/contribute/core/releases.rst | 8 +- .../classes/Elgg/Project/ChangelogWriter.php | 490 +++ package-lock.json | 3736 +++++++++-------- package.json | 3 +- yarn.lock | 206 +- 7 files changed, 2485 insertions(+), 2017 deletions(-) delete mode 100755 .scripts/write-changelog.js create mode 100644 engine/classes/Elgg/Project/ChangelogWriter.php diff --git a/.scripts/release.php b/.scripts/release.php index 814b520bb91..bd50c2b1be5 100644 --- a/.scripts/release.php +++ b/.scripts/release.php @@ -20,14 +20,21 @@ $matches = []; if (!preg_match($regexp, $version, $matches)) { - echo 'Bad version format. You must follow the format of X.Y.Z with an optional suffix of' - . ' -alpha.N, -beta.N, or -rc.N (where N is a number).' . PHP_EOL; + echo 'Bad version format. You must follow the format of X.Y.Z with an optional suffix of'; + echo ' -alpha.N, -beta.N, or -rc.N (where N is a number).' . PHP_EOL; exit(1); } require_once dirname(__DIR__) . '/vendor/autoload.php'; -function run_commands($commands) { +/** + * Execute a command in the commandline + * + * @param array $commands all commands to execute + * + * @return void + */ +function run_commands(array $commands): void { foreach ($commands as $command) { echo $command . PHP_EOL; @@ -62,16 +69,18 @@ function run_commands($commands) { $json = json_encode($composer_config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL; file_put_contents($composer_path, $json); +// write the changelog +$changelog = new \Elgg\Project\ChangelogWriter([ + 'version' => $version, +]); +$changelog(); + // make the new release -run_commands(array( +run_commands([ // update hash in composer.lock, because version was updated and now there is a mismatch between .json and .lock 'composer update --lock', - // Generate changelog - 'yarn install', - 'node .scripts/write-changelog.js', - // commit everything to GitHub 'git add .', "git commit -am \"chore(release): v{$version}\"", -)); +]); diff --git a/.scripts/write-changelog.js b/.scripts/write-changelog.js deleted file mode 100755 index 160abec5fa9..00000000000 --- a/.scripts/write-changelog.js +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env node - -var pkg = require('../composer.json'); -var fs = require('fs'); -var changelog = require('elgg-conventional-changelog'); - -changelog({ - version: pkg.version, - repository: 'https://github.com/Elgg/Elgg', - types: { - feat: 'Features', - feature: 'Features', - perf: 'Performance', - performance: 'Performance', - doc: 'Documentation', - docs: 'Documentation', - fix: 'Bug Fixes', - fixes: 'Bug Fixes', - fixed: 'Bug Fixes', - deprecate: 'Deprecations', - deprecates: 'Deprecations', - deprecated: 'Deprecations', - break: 'Breaking Changes', - breaks: 'Breaking Changes', - removed: 'Removed' - } -}, function (err, log) { - if (err) - throw new Error(err); - fs.writeFileSync('CHANGELOG.md', log); -}); - diff --git a/docs/contribute/core/releases.rst b/docs/contribute/core/releases.rst index 39e03429dc8..7f634622eea 100644 --- a/docs/contribute/core/releases.rst +++ b/docs/contribute/core/releases.rst @@ -110,13 +110,7 @@ Merge latest commits up from lowest supported branch. Visit ``https://github.com/Elgg/Elgg/compare/...`` and submit the PR if there is anything that needs to be merged up. -Install the prerequisites: - -.. code-block:: sh - - yarn install elgg-conventional-changelog - -.. note:: +.. note:: On Windows you need to run these command in a console with admin privileges diff --git a/engine/classes/Elgg/Project/ChangelogWriter.php b/engine/classes/Elgg/Project/ChangelogWriter.php new file mode 100644 index 00000000000..57f724cd5e9 --- /dev/null +++ b/engine/classes/Elgg/Project/ChangelogWriter.php @@ -0,0 +1,490 @@ + 'Features', + 'performance' => 'Performance', + 'documentation' => 'Documentation', + 'fix' => 'Bug fixes', + 'deprecated' => 'Deprecations', + 'breaking' => 'Breaking Changes', + 'removed' => 'Removed', + ]; + + /** + * Constructor + * + * @param array $options writer options + */ + public function __construct(array $options = []) { + $defaults = [ + 'changelog' => Paths::elgg() . 'CHANGELOG.md', + 'version' => null, + 'notes' => '', + 'repository' => 'https://github.com/Elgg/Elgg/', + ]; + + $options = array_merge($defaults, $options); + if (empty($options['version'])) { + throw new InvalidArgumentException('Please provide a release version number'); + } + + if (!file_exists($options['changelog']) || !is_writable($options['changelog'])) { + throw new InvalidArgumentException("The changelog file doesn't exist or is not writable"); + } + + $this->options = $options; + } + + /** + * Write the changelog for the current release + * + * @return void + */ + public function __invoke(): void { + $tags = $this->getGitTags(); + + $sections = []; + + $sections[] = $this->formatHeader(); + $sections[] = $this->readNotes(); + + $contributors = $this->getGitContributors([ + 'exclude' => $tags, + ]); + $sections[] = $this->formatContributors($contributors); + + $commits = $this->getGitCommits([ + 'exclude' => $tags, + ]); + $sections[] = $this->formatCommits($commits); + + $sections = array_filter($sections); + $output = trim(implode(PHP_EOL . PHP_EOL, $sections)); + + $this->writeChangelog($output); + } + + /** + * Read anything in the changelog before the first '' and consider this release notes + * + * @return string + */ + protected function readNotes(): string { + $contents = file_get_contents($this->getOption('changelog')); + $first_anchor = strpos($contents, 'executeCommand($command); + if (!isset($commits)) { + return []; + } + + $results = []; + $result = [ + 'body' => '', + ]; + $index = 0; + $subject_pattern = '/^((Merge )|(Revert )|((\w*)\(([\w]+)\)\: ([^\n]*))$)/'; + foreach ($commits as $line) { + if ($line === '==END==') { + $result['body'] = trim($result['body'] ?: '', PHP_EOL); + + $results[] = $result; + $index = 0; + $result = [ + 'body' => '', + ]; + continue; + } + + switch ($index) { + case 0: // long hash + $result['hash'] = $line; + break; + + case 1: // short hash + $result['short_hash'] = $line; + break; + + case 2: // subject + $matches = []; + preg_match($subject_pattern, $line, $matches); + + $result['type'] = $matches[5] ?? 'skip'; + $result['component'] = $matches[6] ?? ''; + $result['subject'] = $matches[7] ?? ''; + break; + + default: // the rest of the commit body + if (empty($line)) { + break; + } + + $result['body'] .= $line . PHP_EOL; + break; + } + + $index++; + } + + $filtered = []; + $fixes_pattern = '/(closes|fixes)\s+#(\d+)/i'; + foreach ($results as $result) { + if ($result['type'] === 'skip') { + continue; + } + + // check if the commit contains a breaking change + if (str_contains(strtolower($result['body']), 'breaking change:')) { + $result['type'] = 'break'; + } + + // see if the commit fixed/closed issues + $matches = []; + preg_match_all($fixes_pattern, $result['body'], $matches); + if (!empty($matches) && !empty($matches[2])) { + $result['closes'] = array_map(function ($value) { + return (int) $value; + }, $matches[2]); + } + + $filtered[] = $result; + } + + return $filtered; + } + + /** + * Get the contributors + * + * @param array $options options + * + * @return array + */ + protected function getGitContributors(array $options = []): array { + $defaults = [ + 'exclude' => [], + 'to' => 'HEAD', + ]; + $options = array_merge($defaults, $options); + + $command = vsprintf('git shortlog -sne %s --no-merges %s', [ + $options['to'], + implode(' ', array_map(function ($value) { + if (str_contains(PHP_OS, 'WIN')) { + return "^^{$value}"; + } + + return "^{$value}"; + }, $options['exclude'])), + ]); + + $contributors = $this->executeCommand($command); + if (!isset($contributors)) { + return []; + } + + $contributor_pattern = '/\s+([0-9]+)\s+(.*)\s<(.*)>/'; + $result = []; + foreach ($contributors as $contributor) { + $matches = []; + preg_match($contributor_pattern, $contributor, $matches); + if (empty($matches)) { + continue; + } + + $result[] = [ + 'count' => (int) $matches[1], + 'name' => $matches[2], + 'email' => $matches[3], + ]; + } + + // sort the contributors with most contributed first + usort($result, function ($a, $b) { + return $b['count'] - $a['count']; + }); + + return $result; + } + + /** + * Format the different commits into sections + * + * @param array $commits all the commits + * + * @return string + */ + protected function formatCommits(array $commits): string { + if (empty($commits)) { + return ''; + } + + // group commits by type + $types = []; + foreach ($commits as $commit) { + $type = $commit['type']; + if (str_starts_with($type, 'feat')) { + $type = 'feature'; + } elseif (str_starts_with($type, 'fix')) { + $type = 'fix'; + } elseif (str_starts_with($type, 'perf')) { + $type = 'performance'; + } elseif (str_starts_with($type, 'doc')) { + $type = 'documentation'; + } elseif (str_starts_with($type, 'deprecate')) { + $type = 'deprecated'; + } elseif (str_starts_with($type, 'break')) { + $type = 'breaking'; + } elseif (str_starts_with($type, 'remove')) { + $type = 'removed'; + } else { + continue; + } + + if (!isset($types[$type])) { + $types[$type] = []; + } + + $component = $commit['component']; + if (!isset($types[$type][$component])) { + $types[$type][$component] = []; + } + + $subject = $commit['subject']; + $commit_link = $this->makeCommitLink($commit); + $closes = ''; + if (!empty($commit['closes'])) { + $closes .= 'closes '; + foreach ($commit['closes'] as $issue_id) { + $closes .= $this->makeIssueLink($issue_id) . ', '; + } + } + + $types[$type][$component][] = trim(vsprintf('%s %s %s', [ + $subject, + $commit_link, + $closes, + ]), ' ,'); + } + + if (empty($types)) { + return ''; + } + + // format the different types into sections + $sections = []; + foreach ($this->commit_types as $type => $label) { + if (!isset($types[$type])) { + continue; + } + + $section = "#### {$label}" . PHP_EOL . PHP_EOL; + + foreach ($types[$type] as $component => $commits) { + if (count($commits) === 1) { + $section .= "* **{$component}:** {$commits[0]}" . PHP_EOL; + } else { + $section .= "* **{$component}:**" . PHP_EOL; + + foreach ($commits as $commit) { + $section .= ' * ' . $commit . PHP_EOL; + } + } + } + + $sections[] = $section; + } + + return trim(implode(PHP_EOL . PHP_EOL, $sections)); + } + + /** + * Format the contributors into a section + * + * @param array $contributors contributors + * + * @return string + */ + protected function formatContributors(array $contributors): string { + if (empty($contributors)) { + return ''; + } + + $section = '#### Contributors' . PHP_EOL . PHP_EOL; + + foreach ($contributors as $contributor) { + $section .= "* {$contributor['name']} ({$contributor['count']})" . PHP_EOL; + } + + return trim($section); + } + + /** + * Format release header + * + * @return string + */ + protected function formatHeader(): string { + $version = $this->getOption('version', ''); + $parts = explode('.', $version); + $date = date('Y-m-d'); + + $section = '' . PHP_EOL; + if ($parts[2] === '0') { + // major version + $section .= "## {$version} ({$date})"; + } else { + // patch version + $section .= "### {$version} ({$date})"; + } + + return trim($section); + } + + /** + * Get a link to a GitHub commit + * + * @param array $commit commit information + * + * @return string + */ + protected function makeCommitLink(array $commit): string { + if (empty($commit)) { + return ''; + } + + return vsprintf('[%s](%s/commit/%s)', [ + $commit['short_hash'], + $this->getOption('repository'), + $commit['hash'], + ]); + } + + /** + * Generate a link to a GitHub issue + * + * @param int $issue_id the issue ID + * + * @return string + */ + protected function makeIssueLink(int $issue_id): string { + if (empty($issue_id)) { + return ''; + } + + return vsprintf('[#%s](%s/commit/%s)', [ + $issue_id, + $this->getOption('repository'), + $issue_id, + ]); + } + + /** + * Write the release notes to the changelog + * + * @param string $release_notes release notes + * + * @return void + */ + protected function writeChangelog(string $release_notes): void { + $contents = file_get_contents($this->getOption('changelog')); + $first_anchor = strpos($contents, '= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } + "bindings": "^1.5.0", + "nan": "^2.12.1" } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "gaze": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", @@ -1809,51 +1596,43 @@ "globule": "~0.1.0" } }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dev": true, "requires": { - "is-property": "^1.0.2" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" } }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true }, "getobject": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "integrity": "sha512-hIGEBfnHcZpWkXPsAVeVmpYDvfy/matVl03yOY91FPmnpCC12Lm5izNxCjO3lHAeO6uaTwMxu7g450Siknlhig==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "glob": { @@ -1878,7 +1657,7 @@ "glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", "dev": true, "requires": { "glob-parent": "^2.0.0", @@ -1888,7 +1667,7 @@ "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", "dev": true, "requires": { "is-glob": "^2.0.0" @@ -1913,40 +1692,138 @@ } } }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "grunt": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", - "dev": true, - "requires": { - "async": "~0.1.22", - "coffee-script": "~1.3.3", - "colors": "~0.6.2", - "dateformat": "1.0.2-1.2.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.1.2", - "getobject": "~0.1.0", - "glob": "~3.1.21", - "grunt-legacy-log": "~0.1.0", - "grunt-legacy-util": "~0.2.0", - "hooker": "~0.2.3", - "iconv-lite": "~0.2.11", - "js-yaml": "~2.0.5", - "lodash": "~0.9.2", - "minimatch": "~0.2.12", - "nopt": "~1.0.10", - "rimraf": "~2.2.8", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - } - }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "grunt": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz", + "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==", + "dev": true, + "requires": { + "coffeescript": "~1.10.0", + "dateformat": "~1.0.12", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.3.0", + "glob": "~7.0.0", + "grunt-cli": "~1.2.0", + "grunt-known-options": "~1.1.0", + "grunt-legacy-log": "~2.0.0", + "grunt-legacy-util": "~1.1.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.13.0", + "minimatch": "~3.0.2", + "mkdirp": "~0.5.1", + "nopt": "~3.0.6", + "path-is-absolute": "~1.0.0", + "rimraf": "~2.6.2" + }, + "dependencies": { + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==", + "dev": true, + "requires": { + "glob": "~5.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "grunt-cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha512-8oM6ZAe4yG8Y7co/Ejc9613AixyN+gdCADyAFvJ1BbHGvrNa0ltaqrEWXV9P/W0gbQbAh3C8swJIaDuAX7syiw==", + "dev": true, + "requires": { + "findup-sync": "~0.3.0", + "grunt-known-options": "~1.1.0", + "nopt": "~3.0.6", + "resolve": "~1.1.0" + } + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + } + } + }, "grunt-contrib-clean": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", @@ -2009,71 +1886,47 @@ "integrity": "sha1-QAUf+k6wyWV+BTuV6I1ENSocLCU=", "dev": true }, + "grunt-known-options": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", + "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "dev": true + }, "grunt-legacy-log": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", + "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", "dev": true, "requires": { - "colors": "~0.6.2", - "grunt-legacy-log-utils": "~0.1.1", + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.0.0", "hooker": "~0.2.3", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - } + "lodash": "~4.17.5" } }, "grunt-legacy-log-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", + "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", "dev": true, "requires": { - "colors": "~0.6.2", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - } + "chalk": "~2.4.1", + "lodash": "~4.17.10" } }, "grunt-legacy-util": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", + "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", "dev": true, "requires": { - "async": "~0.1.22", + "async": "~1.5.2", "exit": "~0.1.1", "getobject": "~0.1.0", "hooker": "~0.2.3", - "lodash": "~0.9.2", - "underscore.string": "~2.2.1", - "which": "~1.0.5" + "lodash": "~4.17.10", + "underscore.string": "~3.3.4", + "which": "~1.3.0" } }, "grunt-open": { @@ -2096,39 +1949,68 @@ } } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true + }, "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - } + "ajv": "^6.12.3", + "har-schema": "^2.0.0" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha512-k1Umb4/jrBWZbtL+QKSji8qWeoZ7ZTkXdnDXt1wxwBKAFM0//u96wDj43mBIqCIas8rDQMYyrBEvcS8hdGd4Sg==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "isarray": "0.0.1" } }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "requires": { "get-value": "^2.0.6", @@ -2139,7 +2021,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true } } @@ -2147,7 +2029,7 @@ "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -2157,7 +2039,7 @@ "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -2166,7 +2048,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -2177,7 +2059,7 @@ "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -2188,35 +2070,23 @@ "hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "integrity": "sha512-jZ38TU/EBiGKrmyTNNZgnvCZHNowiRI4+w/I9noMlekHTZH3KyGgvJLmhSgykeAQ9j2SYPDosM0Bg3wHfzibAQ==", "dev": true, "requires": { "is-stream": "^1.0.1", "pinkie-promise": "^2.0.0" } }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-errors": { @@ -2230,44 +2100,55 @@ } }, "http-proxy": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-0.10.4.tgz", - "integrity": "sha1-FLoM6qIZf4n6MN6p57CeGc2Twi8=", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { - "colors": "0.x.x", - "optimist": "0.6.x", - "pkginfo": "0.3.x", - "utile": "~0.2.1" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" } }, "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { - "assert-plus": "^0.2.0", + "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, - "i": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", - "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", - "dev": true - }, "iconv-lite": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -2283,16 +2164,22 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" } }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "requires": { "binary-extensions": "^1.0.0" @@ -2304,10 +2191,19 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -2335,13 +2231,13 @@ "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==", "dev": true }, "is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", "dev": true, "requires": { "is-primitive": "^2.0.0" @@ -2350,47 +2246,34 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", "dev": true, "requires": { "is-extglob": "^1.0.0" } }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", - "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -2408,7 +2291,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true } } @@ -2416,31 +2299,31 @@ "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==", "dev": true }, "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==", "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "is-windows": { @@ -2461,6 +2344,15 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2470,7 +2362,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "requires": { "isarray": "1.0.0" @@ -2479,7 +2371,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true } } @@ -2487,7 +2379,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "jit-grunt": { @@ -2497,193 +2389,361 @@ "dev": true }, "jquery": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", - "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz", + "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==", "dev": true }, "jquery-mockjax": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jquery-mockjax/-/jquery-mockjax-2.5.1.tgz", - "integrity": "sha512-VObCYFUWI0i14GjhFyqd/9fYz3LyB2iqcMLxJNTH1H2sLpTSgmfty1JMwtql9Dnd744yss1jxwKO1kM0eNrMrA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jquery-mockjax/-/jquery-mockjax-2.6.0.tgz", + "integrity": "sha512-KNlIYbC5m+dr6t5ZQJSW+9cZf6wMiAc2XiJXAywBjvxnfRWTF+qaZLLk2mTc8NGXbPE0RQsfYu+mbS83ScALhg==", "dev": true, "requires": { "jquery": ">=1.5.2" } }, "js-yaml": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + } } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha512-I5YLeauH3rIaE99EE++UeH2M2gSYo8/2TqDac7oZEH6D/DSQ4Woa628Qrfj1X9/OY5Mk5VvIDQaKCDchXaKrmA==", "dev": true }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "dev": true, "requires": { "graceful-fs": "^4.1.6" }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "optional": true } } }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "karma": { - "version": "0.12.37", - "resolved": "https://registry.npmjs.org/karma/-/karma-0.12.37.tgz", - "integrity": "sha1-Gp9/3szWneLoNeBO26wuzT+mReQ=", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", + "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==", "dev": true, "requires": { - "chokidar": "^1.0.1", + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^1.4.1", "colors": "^1.1.0", - "connect": "^2.29.2", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", "di": "^0.0.1", - "glob": "^5.0.6", - "graceful-fs": "^3.0.6", - "http-proxy": "^0.10", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", "lodash": "^3.8.0", - "log4js": "^0.6.25", + "log4js": "^0.6.31", "mime": "^1.3.4", - "minimatch": "^2.0.7", + "minimatch": "^3.0.2", "optimist": "^0.6.1", - "q": "^1.4.1", - "rimraf": "^2.3.3", - "socket.io": "0.9.16", - "source-map": "^0.4.2", - "useragent": "^2.1.6" + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "1.7.3", + "source-map": "^0.5.3", + "tmp": "0.0.31", + "useragent": "^2.1.12" }, "dependencies": { - "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", "dev": true }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "brace-expansion": "^1.1.7" } }, - "graceful-fs": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "requires": { - "natives": "^1.1.0" + "ee-first": "1.1.1" } }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "requires": { - "brace-expansion": "^1.0.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true } } }, @@ -2715,12 +2775,13 @@ "dev": true }, "karma-phantomjs-launcher": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz", - "integrity": "sha1-TvluQyL/Y65dkY5RwlshNyMjjzA=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", + "integrity": "sha512-tf4P3plsE7wb5Pqh8GJ6RnElxfI/UM4MtVnjbSIZFpdFJlKnjRzfIx8MLCcSYJBwZ1+qSKFz4uBe3XNoq2t3KA==", "dev": true, "requires": { - "phantomjs": "~1.9" + "lodash": "^4.0.1", + "phantomjs-prebuilt": "^2.1.7" } }, "karma-requirejs": { @@ -2732,13 +2793,13 @@ "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "integrity": "sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ==", "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -2747,16 +2808,16 @@ "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "dev": true, "requires": { "graceful-fs": "^4.1.9" }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "optional": true } @@ -2865,186 +2926,43 @@ } } }, - "lodash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", - "dev": true - }, - "lodash-node": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash-node/-/lodash-node-2.4.1.tgz", - "integrity": "sha1-6oL3sQDHM9GkKvdoAeUGEF4qgOw=", - "dev": true - }, - "lodash._basebind": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.4.1.tgz", - "integrity": "sha1-6UC5690nwyfgqNqxtVkWxTQelXU=", - "dev": true, - "requires": { - "lodash._basecreate": "~2.4.1", - "lodash._setbinddata": "~2.4.1", - "lodash._slice": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "lodash._basecreate": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.4.1.tgz", - "integrity": "sha1-+Ob1tXip405UEXm1a47uv0oofgg=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash.isobject": "~2.4.1", - "lodash.noop": "~2.4.1" - } - }, - "lodash._basecreatecallback": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.4.1.tgz", - "integrity": "sha1-fQsmdknLKeehOdAQO3wR+uhOSFE=", - "dev": true, - "requires": { - "lodash._setbinddata": "~2.4.1", - "lodash.bind": "~2.4.1", - "lodash.identity": "~2.4.1", - "lodash.support": "~2.4.1" - } - }, - "lodash._basecreatewrapper": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.4.1.tgz", - "integrity": "sha1-TTHy595+E0+/KAN2K4FQsyUZZm8=", - "dev": true, - "requires": { - "lodash._basecreate": "~2.4.1", - "lodash._setbinddata": "~2.4.1", - "lodash._slice": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "lodash._createwrapper": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.4.1.tgz", - "integrity": "sha1-UdaVeXPaTtVW43KQ2MGhjFPeFgc=", - "dev": true, - "requires": { - "lodash._basebind": "~2.4.1", - "lodash._basecreatewrapper": "~2.4.1", - "lodash._slice": "~2.4.1", - "lodash.isfunction": "~2.4.1" - } - }, - "lodash._isnative": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", - "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", - "dev": true - }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, - "lodash._setbinddata": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.4.1.tgz", - "integrity": "sha1-98IAzRuS7yNrOZ7s9zxkjReqlNI=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash.noop": "~2.4.1" - } - }, - "lodash._shimkeys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", - "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } - }, - "lodash._slice": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.4.1.tgz", - "integrity": "sha1-dFz0GlNZexj2iImFREBe+isG2Q8=", - "dev": true - }, - "lodash.assign": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-2.4.1.tgz", - "integrity": "sha1-hMOVlt1xGBqXsGUpE6fJZ15Jsao=", - "dev": true, - "requires": { - "lodash._basecreatecallback": "~2.4.1", - "lodash._objecttypes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash.bind": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.4.1.tgz", - "integrity": "sha1-XRn6AFyMTSNvr0dCx7eh/Kvikmc=", + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "requires": { - "lodash._createwrapper": "~2.4.1", - "lodash._slice": "~2.4.1" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + } } }, - "lodash.identity": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.4.1.tgz", - "integrity": "sha1-ZpTP+mX++TH3wxzobHRZfPVg9PE=", - "dev": true - }, - "lodash.isfunction": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.4.1.tgz", - "integrity": "sha1-LP1XXHPkmKtX4xm3f6Aq3vE6lNE=", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } - }, - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "lodash.noop": { + "lodash-node": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.4.1.tgz", - "integrity": "sha1-T7VPgWZS5a4Q6PcvcXo4jHMmU4o=", + "resolved": "https://registry.npmjs.org/lodash-node/-/lodash-node-2.4.1.tgz", + "integrity": "sha1-6oL3sQDHM9GkKvdoAeUGEF4qgOw=", "dev": true }, - "lodash.support": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.4.1.tgz", - "integrity": "sha1-Mg4LZwMWc8KNeiu12eAzGkUkBRU=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1" - } - }, "log4js": { "version": "0.6.38", "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", - "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "integrity": "sha512-Cd+klbx7lkiaamEId9/0odHxv/PFHDz2E12kEfd6/CzIOZD084DzysASR/Dot4i1dYPBQKC3r2XIER+dfbLOmw==", "dev": true, "requires": { "readable-stream": "~1.0.2", @@ -3054,7 +2972,7 @@ "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -3062,9 +2980,25 @@ "isarray": "0.0.1", "string_decoder": "~0.10.x" } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true } } }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, "lru-cache": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", @@ -3074,19 +3008,19 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "requires": { "object-visit": "^1.0.0" @@ -3104,6 +3038,24 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, "method-override": { "version": "2.3.10", "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz", @@ -3148,7 +3100,7 @@ "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", "dev": true, "requires": { "arr-diff": "^2.0.0", @@ -3198,15 +3150,15 @@ } }, "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -3225,20 +3177,12 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "minimist": "^1.2.6" } }, "morgan": { @@ -3271,9 +3215,9 @@ } }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, @@ -3299,51 +3243,33 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true - }, - "ncp": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", - "dev": true - }, "negotiator": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=", "dev": true }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "dev": true - }, "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "requires": { "abbrev": "1" @@ -3369,10 +3295,22 @@ } } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -3385,15 +3323,27 @@ "dev": true }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha512-S0sN3agnVh2SZNEIGc0N1X4Z5K0JeFbGBrnuZpsxuUh5XLF0BnvWkMjRXo/zGKLd/eghvNIKcx1pQkmUjXIyrA==", "dev": true }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "requires": { "copy-descriptor": "^0.1.0", @@ -3404,7 +3354,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -3412,10 +3362,16 @@ } } }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "requires": { "isobject": "^3.0.0" @@ -3424,7 +3380,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true } } @@ -3432,7 +3388,7 @@ "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", "dev": true, "requires": { "for-own": "^0.1.4", @@ -3442,7 +3398,7 @@ "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "requires": { "isobject": "^3.0.1" @@ -3451,7 +3407,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true } } @@ -3474,7 +3430,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -3489,29 +3445,37 @@ "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + } } }, "options": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "integrity": "sha512-bOj3L1ypm++N+n7CEbbe473A414AB7z+amKYshRb//iuL3MpdDCLhPnw6aVTdKB9g5ZRVHIEp8eUln6L2NUStg==", "dev": true }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", "dev": true, "requires": { "glob-base": "^0.3.0", @@ -3520,6 +3484,42 @@ "is-glob": "^2.0.0" } }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha512-v38ZjVbinlZ2r1Rz06WUZEnGoSRcEGX+roMsiWjHeAe23s2qlQUyfmsPQZvh7d8l0E8AZzTIO/RkUr00LfkSiA==", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha512-B3Nrjw2aL7aI4TDujOzfA4NsEc4u1lVcIRE0xesutH8kjeWF70uk+W5cBlIQx04zUH9NTBvuN36Y9xLRPK6Jjw==", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha512-ijhdxJu6l5Ru12jF0JvzXVPvsC+VibqeaExlNoMhWN6VQ79PGjkmc7oA4W1lp00sFkNyj0fx6ivPLdV51/UMog==", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -3529,89 +3529,104 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, - "pause": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz", - "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q=", + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, "requires": { - "through": "~2.3" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + } } }, + "pause": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz", + "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q=", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, - "phantomjs": { - "version": "1.9.20", - "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.20.tgz", - "integrity": "sha1-RCSsog4U0lXAsIia9va4lz2hDg0=", + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha512-PIiRzBhW85xco2fuj41FmsyuYHKjKuXWmhjy3A/Y+CMpN/63TV+s9uzfVhsUwFe0G77xWtHBG8xmXf5BqEUEuQ==", "dev": true, "requires": { - "extract-zip": "~1.5.0", - "fs-extra": "~0.26.4", + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", "hasha": "^2.2.0", - "kew": "~0.7.0", - "progress": "~1.1.8", - "request": "~2.67.0", - "request-progress": "~2.0.1", - "which": "~1.2.2" - }, - "dependencies": { - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "requires": { "pinkie": "^2.0.0" - } - }, - "pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", - "dev": true - }, - "policyfile": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz", - "integrity": "sha1-1rgurZiueeviKOLa9ZAzEeyYLk0=", - "dev": true + } }, "portscanner": { "version": "1.2.0", @@ -3633,37 +3648,49 @@ "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==", "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", "dev": true }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { @@ -3696,9 +3723,9 @@ "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } @@ -3734,6 +3761,27 @@ } } }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", @@ -3760,13 +3808,13 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, "braces": { @@ -3790,7 +3838,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -3810,7 +3858,7 @@ "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "requires": { "debug": "^2.3.3", @@ -3825,7 +3873,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -3834,7 +3882,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -3843,7 +3891,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -3852,7 +3900,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -3863,7 +3911,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -3872,7 +3920,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -3918,7 +3966,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -3927,7 +3975,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -3938,7 +3986,7 @@ "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -3950,7 +3998,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -3959,9 +4007,9 @@ } }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "is-accessor-descriptor": { @@ -3996,7 +4044,7 @@ "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -4005,7 +4053,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -4016,19 +4064,19 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "micromatch": { @@ -4055,13 +4103,13 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -4073,6 +4121,12 @@ "util-deprecate": "~1.0.1" } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -4084,12 +4138,15 @@ } } }, - "redis": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz", - "integrity": "sha1-7le3pE0l7BWU5ENl2BZfp9HUgRo=", + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", "dev": true, - "optional": true + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } }, "regex-cache": { "version": "0.4.4", @@ -4113,53 +4170,62 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, "request": { - "version": "2.67.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", - "integrity": "sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I=", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { - "aws-sign2": "~0.6.0", - "bl": "~1.0.0", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~1.0.0-rc3", - "har-validator": "~2.0.2", - "hawk": "~3.1.0", - "http-signature": "~1.1.0", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.0", - "qs": "~5.2.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.2.0", - "tunnel-agent": "~0.4.1" + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" }, "dependencies": { "qs": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", - "integrity": "sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw=", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true } } @@ -4167,7 +4233,7 @@ "request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "integrity": "sha512-dxdraeZVUNEn9AvLrxkgB2k6buTlym71dJk1fk4v8j3Ou3RKNm07BcgbHdj2lLgYGfqX71F+awb1MR+tWPFJzA==", "dev": true, "requires": { "throttleit": "^1.0.0" @@ -4179,10 +4245,27 @@ "integrity": "sha1-DysVOK8rjQpP///eXTZ6qc1M/oQ=", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "dev": true }, "response-time": { @@ -4222,15 +4305,15 @@ "dev": true }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "requires": { "ret": "~0.1.10" @@ -4243,9 +4326,9 @@ "dev": true }, "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "send": { @@ -4329,9 +4412,9 @@ } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -4343,7 +4426,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -4351,12 +4434,35 @@ } } }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -4376,7 +4482,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -4385,17 +4491,11 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, @@ -4413,7 +4513,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -4451,13 +4551,13 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } @@ -4471,55 +4571,146 @@ "kind-of": "^3.2.0" } }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "socket.io": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz", + "integrity": "sha512-CmZLQTyj5nKKVBoguhisLP5Yl6oEfEWbQQQQ0MdXAazCZdRpGR4FG6rd13ryovTa75S36PgXsAGtzwllCWrgbQ==", "dev": true, "requires": { - "hoek": "2.x.x" + "debug": "2.3.3", + "engine.io": "1.8.3", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha512-dCHp4G+F11zb+RtEu7BE2U8R32AYmM/4bljQfut8LipH3PdwsVBVGh083MXvtKkB7HSQUzSwiXz53c4mzJvYfw==", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha512-5NnE67nQSQDJHVahPJna1PQ/zCXMnQop3yUCxjKPNzCxuyPSKWTQ/5Gu5CZmjetwGLWRA+PzeF5thlbOdbQldA==", + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha512-Lbc7GfN7XFaK30bzUN3cDYLOkT0dH05S0ax1QikylHUD9+Z9PRF3G1iYwX3kcz+6AlzTFGkUgMxz6l3aUwbwTA==", + "dev": true + } } }, - "socket.io": { - "version": "0.9.16", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-0.9.16.tgz", - "integrity": "sha1-O6sEROSbVfu8FXQk29Qao3WlGnY=", + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha512-zmYvlFJay9skt4yk1MffE9p93HKvQtyy0BLZ5dRM73bOXFJXNZWq8qZVdY456sLaxdK6fHGiZ7glxzqvzwGzkw==", "dev": true, "requires": { - "base64id": "0.1.0", - "policyfile": "0.0.4", - "redis": "0.7.3", - "socket.io-client": "0.9.16" + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha512-dCHp4G+F11zb+RtEu7BE2U8R32AYmM/4bljQfut8LipH3PdwsVBVGh083MXvtKkB7HSQUzSwiXz53c4mzJvYfw==", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha512-5NnE67nQSQDJHVahPJna1PQ/zCXMnQop3yUCxjKPNzCxuyPSKWTQ/5Gu5CZmjetwGLWRA+PzeF5thlbOdbQldA==", + "dev": true + } } }, "socket.io-client": { - "version": "0.9.16", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz", - "integrity": "sha1-TadRXF53MEHRtCOXBBW8xDDzX8Y=", - "dev": true, - "requires": { - "active-x-obfuscator": "0.0.1", - "uglify-js": "1.2.5", - "ws": "0.4.x", - "xmlhttprequest": "1.4.2" + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz", + "integrity": "sha512-ZEPOqFboJuuVau/3sMF4PgzJM/X+TDhssgufCnGtPtSL2Nmt4dL3i9JheCT1B45hiYM5cgO+wTO8EYmxbpwHSw==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.3", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==", + "dev": true + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha512-dCHp4G+F11zb+RtEu7BE2U8R32AYmM/4bljQfut8LipH3PdwsVBVGh083MXvtKkB7HSQUzSwiXz53c4mzJvYfw==", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha512-5NnE67nQSQDJHVahPJna1PQ/zCXMnQop3yUCxjKPNzCxuyPSKWTQ/5Gu5CZmjetwGLWRA+PzeF5thlbOdbQldA==", + "dev": true + } } }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha512-j6l4g/+yWQjmy1yByzg1DPFL4vxQw+NwCJatIxni/AE1wfm17FBtIKSWU4Ay+onrJwDxmC4eK4QS/04ZsqYwZQ==", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha512-YhIbp3PJiznERfjlIkK0ue4obZxt2S60+0W8z24ZymOHT8sHloOqWOqZRU2eN5OlY8U08VFsP02letcu26FilA==", + "dev": true + } } }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true + }, "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "dev": true, "requires": { - "atob": "^2.1.1", + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -4527,20 +4718,43 @@ } }, "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, - "split": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/split/-/split-0.2.10.tgz", - "integrity": "sha1-Zwl8YB1pfOE2j0GPBs0gHPBSGlc=", + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { - "through": "2" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -4550,10 +4764,16 @@ "extend-shallow": "^3.0.0" } }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -4565,20 +4785,12 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "requires": { "define-property": "^0.2.5", @@ -4588,7 +4800,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -4602,15 +4814,6 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, "stream-counter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", @@ -4626,37 +4829,43 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", - "dev": true + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "get-stdin": "^4.0.1" } }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", "dev": true }, "tiny-lr-fork": { @@ -4685,25 +4894,25 @@ } } }, - "tinycolor": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", - "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=", - "dev": true - }, "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha512-lfyEfOppKvWNeId5CArFLwgwef+iCnbEIy0JWYf1httIEXnx4ndL4Dr1adw7hPgeQfSlTbc/gqn6iaKcROpw5Q==", "dev": true, "requires": { - "os-tmpdir": "~1.0.2" + "os-tmpdir": "~1.0.1" } }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -4724,7 +4933,7 @@ "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -4734,7 +4943,7 @@ "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -4742,10 +4951,26 @@ } } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, "tough-cookie": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", - "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", "dev": true }, "tsscmp": { @@ -4755,15 +4980,18 @@ "dev": true }, "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "type-is": { @@ -4779,13 +5007,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-js": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz", - "integrity": "sha1-tULCx29477NLIAsgF3Y0Mw/3ArY=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "uid-safe": { @@ -4797,6 +5019,12 @@ "random-bytes": "~1.0.0" } }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha512-QMpnpVtYaWEeY+MwKDN/UdKlE/LsFZXM5lO1u7GaZzNgmIbGixHEmVMIKT+vqYOALu3m5GYQy9kz4Xu4IVn7Ow==", + "dev": true + }, "underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", @@ -4804,44 +5032,25 @@ "dev": true }, "underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", - "dev": true + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "requires": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unpipe": { @@ -4853,7 +5062,7 @@ "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "requires": { "has-value": "^0.3.1", @@ -4863,7 +5072,7 @@ "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "requires": { "get-value": "^2.0.3", @@ -4874,7 +5083,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "requires": { "isarray": "1.0.0" @@ -4885,27 +5094,36 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true } } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "dev": true }, "use": { @@ -4939,37 +5157,31 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "utile": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", - "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", - "dev": true, - "requires": { - "async": "~0.2.9", - "deep-equal": "*", - "i": "0.3.x", - "mkdirp": "0.x.x", - "ncp": "0.4.x", - "rimraf": "2.x.x" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", - "dev": true - } - } - }, "utils-merge": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", "dev": true }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vary": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", @@ -4979,20 +5191,12 @@ "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } } }, "vhost": { @@ -5001,75 +5205,75 @@ "integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU=", "dev": true }, - "which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", "dev": true }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "ws": { - "version": "0.4.32", - "resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz", - "integrity": "sha1-eHphVEFPPJntg8V3IVOyD+sM7DI=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", + "integrity": "sha512-lobrh3Dhp6tD1hv7NAIMx+oX/rsH/yd6/4krpBmJ/6ulsMZgQMuttlWTuYVWLV6ZjlpWIOjz55KbQbcKSQywEQ==", "dev": true, "requires": { - "commander": "~2.1.0", - "nan": "~1.0.0", "options": ">=0.0.5", - "tinycolor": "0.x" - }, - "dependencies": { - "nan": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz", - "integrity": "sha1-riT4hQgY1mL8q1rPfzuVv6oszzg=", - "dev": true - } + "ultron": "1.0.x" } }, - "xmlhttprequest": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz", - "integrity": "sha1-AUU6HZvtHo8XL2SVu/TIxCYyFQA=", + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha512-qfR6ovmRRMxNHgUNYI9LRdVofApe/eYrv4ggNOvvCP+pPdEo9Ym93QN4jUceGD6PignBbp2zAzgoE7GibAdq2A==", "dev": true }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha512-kauAa/1btT613pYX92WXR6kx5trYeckB5YMd3pPvtkMo2Twdfhwl683M8NiSqWHHo97xAC6bnvK1DWFKxfmejg==", "dev": true }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true }, "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { - "fd-slicer": "~1.0.1" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, - "zeparser": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/zeparser/-/zeparser-0.0.5.tgz", - "integrity": "sha1-A3JlYbwmjy5URPVMZlt/1KjAKeI=", + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==", "dev": true } } diff --git a/package.json b/package.json index 6034ca2cd3e..6f4a41d4fc3 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "chrome": "karma start engine/tests/js/karma.conf.js --browsers Chrome" }, "devDependencies": { - "elgg-conventional-changelog": "~0.1.2", "formdata-polyfill": "~3.0.20", "grunt": "~1.0.1", "grunt-contrib-clean": "~0.6.0", @@ -24,7 +23,7 @@ "grunt-contrib-watch": "~0.6.1", "grunt-exec": "~0.4.6", "grunt-open": "~0.2.3", - "jquery-mockjax": "^2.1.1", + "jquery-mockjax": "^2.6.0", "karma": "^1.6", "karma-chrome-launcher": "^0.2.3", "karma-jasmine": "~0.2.0", diff --git a/yarn.lock b/yarn.lock index a3d7b6fc5d5..22743b873db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -862,11 +862,6 @@ dom-serialize@^2.2.0: extend "^3.0.0" void-elements "^2.0.0" -duplexer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -880,14 +875,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -elgg-conventional-changelog@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/elgg-conventional-changelog/-/elgg-conventional-changelog-0.1.4.tgz#9eea9da38362d8fdf61fd37a05628f8898ed1a3d" - integrity sha1-nuqdo4Ni2P32H9N6BWKPiJjtGj0= - dependencies: - event-stream "~3.1.0" - lodash.assign "~2.4.1" - encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -990,19 +977,6 @@ etag@~1.7.0: resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" integrity sha1-A9MLX2fdbmMtKUXTDWZScxo01dg= -event-stream@~3.1.0: - version "3.1.7" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.1.7.tgz#b4c540012d0fe1498420f3d8946008db6393c37a" - integrity sha1-tMVAAS0P4UmEIPPYlGAI22OTw3o= - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.2" - stream-combiner "~0.0.4" - through "~2.3.1" - eventemitter2@~0.4.13: version "0.4.14" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" @@ -1282,11 +1256,6 @@ fresh@0.3.0: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" integrity sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8= -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - fs-access@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" @@ -1983,10 +1952,10 @@ jit-grunt@~0.8.0: resolved "https://registry.yarnpkg.com/jit-grunt/-/jit-grunt-0.8.0.tgz#75c4b3dfb82fb56e63d7cf96d5971ee8ecef7e35" integrity sha1-dcSz37gvtW5j18+W1Zce6OzvfjU= -jquery-mockjax@^2.1.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/jquery-mockjax/-/jquery-mockjax-2.5.0.tgz#d9c553d26e8ee849884b8d290be0776e21cd9801" - integrity sha512-mmQ/A0ktyJnrJVAoJEYzJk1selYOKrRTmvfrx7p1V/l8eF56Pw1CnIero4sKrKEXADg1/wWvA53DU5H5P0bnYg== +jquery-mockjax@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/jquery-mockjax/-/jquery-mockjax-2.6.0.tgz#e96737d7c312965f2514b97ce9662db36b7d5ef4" + integrity sha512-KNlIYbC5m+dr6t5ZQJSW+9cZf6wMiAc2XiJXAywBjvxnfRWTF+qaZLLk2mTc8NGXbPE0RQsfYu+mbS83ScALhg== dependencies: jquery ">=1.5.2" @@ -2184,140 +2153,6 @@ lodash-node@~2.4.1: resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-2.4.1.tgz#ea82f7b100c733d1a42af76801e506105e2a80ec" integrity sha1-6oL3sQDHM9GkKvdoAeUGEF4qgOw= -lodash._basebind@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.4.1.tgz#e940b9ebdd27c327e0a8dab1b55916c5341e9575" - integrity sha1-6UC5690nwyfgqNqxtVkWxTQelXU= - dependencies: - lodash._basecreate "~2.4.1" - lodash._setbinddata "~2.4.1" - lodash._slice "~2.4.1" - lodash.isobject "~2.4.1" - -lodash._basecreate@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.4.1.tgz#f8e6f5b578a9e34e541179b56b8eeebf4a287e08" - integrity sha1-+Ob1tXip405UEXm1a47uv0oofgg= - dependencies: - lodash._isnative "~2.4.1" - lodash.isobject "~2.4.1" - lodash.noop "~2.4.1" - -lodash._basecreatecallback@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.4.1.tgz#7d0b267649cb29e7a139d0103b7c11fae84e4851" - integrity sha1-fQsmdknLKeehOdAQO3wR+uhOSFE= - dependencies: - lodash._setbinddata "~2.4.1" - lodash.bind "~2.4.1" - lodash.identity "~2.4.1" - lodash.support "~2.4.1" - -lodash._basecreatewrapper@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.4.1.tgz#4d31f2e7de7e134fbf2803762b8150b32519666f" - integrity sha1-TTHy595+E0+/KAN2K4FQsyUZZm8= - dependencies: - lodash._basecreate "~2.4.1" - lodash._setbinddata "~2.4.1" - lodash._slice "~2.4.1" - lodash.isobject "~2.4.1" - -lodash._createwrapper@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.4.1.tgz#51d6957973da4ed556e37290d8c1a18c53de1607" - integrity sha1-UdaVeXPaTtVW43KQ2MGhjFPeFgc= - dependencies: - lodash._basebind "~2.4.1" - lodash._basecreatewrapper "~2.4.1" - lodash._slice "~2.4.1" - lodash.isfunction "~2.4.1" - -lodash._isnative@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._isnative/-/lodash._isnative-2.4.1.tgz#3ea6404b784a7be836c7b57580e1cdf79b14832c" - integrity sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw= - -lodash._objecttypes@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz#7c0b7f69d98a1f76529f890b0cdb1b4dfec11c11" - integrity sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE= - -lodash._setbinddata@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.4.1.tgz#f7c200cd1b92ef236b399eecf73c648d17aa94d2" - integrity sha1-98IAzRuS7yNrOZ7s9zxkjReqlNI= - dependencies: - lodash._isnative "~2.4.1" - lodash.noop "~2.4.1" - -lodash._shimkeys@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203" - integrity sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM= - dependencies: - lodash._objecttypes "~2.4.1" - -lodash._slice@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.4.1.tgz#745cf41a53597b18f688898544405efa2b06d90f" - integrity sha1-dFz0GlNZexj2iImFREBe+isG2Q8= - -lodash.assign@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-2.4.1.tgz#84c39596dd71181a97b0652913a7c9675e49b1aa" - integrity sha1-hMOVlt1xGBqXsGUpE6fJZ15Jsao= - dependencies: - lodash._basecreatecallback "~2.4.1" - lodash._objecttypes "~2.4.1" - lodash.keys "~2.4.1" - -lodash.bind@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.4.1.tgz#5d19fa005c8c4d236faf4742c7b7a1fcabe29267" - integrity sha1-XRn6AFyMTSNvr0dCx7eh/Kvikmc= - dependencies: - lodash._createwrapper "~2.4.1" - lodash._slice "~2.4.1" - -lodash.identity@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.4.1.tgz#6694cffa65fef931f7c31ce86c74597cf560f4f1" - integrity sha1-ZpTP+mX++TH3wxzobHRZfPVg9PE= - -lodash.isfunction@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.4.1.tgz#2cfd575c73e498ab57e319b77fa02adef13a94d1" - integrity sha1-LP1XXHPkmKtX4xm3f6Aq3vE6lNE= - -lodash.isobject@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5" - integrity sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU= - dependencies: - lodash._objecttypes "~2.4.1" - -lodash.keys@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.4.1.tgz#48dea46df8ff7632b10d706b8acb26591e2b3727" - integrity sha1-SN6kbfj/djKxDXBrissmWR4rNyc= - dependencies: - lodash._isnative "~2.4.1" - lodash._shimkeys "~2.4.1" - lodash.isobject "~2.4.1" - -lodash.noop@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.4.1.tgz#4fb54f816652e5ae10e8f72f717a388c7326538a" - integrity sha1-T7VPgWZS5a4Q6PcvcXo4jHMmU4o= - -lodash.support@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.4.1.tgz#320e0b67031673c28d7a2bb5d9e0331a45240515" - integrity sha1-Mg4LZwMWc8KNeiu12eAzGkUkBRU= - dependencies: - lodash._isnative "~2.4.1" - lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -2377,11 +2212,6 @@ map-obj@^1.0.0, map-obj@^1.0.1: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= - map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -2930,13 +2760,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - dependencies: - through "~2.3" - pause@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/pause/-/pause-0.1.0.tgz#ebc8a4a8619ff0b8a81ac1513c3434ff469fdb74" @@ -3254,7 +3077,7 @@ request@^2.81.0: requirejs@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.2.0.tgz#0f2b1538af2b8d0a4fffffde5d367aa9cd4cfe84" - integrity sha1-DysVOK8rjQpP///eXTZ6qc1M/oQ= + integrity sha512-yBSdSFVMI1XHt3yjc6inqgSouhyv/gTWzT0QXrYpMvx1P4SGN2kjZg4d15EgrhOPAle3Yjud5nSJ/zBNTKeYOA== requires-port@^1.0.0: version "1.0.0" @@ -3564,13 +3387,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split@0.2: - version "0.2.10" - resolved "https://registry.yarnpkg.com/split/-/split-0.2.10.tgz#67097c601d697ce1368f418f06cd201cf0521a57" - integrity sha1-Zwl8YB1pfOE2j0GPBs0gHPBSGlc= - dependencies: - through "2" - sprintf-js@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" @@ -3614,13 +3430,6 @@ statuses@~1.2.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg= -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= - dependencies: - duplexer "~0.1.1" - stream-counter@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-0.2.0.tgz#ded266556319c8b0e222812b9cf3b26fa7d947de" @@ -3715,11 +3524,6 @@ throttleit@^1.0.0: resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= -through@2, through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - tiny-lr-fork@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz#1e99e1e2a8469b736ab97d97eefa98c71f76ed0a" From c41e2682dbf35d5473d2a34a4b9900215603a370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 20 Jun 2023 15:39:58 +0200 Subject: [PATCH 004/240] chore(npm): update requirejs to the same version as in composer --- package-lock.json | 6 +- package.json | 2 +- yarn.lock | 1657 ++++++++++++++++++++------------------------- 3 files changed, 740 insertions(+), 925 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6527ba63e8..ccb9033a57c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4240,9 +4240,9 @@ } }, "requirejs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.2.0.tgz", - "integrity": "sha1-DysVOK8rjQpP///eXTZ6qc1M/oQ=", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", + "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", "dev": true }, "requires-port": { diff --git a/package.json b/package.json index 6f4a41d4fc3..ce654632d0d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,6 @@ "karma-phantomjs-launcher": "^1.0.4", "karma-requirejs": "~0.2", "load-grunt-config": "~0.16.0", - "requirejs": "~2.2.0" + "requirejs": "^2.3.6" } } diff --git a/yarn.lock b/yarn.lock index 22743b873db..6134a7edb0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,7 +10,7 @@ abbrev@1: accepts@1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - integrity sha1-w8p0NJOGSMPg2cHjKN1otiLChMo= + integrity sha512-AOPopplFOUlmUugwiZUCDpOwmqvSgdCyE8iJVLWI4NcB7qfMKQN34dn5xYtlUU03XGG5egRWW4NW5gIxpa5hEA== dependencies: mime-types "~2.1.11" negotiator "0.6.1" @@ -18,44 +18,34 @@ accepts@1.3.3: accepts@~1.2.12, accepts@~1.2.13: version "1.2.13" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.2.13.tgz#e5f1f3928c6d95fd96558c36ec3d9d0de4a6ecea" - integrity sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo= + integrity sha512-R190A3EzrS4huFOVZajhXCYZt5p5yrkaQOB4nsWzfth0cYaDcSN5J86l58FJ1dt7igp37fB/QhnuFkGAJmr+eg== dependencies: mime-types "~2.1.6" negotiator "0.5.3" accepts@~1.3.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" + mime-types "~2.1.34" + negotiator "0.6.3" after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" - integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + integrity sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA== -ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -71,19 +61,6 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -94,7 +71,7 @@ argparse@^1.0.7: "argparse@~ 0.1.11": version "0.1.16" resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" - integrity sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw= + integrity sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw== dependencies: underscore "~1.7.0" underscore.string "~2.4.0" @@ -102,14 +79,14 @@ argparse@^1.0.7: arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + integrity sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA== dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" @@ -119,76 +96,76 @@ arr-flatten@^1.0.1, arr-flatten@^1.1.0: arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + integrity sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw== array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= + integrity sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q== array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + integrity sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg== array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== arraybuffer.slice@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" - integrity sha1-8zshWfBTKj8xB6JywMz70a0peco= + integrity sha512-6ZjfQaBSy6CuIH0+B0NrxMfDE5VIOCP/5gOqSpEIsaAZx9/giszzrXg6PZ7G51U/n88UmlAgYLNQ9wAnII7PJA== asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== async-each@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.6.tgz#52f1d9403818c179b7561e11a5d1b77eb2160e77" + integrity sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg== async@1.5.2, async@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== async@^0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" - integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + integrity sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw== async@~0.2.10, async@~0.2.9: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= + integrity sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -atob@^2.1.1: +atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== @@ -196,37 +173,37 @@ atob@^2.1.1: aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + version "1.12.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + integrity sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA== balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" - integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + integrity sha512-437oANT9tP582zZMwSvZGy2nmSeAb8DW2me3y+Uv1Wp2Rulr8Mqlyrv3E7MLxmsiaPSMMDmiDVzgE+e8zlMx9g== base64-url@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.2.1.tgz#199fd661702a0e7b7dcae6e0698bb089c52f6d78" - integrity sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg= + integrity sha512-V8E0l1jyyeSSS9R+J9oljx5eq2rqzClInuwaPcyuv0Mm3ViI/3/rcc4rCEO8i4eQ4I0O0FAGYDA2i5xWHHPhzg== base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" - integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + integrity sha512-rz8L+d/xByiB/vLVftPkyY215fqNrmasrcJsYkVcm4TgJNz+YXKrFaFAWibSaHkiKoSgMDCb+lipOIRQNGYesw== base@^0.11.1: version "0.11.2" @@ -244,29 +221,29 @@ base@^0.11.1: basic-auth-connect@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz#fdb0b43962ca7b40456a7c2bb48fe173da2d2122" - integrity sha1-/bC0OWLKe0BFanwrtI/hc9otISI= + integrity sha512-kiV+/DTgVro4aZifY/hwRwALBISViL5NP4aReaR2EVJEObpbUBHIkdJh/YpcoEiYt7nBodZ6U2ajZeZvSxUCCg== basic-auth@~1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" - integrity sha1-Awk1sB3nyblKgksp8/zLdQ06UpA= + integrity sha512-uvq3I/zC5TmG0WZJDzsXzIytU9GiiSq23Gl27Dq9sV81JTfPfQhtdADECP1DJZeJoZPuYU0Y81hWC5y/dOR+Yw== batch@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" - integrity sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ= + integrity sha512-aQgHPLH2DHpFTpBl5/GiVdNzHEqsLCSs1RiPvqkKP1+7RkNJlv71kL8/KXmvvaLqoZ7ylmvqkZhLjjAoRz8Xgw== bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" - integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + integrity sha512-bYeph2DFlpK1XmGs6fvlLRUN29QISM3GBuUwSFsMY2XRx4AvC0WNCS57j4c/xGrK2RS24C1w3YoBOsw9fT46tQ== dependencies: callsite "1.0.0" @@ -275,36 +252,45 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= + integrity sha512-YRc9zvVz4wNaxcXmiSgb9LAg7YYwqQ2xd0Sj6osfA7k/PKmIGVlnOYs3wOFdkRC9/JpQu8sGt/zHgJV7xzerfg== bluebird@^3.3.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" - integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== body-parser@^1.16.1: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== dependencies: - bytes "3.1.0" - content-type "~1.0.4" + bytes "3.1.2" + content-type "~1.0.5" debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" body-parser@~1.13.3: version "1.13.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.13.3.tgz#c08cf330c3358e151016a05746f13f029c97fa97" - integrity sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc= + integrity sha512-ypX8/9uws2W+CjPp3QMmz1qklzlhRBknQve22Y+WFecHql+qDFfG+VVNX7sooA4Q3+2fdq4ZZj6Xr07gA90RZg== dependencies: bytes "2.1.0" content-type "~1.0.1" @@ -328,14 +314,14 @@ brace-expansion@^1.1.7: braces@^0.1.2: version "0.1.5" resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6" - integrity sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY= + integrity sha512-EIMHIv2UXHWFY2xubUGKz+hq9hNkENj4Pjvr7h58cmJgpkK2yMlKA8I484f7MSttkzVAy/lL7X9xDaILd6avzA== dependencies: expand-range "^0.1.0" braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + integrity sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw== dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -370,30 +356,35 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== bytes@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.1.0.tgz#ac93c410e2ffc9cc7cf4b464b38289067f5e47b4" - integrity sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q= + integrity sha512-k9VSlRfRi5JYyQWMylSOgjld96ta1qaQUIvmn+na0BzViclH04PBumewv4z5aeXNkn6Z/gAN5FtPeBLvV20F9w== bytes@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" - integrity sha1-fZcZb51br39pNeJZhVSe3SpsIzk= + integrity sha512-SvUX8+c/Ga454a4fprIdIUzUN9xfd1YTvYh7ub5ZPJ+ZJ/+K2Bp6IpWGmnw8r3caLTsmhvJAKZz3qjIo9+XuCQ== -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cache-base@^1.0.1: version "1.0.1" @@ -410,15 +401,23 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" - integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + integrity sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ== camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + integrity sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ== dependencies: camelcase "^2.0.0" map-obj "^1.0.0" @@ -426,12 +425,12 @@ camelcase-keys@^2.0.0: camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + integrity sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw== caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== chalk@~2.4.1: version "2.4.2" @@ -445,7 +444,7 @@ chalk@~2.4.1: chokidar@^1.4.1: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= + integrity sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg== dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -458,11 +457,6 @@ chokidar@^1.4.1: optionalDependencies: fsevents "^1.0.0" -chownr@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" - integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -473,20 +467,15 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - coffeescript@~1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.10.0.tgz#e7aa8301917ef621b35d8a39f348dcdd1db7e33e" - integrity sha1-56qDAZF+9iGzXYo580jc3R234z4= + integrity sha512-ZQmMbvOYLFz9ylTKWCdWmGPWMMCRFhz3pC4R0IBikWUpEvwsJk9P0ut/eQU39TbU3vBaBEWsJZngkIruVV7Yqw== collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -501,7 +490,7 @@ color-convert@^1.9.0: color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== colors@^1.1.0: version "1.4.0" @@ -511,12 +500,12 @@ colors@^1.1.0: colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= + integrity sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w== combine-lists@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" - integrity sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y= + integrity sha512-4Mi0V7N48B9KzC8Zl/U7wiWuxMFEHf44N3/PSoAvWDu8IOPrddNo1y1tC/kXbP7IvVMhgCFMMNzgKb0pWoin9w== dependencies: lodash "^4.5.0" @@ -530,17 +519,17 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" - integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + integrity sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw== component-emitter@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" - integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM= + integrity sha512-YhIbp3PJiznERfjlIkK0ue4obZxt2S60+0W8z24ZymOHT8sHloOqWOqZRU2eN5OlY8U08VFsP02letcu26FilA== component-emitter@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + integrity sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA== component-emitter@^1.2.1: version "1.3.0" @@ -550,19 +539,19 @@ component-emitter@^1.2.1: component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" - integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + integrity sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA== compressible@~2.0.5: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: - mime-db ">= 1.40.0 < 2" + mime-db ">= 1.43.0 < 2" compression@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/compression/-/compression-1.5.2.tgz#b03b8d86e6f8ad29683cba8df91ddc6ffc77b395" - integrity sha1-sDuNhub4rSloPLqN+R3cb/x3s5U= + integrity sha512-+2fE8M8+Oe0kAlbMPz6UinaaH/HaGf+c5HlWRyYtPga/PHKxStJJKTU4xca8StY0JQ78L2kJaslpgSzCKgHaxQ== dependencies: accepts "~1.2.12" bytes "2.1.0" @@ -574,9 +563,9 @@ compression@~1.5.2: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@1.6.2: +concat-stream@^1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -589,12 +578,12 @@ concat-stream@1.6.2: connect-livereload@^0.5.0: version "0.5.4" resolved "https://registry.yarnpkg.com/connect-livereload/-/connect-livereload-0.5.4.tgz#80157d1371c9f37cc14039ab1895970d119dc3bc" - integrity sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w= + integrity sha512-3KnRwsWf4VmP01I4hCDQqTc4e2UxOvJIi8i08GiwqX2oymzxNFY7PqjFkwHglYTJ0yzUJkO5yqdPxVaIz3Pbug== connect-timeout@~1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/connect-timeout/-/connect-timeout-1.6.2.tgz#de9a5ec61e33a12b6edaab7b5f062e98c599b88e" - integrity sha1-3ppexh4zoStu2qt7XwYumMWZuI4= + integrity sha512-qIFt3Ja6gRuJtVoWhPa5FtOO8ERs0MfW/QkmQ0vjrAL78otrkxe8w/qjTAgU/T1W/jH5qeZXJHilmOPKNTiEQw== dependencies: debug "~2.2.0" http-errors "~1.3.1" @@ -604,7 +593,7 @@ connect-timeout@~1.6.2: connect@^2.27.1: version "2.30.2" resolved "https://registry.yarnpkg.com/connect/-/connect-2.30.2.tgz#8da9bcbe8a054d3d318d74dfec903b5c39a1b609" - integrity sha1-jam8vooFTT0xjXTf7JA7XDmhtgk= + integrity sha512-eY4YHls5bz/g6h9Q8B/aVkS6D7+TRiRlI3ksuruv3yc2rLbTG7HB/7T/CoZsuVH5e2i3S9J+2eARV5o7GIYq8Q== dependencies: basic-auth-connect "1.0.0" body-parser "~1.13.3" @@ -648,20 +637,15 @@ connect@^3.6.0: parseurl "~1.3.3" utils-merge "1.0.1" -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -content-type@~1.0.1, content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.1, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== cookie-parser@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.3.5.tgz#9d755570fb5d17890771227a02314d9be7cf8356" - integrity sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y= + integrity sha512-YN/8nzPcK5o6Op4MIzAd4H4qUal5+3UaMhVIeaafFYL0pKvBQA/9Yhzo7ZwvBpjdGshsiTAb1+FC37M6RdPDFg== dependencies: cookie "0.1.3" cookie-signature "1.0.6" @@ -669,42 +653,47 @@ cookie-parser@~1.3.5: cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.3.tgz#e734a5c1417fce472d5aef82c381cabb64d1a435" - integrity sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU= + integrity sha512-mWkFhcL+HVG1KjeCjEBVJJ7s4sAGMLiBDFSDs4bzzvgLZt7rW8BhP6XV/8b1+pNvx/skd3yYxPuaF3Z6LlQzyw== cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + integrity sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw== copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== core-js@^2.2.0: - version "2.6.10" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" - integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== crc@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/crc/-/crc-3.3.0.tgz#fa622e1bc388bf257309082d6b65200ce67090ba" - integrity sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo= + integrity sha512-QCx3z7FOZbJrapsnewTkh1Hxh6PHV61SRHbx6Q65Uih3y0kfIj+dDGI3uQ4Q1DLKOILyvpZxvJpoKPrxathpCg== csrf@~3.0.0: version "3.0.6" resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.0.6.tgz#b61120ddceeafc91e76ed5313bb5c0b2667b710a" - integrity sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo= + integrity sha512-3q1ocniLMgk9nHHEt/I/JsN9IfiGjgp6MHgYNT7+CPmQvi5DF6qzenXnZSH6f9Qaa+4DhmUDJa8SgFZ+OFf9Qg== dependencies: rndm "1.2.0" tsscmp "1.0.5" @@ -713,7 +702,7 @@ csrf@~3.0.0: csurf@~1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/csurf/-/csurf-1.8.3.tgz#23f2a13bf1d8fce1d0c996588394442cba86a56a" - integrity sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo= + integrity sha512-p2NJ9fGOn5HCaV9jAOBCSjIGMRMrpm9/yDswD0bFi7zQv1ifDufIKI5nem9RmhMsH6jVD6Sx6vs57hnivvkJJw== dependencies: cookie "0.1.3" cookie-signature "1.0.6" @@ -723,26 +712,26 @@ csurf@~1.8.3: currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + integrity sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng== dependencies: array-find-index "^1.0.1" custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" - integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== dependencies: assert-plus "^1.0.0" dateformat@~1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" - integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk= + integrity sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg== dependencies: get-stdin "^4.0.1" meow "^3.3.0" @@ -750,62 +739,50 @@ dateformat@~1.0.12: debug@2.2.0, debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - integrity sha1-+HBX6ZWxofauaklgZkE3vFbwOdo= + integrity sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw== dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" - integrity sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w= + integrity sha512-dCHp4G+F11zb+RtEu7BE2U8R32AYmM/4bljQfut8LipH3PdwsVBVGh083MXvtKkB7HSQUzSwiXz53c4mzJvYfw== dependencies: ms "0.7.2" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@~0.7.0: version "0.7.4" resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - integrity sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk= + integrity sha512-EohAb3+DSHSGx8carOSKJe8G0ayV5/i609OD0J2orCkuyae7SyZSz2aoLmQF2s0Pj5gITDebwPH7GFBlqOUQ1Q== decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== dependencies: is-descriptor "^1.0.0" @@ -820,42 +797,42 @@ define-property@^2.0.2: delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== depd@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.0.1.tgz#80aec64c9d6d97e65cc2a9caa93c0aa6abf73aaa" - integrity sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo= + integrity sha512-OEWAMbCkK9IWQ8pfTvHBhCSqHgR+sk5pbiYqq0FqfARG4Cy+cRsCbITx6wh5pcsmfBPiJAcbd98tfdz5fnBbag== -depd@~1.1.0, depd@~1.1.2: +depd@~1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + integrity sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg== di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" - integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== dom-serialize@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" - integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== dependencies: custom-event "~1.0.0" ent "~2.2.0" @@ -865,7 +842,7 @@ dom-serialize@^2.2.0: ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -873,17 +850,17 @@ ecc-jsbn@~0.1.1: ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== engine.io-client@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab" - integrity sha1-F5jtk0USRkU9TG9jXXogH+lA1as= + integrity sha512-260nnbHkYPTPnA9cjH2oCvWmqNwYofsNBkDfViI9iS487oMcl3kUeSgXJCwMxASgOL5DVlQF4hb0NzRNFkUaFg== dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -901,7 +878,7 @@ engine.io-client@1.8.3: engine.io-parser@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a" - integrity sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo= + integrity sha512-3UyTJo+5Jbmr7rd3MosTAApK7BOIo4sjx8dJYSHa3Em5R3A9Y2s9GWu4JFJe6Px0VieJC0hKUA5NBytC+O7k2A== dependencies: after "0.8.2" arraybuffer.slice "0.0.6" @@ -913,7 +890,7 @@ engine.io-parser@1.3.2: engine.io@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.3.tgz#8de7f97895d20d39b85f88eeee777b2bd42b13d4" - integrity sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q= + integrity sha512-VNQ79eqoDiapJ2tDMu+N7SPDm11btXpO7b2gsxBVd1XbxBCx6xLyTESIuFlWUspsbuif6Rq88pYNrQce5G7bqw== dependencies: accepts "1.3.3" base64id "1.0.0" @@ -925,7 +902,7 @@ engine.io@1.8.3: ent@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== error-ex@^1.2.0: version "1.3.2" @@ -937,7 +914,7 @@ error-ex@^1.2.0: errorhandler@~1.4.2: version "1.4.3" resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.4.3.tgz#b7b70ed8f359e9db88092f2d20c0f831420ad83f" - integrity sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8= + integrity sha512-pp1hk9sZBq4Bj/e/Cl84fJ3cYiQDFZk3prp7jrurUbPGOlY7zA2OubjhhEAWuUb8VNTFIkGwoby7Uq6YpicfvQ== dependencies: accepts "~1.3.0" escape-html "~1.0.3" @@ -950,17 +927,17 @@ es6-promise@^4.0.3: escape-html@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.2.tgz#d77d32fa98e38c2f41ae85e9278e0e0e6ba1022c" - integrity sha1-130y+pjjjC9BroXpJ44ODmuhAiw= + integrity sha512-J5ahyCRC4liskWVAfkmosNWfG0eHQxI0W+Ko7k3cZaYVMfgt05dwZ68vw6S/TZM1BPvuTv3kq6CRCb7WWtBUVA== escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== esprima@^4.0.0: version "4.0.1" @@ -970,32 +947,32 @@ esprima@^4.0.0: "esprima@~ 1.0.2": version "1.0.4" resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - integrity sha1-n1V+CPw7TSbs6d00+Pv0drYlha0= + integrity sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA== etag@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" - integrity sha1-A9MLX2fdbmMtKUXTDWZScxo01dg= + integrity sha512-Mbv5pNpLNPrm1b4rzZlZlfTRpdDr31oiD43N362sIyvSWVNu5Du33EcJGzvEV4YdYLuENB1HzND907cQkFmXNw== eventemitter2@~0.4.13: version "0.4.14" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" - integrity sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas= + integrity sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ== eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== exit@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" - integrity sha1-SIsdHSRRyz06axks/AMPRMWFX+o= + integrity sha512-zOOsEnAhvIxxd0esCNbYG2xerGf46niZ1egS43eV7Fu4t7VIScgPXMcMabCLaPrqkzwvwo6zZipDiX3t0ILF2w== dependencies: array-slice "^0.2.3" array-unique "^0.2.1" @@ -1004,14 +981,14 @@ expand-braces@^0.1.1: expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + integrity sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA== dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -1024,7 +1001,7 @@ expand-brackets@^2.1.4: expand-range@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044" - integrity sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ= + integrity sha512-busOHJ0t7t5UcutcyNDqmaDX+1cb0XlqsAUgTlmplVv0rIqBaMcBSZRLlkDm0nxtl8O3o/EvRRrdQ/WnyPERLQ== dependencies: is-number "^0.1.1" repeat-string "^0.2.2" @@ -1032,14 +1009,14 @@ expand-range@^0.1.0: expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + integrity sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA== dependencies: fill-range "^2.1.0" express-session@~1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.11.3.tgz#5cc98f3f5ff84ed835f91cbf0aabd0c7107400af" - integrity sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8= + integrity sha512-QdSbGRRg+JMvlYpancRDFXDmIMqjEdpowriwQc4Kz3mvPwTnOPD/h5FSS21+4z4Isosta+ULmEwL6F3/lylWWg== dependencies: cookie "0.1.3" cookie-signature "1.0.6" @@ -1054,14 +1031,14 @@ express-session@~1.11.3: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -1074,7 +1051,7 @@ extend@^3.0.0, extend@~3.0.2: extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + integrity sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg== dependencies: is-extglob "^1.0.0" @@ -1093,51 +1070,56 @@ extglob@^2.0.4: to-regex "^3.0.1" extract-zip@^1.6.5: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" + yauzl "^2.10.0" extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== faye-websocket@~0.4.3: version "0.4.4" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.4.4.tgz#c14c5b3bf14d7417ffbfd990c0a7495cd9f337bc" - integrity sha1-wUxbO/FNdBf/v9mQwKdJXNnzN7w= + integrity sha512-78pqrJbvGZSe8i+PLsPd+aJqTyGqgyWLnMw5NOwtXCTVMzEFh1zQPwIuIL/ycTj4rkDy5zZ9B6frYPqVPJBzyQ== -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== dependencies: pend "~1.2.0" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + integrity sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ== fill-range@^2.1.0: version "2.2.4" @@ -1153,7 +1135,7 @@ fill-range@^2.1.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -1163,7 +1145,7 @@ fill-range@^4.0.0: finalhandler@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.4.0.tgz#965a52d9e8d05d2b857548541fb89b53a2497d9b" - integrity sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs= + integrity sha512-jJU2WE88OqUvwAIf/1K2G2fTdKKZ8LvSwYQyFFekDcmBnBmht38enbcmErnA7iNZktcEo/o2JAHYbe1QDOAgaA== dependencies: debug "~2.2.0" escape-html "1.0.2" @@ -1186,7 +1168,7 @@ finalhandler@1.1.2: find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + integrity sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -1194,7 +1176,7 @@ find-up@^1.0.0: findup-sync@~0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683" - integrity sha1-fz56l7gjksZTvwZYm9hRkOk8NoM= + integrity sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw== dependencies: glob "~3.2.9" lodash "~2.4.1" @@ -1202,33 +1184,31 @@ findup-sync@~0.1.2: findup-sync@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - integrity sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY= + integrity sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg== dependencies: glob "~5.0.0" follow-redirects@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f" - integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A== - dependencies: - debug "^3.0.0" + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + integrity sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw== dependencies: for-in "^1.0.1" forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== form-data@~2.3.2: version "2.3.3" @@ -1247,98 +1227,92 @@ formdata-polyfill@~3.0.20: fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== dependencies: map-cache "^0.2.2" fresh@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" - integrity sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8= + integrity sha512-akx5WBKAwMSg36qoHTuMMVncHWctlaDGslJASDYAhoLrzDUDCjZlOngNa/iC6lPm9aA0qk8pN5KnpmbJHSIIQQ== fs-access@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" - integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= + integrity sha512-05cXDIwNbFaoFWaz5gNHlUTbH5whiss/hr/ibzPd4MH3cR4w0ZKeIPiVdbyJurg3O5r/Bjpvn9KOb1/rPMf3nA== dependencies: null-check "^1.0.0" fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - integrity sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA= + integrity sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ== dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" klaw "^1.0.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^1.0.0: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== dependencies: + bindings "^1.5.0" nan "^2.12.1" - node-pre-gyp "^0.12.0" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== gaze@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f" - integrity sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8= + integrity sha512-3IWbXGkDDHFX8zIlNdfnmhvlSMhpBO6tDr4InB8fGku6dh/gjFPGNqcdsXJajZg05x9jRzXbL6gCnCnuMap4tw== dependencies: globule "~0.1.0" +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + integrity sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== getobject@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/getobject/-/getobject-0.1.0.tgz#047a449789fa160d018f5486ed91320b6ec7885c" - integrity sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw= + integrity sha512-hIGEBfnHcZpWkXPsAVeVmpYDvfy/matVl03yOY91FPmnpCC12Lm5izNxCjO3lHAeO6uaTwMxu7g450Siknlhig== getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== dependencies: assert-plus "^1.0.0" glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + integrity sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA== dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -1346,26 +1320,26 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + integrity sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w== dependencies: is-glob "^2.0.0" glob@^7.1.1, glob@^7.1.3: - version "7.1.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" - integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" glob@~3.1.21: version "3.1.21" resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" - integrity sha1-0p4KBV3qUTj00H7UDomC6DwgZs0= + integrity sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ== dependencies: graceful-fs "~1.2.0" inherits "1" @@ -1374,7 +1348,7 @@ glob@~3.1.21: glob@~3.2.6, glob@~3.2.7, glob@~3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - integrity sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0= + integrity sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g== dependencies: inherits "2" minimatch "0.3" @@ -1382,7 +1356,7 @@ glob@~3.2.6, glob@~3.2.7, glob@~3.2.9: glob@~5.0.0: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + integrity sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA== dependencies: inflight "^1.0.4" inherits "2" @@ -1393,7 +1367,7 @@ glob@~5.0.0: glob@~7.0.0: version "7.0.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" - integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= + integrity sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -1405,7 +1379,7 @@ glob@~7.0.0: globule@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" - integrity sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU= + integrity sha512-3eIcA2OjPCm4VvwIwZPzIxCVssA8HSpM2C6c6kK5ufJH4FGwWoyqL3In19uuX4oe+TwH3w2P1nQDmW56iehO4A== dependencies: glob "~3.1.21" lodash "~1.0.1" @@ -1414,26 +1388,26 @@ globule@~0.1.0: globule@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/globule/-/globule-0.2.0.tgz#26b64d10e1edcab6098d8fe00bd2b73cca08a8fb" - integrity sha1-JrZNEOHtyrYJjY/gC9K3PMoIqPs= + integrity sha512-mMhYxzb8wpE7VtHkJi+jk0yjlBLFetYMAnkcFutmDo4uSFAHu/1tLgVm9Y6HcaTaX1DZBJjZOM1KqqCZDvBLBw== dependencies: glob "~3.2.7" lodash "~2.4.1" minimatch "~0.2.11" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graceful-fs@~1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= + integrity sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ== grunt-cli@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-1.2.0.tgz#562b119ebb069ddb464ace2845501be97b35b6a8" - integrity sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg= + integrity sha512-8oM6ZAe4yG8Y7co/Ejc9613AixyN+gdCADyAFvJ1BbHGvrNa0ltaqrEWXV9P/W0gbQbAh3C8swJIaDuAX7syiw== dependencies: findup-sync "~0.3.0" grunt-known-options "~1.1.0" @@ -1443,14 +1417,14 @@ grunt-cli@~1.2.0: grunt-contrib-clean@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz#f532dba4b8212674c7c013e146bda6638b9048f6" - integrity sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY= + integrity sha512-uCUI26rYAufDndSt2rxevuLWhc1opLRQY6lyPnJeLVSDFZgktRAD/xqY9kWB02353LR/CQnQbmK0NwSB53I0Zw== dependencies: rimraf "~2.2.1" grunt-contrib-connect@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/grunt-contrib-connect/-/grunt-contrib-connect-0.9.0.tgz#deda5a5bd875a5ba2fdd4b77ae7d0689d5dee4c8" - integrity sha1-3tpaW9h1pbov3Ut3rn0GidXe5Mg= + integrity sha512-VNoUW1vVSB06MCqWgk7H53xmfWqqQdFzdXlvPJxSjFJDi1By6+dUBwreGVBUFZYrhsELTKUZ3QX5i6F6D656gA== dependencies: async "^0.9.0" connect "^2.27.1" @@ -1461,7 +1435,7 @@ grunt-contrib-connect@~0.9.0: grunt-contrib-watch@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/grunt-contrib-watch/-/grunt-contrib-watch-0.6.1.tgz#64fdcba25a635f5b4da1b6ce6f90da0aeb6e3f15" - integrity sha1-ZP3LolpjX1tNobbOb5DaCutuPxU= + integrity sha512-Ea4f3anehA6G+S88vyTwewA/Mf6SbadTIxSgQClKbZYnHOcJ0PrGc2p+uzR6hS9gp7DG6ObvaxkmE8HKnLOsfA== dependencies: async "~0.2.9" gaze "~0.5.1" @@ -1471,7 +1445,7 @@ grunt-contrib-watch@~0.6.1: grunt-exec@~0.4.6: version "0.4.7" resolved "https://registry.yarnpkg.com/grunt-exec/-/grunt-exec-0.4.7.tgz#40051ffa4eb0c9657e053b95e88d44352a1c2c25" - integrity sha1-QAUf+k6wyWV+BTuV6I1ENSocLCU= + integrity sha512-AJw+ccLkJnycdyiTXFpt1ELpRbiMDn0uj3b04W0kmmjEZCz3j1LSO2bH9GxgQniUZc2mQFMEew9Bw9tWCu+1zw== grunt-known-options@~1.1.0: version "1.1.1" @@ -1542,42 +1516,47 @@ grunt@~1.0.1: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: - ajv "^6.5.5" + ajv "^6.12.3" har-schema "^2.0.0" has-binary@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" - integrity sha1-aOYesWIQyVRaClzOBqhzkS/h5ow= + integrity sha512-k1Umb4/jrBWZbtL+QKSji8qWeoZ7ZTkXdnDXt1wxwBKAFM0//u96wDj43mBIqCIas8rDQMYyrBEvcS8hdGd4Sg== dependencies: isarray "0.0.1" has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" - integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + integrity sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA== has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -1586,7 +1565,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -1595,20 +1574,27 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== dependencies: is-number "^3.0.0" kind-of "^4.0.0" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hasha@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" - integrity sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE= + integrity sha512-jZ38TU/EBiGKrmyTNNZgnvCZHNowiRI4+w/I9noMlekHTZH3KyGgvJLmhSgykeAQ9j2SYPDosM0Bg3wHfzibAQ== dependencies: is-stream "^1.0.1" pinkie-promise "^2.0.0" @@ -1616,36 +1602,36 @@ hasha@^2.2.0: hooker@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959" - integrity sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk= + integrity sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA== hosted-git-info@^2.1.4: - version "2.8.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" - integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" http-errors@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.3.1.tgz#197e22cdebd4198585e8694ef6786197b91ed942" - integrity sha1-GX4izevUGYWF6GlO9nhhl7ke2UI= + integrity sha512-gMygNskMurDCWfoCdyh1gOeDfSbkAHXqz94QoPj5IHIUjC/BG8/xv7FSEUr7waR5RcAya4j58bft9Wu/wHNeXA== dependencies: inherits "~2.0.1" statuses "1" http-proxy@^1.13.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" - integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" follow-redirects "^1.0.0" @@ -1654,7 +1640,7 @@ http-proxy@^1.13.0: http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" @@ -1663,43 +1649,36 @@ http-signature@~1.2.0: iconv-lite@0.4.11: version "0.4.11" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.11.tgz#2ecb42fd294744922209a2e7c404dac8793d8ade" - integrity sha1-LstC/SlHRJIiCaLnxATayHk9it4= + integrity sha512-8UmnaYeP5puk18SkBrYULVTiq7REcimhx+ykJVJBiaz89DQmVQAfS29ZhHah86la90/t0xy4vRk86/2cCwNodA== iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" - integrity sha1-H4irpKsLFQjoMSrMOTRfNumS4vI= + integrity sha512-QwVuTNQv7tXC5mMWFX5N5wGjmybjNBBD8P3BReTkPmipoxTUFgWM2gXNvldHQr6T14DH0Dh6qBVg98iJt7u4mQ== -iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + integrity sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg== dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + integrity sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg== inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -1707,27 +1686,17 @@ inflight@^1.0.4: inherits@1: version "1.0.2" resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" - integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js= + integrity sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA== -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== dependencies: kind-of "^3.0.2" @@ -1741,12 +1710,12 @@ is-accessor-descriptor@^1.0.0: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + integrity sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q== dependencies: binary-extensions "^1.0.0" @@ -1755,10 +1724,17 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== dependencies: kind-of "^3.0.2" @@ -1790,19 +1766,19 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + integrity sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg== is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + integrity sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA== dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== is-extendable@^1.0.1: version "1.0.1" @@ -1814,50 +1790,36 @@ is-extendable@^1.0.1: is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + integrity sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww== is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + integrity sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg== dependencies: is-extglob "^1.0.0" is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" - integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY= + integrity sha512-la5kPULwIgkSSaZj9w7/A1uHqOBAgOhDUKQ5CkfL8LZ4Si6r4+2D0hI6b4o60MW4Uj2yNJARWIZUDPxlvOYQcw== is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== dependencies: kind-of "^3.0.2" @@ -1876,27 +1838,27 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + integrity sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ== is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + integrity sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q== is-stream@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== is-windows@^1.0.2: version "1.0.2" @@ -1906,17 +1868,17 @@ is-windows@^1.0.2: is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isbinaryfile@^3.0.0: version "3.0.3" @@ -1928,29 +1890,29 @@ isbinaryfile@^3.0.0: isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== jit-grunt@~0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/jit-grunt/-/jit-grunt-0.8.0.tgz#75c4b3dfb82fb56e63d7cf96d5971ee8ecef7e35" - integrity sha1-dcSz37gvtW5j18+W1Zce6OzvfjU= + integrity sha512-mJ80LXh3rDLhlLMhqZsLu38QZlUR2bKrnT993DnlcvKSECKdt3/1+MNoMaUV8jbKIw16EdxODMPTuLsC8rGg/A== jquery-mockjax@^2.6.0: version "2.6.0" @@ -1960,14 +1922,14 @@ jquery-mockjax@^2.6.0: jquery ">=1.5.2" jquery@>=1.5.2: - version "3.4.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" - integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== + version "3.7.0" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.0.tgz#fe2c01a05da500709006d8790fe21c8a39d75612" + integrity sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ== js-yaml@~3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.0.2.tgz#9937865f8e897a5e894e73c2c5cf2e89b32eb771" - integrity sha1-mTeGX46Jel6JTnPCxc8uibMut3E= + integrity sha512-8PVwV1480dnAPMj8FCW3I/mZZ+gvtOoMAZFWJKagkFq2eWv5kcyzWTR+6MloV0SY57t6jSIaKc7DIz86K9ZCfA== dependencies: argparse "~ 0.1.11" esprima "~ 1.0.2" @@ -1983,49 +1945,49 @@ js-yaml@~3.13.0: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json3@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= + integrity sha512-I5YLeauH3rIaE99EE++UeH2M2gSYo8/2TqDac7oZEH6D/DSQ4Woa628Qrfj1X9/OY5Mk5VvIDQaKCDchXaKrmA== jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== optionalDependencies: graceful-fs "^4.1.6" jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" - json-schema "0.2.3" + json-schema "0.4.0" verror "1.10.0" karma-chrome-launcher@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-0.2.3.tgz#4c6d700d163a9d34c618efd87918be49e7a4a8c9" - integrity sha1-TG1wDRY6nTTGGO/YeRi+SeekqMk= + integrity sha512-AiMVR7eY9MKLF3EVwgB08TyiHCBIUXAypgxcWJeOSUHB7QBvB2ebUr8tl0C0YwPS2Ce+oBAbR/SQkG46aLfJAA== dependencies: fs-access "^1.0.0" which "^1.2.1" @@ -2033,12 +1995,12 @@ karma-chrome-launcher@^0.2.3: karma-jasmine@~0.2.0: version "0.2.3" resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-0.2.3.tgz#c4d3dc1132d5ddc35dada95545c42ce0b6e9999b" - integrity sha1-xNPcETLV3cNdralVRcQs4LbpmZs= + integrity sha512-lb/xAY1rVrzTrfgbjEyL5k2yKUcFXTi3EhjUfnuGERBNdsRdGXaQ92/XsslB6EZeU0pJU06J0RsTgP12eeotbw== karma-phantomjs-launcher@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz#d23ca34801bda9863ad318e3bb4bd4062b13acd2" - integrity sha1-0jyjSAG9qYY60xjju0vUBisTrNI= + integrity sha512-tf4P3plsE7wb5Pqh8GJ6RnElxfI/UM4MtVnjbSIZFpdFJlKnjRzfIx8MLCcSYJBwZ1+qSKFz4uBe3XNoq2t3KA== dependencies: lodash "^4.0.1" phantomjs-prebuilt "^2.1.7" @@ -2046,7 +2008,7 @@ karma-phantomjs-launcher@^1.0.4: karma-requirejs@~0.2: version "0.2.6" resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-0.2.6.tgz#1a770c64f901320a389c65b4944746326372def8" - integrity sha1-GncMZPkBMgo4nGW0lEdGMmNy3vg= + integrity sha512-8T7U+QwCy36XIYvC1obbWnN766kCck6hcJ7ehr6cgSLq9SnsvqWUETexHbkOPQ2SXnabCb6lbLDNUk3yCPbbrA== karma@^1.6: version "1.7.1" @@ -2084,19 +2046,19 @@ karma@^1.6: kew@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" - integrity sha1-edk9LTM2PW/dKXCzNdkUGtWR15s= + integrity sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== dependencies: is-buffer "^1.1.5" @@ -2106,21 +2068,21 @@ kind-of@^5.0.0: integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== optionalDependencies: graceful-fs "^4.1.9" load-grunt-config@~0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/load-grunt-config/-/load-grunt-config-0.16.0.tgz#f402749e6dd808772f1ebbbc5231add20f518091" - integrity sha1-9AJ0nm3YCHcvHru8UjGt0g9RgJE= + integrity sha512-ki8JCmn4Yq7sKE0PREKL5Qij/0F1uYYSYUM+GaN/Xd1h5PUXQSIAg5dR43mxLabC7SZhBI4139ua7NIuoTcUrQ== dependencies: async "~0.2.10" glob "~3.2.6" @@ -2132,7 +2094,7 @@ load-grunt-config@~0.16.0: load-grunt-tasks@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/load-grunt-tasks/-/load-grunt-tasks-0.3.0.tgz#d5273e3d8689019b31d9cdd42e168399d3b45605" - integrity sha1-1Sc+PYaJAZsx2c3ULhaDmdO0VgU= + integrity sha512-bgZqR+scmG37RTcJbZgXbH6pfohQl2F7j5wVqNHXS35B280LQKvI5ftMik0Q5qMR8tTecWEtLVNLRdSQGtQeWQ== dependencies: findup-sync "~0.1.2" globule "~0.2.0" @@ -2140,7 +2102,7 @@ load-grunt-tasks@~0.3.0: load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + integrity sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A== dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -2151,32 +2113,32 @@ load-json-file@^1.0.0: lodash-node@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-2.4.1.tgz#ea82f7b100c733d1a42af76801e506105e2a80ec" - integrity sha1-6oL3sQDHM9GkKvdoAeUGEF4qgOw= + integrity sha512-egEt8eNQp2kZWRmngahiqMoDCDCENv3uM188S7Ed5t4k3v6RrLELXC+FqLNMUnhCo7gvQX3G1V8opK/Lcslahg== lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= + integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== lodash@^4.0.1, lodash@^4.5.0, lodash@~4.17.10, lodash@~4.17.5: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== lodash@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" - integrity sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE= + integrity sha512-0VSEDVec/Me2eATuoiQd8IjyBMMX0fahob8YJ96V1go2RjvCk1m1GxmtfXn8RNSaLaTtop7fsuhhu9oLk3hUgA== lodash@~2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" - integrity sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4= + integrity sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw== log4js@^0.6.31: version "0.6.38" resolved "https://registry.yarnpkg.com/log4js/-/log4js-0.6.38.tgz#2c494116695d6fb25480943d3fc872e662a522fd" - integrity sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0= + integrity sha512-Cd+klbx7lkiaamEId9/0odHxv/PFHDz2E12kEfd6/CzIOZD084DzysASR/Dot4i1dYPBQKC3r2XIER+dfbLOmw== dependencies: readable-stream "~1.0.2" semver "~4.3.3" @@ -2184,7 +2146,7 @@ log4js@^0.6.31: loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + integrity sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ== dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" @@ -2192,7 +2154,7 @@ loud-rejection@^1.0.0: lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= + integrity sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ== lru-cache@4.1.x: version "4.1.5" @@ -2205,17 +2167,17 @@ lru-cache@4.1.x: map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== dependencies: object-visit "^1.0.0" @@ -2227,12 +2189,12 @@ math-random@^1.0.1: media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + integrity sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA== dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -2248,7 +2210,7 @@ meow@^3.3.0: method-override@~2.3.5: version "2.3.10" resolved "https://registry.yarnpkg.com/method-override/-/method-override-2.3.10.tgz#e3daf8d5dee10dd2dce7d4ae88d62bbee77476b4" - integrity sha1-49r41d7hDdLc59SuiNYrvud0drQ= + integrity sha512-Ks2/7e+3JuwQcpLybc6wTHyqg13HDjOhLcE+YaAEub9DbSxF+ieMvxUlybmWW9luRMh9Cd0rO9aNtzUT51xfNQ== dependencies: debug "2.6.9" methods "~1.1.2" @@ -2258,12 +2220,12 @@ method-override@~2.3.5: methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + integrity sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA== dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -2298,27 +2260,22 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -"mime-db@>= 1.40.0 < 2": - version "1.42.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" - integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.6, mime-types@~2.1.9: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34, mime-types@~2.1.6, mime-types@~2.1.9: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.40.0" + mime-db "1.52.0" mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" - integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= + integrity sha512-sAaYXszED5ALBt665F0wMQCUXpGuZsGdopoqcHPdL39ZYdi7uHoZlhrfZfhv8WzivhBzr/oXwaj+yiK5wY8MXQ== mime@^1.3.4: version "1.6.0" @@ -2328,55 +2285,42 @@ mime@^1.3.4: minimatch@0.3: version "0.3.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - integrity sha1-J12O2qxPG7MyZHIInnlJyDlGmd0= + integrity sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA== dependencies: lru-cache "2" sigmund "~1.0.0" -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@~0.2.11: version "0.2.14" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - integrity sha1-x054BXT2PG+aCQ6Q775u9TpqdWo= + integrity sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA== dependencies: lru-cache "2" sigmund "~1.0.0" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimatch@~3.0.2: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" -minimist@^1.1.3, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.1.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" + integrity sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw== mixin-deep@^1.2.0: version "1.3.2" @@ -2386,17 +2330,17 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +mkdirp@^0.5.4, mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "0.0.8" + minimist "^1.2.6" morgan@~1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.6.1.tgz#5fd818398c6819cba28a7cd6664f292fe1c0bbf2" - integrity sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I= + integrity sha512-WWxlTx5xCqbtSeX/gPVHUZBhAhSMfYQLgPrWHEN0FYnF+zf1Ju/Zct6rpeKmvzibrYF4QvFVws7IN61BxnKu+Q== dependencies: basic-auth "~1.0.3" debug "~2.2.0" @@ -2407,35 +2351,30 @@ morgan@~1.6.1: ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - integrity sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= + integrity sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg== ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - integrity sha1-riXPJRKziFodldfwN4aNhDESR2U= + integrity sha512-5NnE67nQSQDJHVahPJna1PQ/zCXMnQop3yUCxjKPNzCxuyPSKWTQ/5Gu5CZmjetwGLWRA+PzeF5thlbOdbQldA== ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== multiparty@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/multiparty/-/multiparty-3.3.2.tgz#35de6804dc19643e5249f3d3e3bdc6c8ce301d3f" - integrity sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8= + integrity sha512-FX6dDOKzDpkrb5/+Imq+V6dmCZNnC02tMDiZfrgHSYgfQj6CVPGzOVqfbHKt/Vy4ZZsmMPXkulyLf92lCyvV7A== dependencies: readable-stream "~1.1.9" stream-counter "~0.2.0" nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + version "2.17.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== nanomatch@^1.2.9: version "1.2.13" @@ -2454,72 +2393,39 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.5.3.tgz#269d5c476810ec92edbe7b6c2f28316384f9a7e8" - integrity sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g= + integrity sha512-oXmnazqehLNFohqgLxRyUdOQU9/UX0NpCpsnbjWUjM62ZM8oSOXYZpHc68XR130ftPNano0oQXGdREAplZRhaQ== negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + integrity sha512-qTxkr1RoLw5Pz+1+PTJ/66hWuyi2LEOeOuIDJDlx6JF8x75bmD5C7qXTg2UlX5W9rLfkqKP+r8q6Vy6NWdWrbw== -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== nopt@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-2.0.0.tgz#ca7416f20a5e3f9c3b86180f96295fa3d0b52e0d" - integrity sha1-ynQW8gpeP5w7hhgPlilfo9C1Lg0= + integrity sha512-uVTsuT8Hm3aN3VttY+BPKw4KU9lVpI0F22UAr/I1r6+kugMr3oyhMALkycikLcdfvGRsgzCYN48DYLBFcJEUVg== dependencies: abbrev "1" nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + integrity sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg== dependencies: abbrev "1" noptify@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/noptify/-/noptify-0.0.3.tgz#58f654a73d9753df0c51d9686dc92104a67f4bbb" - integrity sha1-WPZUpz2XU98MUdlobckhBKZ/S7s= + integrity sha512-EZT35r9AuK+hig+iYv4144kwfDEDhlj3zncVHw9b9d86TUYk/67BtBApkfPD1kslAT/8TTD262xdsVbV+iCSTw== dependencies: nopt "~2.0.0" @@ -2536,42 +2442,14 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: normalize-path@^2.0.0, normalize-path@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== dependencies: remove-trailing-separator "^1.0.1" -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== - -npm-packlist@^1.1.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" - integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - null-check@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" - integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + integrity sha512-j8ZNHg19TyIQOWCGeeQJBuu6xZYIEurf8M1Qsfd8mFrGEfIZytbw18YjKWg+LcO25NowXGZXZpKAx+Ui3TFfDw== oauth-sign@~0.9.0: version "0.9.0" @@ -2581,38 +2459,43 @@ oauth-sign@~0.9.0: object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" - integrity sha1-ejs9DpgGPUP0wD8uiubNUahog6A= + integrity sha512-Lbc7GfN7XFaK30bzUN3cDYLOkT0dH05S0ax1QikylHUD9+Z9PRF3G1iYwX3kcz+6AlzTFGkUgMxz6l3aUwbwTA== -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" - integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + integrity sha512-S0sN3agnVh2SZNEIGc0N1X4Z5K0JeFbGBrnuZpsxuUh5XLF0BnvWkMjRXo/zGKLd/eghvNIKcx1pQkmUjXIyrA== object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + integrity sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA== dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -2620,14 +2503,21 @@ object.omit@^2.0.0: object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== dependencies: isobject "^3.0.1" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== dependencies: ee-first "1.1.1" @@ -2639,14 +2529,14 @@ on-headers@~1.0.0, on-headers@~1.0.1: once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" opn@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/opn/-/opn-1.0.2.tgz#b909643346d00a1abc977a8b96f3ce3c53d5cf5f" - integrity sha1-uQlkM0bQChq8l3qLlvPOPFPVz18= + integrity sha512-4w6LXX5mR/XGoM8QfFOfixA7aCLTUwNXPPAvUM5pXfc/8oGyQx6IskSzjuRvNZvD6tT6SCsBTlw4VBMUR6dA2w== opn@^5.4.0: version "5.5.0" @@ -2658,7 +2548,7 @@ opn@^5.4.0: optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + integrity sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g== dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -2666,30 +2556,17 @@ optimist@^0.6.1: options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + integrity sha512-bOj3L1ypm++N+n7CEbbe473A414AB7z+amKYshRb//iuL3MpdDCLhPnw6aVTdKB9g5ZRVHIEp8eUln6L2NUStg== -os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + integrity sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA== dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -2699,28 +2576,28 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== dependencies: error-ex "^1.2.0" parsejson@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" - integrity sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs= + integrity sha512-v38ZjVbinlZ2r1Rz06WUZEnGoSRcEGX+roMsiWjHeAe23s2qlQUyfmsPQZvh7d8l0E8AZzTIO/RkUr00LfkSiA== dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" - integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + integrity sha512-B3Nrjw2aL7aI4TDujOzfA4NsEc4u1lVcIRE0xesutH8kjeWF70uk+W5cBlIQx04zUH9NTBvuN36Y9xLRPK6Jjw== dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" - integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + integrity sha512-ijhdxJu6l5Ru12jF0JvzXVPvsC+VibqeaExlNoMhWN6VQ79PGjkmc7oA4W1lp00sFkNyj0fx6ivPLdV51/UMog== dependencies: better-assert "~1.0.0" @@ -2732,29 +2609,29 @@ parseurl@~1.3.0, parseurl@~1.3.1, parseurl@~1.3.2, parseurl@~1.3.3: pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + integrity sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== dependencies: pinkie-promise "^2.0.0" path-is-absolute@^1.0.0, path-is-absolute@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + integrity sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg== dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -2763,22 +2640,22 @@ path-type@^1.0.0: pause@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/pause/-/pause-0.1.0.tgz#ebc8a4a8619ff0b8a81ac1513c3434ff469fdb74" - integrity sha1-68ikqGGf8LioGsFRPDQ0/0af23Q= + integrity sha512-aeHLgQCtI3tcuYVnrvAeVb4Tkm1za4r3YDv3hMeUxcRxet3dbEhJOdtoMrsT/Q5tY3Oy2A1A9FD5el5tWp2FSg== pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== phantomjs-prebuilt@^2.1.7: version "2.1.16" resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz#efd212a4a3966d3647684ea8ba788549be2aefef" - integrity sha1-79ISpKOWbTZHaE6ouniFSb4q7+8= + integrity sha512-PIiRzBhW85xco2fuj41FmsyuYHKjKuXWmhjy3A/Y+CMpN/63TV+s9uzfVhsUwFe0G77xWtHBG8xmXf5BqEUEuQ== dependencies: es6-promise "^4.0.3" extract-zip "^1.6.5" @@ -2793,36 +2670,36 @@ phantomjs-prebuilt@^2.1.7: pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== portscanner@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-1.2.0.tgz#b14bbda257d14c310fa9cc09682af02d40961802" - integrity sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI= + integrity sha512-3MCx40XO6ChNJJHw1tTFukQK/M/8FacGZK/vGbnrKpozObrJzembYtfi7ZdA2hkF2Lojg77XhsKUPvF8eHKcDA== dependencies: async "1.5.2" posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + integrity sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ== process-nextick-args@~2.0.0: version "2.0.1" @@ -2832,27 +2709,22 @@ process-nextick-args@~2.0.0: progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= + integrity sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw== pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.24: - version "1.4.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" - integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== + integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== qjobs@^1.1.4: version "1.2.0" @@ -2862,27 +2734,29 @@ qjobs@^1.1.4: qs@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" - integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc= + integrity sha512-8MPmJ83uBOPsQj5tQCv4g04/nTiY+d17yl9o3Bw73vC6XlEm2POIRRlOgWJ8i74bkGLII670cDJJZkgiZ2sIkg== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" qs@~0.5.2: version "0.5.6" resolved "https://registry.yarnpkg.com/qs/-/qs-0.5.6.tgz#31b1ad058567651c526921506b9a8793911a0384" - integrity sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q= + integrity sha512-KbOrQrP5Ye+0gmq+hwxoJwAFRwExACWqwxj1IDFFgqOw9Poxy3wwSbafd9ZqP6T6ykMfnxM573kt/a4i9ybatQ== qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" - integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= + integrity sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ== randomatic@^3.0.0: version "3.1.1" @@ -2901,41 +2775,31 @@ range-parser@^1.2.0: range-parser@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" - integrity sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU= + integrity sha512-nDsRrtIxVUO5opg/A8T2S3ebULVIfuh8ECbh4w3N4mWxIiT3QILDJDUQayPqm2e8Q8NUa0RSUkGCfe33AfjR3Q== -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: - bytes "3.1.0" - http-errors "1.7.2" + bytes "3.1.2" + http-errors "2.0.0" iconv-lite "0.4.24" unpipe "1.0.0" raw-body@~2.1.2: version "2.1.7" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" - integrity sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q= + integrity sha512-x4d27vsIG04gZ1imkuDXB9Rd/EkAx5kYzeMijIYw1PAor0Ld3nTlkQQwDjKu42GdRUFCX1AfGnTSQB4O57eWVg== dependencies: bytes "2.4.0" iconv-lite "0.4.13" unpipe "1.0.0" -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + integrity sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A== dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -2943,16 +2807,16 @@ read-pkg-up@^1.0.1: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + integrity sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ== dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== +readable-stream@^2.0.2, readable-stream@^2.2.2: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -2965,7 +2829,7 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -2975,7 +2839,7 @@ readable-stream@~1.0.2: readable-stream@~1.1.8, readable-stream@~1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -2994,7 +2858,7 @@ readdirp@^2.0.0: redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + integrity sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g== dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" @@ -3017,41 +2881,41 @@ regex-not@^1.0.0, regex-not@^1.0.2: remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" - integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4= + integrity sha512-yHeI3F9v20MY+8/5WAUgIWseMZwpLD+l9h5hGyzh6fQjhle2AwjjRDao1m5IozSDuVvMw09/mvE8AU1oDmZKpQ== repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== dependencies: is-finite "^1.0.0" request-progress@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" - integrity sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg= + integrity sha512-dxdraeZVUNEn9AvLrxkgB2k6buTlym71dJk1fk4v8j3Ou3RKNm07BcgbHdj2lLgYGfqX71F+awb1MR+tWPFJzA== dependencies: throttleit "^1.0.0" request@^2.81.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -3060,7 +2924,7 @@ request@^2.81.0: extend "~3.0.2" forever-agent "~0.6.1" form-data "~2.3.2" - har-validator "~5.1.0" + har-validator "~5.1.3" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" @@ -3070,41 +2934,43 @@ request@^2.81.0: performance-now "^2.1.0" qs "~6.5.2" safe-buffer "^5.1.2" - tough-cookie "~2.4.3" + tough-cookie "~2.5.0" tunnel-agent "^0.6.0" uuid "^3.3.2" -requirejs@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.2.0.tgz#0f2b1538af2b8d0a4fffffde5d367aa9cd4cfe84" - integrity sha512-yBSdSFVMI1XHt3yjc6inqgSouhyv/gTWzT0QXrYpMvx1P4SGN2kjZg4d15EgrhOPAle3Yjud5nSJ/zBNTKeYOA== +requirejs@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== resolve@^1.10.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - path-parse "^1.0.6" + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" resolve@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== response-time@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" - integrity sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo= + integrity sha512-MUIDaDQf+CVqflfTdQ5yam+aYCkXj1PY8fjlPDQ6ppxJlmgZb864pHtA750mayywNg8tx4rS7qH9JXd/OF+3gw== dependencies: depd "~1.1.0" on-headers "~1.0.1" @@ -3114,7 +2980,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rimraf@^2.6.0, rimraf@^2.6.1: +rimraf@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -3124,7 +2990,7 @@ rimraf@^2.6.0, rimraf@^2.6.1: rimraf@~2.2.1: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= + integrity sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg== rimraf@~2.6.2: version "2.6.3" @@ -3136,12 +3002,12 @@ rimraf@~2.6.2: rndm@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" - integrity sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w= + integrity sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw== safe-buffer@^5.0.1, safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" @@ -3151,7 +3017,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== dependencies: ret "~0.1.10" @@ -3160,12 +3026,7 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -"semver@2 || 3 || 4 || 5", semver@^5.3.0: +"semver@2 || 3 || 4 || 5": version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -3173,12 +3034,12 @@ sax@^1.2.4: semver@~4.3.3: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= + integrity sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ== send@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" - integrity sha1-dl52B8gFVFK7pvCwUllTUJhgNt4= + integrity sha512-cQ0rmXHrdO2Iof08igV2bG/yXWD106ANwBg6DkGQNT2Vsznbgq6T0oAIQboy1GoFsIuy51jCim26aA9tj3Z3Zg== dependencies: debug "~2.2.0" depd "~1.1.0" @@ -3196,7 +3057,7 @@ send@0.13.2: serve-favicon@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.3.2.tgz#dd419e268de012ab72b319d337f2105013f9381f" - integrity sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8= + integrity sha512-oHEaA3ohvKxEWhjP97cQ6QuTTbMBF3AxDyMSvBtvnl1jXaB2Ik6kXE7nUtPM3YVU5VHCDe6n7JZrFCWzQuvXEQ== dependencies: etag "~1.7.0" fresh "0.3.0" @@ -3206,7 +3067,7 @@ serve-favicon@~2.3.0: serve-index@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.7.3.tgz#7a057fc6ee28dc63f64566e5fa57b111a86aecd2" - integrity sha1-egV/xu4o3GP2RWbl+lexEahq7NI= + integrity sha512-g18EQWY83uFBldFpCyK/a49yxQgIMEMLA6U9f66FiI848mLkMO8EY/xRAZAoCwNFwSUAiArCF3mdjaNXpd3ghw== dependencies: accepts "~1.2.13" batch "0.5.3" @@ -3219,17 +3080,12 @@ serve-index@~1.7.2: serve-static@~1.10.0: version "1.10.3" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.10.3.tgz#ce5a6ecd3101fed5ec09827dac22a9c29bfb0535" - integrity sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU= + integrity sha512-ScsFovjz3Db+vGgpofR/U8p8UULEcGV9akqyo8TQ1mMnjcxemE7Y5Muo+dvy3tJLY/doY2v1H61eCBMYGmwfrA== dependencies: escape-html "~1.0.3" parseurl "~1.3.1" send "0.13.2" -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -3240,20 +3096,29 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + integrity sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g== signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== snapdragon-node@^2.0.1: version "2.1.1" @@ -3288,7 +3153,7 @@ snapdragon@^0.8.1: socket.io-adapter@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" - integrity sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s= + integrity sha512-zmYvlFJay9skt4yk1MffE9p93HKvQtyy0BLZ5dRM73bOXFJXNZWq8qZVdY456sLaxdK6fHGiZ7glxzqvzwGzkw== dependencies: debug "2.3.3" socket.io-parser "2.3.1" @@ -3296,7 +3161,7 @@ socket.io-adapter@0.5.0: socket.io-client@1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.3.tgz#b30e86aa10d5ef3546601c09cde4765e381da377" - integrity sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c= + integrity sha512-ZEPOqFboJuuVau/3sMF4PgzJM/X+TDhssgufCnGtPtSL2Nmt4dL3i9JheCT1B45hiYM5cgO+wTO8EYmxbpwHSw== dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -3313,7 +3178,7 @@ socket.io-client@1.7.3: socket.io-parser@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" - integrity sha1-3VMgJRA85Clpcya+/WQAX8/ltKA= + integrity sha512-j6l4g/+yWQjmy1yByzg1DPFL4vxQw+NwCJatIxni/AE1wfm17FBtIKSWU4Ay+onrJwDxmC4eK4QS/04ZsqYwZQ== dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -3323,7 +3188,7 @@ socket.io-parser@2.3.1: socket.io@1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b" - integrity sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs= + integrity sha512-CmZLQTyj5nKKVBoguhisLP5Yl6oEfEWbQQQQ0MdXAazCZdRpGR4FG6rd13ryovTa75S36PgXsAGtzwllCWrgbQ== dependencies: debug "2.3.3" engine.io "1.8.3" @@ -3334,51 +3199,51 @@ socket.io@1.7.3: socket.io-parser "2.3.1" source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: - atob "^2.1.1" + atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== source-map@^0.5.3, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -3387,7 +3252,7 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -sprintf-js@^1.0.3: +sprintf-js@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== @@ -3395,12 +3260,12 @@ sprintf-js@^1.0.3: sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -3415,49 +3280,37 @@ sshpk@^1.7.0: static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== dependencies: define-property "^0.2.5" object-copy "^0.1.0" -statuses@1, "statuses@>= 1.5.0 < 2", statuses@~1.5.0: +statuses@1, statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== statuses@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" - integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg= + integrity sha512-pVEuxHdSGrt8QmQ3LOZXLhSA6MP/iPqKzZeO6Squ7PNGkA/9MBsSfV0/L+bIxkoDmjF4tZcLpcVq/fkqoHvuKg== stream-counter@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-0.2.0.tgz#ded266556319c8b0e222812b9cf3b26fa7d947de" - integrity sha1-3tJmVWMZyLDiIoErnPOyb6fZR94= + integrity sha512-GjA2zKc2iXUUKRcOxXQmhEx0Ev3XHJ6c8yWGqhQjWwhGrqNwSsvq9YlRLgoGtZ5Kx2Ln94IedaqJ5GUG6aBbxA== dependencies: readable-stream "~1.1.8" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== string_decoder@~1.1.1: version "1.1.1" @@ -3466,39 +3319,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== dependencies: is-utf8 "^0.2.0" strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + integrity sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA== dependencies: get-stdin "^4.0.1" -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -3506,28 +3340,20 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -tar@^4: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== tiny-lr-fork@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz#1e99e1e2a8469b736ab97d97eefa98c71f76ed0a" - integrity sha1-Hpnh4qhGm3NquX2X7vqYxx927Qo= + integrity sha512-vhcvny/8f46rrViKV0BOUjVl4c/rDTztnT1+kT7iyD/Igqb/uyiRsKLxMc2Z8CNvTE1Px1tuNrPM+BOUL+3vlQ== dependencies: debug "~0.7.0" faye-websocket "~0.4.3" @@ -3537,7 +3363,7 @@ tiny-lr-fork@0.0.5: tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" - integrity sha1-jzirlDjhcxXl29izZX6L+yd65Kc= + integrity sha512-lfyEfOppKvWNeId5CArFLwgwef+iCnbEIy0JWYf1httIEXnx4ndL4Dr1adw7hPgeQfSlTbc/gqn6iaKcROpw5Q== dependencies: os-tmpdir "~1.0.1" @@ -3551,19 +3377,19 @@ tmp@0.0.x: to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" - integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + integrity sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A== to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -3578,42 +3404,42 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: - psl "^1.1.24" - punycode "^1.4.1" + psl "^1.1.28" + punycode "^2.1.1" trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + integrity sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw== tsscmp@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" - integrity sha1-fcSjOvcVgatDN9qR2FylQn69mpc= + integrity sha512-aP/vy9xYiYGvtpW4xBkxdoeqbT+nNeo/37cdQk3iSiGz0xKb20XwOgBSqYo1DzEqt1ycPubEfPU3oHgzsRRL3g== tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== -type-is@~1.6.17, type-is@~1.6.6: +type-is@~1.6.18, type-is@~1.6.6: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -3624,44 +3450,44 @@ type-is@~1.6.17, type-is@~1.6.6: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== uid-safe@2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.4.tgz#3ad6f38368c6d4c8c75ec17623fb79aa1d071d81" - integrity sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE= + integrity sha512-MHTGzIDNPv1XhDK0MyKvEroobUhtpMa649/9SIFbTRO2dshLctD3zxOwQw+gQ+Mlp5osfMdUU1sjcO6Fw4rvCA== dependencies: random-bytes "~1.0.0" uid-safe@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.0.0.tgz#a7f3c6ca64a1f6a5d04ec0ef3e4c3d5367317137" - integrity sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc= + integrity sha512-PH/12q0a/sEGVS28fZ5evILW2Ayn13PwkYmCleDsIPm39vUIqN58hjyqtUd496kyMY6WkXtaDMDpS8nSCmNKTg== dependencies: base64-url "1.2.1" ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= + integrity sha512-QMpnpVtYaWEeY+MwKDN/UdKlE/LsFZXM5lO1u7GaZzNgmIbGixHEmVMIKT+vqYOALu3m5GYQy9kz4Xu4IVn7Ow== underscore.string@~2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" - integrity sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs= + integrity sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ== underscore.string@~3.3.4: - version "3.3.5" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" - integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== + version "3.3.6" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.6.tgz#ad8cf23d7423cb3b53b898476117588f4e2f9159" + integrity sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ== dependencies: - sprintf-js "^1.0.3" + sprintf-js "^1.1.1" util-deprecate "^1.0.2" underscore@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk= + integrity sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA== union-value@^1.0.0: version "1.0.1" @@ -3676,27 +3502,27 @@ union-value@^1.0.0: unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== dependencies: has-value "^0.3.1" isobject "^3.0.0" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== use@^3.1.0: version "3.1.1" @@ -3714,22 +3540,22 @@ useragent@^2.1.12: util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" - integrity sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg= + integrity sha512-HwU9SLQEtyo+0uoKXd1nkLqigUWLB+QuNQR4OcmB73eWqksM5ovuqcycks2x043W8XVb75rG1HQ0h93TMXkzQQ== utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== validate-npm-package-license@^3.0.1: version "3.0.4" @@ -3742,17 +3568,17 @@ validate-npm-package-license@^3.0.1: vary@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.0.1.tgz#99e4981566a286118dfb2b817357df7993376d10" - integrity sha1-meSYFWaihhGN+yuBc1ffeZM3bRA= + integrity sha512-yNsH+tC0r8quK2tg/yqkXqqaYzeKTkSqQ+8T6xCoWgOi/bU/omMYz+6k+I91JJJDeltJzI7oridTOq6OYkY0Tw== vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -3761,12 +3587,12 @@ verror@1.10.0: vhost@~3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/vhost/-/vhost-3.0.2.tgz#2fb1decd4c466aa88b0f9341af33dc1aff2478d5" - integrity sha1-L7HezUxGaqiLD5NBrzPcGv8keNU= + integrity sha512-S3pJdWrpFWrKMboRU4dLYgMrTgoPALsmYwOvyebK2M6X95b9kQrjZy5rwl3uzzpfpENe/XrNYu/2U+e7/bmT5g== void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== which@^1.2.1, which@^1.2.10, which@~1.3.0: version "1.3.1" @@ -3775,27 +3601,20 @@ which@^1.2.1, which@^1.2.10, which@~1.3.0: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + integrity sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw== wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" - integrity sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8= + integrity sha512-lobrh3Dhp6tD1hv7NAIMx+oX/rsH/yd6/4krpBmJ/6ulsMZgQMuttlWTuYVWLV6ZjlpWIOjz55KbQbcKSQywEQ== dependencies: options ">=0.0.5" ultron "1.0.x" @@ -3803,31 +3622,27 @@ ws@1.1.2: wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" - integrity sha1-OS2LotDxw00e4tYw8V0O+2jhBIo= + integrity sha512-qfR6ovmRRMxNHgUNYI9LRdVofApe/eYrv4ggNOvvCP+pPdEo9Ym93QN4jUceGD6PignBbp2zAzgoE7GibAdq2A== xmlhttprequest-ssl@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" - integrity sha1-GFqIjATspGw+QHDZn3tJ3jUomS0= + integrity sha512-kauAa/1btT613pYX92WXR6kx5trYeckB5YMd3pPvtkMo2Twdfhwl683M8NiSqWHHo97xAC6bnvK1DWFKxfmejg== yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== -yallist@^3.0.0, yallist@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== dependencies: - fd-slicer "~1.0.1" + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" - integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= + integrity sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg== From 22cd62e897c7c5760246926da24494069168b7d7 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 19 Jun 2023 12:21:13 +0200 Subject: [PATCH 005/240] feat(developers): the theme sandbox is now a separated plugin ref #9730 --- .github/workflows/codecoverage.yml | 2 +- .github/workflows/phpunit.yml | 2 +- .github/workflows/upgrade.yml | 2 +- .gitignore | 1 + docs/plugins/index.rst | 1 + engine/classes/Elgg/Database/Plugins.php | 1 + .../classes/Elgg/Mocks/Database/Plugins.php | 1 + .../actions/developers/settings.php | 49 ------ .../Elgg/Developers/AppendTranslator.php | 1 - .../classes/Elgg/Developers/Bootstrap.php | 16 +- .../classes/Elgg/Developers/Events.php | 68 +------- .../classes/Elgg/Developers/HandlerLogger.php | 1 - .../Elgg/Developers/Menus/AdminHeader.php | 32 ++-- .../classes/Elgg/Developers/Menus/Entity.php | 2 - .../Developers/PluginSettingsSaveHandler.php | 48 ++++++ .../Elgg/Developers/ViewWrapperHandler.php | 76 +++++++++ mod/developers/elgg-plugin.php | 52 ++---- mod/developers/languages/en.php | 30 +--- mod/developers/lib/functions.php | 69 -------- .../default/admin/developers/settings.php | 129 -------------- .../{elgg/dev => developers}/amd_monitor.js | 0 .../views/default/developers/gear_popup.php | 30 ---- .../views/default/elgg/dev/gear.css | 64 ------- .../views/default/elgg/dev/gear.html.php | 3 - mod/developers/views/default/elgg/dev/gear.js | 50 ------ .../default/forms/developers/settings.js | 10 -- .../default/forms/developers/settings.php | 39 ----- .../default/plugins/developers/settings.js | 9 + .../default/plugins/developers/settings.php | 158 ++++++++++++++++++ .../actions/theme_sandbox}/ajax_demo.php | 2 +- .../actions/theme_sandbox}/test_email.php | 0 .../Elgg/ThemeSandbox/Menus/AdminHeader.php | 36 ++++ .../classes/ThemeSandboxObject.php | 0 mod/theme_sandbox/composer.json | 24 +++ mod/theme_sandbox/elgg-plugin.php | 52 ++++++ mod/theme_sandbox/languages/en.php | 29 ++++ .../forms/theme_sandbox}/ajax_demo.php | 2 +- .../resources/theme_sandbox}/ajax_demo.php | 0 .../resources/theme_sandbox}/email.php | 0 .../resources/theme_sandbox/index.php} | 2 +- .../views/default/theme_sandbox/buttons.php | 0 .../default/theme_sandbox/components.php | 0 .../theme_sandbox/components/full_listing.php | 2 +- .../theme_sandbox/components/image_block.php | 2 +- .../components/image_block_alt.php | 2 +- .../default/theme_sandbox/components/list.php | 2 +- .../theme_sandbox/components/messages.php | 0 .../components/summary_listing.php | 2 +- .../theme_sandbox/components/table.php | 0 .../default/theme_sandbox/components/tabs.php | 2 +- .../theme_sandbox/components/tabs/ajax.php | 0 .../default/theme_sandbox/components/tags.php | 0 .../default/theme_sandbox/demo}/ajax.php | 2 +- .../theme_sandbox/demo}/ajax_demo.html.php | 0 .../default/theme_sandbox/demo}/ajax_demo.js | 12 +- .../default/theme_sandbox/demo}/ipsum.php | 0 .../views/default/theme_sandbox/email.php | 4 +- .../views/default/theme_sandbox/forms.php | 2 +- .../views/default/theme_sandbox/grid.php | 0 .../views/default/theme_sandbox/icons.php | 0 .../default/theme_sandbox/icons/avatars.php | 0 .../default/theme_sandbox/icons/loader.php | 0 .../default/theme_sandbox/icons/sprites.php | 0 .../views/default/theme_sandbox/intro.php | 3 +- .../default/theme_sandbox/javascript.php | 0 .../theme_sandbox/javascript/lightbox.js | 0 .../theme_sandbox/javascript/lightbox.php | 4 +- .../default/theme_sandbox/javascript/popup.js | 2 +- .../theme_sandbox/javascript/popup.php | 2 +- .../theme_sandbox/javascript/spinner.php | 0 .../javascript/system_messages.php | 4 +- .../theme_sandbox/javascript/toggle.php | 2 +- .../javascript/user_hover_menu.php | 0 .../views/default/theme_sandbox/layouts.php | 0 .../theme_sandbox/layouts/one_column.php | 2 +- .../theme_sandbox/layouts/one_sidebar.php | 2 +- .../theme_sandbox/layouts/two_sidebar.php | 2 +- .../views/default/theme_sandbox/modules.php | 0 .../default/theme_sandbox/modules/modules.php | 2 +- .../default/theme_sandbox/modules/widgets.php | 2 +- .../default/theme_sandbox/navigation.php | 0 .../theme_sandbox/navigation/anchors.php | 0 .../theme_sandbox/navigation/breadcrumbs.php | 0 .../theme_sandbox/navigation/default.php | 0 .../theme_sandbox/navigation/dropdown.php | 0 .../theme_sandbox/navigation/entity.php | 0 .../theme_sandbox/navigation/filter.php | 0 .../theme_sandbox/navigation/footer.php | 0 .../theme_sandbox/navigation/horizontal.php | 0 .../theme_sandbox/navigation/owner_block.php | 0 .../default/theme_sandbox/navigation/page.php | 0 .../theme_sandbox/navigation/pagination.php | 0 .../theme_sandbox/navigation/require.js | 0 .../theme_sandbox/navigation/require.php | 0 .../default/theme_sandbox/navigation/site.php | 0 .../default/theme_sandbox/navigation/tabs.php | 0 .../theme_sandbox/navigation/toggle.php | 0 .../default/theme_sandbox}/theme_sandbox.js | 4 +- .../default/theme_sandbox/typography.php | 0 .../theme_sandbox/typography/fonts.php | 0 .../theme_sandbox/typography/headings.php | 0 .../default/theme_sandbox/typography/misc.php | 2 +- .../theme_sandbox/typography/paragraph.php | 0 103 files changed, 502 insertions(+), 656 deletions(-) delete mode 100644 mod/developers/actions/developers/settings.php create mode 100644 mod/developers/classes/Elgg/Developers/PluginSettingsSaveHandler.php create mode 100644 mod/developers/classes/Elgg/Developers/ViewWrapperHandler.php delete mode 100644 mod/developers/lib/functions.php delete mode 100644 mod/developers/views/default/admin/developers/settings.php rename mod/developers/views/default/{elgg/dev => developers}/amd_monitor.js (100%) delete mode 100644 mod/developers/views/default/developers/gear_popup.php delete mode 100644 mod/developers/views/default/elgg/dev/gear.css delete mode 100644 mod/developers/views/default/elgg/dev/gear.html.php delete mode 100644 mod/developers/views/default/elgg/dev/gear.js delete mode 100644 mod/developers/views/default/forms/developers/settings.js delete mode 100644 mod/developers/views/default/forms/developers/settings.php create mode 100644 mod/developers/views/default/plugins/developers/settings.js create mode 100644 mod/developers/views/default/plugins/developers/settings.php rename mod/{developers/actions/developers => theme_sandbox/actions/theme_sandbox}/ajax_demo.php (82%) rename mod/{developers/actions/developers => theme_sandbox/actions/theme_sandbox}/test_email.php (100%) create mode 100644 mod/theme_sandbox/classes/Elgg/ThemeSandbox/Menus/AdminHeader.php rename mod/{developers => theme_sandbox}/classes/ThemeSandboxObject.php (100%) create mode 100644 mod/theme_sandbox/composer.json create mode 100644 mod/theme_sandbox/elgg-plugin.php create mode 100644 mod/theme_sandbox/languages/en.php rename mod/{developers/views/default/forms/developers => theme_sandbox/views/default/forms/theme_sandbox}/ajax_demo.php (67%) rename mod/{developers/views/default/resources/developers => theme_sandbox/views/default/resources/theme_sandbox}/ajax_demo.php (100%) rename mod/{developers/views/default/resources/developers => theme_sandbox/views/default/resources/theme_sandbox}/email.php (100%) rename mod/{developers/views/default/resources/theme_sandbox.php => theme_sandbox/views/default/resources/theme_sandbox/index.php} (94%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/buttons.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/full_listing.php (92%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/image_block.php (85%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/image_block_alt.php (85%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/list.php (90%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/messages.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/summary_listing.php (90%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/table.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/tabs.php (97%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/tabs/ajax.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/components/tags.php (100%) rename mod/{developers/views/default/developers => theme_sandbox/views/default/theme_sandbox/demo}/ajax.php (90%) rename mod/{developers/views/default/developers => theme_sandbox/views/default/theme_sandbox/demo}/ajax_demo.html.php (100%) rename mod/{developers/views/default/developers => theme_sandbox/views/default/theme_sandbox/demo}/ajax_demo.js (85%) rename mod/{developers/views/default/developers => theme_sandbox/views/default/theme_sandbox/demo}/ipsum.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/email.php (70%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/forms.php (99%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/grid.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/icons.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/icons/avatars.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/icons/loader.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/icons/sprites.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/intro.php (83%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/lightbox.js (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/lightbox.php (93%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/popup.js (93%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/popup.php (93%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/spinner.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/system_messages.php (92%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/toggle.php (85%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/javascript/user_hover_menu.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/layouts.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/layouts/one_column.php (91%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/layouts/one_sidebar.php (92%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/layouts/two_sidebar.php (92%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/modules.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/modules/modules.php (95%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/modules/widgets.php (97%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/anchors.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/breadcrumbs.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/default.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/dropdown.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/entity.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/filter.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/footer.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/horizontal.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/owner_block.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/page.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/pagination.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/require.js (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/require.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/site.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/tabs.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/navigation/toggle.php (100%) rename mod/{developers/views/default/elgg/dev => theme_sandbox/views/default/theme_sandbox}/theme_sandbox.js (77%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/typography.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/typography/fonts.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/typography/headings.php (100%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/typography/misc.php (91%) rename mod/{developers => theme_sandbox}/views/default/theme_sandbox/typography/paragraph.php (100%) diff --git a/.github/workflows/codecoverage.yml b/.github/workflows/codecoverage.yml index 935631aacee..83de7354ef3 100644 --- a/.github/workflows/codecoverage.yml +++ b/.github/workflows/codecoverage.yml @@ -65,7 +65,7 @@ jobs: - name: Enable Elgg plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - name: Generate code coverage diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 1b3a09fa03a..e8c8fc08651 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -110,7 +110,7 @@ jobs: - name: Enable Elgg plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - name: Seed Elgg database diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml index 2e021f15e76..0b6b78402b6 100644 --- a/.github/workflows/upgrade.yml +++ b/.github/workflows/upgrade.yml @@ -133,7 +133,7 @@ jobs: - name: Activate current plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - name: Start Elgg webserver diff --git a/.gitignore b/.gitignore index af1cfb1c8ef..bb09198e628 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ !/mod/site_notifications/ !/mod/system_log/ !/mod/tagcloud/ +!/mod/theme_sandbox/ !/mod/thewire/ !/mod/uservalidationbyemail/ !/mod/web_services/ diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index dfa054d2cf2..04933883426 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -37,4 +37,5 @@ The following plugins are also bundled with Elgg, but are not (yet) documented - search - system_log - tagcloud +- theme_sandbox - web_services diff --git a/engine/classes/Elgg/Database/Plugins.php b/engine/classes/Elgg/Database/Plugins.php index f1e1c7efd20..1fe69e15680 100644 --- a/engine/classes/Elgg/Database/Plugins.php +++ b/engine/classes/Elgg/Database/Plugins.php @@ -60,6 +60,7 @@ class Plugins { 'site_notifications', 'system_log', 'tagcloud', + 'theme_sandbox', 'thewire', 'uservalidationbyemail', 'web_services', diff --git a/engine/tests/classes/Elgg/Mocks/Database/Plugins.php b/engine/tests/classes/Elgg/Mocks/Database/Plugins.php index a25b82487d6..99d3ff8a92d 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/Plugins.php +++ b/engine/tests/classes/Elgg/Mocks/Database/Plugins.php @@ -43,6 +43,7 @@ class Plugins extends DbPlugins { 'site_notifications', 'system_log', 'tagcloud', + 'theme_sandbox', 'thewire', 'uservalidationbyemail', 'web_services', diff --git a/mod/developers/actions/developers/settings.php b/mod/developers/actions/developers/settings.php deleted file mode 100644 index e24e900790d..00000000000 --- a/mod/developers/actions/developers/settings.php +++ /dev/null @@ -1,49 +0,0 @@ -config->hasInitialValue('simplecache_enabled')) { - if (get_input('simple_cache')) { - elgg_enable_simplecache(); - } else { - elgg_disable_simplecache(); - } -} - -if (get_input('system_cache')) { - elgg_enable_system_cache(); -} else { - elgg_disable_system_cache(); -} - -if (!elgg()->config->hasInitialValue('debug')) { - $debug = get_input('debug_level'); - if ($debug) { - elgg_save_config('debug', $debug); - } else { - elgg_remove_config('debug'); - } -} - -$simple_settings = [ - 'display_errors', - 'screen_log', - 'show_strings', - 'wrap_views', - 'log_events', - 'show_gear', - 'show_modules', - 'block_email', - 'forward_email', - 'enable_error_log', -]; - -$plugin = elgg_get_plugin_from_id('developers'); -foreach ($simple_settings as $setting) { - $plugin->setSetting($setting, get_input($setting)); -} - -elgg_invalidate_caches(); - -return elgg_ok_response('', elgg_echo('developers:settings:success')); diff --git a/mod/developers/classes/Elgg/Developers/AppendTranslator.php b/mod/developers/classes/Elgg/Developers/AppendTranslator.php index be791dd0443..e8c2f88af93 100644 --- a/mod/developers/classes/Elgg/Developers/AppendTranslator.php +++ b/mod/developers/classes/Elgg/Developers/AppendTranslator.php @@ -11,7 +11,6 @@ * easily tell what the available keys are for changing the wording of UI elements. * * @since 4.1 - * @internal */ final class AppendTranslator extends Translator { diff --git a/mod/developers/classes/Elgg/Developers/Bootstrap.php b/mod/developers/classes/Elgg/Developers/Bootstrap.php index 82bdd08e809..07fcfb19ac8 100644 --- a/mod/developers/classes/Elgg/Developers/Bootstrap.php +++ b/mod/developers/classes/Elgg/Developers/Bootstrap.php @@ -9,7 +9,6 @@ * Bootstraps the plugin * * @since 4.0 - * @internal */ class Bootstrap extends DefaultPluginBootstrap { @@ -110,27 +109,16 @@ protected function processSettings() { } if (!empty($settings['show_modules'])) { - elgg_require_js('elgg/dev/amd_monitor'); + elgg_require_js('developers/amd_monitor'); } if (!empty($settings['wrap_views'])) { - $events->registerHandler('view', 'all', 'developers_wrap_views', 600); + $events->registerHandler('view', 'all', __NAMESPACE__ . '\ViewWrapperHandler', 600); } if (!empty($settings['log_events'])) { $events->registerHandler('all', 'all', __NAMESPACE__ . '\HandlerLogger::trackEvent', 1); } - - if (!empty($settings['show_gear']) && elgg_is_admin_logged_in() && !elgg_in_context('admin')) { - elgg_require_js('elgg/dev/gear'); - elgg_require_css('elgg/dev/gear'); - elgg_register_ajax_view('developers/gear_popup'); - elgg_register_simplecache_view('elgg/dev/gear.html'); - - $events->registerHandler('view_vars', 'navigation/menu/elements/section', __NAMESPACE__ . '\Events::alterMenuSectionVars'); - $events->registerHandler('view', 'navigation/menu/elements/section', __NAMESPACE__ . '\Events::alterMenuSections'); - $events->registerHandler('view', 'navigation/menu/default', __NAMESPACE__ . '\Events::alterMenu'); - } if (!empty($settings['block_email'])) { $events->registerHandler('transport', 'system:email', __NAMESPACE__ . '\Events::blockOutgoingEmails'); diff --git a/mod/developers/classes/Elgg/Developers/Events.php b/mod/developers/classes/Elgg/Developers/Events.php index 5f0fd87fda0..977f45750d1 100644 --- a/mod/developers/classes/Elgg/Developers/Events.php +++ b/mod/developers/classes/Elgg/Developers/Events.php @@ -7,72 +7,6 @@ */ class Events { - /** - * Alter input of menu sections in "gear" popup - * - * @param \Elgg\Event $event 'view_vars', 'navigation/menu/elements/section' - * - * @return mixed - */ - public static function alterMenuSectionVars(\Elgg\Event $event) { - if (!elgg_in_context('developers_gear')) { - return; - } - - $value = $event->getValue(); - $idx = array_search('elgg-menu-page', $value['class']); - if ($idx !== false) { - unset($value['class'][$idx]); - $value['class'][] = 'elgg-menu-gear'; - } - - // remove the display options - foreach ($value['items'] as $item) { - /* @var \ElggMenuItem $item */ - $child_opts = $item->getChildMenuOptions(); - unset($child_opts['display']); - $item->setChildMenuOptions($child_opts); - } - - return $value; - } - - /** - * Alter output of menu sections in "gear" popup - * - * @param \Elgg\Event $event 'view', 'navigation/menu/elements/section' - * - * @return mixed - */ - public static function alterMenuSections(\Elgg\Event $event) { - if (!elgg_in_context('developers_gear')) { - return; - } - - $params = $event->getParams(); - if (in_array('elgg-developers-gear', $params['vars']['class'])) { - return elgg_format_element('section', [], $event->getValue()); - } - } - - /** - * Alter output of complete menu in "gear" popup - * - * @param \Elgg\Event $event 'view', 'navigation/menu/default' - * - * @return mixed - */ - public static function alterMenu(\Elgg\Event $event) { - if (!elgg_in_context('developers_gear')) { - return; - } - - $output = $event->getValue(); - $output = preg_replace('~^]+>~', '', $output); - - return preg_replace('~^$~', '', $output); - } - /** * Change the to address if a forwarding address isset * @@ -92,7 +26,7 @@ public static function setForwardEmailAddress(\Elgg\Event $event) { } $email = $event->getValue(); - if (!($email instanceof \Elgg\Email)) { + if (!$email instanceof \Elgg\Email) { return; } diff --git a/mod/developers/classes/Elgg/Developers/HandlerLogger.php b/mod/developers/classes/Elgg/Developers/HandlerLogger.php index 8ee36282b55..beeda8290e7 100644 --- a/mod/developers/classes/Elgg/Developers/HandlerLogger.php +++ b/mod/developers/classes/Elgg/Developers/HandlerLogger.php @@ -6,7 +6,6 @@ * Track events * * @since 4.0 - * @internal */ class HandlerLogger { diff --git a/mod/developers/classes/Elgg/Developers/Menus/AdminHeader.php b/mod/developers/classes/Elgg/Developers/Menus/AdminHeader.php index c869bad1ddd..f8aebe4c598 100644 --- a/mod/developers/classes/Elgg/Developers/Menus/AdminHeader.php +++ b/mod/developers/classes/Elgg/Developers/Menus/AdminHeader.php @@ -6,8 +6,6 @@ * Event callbacks for menus * * @since 5.0 - * - * @internal */ class AdminHeader { @@ -19,7 +17,7 @@ class AdminHeader { * @return void|\Elgg\Menu\MenuItems */ public static function register(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -34,18 +32,20 @@ public static function register(\Elgg\Event $event) { $return[] = \ElggMenuItem::factory([ 'name' => 'dev_settings', 'text' => elgg_echo('settings'), - 'href' => 'admin/developers/settings', + 'href' => 'admin/plugin_settings/developers', 'priority' => 10, 'parent_name' => 'develop', ]); - $return[] = \ElggMenuItem::factory([ - 'name' => 'error_log', - 'text' => elgg_echo('admin:develop_tools:error_log'), - 'href' => 'admin/develop_tools/error_log', - 'parent_name' => 'develop', - ]); - + if (elgg_get_plugin_setting('enable_error_log', 'developers')) { + $return[] = \ElggMenuItem::factory([ + 'name' => 'error_log', + 'text' => elgg_echo('admin:develop_tools:error_log'), + 'href' => 'admin/develop_tools/error_log', + 'parent_name' => 'develop', + ]); + } + $return[] = \ElggMenuItem::factory([ 'name' => 'develop_tools:entity_explorer', 'text' => elgg_echo('admin:develop_tools:entity_explorer'), @@ -53,14 +53,6 @@ public static function register(\Elgg\Event $event) { 'parent_name' => 'develop', ]); - $return[] = \ElggMenuItem::factory([ - 'name' => 'develop_tools:sandbox', - 'text' => elgg_echo('admin:develop_tools:sandbox'), - 'href' => 'theme_sandbox/intro', - 'parent_name' => 'develop', - 'target' => '_blank', - ]); - $return[] = \ElggMenuItem::factory([ 'name' => 'inspect', 'text' => elgg_echo('admin:inspect'), @@ -88,7 +80,7 @@ public static function register(\Elgg\Event $event) { * * @return array */ - protected static function getInspectOptions() { + protected static function getInspectOptions(): array { $options = [ 'Actions' => elgg_echo('developers:inspect:actions'), 'Events' => elgg_echo('developers:inspect:events'), diff --git a/mod/developers/classes/Elgg/Developers/Menus/Entity.php b/mod/developers/classes/Elgg/Developers/Menus/Entity.php index fade945e384..eb0d531bda6 100644 --- a/mod/developers/classes/Elgg/Developers/Menus/Entity.php +++ b/mod/developers/classes/Elgg/Developers/Menus/Entity.php @@ -6,8 +6,6 @@ * Event callbacks for menus * * @since 4.0 - * - * @internal */ class Entity { diff --git a/mod/developers/classes/Elgg/Developers/PluginSettingsSaveHandler.php b/mod/developers/classes/Elgg/Developers/PluginSettingsSaveHandler.php new file mode 100644 index 00000000000..f0574f65612 --- /dev/null +++ b/mod/developers/classes/Elgg/Developers/PluginSettingsSaveHandler.php @@ -0,0 +1,48 @@ +config->hasInitialValue('simplecache_enabled')) { + if (get_input('simple_cache')) { + elgg_enable_simplecache(); + } else { + elgg_disable_simplecache(); + } + } + + if (get_input('system_cache')) { + elgg_enable_system_cache(); + } else { + elgg_disable_system_cache(); + } + + if (!elgg()->config->hasInitialValue('debug')) { + $debug = get_input('debug_level'); + if ($debug) { + elgg_save_config('debug', $debug); + } else { + elgg_remove_config('debug'); + } + } + } +} diff --git a/mod/developers/classes/Elgg/Developers/ViewWrapperHandler.php b/mod/developers/classes/Elgg/Developers/ViewWrapperHandler.php new file mode 100644 index 00000000000..f17fd911374 --- /dev/null +++ b/mod/developers/classes/Elgg/Developers/ViewWrapperHandler.php @@ -0,0 +1,76 @@ +getValue(); + if (elgg_get_viewtype() !== 'default' || elgg_is_empty($result)) { + return null; + } + + if (elgg_stristr(elgg_get_current_url(), elgg_normalize_url('cache/'))) { + return null; + } + + $excluded_views = [ + 'page/default', + 'page/admin', + 'page/elements/head', + 'page/elements/html', + ]; + + $view = (string) $event->getParam('view'); + if (in_array($view, $excluded_views)) { + return null; + } + + $excluded_bases = [ + 'resources', + 'input', // because of possible html encoding in views, which would result in debug code being shown to users + 'output', // because of possible html encoding in views, which would result in debug code being shown to users + 'embed', + 'icon', + 'json', + 'xml', + ]; + + $view_hierarchy = explode('/', $view); + if (in_array($view_hierarchy[0], $excluded_bases)) { + return null; + } + + if ((new \SplFileInfo($view))->getExtension()) { + // don't wrap views with extension + // for example: elements/buttons.css + return null; + } + + $view_location = _elgg_services()->views->findViewFile($view, 'default'); + $project_path = \Elgg\Project\Paths::sanitize(\Elgg\Project\Paths::project()); // handle Windows paths + $view_location = str_ireplace($project_path, '', $view_location); // strip project path from view location + + return "{$result}"; + } +} diff --git a/mod/developers/elgg-plugin.php b/mod/developers/elgg-plugin.php index 2d04f6e444d..3826bc2f4fd 100644 --- a/mod/developers/elgg-plugin.php +++ b/mod/developers/elgg-plugin.php @@ -1,51 +1,29 @@ [ 'name' => 'Elgg Developer Tools', ], + 'settings' => [ + 'screen_log' => 0, + 'show_strings' => 0, + 'show_modules' => 0, + 'wrap_views' => 0, + 'log_events' => 0, + 'enable_error_log' => 0, + ], 'bootstrap' => \Elgg\Developers\Bootstrap::class, 'actions' => [ - 'developers/settings' => [ - 'access' => 'admin', - ], - 'developers/ajax_demo' => [ - 'access' => 'admin', - ], 'developers/entity_explorer_delete' => [ 'access' => 'admin', ], - 'developers/test_email' => [], ], - 'routes' => [ - 'default:theme_sandbox' => [ - 'path' => '/theme_sandbox/{page?}', - 'resource' => 'theme_sandbox', - 'defaults' => [ - 'page' => 'intro', - ], - 'middleware' => [ - \Elgg\Router\Middleware\AdminGatekeeper::class, - ], - ], - 'default:developers:ajax_demo' => [ - 'path' => '/developers_ajax_demo', - 'resource' => 'developers/ajax_demo', - 'middleware' => [ - \Elgg\Router\Middleware\AdminGatekeeper::class, - ], - ], - 'default:developers:email' => [ - 'path' => '/developers_email', - 'resource' => 'developers/email', - 'middleware' => [ - \Elgg\Router\Middleware\AdminGatekeeper::class, + 'events' => [ + 'action:validate' => [ + 'plugins/settings/save' => [ + 'Elgg\Developers\PluginSettingsSaveHandler' => [], ], ], - ], - 'events' => [ 'register' => [ 'menu:admin_header' => [ 'Elgg\Developers\Menus\AdminHeader::register' => [], @@ -58,10 +36,4 @@ ], ], ], - 'view_options' => [ - 'developers/ajax' => ['ajax' => true], - 'developers/ajax_demo.html' => ['ajax' => true], - 'forms/developers/ajax_demo' => ['ajax' => true], - 'theme_sandbox/components/tabs/ajax' => ['ajax' => true], - ], ]; diff --git a/mod/developers/languages/en.php b/mod/developers/languages/en.php index a1b915d3773..fcbed1b86fe 100644 --- a/mod/developers/languages/en.php +++ b/mod/developers/languages/en.php @@ -9,7 +9,6 @@ 'admin:develop_tools' => 'Tools', // menu - 'admin:develop_tools:sandbox' => 'Theme Sandbox', 'admin:develop_tools:inspect' => 'Inspect', 'admin:inspect' => 'Inspect', 'admin:develop_tools:unit_tests' => 'Unit Tests', @@ -38,11 +37,9 @@ 'developers:help:show_modules' => "Streams loaded modules and values to your JavaScript console.", 'developers:label:wrap_views' => "Wrap views", 'developers:help:wrap_views' => "This wraps almost every view with HTML comments. Useful for finding the view creating particular HTML. - This can break non-HTML views in the default viewtype. See developers_wrap_views() for details.", + This can break non-HTML views in the default viewtype.", 'developers:label:log_events' => "Log events", 'developers:help:log_events' => "Write events to the log. Warning: there are many of these per page.", - 'developers:label:show_gear' => "Use %s outside admin area", - 'developers:help:show_gear' => "An icon on the bottom right of the viewport that gives admins access to developer settings and links.", 'developers:label:block_email' => "Block all outgoing e-mails", 'developers:help:block_email' => "You can block outgoing e-mail to regular users or to all users", 'developers:label:forward_email' => "Forward all outgoing e-mails to one address", @@ -50,8 +47,6 @@ 'developers:label:enable_error_log' => "Enable error log", 'developers:help:enable_error_log' => "Maintain a separate log of errors and messages logged to the error_log() based on your trace level setting. The log is viewable via admin interface.", - 'developers:label:submit' => "Save and flush caches", - 'developers:block_email:forward' => 'Forward all e-mails', 'developers:block_email:users' => 'Only regular users', 'developers:block_email:all' => 'Admins and regular users', @@ -112,29 +107,6 @@ 'developers:boot_cache_rebuilt' => "The boot cache was rebuilt for this request", 'developers:elapsed_time' => "Elapsed time (s)", - // theme sandbox - 'theme_sandbox:intro' => 'Introduction', - 'theme_sandbox:breakout' => 'Break out of iframe', - 'theme_sandbox:buttons' => 'Buttons', - 'theme_sandbox:components' => 'Components', - 'theme_sandbox:email' => 'Email', - 'theme_sandbox:forms' => 'Forms', - 'theme_sandbox:grid' => 'Grid', - 'theme_sandbox:icons' => 'Icons', - 'theme_sandbox:javascript' => 'JavaScript', - 'theme_sandbox:layouts' => 'Layouts', - 'theme_sandbox:modules' => 'Modules', - 'theme_sandbox:navigation' => 'Navigation', - 'theme_sandbox:typography' => 'Typography', - - 'theme_sandbox:icons:blurb' => 'Use elgg_view_icon($name) to display icons.', - - 'theme_sandbox:test_email:button' => "Send Test Mail", - 'theme_sandbox:test_email:success' => "Test mail sent to: %s", - - // status messages - 'developers:settings:success' => 'Settings saved and caches flushed', - 'developers:amd' => 'AMD', 'admin:develop_tools:error_log' => 'Error Log', diff --git a/mod/developers/lib/functions.php b/mod/developers/lib/functions.php deleted file mode 100644 index 21d34620c78..00000000000 --- a/mod/developers/lib/functions.php +++ /dev/null @@ -1,69 +0,0 @@ -getValue(); - if (elgg_get_viewtype() !== 'default' || elgg_is_empty($result)) { - return; - } - - if (elgg_stristr(elgg_get_current_url(), elgg_normalize_url('cache/'))) { - return; - } - - $excluded_views = [ - 'page/default', - 'page/admin', - 'page/elements/head', - 'page/elements/html', - ]; - - $view = (string) $event->getParam('view'); - if (in_array($view, $excluded_views)) { - return; - } - - $excluded_bases = [ - 'resources', - 'input', // because of possible html encoding in views, which would result in debug code being shown to users - 'output', // because of possible html encoding in views, which would result in debug code being shown to users - 'embed', - 'icon', - 'json', - 'xml', - ]; - - $view_hierarchy = explode('/', $view); - if (in_array($view_hierarchy[0], $excluded_bases)) { - return; - } - - if ((new \SplFileInfo($view))->getExtension()) { - // don't wrap views with extension - // for example: elements/buttons.css - return; - } - - $view_location = _elgg_services()->views->findViewFile($view, 'default'); - $project_path = str_replace('\\', '/', Elgg\Project\Paths::project()); // handle Windows paths - $view_location = str_ireplace($project_path, '', $view_location); // strip project path from view location - - return "{$result}"; -} diff --git a/mod/developers/views/default/admin/developers/settings.php b/mod/developers/views/default/admin/developers/settings.php deleted file mode 100644 index 0a49492a1ec..00000000000 --- a/mod/developers/views/default/admin/developers/settings.php +++ /dev/null @@ -1,129 +0,0 @@ -config; -$debug_value = $config->hasInitialValue('debug') ? $config->getInitialValue('debug') : $config->debug; - -$debug_help = elgg_echo('developers:help:debug_level'); -if ($config->hasInitialValue('debug')) { - $debug_help .= '
' . elgg_echo('admin:settings:in_settings_file'); -} - -$data = [ - 'simple_cache' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => $config->simplecache_enabled == 1, - 'disabled' => $config->hasInitialValue('simplecache_enabled'), - 'switch' => true, - ], - - 'system_cache' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_is_system_cache_enabled(), - 'switch' => true, - ], - - 'display_errors' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('display_errors', 'developers') == 1, - 'switch' => true, - ], - - 'debug_level' => [ - '#type' => 'select', - '#help' => $debug_help, - 'value' => $debug_value, - 'disabled' => $config->hasInitialValue('debug'), - 'options_values' => [ - '' => elgg_echo('developers:debug:off'), - 'ERROR' => elgg_echo('developers:debug:error'), - 'WARNING' => elgg_echo('developers:debug:warning'), - 'NOTICE' => elgg_echo('developers:debug:notice'), - 'INFO' => elgg_echo('developers:debug:info'), - ], - ], - - 'screen_log' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('screen_log', 'developers') == 1, - 'switch' => true, - ], - - 'show_strings' => [ - '#type' => 'select', - 'options_values' => [ - 0 => elgg_echo('developers:show_strings:default'), - 1 => elgg_echo('developers:show_strings:key_append'), - 2 => elgg_echo('developers:show_strings:key_only'), - ], - 'value' => elgg_get_plugin_setting('show_strings', 'developers', 0), - ], - - 'show_modules' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('show_modules', 'developers') == 1, - 'switch' => true, - ], - - 'wrap_views' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('wrap_views', 'developers') == 1, - 'switch' => true, - ], - - 'log_events' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('log_events', 'developers') == 1, - 'switch' => true, - ], - - 'show_gear' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('show_gear', 'developers') == 1, - 'switch' => true, - ], - - 'block_email' => [ - '#type' => 'select', - 'value' => elgg_get_plugin_setting('block_email', 'developers'), - 'options_values' => [ - '' => elgg_echo('option:no'), - 'forward' => elgg_echo('developers:block_email:forward'), - 'users' => elgg_echo('developers:block_email:users'), - 'all' => elgg_echo('developers:block_email:all'), - ], - ], - - 'forward_email' => [ - '#type' => 'email', - '#class' => elgg_get_plugin_setting('block_email', 'developers') === 'forward' ? '' : 'hidden', - 'value' => elgg_get_plugin_setting('forward_email', 'developers'), - ], - - 'enable_error_log' => [ - '#type' => 'checkbox', - 'value' => 1, - 'checked' => elgg_get_plugin_setting('enable_error_log', 'developers') == 1, - 'switch' => true, - ], -]; - -$form_vars = [ - 'id' => 'developer-settings-form', - 'class' => 'elgg-form-settings', -]; -$body_vars = [ - 'data' => $data, -]; - -echo elgg_view_form('developers/settings', $form_vars, $body_vars); diff --git a/mod/developers/views/default/elgg/dev/amd_monitor.js b/mod/developers/views/default/developers/amd_monitor.js similarity index 100% rename from mod/developers/views/default/elgg/dev/amd_monitor.js rename to mod/developers/views/default/developers/amd_monitor.js diff --git a/mod/developers/views/default/developers/gear_popup.php b/mod/developers/views/default/developers/gear_popup.php deleted file mode 100644 index 07eb7f1f3cd..00000000000 --- a/mod/developers/views/default/developers/gear_popup.php +++ /dev/null @@ -1,30 +0,0 @@ - true, - 'class' => 'elgg-developers-gear', - 'prepare_vertical' => true, -]); - -$settings_form = elgg_view('admin/developers/settings'); - -elgg_pop_context(); -elgg_pop_context(); - -$form_heading = elgg_echo('menu:page:header:develop') . ': ' . elgg_echo('admin:developers:settings'); - -?> -
- - -
-

- -
-
diff --git a/mod/developers/views/default/elgg/dev/gear.css b/mod/developers/views/default/elgg/dev/gear.css deleted file mode 100644 index 505f55fb2f8..00000000000 --- a/mod/developers/views/default/elgg/dev/gear.css +++ /dev/null @@ -1,64 +0,0 @@ -.developers-gear { - position: fixed; - z-index: 1000; - bottom: 0; - right: 0; - cursor: pointer; - padding: 5px 8px; -} - -.developers-gear-popup { - display: flex; - justify-content: space-evenly; - - > section { - width: 16em; - } - > section.developers-form { - width: 24em; - } - - .elgg-menu-section-header { - margin-bottom: 10px; - font-size: 1.5rem; - font-weight: 500; - } - - .elgg-child-menu { - margin-left: 20px; - margin-bottom: 10px; - } - - .elgg-menu-parent, - .elgg-menu-parent:hover { - color: #000; - text-decoration: none; - cursor: default; - } - - .elgg-text-help { - display: none; - } - - label { - font-weight: inherit; - } - - fieldset > div { - margin-bottom: 5px; - } - - #developer-settings-form { - label .elgg-icon-info, - label .elgg-text-help { - margin-left: 10px; - vertical-align: text-top; - cursor: pointer; - } - - .elgg-foot { - margin-top: 15px; - margin-bottom: 0; - } - } -} diff --git a/mod/developers/views/default/elgg/dev/gear.html.php b/mod/developers/views/default/elgg/dev/gear.html.php deleted file mode 100644 index 76f39aede35..00000000000 --- a/mod/developers/views/default/elgg/dev/gear.html.php +++ /dev/null @@ -1,3 +0,0 @@ - 'developers-gear'], elgg_view_icon('settings-alt')); diff --git a/mod/developers/views/default/elgg/dev/gear.js b/mod/developers/views/default/elgg/dev/gear.js deleted file mode 100644 index 6365002eeb6..00000000000 --- a/mod/developers/views/default/elgg/dev/gear.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Note, depends on $.colorbox! - */ -define(['jquery', 'elgg', 'elgg/spinner', 'text!elgg/dev/gear.html', 'elgg/lightbox', 'elgg/i18n'], function ($, elgg, spinner, gear_html, lightbox, i18n) { - - $(gear_html) - .appendTo('body') - .find('.elgg-icon') - .prop('title', i18n.echo('admin:developers:settings')) - .on('click', function () { - lightbox.open({ - href: elgg.get_site_url() + 'ajax/view/developers/gear_popup', - initialWidth: '90%', - maxWidth: false, - width: '90%', - speed: 0, - onComplete: function () { - $('#developer-settings-form') - .on('submit', spinner.start) - .find('fieldset > div') - .each(function () { - var $help = $('span.elgg-text-help', this), - $label = $('label', this); - - if ($help.length != 1 || $label.length != 1) { - return; - } - - var $icon = $(''), - $both = $([$icon[0], $help[0]]) - .appendTo($label) - .on('click', function () { - $both.toggle(); - $.colorbox.resize(); - return false; - }); - }); - lightbox.resize(); - } - }); - }); - - $(document).on('click', '.developers-gear-popup a', function() { - if ($(this).is('.elgg-menu-parent')) { - return false; - } - - spinner.start(); - }); -}); diff --git a/mod/developers/views/default/forms/developers/settings.js b/mod/developers/views/default/forms/developers/settings.js deleted file mode 100644 index 2b68b11f695..00000000000 --- a/mod/developers/views/default/forms/developers/settings.js +++ /dev/null @@ -1,10 +0,0 @@ -define(['jquery'], function($) { - - $(document).on('change', '.elgg-form-developers-settings select[name="block_email"]', function() { - if ($(this).val() === 'forward') { - $('.elgg-form-developers-settings input[name="forward_email"]').closest('.elgg-field').removeClass('hidden'); - } else { - $('.elgg-form-developers-settings input[name="forward_email"]').closest('.elgg-field').addClass('hidden'); - } - }); -}); diff --git a/mod/developers/views/default/forms/developers/settings.php b/mod/developers/views/default/forms/developers/settings.php deleted file mode 100644 index d6fa4140b30..00000000000 --- a/mod/developers/views/default/forms/developers/settings.php +++ /dev/null @@ -1,39 +0,0 @@ - elgg_echo('elgg_dev_tools:settings:explanation'), - ]); -} - -foreach ($vars['data'] as $name => $info) { - $info['name'] = $name; - - $echo_vars = ($name === 'show_gear') ? [elgg_view_icon('settings-alt')] : []; - if (empty($echo_vars)) { - $info['#label'] = elgg_echo("developers:label:$name"); - } else { - $info['#label'] = elgg_echo("developers:label:$name", $echo_vars); - } - - if (empty($info['#help'])) { - $info['#help'] = elgg_echo("developers:help:$name"); - } - - echo elgg_view_field($info); -} - -// form footer -$footer = elgg_view_field([ - '#type' => 'submit', - 'value' => elgg_echo('developers:label:submit'), -]); - -elgg_set_form_footer($footer); diff --git a/mod/developers/views/default/plugins/developers/settings.js b/mod/developers/views/default/plugins/developers/settings.js new file mode 100644 index 00000000000..6c5bebd5493 --- /dev/null +++ b/mod/developers/views/default/plugins/developers/settings.js @@ -0,0 +1,9 @@ +define(['jquery'], function($) { + $(document).on('change', '#developers-settings select[name="params[block_email]"]', function() { + if ($(this).val() === 'forward') { + $('#developers-settings input[name="params[forward_email]"]').closest('.elgg-field').removeClass('hidden'); + } else { + $('#developers-settings input[name="params[forward_email]"]').closest('.elgg-field').addClass('hidden'); + } + }); +}); diff --git a/mod/developers/views/default/plugins/developers/settings.php b/mod/developers/views/default/plugins/developers/settings.php new file mode 100644 index 00000000000..94663a9c02a --- /dev/null +++ b/mod/developers/views/default/plugins/developers/settings.php @@ -0,0 +1,158 @@ +config; + +echo elgg_view('output/longtext', [ + 'value' => elgg_echo('elgg_dev_tools:settings:explanation'), +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:simple_cache'), + '#help' => elgg_echo('developers:help:simple_cache'), + 'name' => 'simple_cache', + 'value' => 1, + 'checked' => elgg_is_simplecache_enabled(), + 'disabled' => $config->hasInitialValue('simplecache_enabled'), + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:system_cache'), + '#help' => elgg_echo('developers:help:system_cache'), + 'name' => 'system_cache', + 'value' => 1, + 'checked' => elgg_is_system_cache_enabled(), + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:display_errors'), + '#help' => elgg_echo('developers:help:display_errors'), + 'name' => 'params[display_errors]', + 'value' => 1, + 'checked' => $plugin->display_errors === '1', + 'switch' => true, +]); + +$debug_value = $config->hasInitialValue('debug') ? $config->getInitialValue('debug') : $config->debug; + +$debug_help = elgg_echo('developers:help:debug_level'); +if ($config->hasInitialValue('debug')) { + $debug_help .= '
' . elgg_echo('admin:settings:in_settings_file'); +} + +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('developers:label:debug_level'), + '#help' => $debug_help, + 'name' => 'debug_level', + 'value' => $debug_value, + 'disabled' => $config->hasInitialValue('debug'), + 'options_values' => [ + '' => elgg_echo('developers:debug:off'), + 'ERROR' => elgg_echo('developers:debug:error'), + 'WARNING' => elgg_echo('developers:debug:warning'), + 'NOTICE' => elgg_echo('developers:debug:notice'), + 'INFO' => elgg_echo('developers:debug:info'), + ], +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:screen_log'), + '#help' => elgg_echo('developers:help:screen_log'), + 'name' => 'params[screen_log]', + 'value' => 1, + 'checked' => $plugin->screen_log === '1', + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('developers:label:show_strings'), + '#help' => elgg_echo('developers:help:show_strings'), + 'name' => 'params[show_strings]', + 'options_values' => [ + 0 => elgg_echo('developers:show_strings:default'), + 1 => elgg_echo('developers:show_strings:key_append'), + 2 => elgg_echo('developers:show_strings:key_only'), + ], + 'value' => $plugin->show_strings, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:show_modules'), + '#help' => elgg_echo('developers:help:show_modules'), + 'name' => 'params[show_modules]', + 'value' => 1, + 'checked' => $plugin->show_modules === '1', + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:wrap_views'), + '#help' => elgg_echo('developers:help:wrap_views'), + 'name' => 'params[wrap_views]', + 'value' => 1, + 'checked' => $plugin->wrap_views === '1', + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:log_events'), + '#help' => elgg_echo('developers:help:log_events'), + 'name' => 'params[log_events]', + 'value' => 1, + 'checked' => $plugin->log_events === '1', + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('developers:label:block_email'), + '#help' => elgg_echo('developers:help:block_email'), + 'name' => 'params[block_email]', + 'value' => $plugin->block_email, + 'options_values' => [ + '' => elgg_echo('option:no'), + 'forward' => elgg_echo('developers:block_email:forward'), + 'users' => elgg_echo('developers:block_email:users'), + 'all' => elgg_echo('developers:block_email:all'), + ], +]); + +echo elgg_view_field([ + '#type' => 'email', + '#label' => elgg_echo('developers:label:forward_email'), + '#help' => elgg_echo('developers:help:forward_email'), + '#class' => $plugin->block_email === 'forward' ? '' : 'hidden', + 'name' => 'params[forward_email]', + 'value' => $plugin->forward_email, +]); + +echo elgg_view_field([ + '#type' => 'checkbox', + '#label' => elgg_echo('developers:label:enable_error_log'), + '#help' => elgg_echo('developers:help:enable_error_log'), + 'name' => 'params[enable_error_log]', + 'value' => 1, + 'checked' => $plugin->enable_error_log === '1', + 'switch' => true, +]); + +echo elgg_view_field([ + '#type' => 'hidden', + 'name' => 'flush_cache', + 'value' => 1, +]); diff --git a/mod/developers/actions/developers/ajax_demo.php b/mod/theme_sandbox/actions/theme_sandbox/ajax_demo.php similarity index 82% rename from mod/developers/actions/developers/ajax_demo.php rename to mod/theme_sandbox/actions/theme_sandbox/ajax_demo.php index af57a9f58ba..603a1aebd44 100644 --- a/mod/developers/actions/developers/ajax_demo.php +++ b/mod/theme_sandbox/actions/theme_sandbox/ajax_demo.php @@ -1,6 +1,6 @@ getValue(); diff --git a/mod/developers/actions/developers/test_email.php b/mod/theme_sandbox/actions/theme_sandbox/test_email.php similarity index 100% rename from mod/developers/actions/developers/test_email.php rename to mod/theme_sandbox/actions/theme_sandbox/test_email.php diff --git a/mod/theme_sandbox/classes/Elgg/ThemeSandbox/Menus/AdminHeader.php b/mod/theme_sandbox/classes/Elgg/ThemeSandbox/Menus/AdminHeader.php new file mode 100644 index 00000000000..08e119405c8 --- /dev/null +++ b/mod/theme_sandbox/classes/Elgg/ThemeSandbox/Menus/AdminHeader.php @@ -0,0 +1,36 @@ +getValue(); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'information:theme_sandbox', + 'text' => elgg_echo('admin:information:theme_sandbox'), + 'href' => elgg_generate_url('default:theme_sandbox'), + 'parent_name' => 'information', + 'target' => '_blank', + ]); + + return $return; + } +} diff --git a/mod/developers/classes/ThemeSandboxObject.php b/mod/theme_sandbox/classes/ThemeSandboxObject.php similarity index 100% rename from mod/developers/classes/ThemeSandboxObject.php rename to mod/theme_sandbox/classes/ThemeSandboxObject.php diff --git a/mod/theme_sandbox/composer.json b/mod/theme_sandbox/composer.json new file mode 100644 index 00000000000..40f3dc9268a --- /dev/null +++ b/mod/theme_sandbox/composer.json @@ -0,0 +1,24 @@ +{ + "name": "elgg/theme_sandbox", + "type": "elgg-plugin", + "description": "Theme sandbox", + "license": "GPL-2.0-only", + "keywords": ["development", "theme"], + "homepage": "https://elgg.org", + "authors": [ + { + "name": "Elgg Core Team", + "role": "Developer" + } + ], + "support": { + "source": "https://github.com/elgg/elgg", + "issues": "https://github.com/elgg/elgg/issues" + }, + "require": { + "composer/installers": "^1.0.8" + }, + "conflict": { + "elgg/elgg": "<5.0" + } +} diff --git a/mod/theme_sandbox/elgg-plugin.php b/mod/theme_sandbox/elgg-plugin.php new file mode 100644 index 00000000000..0f21921b9fc --- /dev/null +++ b/mod/theme_sandbox/elgg-plugin.php @@ -0,0 +1,52 @@ + [ + 'name' => 'Theme Sandbox', + ], + 'actions' => [ + 'theme_sandbox/ajax_demo' => [ + 'access' => 'admin', + ], + 'theme_sandbox/test_email' => [], + ], + 'routes' => [ + 'default:theme_sandbox' => [ + 'path' => '/theme_sandbox/{page?}', + 'resource' => 'theme_sandbox/index', + 'defaults' => [ + 'page' => 'intro', + ], + 'middleware' => [ + \Elgg\Router\Middleware\AdminGatekeeper::class, + ], + ], + 'default:theme_sandbox:ajax_demo' => [ + 'path' => '/theme_sandbox_ajax_demo', + 'resource' => 'theme_sandbox/ajax_demo', + 'middleware' => [ + \Elgg\Router\Middleware\AdminGatekeeper::class, + ], + ], + 'default:theme_sandbox:email' => [ + 'path' => '/theme_sandbox_email', + 'resource' => 'theme_sandbox/email', + 'middleware' => [ + \Elgg\Router\Middleware\AdminGatekeeper::class, + ], + ], + ], + 'events' => [ + 'register' => [ + 'menu:admin_header' => [ + 'Elgg\ThemeSandbox\Menus\AdminHeader::register' => [], + ], + ], + ], + 'view_options' => [ + 'theme_sandbox/demo/ajax' => ['ajax' => true], + 'theme_sandbox/demo/ajax_demo.html' => ['ajax' => true], + 'forms/theme_sandbox/ajax_demo' => ['ajax' => true], + 'theme_sandbox/components/tabs/ajax' => ['ajax' => true], + ], +]; diff --git a/mod/theme_sandbox/languages/en.php b/mod/theme_sandbox/languages/en.php new file mode 100644 index 00000000000..1b5b1763c33 --- /dev/null +++ b/mod/theme_sandbox/languages/en.php @@ -0,0 +1,29 @@ + 'Theme Sandbox', + + 'theme_sandbox:intro' => 'Introduction', + 'theme_sandbox:breakout' => 'Break out of iframe', + 'theme_sandbox:buttons' => 'Buttons', + 'theme_sandbox:components' => 'Components', + 'theme_sandbox:email' => 'Email', + 'theme_sandbox:forms' => 'Forms', + 'theme_sandbox:grid' => 'Grid', + 'theme_sandbox:icons' => 'Icons', + 'theme_sandbox:javascript' => 'JavaScript', + 'theme_sandbox:layouts' => 'Layouts', + 'theme_sandbox:modules' => 'Modules', + 'theme_sandbox:navigation' => 'Navigation', + 'theme_sandbox:typography' => 'Typography', + + 'theme_sandbox:icons:blurb' => 'Use elgg_view_icon($name) to display icons.', + + 'theme_sandbox:test_email:button' => "Send Test Mail", + 'theme_sandbox:test_email:success' => "Test mail sent to: %s", +); diff --git a/mod/developers/views/default/forms/developers/ajax_demo.php b/mod/theme_sandbox/views/default/forms/theme_sandbox/ajax_demo.php similarity index 67% rename from mod/developers/views/default/forms/developers/ajax_demo.php rename to mod/theme_sandbox/views/default/forms/theme_sandbox/ajax_demo.php index 8cc1975ae12..42ac1ccc592 100644 --- a/mod/developers/views/default/forms/developers/ajax_demo.php +++ b/mod/theme_sandbox/views/default/forms/theme_sandbox/ajax_demo.php @@ -1,6 +1,6 @@ title = 'Test Object'; diff --git a/mod/developers/views/default/theme_sandbox/components/image_block.php b/mod/theme_sandbox/views/default/theme_sandbox/components/image_block.php similarity index 85% rename from mod/developers/views/default/theme_sandbox/components/image_block.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/image_block.php index f6715d6ada5..96d0551ff2c 100644 --- a/mod/developers/views/default/theme_sandbox/components/image_block.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/components/image_block.php @@ -1,5 +1,5 @@ title = 'Object 1'; diff --git a/mod/developers/views/default/theme_sandbox/components/messages.php b/mod/theme_sandbox/views/default/theme_sandbox/components/messages.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/components/messages.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/messages.php diff --git a/mod/developers/views/default/theme_sandbox/components/summary_listing.php b/mod/theme_sandbox/views/default/theme_sandbox/components/summary_listing.php similarity index 90% rename from mod/developers/views/default/theme_sandbox/components/summary_listing.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/summary_listing.php index 46b7942ed95..ffcc79447c0 100644 --- a/mod/developers/views/default/theme_sandbox/components/summary_listing.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/components/summary_listing.php @@ -1,6 +1,6 @@ title = 'Test Object'; diff --git a/mod/developers/views/default/theme_sandbox/components/table.php b/mod/theme_sandbox/views/default/theme_sandbox/components/table.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/components/table.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/table.php diff --git a/mod/developers/views/default/theme_sandbox/components/tabs.php b/mod/theme_sandbox/views/default/theme_sandbox/components/tabs.php similarity index 97% rename from mod/developers/views/default/theme_sandbox/components/tabs.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/tabs.php index 181a078c199..c40a49df766 100644 --- a/mod/developers/views/default/theme_sandbox/components/tabs.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/components/tabs.php @@ -4,7 +4,7 @@ 'tabs' => [ 'inline' => [ 'text' => 'Inline Content', - 'content' => elgg_view('developers/ipsum'), + 'content' => elgg_view('theme_sandbox/demo/ipsum'), ], 'ajax' => [ 'text' => 'Ajax [selected]', diff --git a/mod/developers/views/default/theme_sandbox/components/tabs/ajax.php b/mod/theme_sandbox/views/default/theme_sandbox/components/tabs/ajax.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/components/tabs/ajax.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/tabs/ajax.php diff --git a/mod/developers/views/default/theme_sandbox/components/tags.php b/mod/theme_sandbox/views/default/theme_sandbox/components/tags.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/components/tags.php rename to mod/theme_sandbox/views/default/theme_sandbox/components/tags.php diff --git a/mod/developers/views/default/developers/ajax.php b/mod/theme_sandbox/views/default/theme_sandbox/demo/ajax.php similarity index 90% rename from mod/developers/views/default/developers/ajax.php rename to mod/theme_sandbox/views/default/theme_sandbox/demo/ajax.php index deb3f8024b9..76b48d287c2 100644 --- a/mod/developers/views/default/developers/ajax.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/demo/ajax.php @@ -3,7 +3,7 @@ * A view to load through ajax for the lightbox demo */ -$ipsum = elgg_view('developers/ipsum'); +$ipsum = elgg_view('theme_sandbox/demo/ipsum'); $resize_button = elgg_view('input/button', [ 'id' => 'elgg-lightbox-test-resize', diff --git a/mod/developers/views/default/developers/ajax_demo.html.php b/mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.html.php similarity index 100% rename from mod/developers/views/default/developers/ajax_demo.html.php rename to mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.html.php diff --git a/mod/developers/views/default/developers/ajax_demo.js b/mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.js similarity index 85% rename from mod/developers/views/default/developers/ajax_demo.js rename to mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.js index 519ba546473..f1a54f6c348 100644 --- a/mod/developers/views/default/developers/ajax_demo.js +++ b/mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.js @@ -6,7 +6,7 @@ define(['elgg/hooks', 'elgg/Ajax'], function(hooks, Ajax) { // alter request data for the action hooks.register( Ajax.REQUEST_DATA_HOOK, - 'action:developers/ajax_demo', + 'action:theme_sandbox/demo/ajax_demo', function (name, type, params, value) { // alter the data object sent to server value.client_request_altered = 1; @@ -21,7 +21,7 @@ define(['elgg/hooks', 'elgg/Ajax'], function(hooks, Ajax) { // alter request data response for the action hooks.register( Ajax.RESPONSE_DATA_HOOK, - 'action:developers/ajax_demo', + 'action:theme_sandbox/demo/ajax_demo', function (name, type, params, data) { // check the data wrapper for our expected metadata if (data.server_response_altered) { @@ -37,12 +37,12 @@ define(['elgg/hooks', 'elgg/Ajax'], function(hooks, Ajax) { // we make 4 successive ajax calls, here chained together by Promises - ajax.path('developers_ajax_demo') + ajax.path('theme_sandbox_ajax_demo') .then(function (html_page) { if (html_page.indexOf('path demo') != -1) { log("PASS path()"); - return ajax.view('developers/ajax_demo.html', { + return ajax.view('theme_sandbox/demo/ajax_demo.html', { data: {guid: 1} }); } @@ -51,7 +51,7 @@ define(['elgg/hooks', 'elgg/Ajax'], function(hooks, Ajax) { if (div.indexOf('view demo') != -1) { log("PASS view()"); - return ajax.form('developers/ajax_demo', { + return ajax.form('theme_sandbox/demo/ajax_demo', { data: {guid: 1} }); } @@ -60,7 +60,7 @@ define(['elgg/hooks', 'elgg/Ajax'], function(hooks, Ajax) { if (form.indexOf('form demo') != -1) { log("PASS form()"); - return ajax.action('developers/ajax_demo', { + return ajax.action('theme_sandbox/demo/ajax_demo', { data: {arg1: 2, arg2: 3}, success: function (obj) { // we should not get two sets of system messages diff --git a/mod/developers/views/default/developers/ipsum.php b/mod/theme_sandbox/views/default/theme_sandbox/demo/ipsum.php similarity index 100% rename from mod/developers/views/default/developers/ipsum.php rename to mod/theme_sandbox/views/default/theme_sandbox/demo/ipsum.php diff --git a/mod/developers/views/default/theme_sandbox/email.php b/mod/theme_sandbox/views/default/theme_sandbox/email.php similarity index 70% rename from mod/developers/views/default/theme_sandbox/email.php rename to mod/theme_sandbox/views/default/theme_sandbox/email.php index 7102deb6ab1..85fb5cb2837 100644 --- a/mod/developers/views/default/theme_sandbox/email.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/email.php @@ -5,13 +5,13 @@ elgg_register_menu_item('title', [ 'name' => 'mail', - 'href' => elgg_generate_action_url('developers/test_email'), + 'href' => elgg_generate_action_url('theme_sandbox/test_email'), 'text' => elgg_echo('theme_sandbox:test_email:button'), 'icon' => 'mail', 'link_class' => 'elgg-button elgg-button-action', ]); echo elgg_view('output/iframe', [ - 'src' => elgg_generate_url('default:developers:email'), + 'src' => elgg_generate_url('default:theme_sandbox:email'), 'style' => 'width: 100%; height: 800px', ]); diff --git a/mod/developers/views/default/theme_sandbox/forms.php b/mod/theme_sandbox/views/default/theme_sandbox/forms.php similarity index 99% rename from mod/developers/views/default/theme_sandbox/forms.php rename to mod/theme_sandbox/views/default/theme_sandbox/forms.php index 3b056be9f6f..3c1eb1845c7 100644 --- a/mod/developers/views/default/theme_sandbox/forms.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/forms.php @@ -1,5 +1,5 @@
diff --git a/mod/developers/views/default/theme_sandbox/grid.php b/mod/theme_sandbox/views/default/theme_sandbox/grid.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/grid.php rename to mod/theme_sandbox/views/default/theme_sandbox/grid.php diff --git a/mod/developers/views/default/theme_sandbox/icons.php b/mod/theme_sandbox/views/default/theme_sandbox/icons.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/icons.php rename to mod/theme_sandbox/views/default/theme_sandbox/icons.php diff --git a/mod/developers/views/default/theme_sandbox/icons/avatars.php b/mod/theme_sandbox/views/default/theme_sandbox/icons/avatars.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/icons/avatars.php rename to mod/theme_sandbox/views/default/theme_sandbox/icons/avatars.php diff --git a/mod/developers/views/default/theme_sandbox/icons/loader.php b/mod/theme_sandbox/views/default/theme_sandbox/icons/loader.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/icons/loader.php rename to mod/theme_sandbox/views/default/theme_sandbox/icons/loader.php diff --git a/mod/developers/views/default/theme_sandbox/icons/sprites.php b/mod/theme_sandbox/views/default/theme_sandbox/icons/sprites.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/icons/sprites.php rename to mod/theme_sandbox/views/default/theme_sandbox/icons/sprites.php diff --git a/mod/developers/views/default/theme_sandbox/intro.php b/mod/theme_sandbox/views/default/theme_sandbox/intro.php similarity index 83% rename from mod/developers/views/default/theme_sandbox/intro.php rename to mod/theme_sandbox/views/default/theme_sandbox/intro.php index ef58281bc1a..b655d98ddc8 100644 --- a/mod/developers/views/default/theme_sandbox/intro.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/intro.php @@ -16,11 +16,10 @@ if ($simple_cache || $system_cache) { $advanced = elgg_view_url('admin/site_settings', 'Advanced Settings'); - $developers = elgg_view_url('admin/developers/settings', 'Developers\' Plugin Settings'); $body = "Caches are enabled. Changes you make to CSS and views might not appear. It is always recommended to disable caches while developing themes and plugins. To - disable caches, visit the $advanced or $developers pages."; + disable caches visit the {$advanced} pages."; echo elgg_view_message('warning', $body); } diff --git a/mod/developers/views/default/theme_sandbox/javascript.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/javascript.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript.php diff --git a/mod/developers/views/default/theme_sandbox/javascript/lightbox.js b/mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.js similarity index 100% rename from mod/developers/views/default/theme_sandbox/javascript/lightbox.js rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.js diff --git a/mod/developers/views/default/theme_sandbox/javascript/lightbox.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.php similarity index 93% rename from mod/developers/views/default/theme_sandbox/javascript/lightbox.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.php index fccaf5e2e66..3275bb17122 100644 --- a/mod/developers/views/default/theme_sandbox/javascript/lightbox.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.php @@ -2,7 +2,7 @@ echo elgg_view('output/url', [ 'text' => 'Open lightbox', - 'href' => 'ajax/view/developers/ajax', + 'href' => 'ajax/view/theme_sandbox/demo/ajax', 'class' => 'elgg-lightbox' ]); @@ -27,7 +27,7 @@ ?> 'Popup content', diff --git a/mod/developers/views/default/theme_sandbox/javascript/spinner.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript/spinner.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/javascript/spinner.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/spinner.php diff --git a/mod/developers/views/default/theme_sandbox/javascript/system_messages.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript/system_messages.php similarity index 92% rename from mod/developers/views/default/theme_sandbox/javascript/system_messages.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/system_messages.php index fb762313466..82566e21870 100644 --- a/mod/developers/views/default/theme_sandbox/javascript/system_messages.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/javascript/system_messages.php @@ -12,14 +12,14 @@ 'text' => 'Show system message (elgg_register_success_message())', 'is_trusted' => true, 'href' => '#', - 'id' => 'developers-system-message', + 'id' => 'theme-sandbox-system-message', ]); $error = elgg_view('output/url', [ 'text' => 'Show error message (elgg_register_error_message())', 'is_trusted' => true, 'href' => '#', - 'id' => 'developers-error-message', + 'id' => 'theme-sandbox-error-message', ]); ?> diff --git a/mod/developers/views/default/theme_sandbox/javascript/toggle.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript/toggle.php similarity index 85% rename from mod/developers/views/default/theme_sandbox/javascript/toggle.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/toggle.php index 8303d94adb4..5c5b8377901 100644 --- a/mod/developers/views/default/theme_sandbox/javascript/toggle.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/javascript/toggle.php @@ -1,6 +1,6 @@ 'Toggle content', diff --git a/mod/developers/views/default/theme_sandbox/javascript/user_hover_menu.php b/mod/theme_sandbox/views/default/theme_sandbox/javascript/user_hover_menu.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/javascript/user_hover_menu.php rename to mod/theme_sandbox/views/default/theme_sandbox/javascript/user_hover_menu.php diff --git a/mod/developers/views/default/theme_sandbox/layouts.php b/mod/theme_sandbox/views/default/theme_sandbox/layouts.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/layouts.php rename to mod/theme_sandbox/views/default/theme_sandbox/layouts.php diff --git a/mod/developers/views/default/theme_sandbox/layouts/one_column.php b/mod/theme_sandbox/views/default/theme_sandbox/layouts/one_column.php similarity index 91% rename from mod/developers/views/default/theme_sandbox/layouts/one_column.php rename to mod/theme_sandbox/views/default/theme_sandbox/layouts/one_column.php index 019840b20d4..de30a9bfa40 100644 --- a/mod/developers/views/default/theme_sandbox/layouts/one_column.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/layouts/one_column.php @@ -1,6 +1,6 @@
diff --git a/mod/developers/views/default/theme_sandbox/modules/widgets.php b/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php similarity index 97% rename from mod/developers/views/default/theme_sandbox/modules/widgets.php rename to mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php index 5146a31ceb5..b2ebcfee57d 100644 --- a/mod/developers/views/default/theme_sandbox/modules/widgets.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php @@ -13,7 +13,7 @@ * @return string */ function css_widget_content() { - return elgg_view('developers/ipsum'); + return elgg_view('theme_sandbox/demo/ipsum'); } /** diff --git a/mod/developers/views/default/theme_sandbox/navigation.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/anchors.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/anchors.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/anchors.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/anchors.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/breadcrumbs.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/breadcrumbs.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/breadcrumbs.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/breadcrumbs.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/default.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/default.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/default.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/default.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/dropdown.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/dropdown.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/dropdown.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/dropdown.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/entity.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/entity.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/entity.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/entity.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/filter.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/filter.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/filter.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/filter.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/footer.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/footer.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/footer.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/footer.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/horizontal.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/horizontal.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/horizontal.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/horizontal.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/owner_block.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/owner_block.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/owner_block.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/owner_block.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/page.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/page.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/page.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/page.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/pagination.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/pagination.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/pagination.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/pagination.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/require.js b/mod/theme_sandbox/views/default/theme_sandbox/navigation/require.js similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/require.js rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/require.js diff --git a/mod/developers/views/default/theme_sandbox/navigation/require.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/require.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/require.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/require.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/site.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/site.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/site.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/site.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/tabs.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/tabs.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/tabs.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/tabs.php diff --git a/mod/developers/views/default/theme_sandbox/navigation/toggle.php b/mod/theme_sandbox/views/default/theme_sandbox/navigation/toggle.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/navigation/toggle.php rename to mod/theme_sandbox/views/default/theme_sandbox/navigation/toggle.php diff --git a/mod/developers/views/default/elgg/dev/theme_sandbox.js b/mod/theme_sandbox/views/default/theme_sandbox/theme_sandbox.js similarity index 77% rename from mod/developers/views/default/elgg/dev/theme_sandbox.js rename to mod/theme_sandbox/views/default/theme_sandbox/theme_sandbox.js index 7b8bc387832..e423615fa84 100644 --- a/mod/developers/views/default/elgg/dev/theme_sandbox.js +++ b/mod/theme_sandbox/views/default/theme_sandbox/theme_sandbox.js @@ -5,11 +5,11 @@ define(['jquery', 'elgg/spinner', 'elgg/system_messages'], function ($, spinner, return false; }); - $('#developers-system-message').click(function() { + $('#theme-sandbox-system-message').click(function() { system_messages.success('Elgg System Message'); }); - $('#developers-error-message').click(function() { + $('#theme-sandbox-error-message').click(function() { system_messages.error('Elgg Error Message'); }); }); diff --git a/mod/developers/views/default/theme_sandbox/typography.php b/mod/theme_sandbox/views/default/theme_sandbox/typography.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/typography.php rename to mod/theme_sandbox/views/default/theme_sandbox/typography.php diff --git a/mod/developers/views/default/theme_sandbox/typography/fonts.php b/mod/theme_sandbox/views/default/theme_sandbox/typography/fonts.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/typography/fonts.php rename to mod/theme_sandbox/views/default/theme_sandbox/typography/fonts.php diff --git a/mod/developers/views/default/theme_sandbox/typography/headings.php b/mod/theme_sandbox/views/default/theme_sandbox/typography/headings.php similarity index 100% rename from mod/developers/views/default/theme_sandbox/typography/headings.php rename to mod/theme_sandbox/views/default/theme_sandbox/typography/headings.php diff --git a/mod/developers/views/default/theme_sandbox/typography/misc.php b/mod/theme_sandbox/views/default/theme_sandbox/typography/misc.php similarity index 91% rename from mod/developers/views/default/theme_sandbox/typography/misc.php rename to mod/theme_sandbox/views/default/theme_sandbox/typography/misc.php index 159878a3d7a..00bb5f122a7 100644 --- a/mod/developers/views/default/theme_sandbox/typography/misc.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/typography/misc.php @@ -9,7 +9,7 @@
  • I am the i tag example
  • I am the strong tag example
  • -

    Paragraph inside Blockquote:

    +

    Paragraph inside Blockquote:

     	Preformated:Testing one row
     	and another
    diff --git a/mod/developers/views/default/theme_sandbox/typography/paragraph.php b/mod/theme_sandbox/views/default/theme_sandbox/typography/paragraph.php
    similarity index 100%
    rename from mod/developers/views/default/theme_sandbox/typography/paragraph.php
    rename to mod/theme_sandbox/views/default/theme_sandbox/typography/paragraph.php
    
    From 6f24dd4df4c6fde077f46facb561fe43b4000851 Mon Sep 17 00:00:00 2001
    From: Jeroen Dalsem 
    Date: Mon, 19 Jun 2023 14:21:34 +0200
    Subject: [PATCH 006/240] chore(css): use css :target to highlight linked
     comments
    
    ---
     views/default/elements/components/comments.css | 1 +
     views/default/elgg.js.php                      | 4 ----
     2 files changed, 1 insertion(+), 4 deletions(-)
    
    diff --git a/views/default/elements/components/comments.css b/views/default/elements/components/comments.css
    index 372c021907e..0a1600f86fb 100644
    --- a/views/default/elements/components/comments.css
    +++ b/views/default/elements/components/comments.css
    @@ -45,6 +45,7 @@
     		margin-top: -1px;
     		padding: 0;
     		
    +		&:target,
     		&.elgg-state-highlight {
     			> .elgg-listing-full > .elgg-listing-full-header {
     				animation: comment-highlight 5s;
    diff --git a/views/default/elgg.js.php b/views/default/elgg.js.php
    index a675d9702f0..ec7668ff572 100644
    --- a/views/default/elgg.js.php
    +++ b/views/default/elgg.js.php
    @@ -26,10 +26,6 @@
     	// iOS Hover Event Class Fix
     	$('.elgg-page').attr('onclick', 'return true');
     	
    -	// Allow element to be highlighted using CSS if its id is found from the URL
    -	var elementId = elgg.getSelectorFromUrlFragment(document.URL);
    -	$(elementId).addClass('elgg-state-highlight');
    -	
     	/**
     	 * Calls a confirm() and returns false if denied.
     	 *
    
    From 99dc007a20460dfe8d96a19b93d85e450aae9973 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Thu, 22 Jun 2023 08:08:38 +0200
    Subject: [PATCH 007/240] chore(webservices): correctly document api
     registration option
    
    ---
     .../classes/Elgg/WebServices/ApiMethod.php    | 26 +++++++++----------
     1 file changed, 13 insertions(+), 13 deletions(-)
    
    diff --git a/mod/web_services/classes/Elgg/WebServices/ApiMethod.php b/mod/web_services/classes/Elgg/WebServices/ApiMethod.php
    index ab93e7c6620..41385641cac 100644
    --- a/mod/web_services/classes/Elgg/WebServices/ApiMethod.php
    +++ b/mod/web_services/classes/Elgg/WebServices/ApiMethod.php
    @@ -154,19 +154,19 @@ public function __isset($name): bool {
     	 * 	(string) callback: Callback function when the API method is called
     	 *
     	 * Optional options are:
    -	 * 	(bool)   associative:       Will the input params be provided as an array to the callback (default: false)
    -	 * 	(string) call_method:       The HTTP call method (GET|POST) (default: GET)
    -	 * 	(string) description:       The description of the API method
    -	 * 	(array)  params:            The input parameters for the API call. In the format:
    -	 *                              [
    -	 *                                 'variable' = [
    -	 *                                    'type' => 'int' | 'bool' | 'float' | 'string' | 'array',
    -	 *                                    'required' => true (default) | false,
    -	 *                                    'default' => value (optional),
    -	 *                                 ],
    -	 *                              ]
    -	 * 	(bool)   require_api_auth:  Does the API require API authentication (default: false)
    -	 * 	(bool)   require_user_auth: Does the API require user authentication (default: false)
    +	 *  (string) call_method:        The HTTP call method (GET|POST) (default: GET)
    +	 *  (string) description:        The description of the API method
    +	 *  (array)  params:             The input parameters for the API call. In the format:
    +	 *                               [
    +	 *                                  'variable' = [
    +	 *                                     'type' => 'int' | 'bool' | 'float' | 'string' | 'array',
    +	 *                                     'required' => true (default) | false,
    +	 *                                     'default' => value (optional),
    +	 *                                  ],
    +	 *                               ]
    +	 *  (bool)   require_api_auth:   Does the API require API authentication (default: false)
    +	 *  (bool)   require_user_auth:  Does the API require user authentication (default: false)
    +	 *  (bool)   supply_associative: Will the input params be provided as an array to the callback (default: false)
     	 *
     	 * @param array $options Option array of key value pairs
     	 *
    
    From ad8bd918edad2c312a4f6bbac042119b446cdc12 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Tue, 27 Jun 2023 14:00:58 +0200
    Subject: [PATCH 008/240] perf(site_notifications): simplify site_notification
     removal query
    
    ---
     .../classes/Elgg/SiteNotifications/Cron.php                  | 5 ++++-
     1 file changed, 4 insertions(+), 1 deletion(-)
    
    diff --git a/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php b/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php
    index 98870177dda..e6391a439b0 100644
    --- a/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php
    +++ b/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php
    @@ -43,17 +43,20 @@ public static function cleanupSiteNotificationsWithRemovedLinkedEntities(\Elgg\E
     			$batch = elgg_get_entities([
     				'type' => 'object',
     				'subtype' => 'site_notification',
    +				'distinct' => false,
     				'limit' => false,
     				'wheres' => [
     					function (QueryBuilder $qb, $main_alias) {
     						$md = $qb->joinMetadataTable($main_alias, 'guid', 'linked_entity_guid', 'inner', 'lmd');
     						
     						$sub = $qb->subquery('entities');
    -						$sub->select('guid');
    +						$sub->select('guid')
    +							->where($qb->compare('subtype', '!=', 'site_notification', ELGG_VALUE_STRING));
     						
     						return $qb->compare("{$md}.value", 'not in', $sub->getSQL());
     					},
     				],
    +				'order_by' => false,
     				'batch' => true,
     				'batch_inc_offset' => false,
     				'batch_size' => 100,
    
    From 585903bb94ecb97983bd0754e471fb5d3123cab0 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Wed, 28 Jun 2023 11:34:16 +0200
    Subject: [PATCH 009/240] feat(input): the value output view for an userpicker
     can be set
    
    ---
     views/default/input/userpicker.php | 24 +++++++++++++-----------
     1 file changed, 13 insertions(+), 11 deletions(-)
    
    diff --git a/views/default/input/userpicker.php b/views/default/input/userpicker.php
    index 3a46e6e4bee..b34edb836c1 100644
    --- a/views/default/input/userpicker.php
    +++ b/views/default/input/userpicker.php
    @@ -1,17 +1,18 @@
      $entity,
     		'input_name' => $name,
     	]);
    
    From 92dc5d6df4b1afdd5359211711ec9d66a1dcbc7e Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Wed, 28 Jun 2023 13:13:41 +0200
    Subject: [PATCH 010/240] fix(views): correctly handle errors in mention
     parsing
    
    ---
     engine/classes/Elgg/Views/HtmlFormatter.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/engine/classes/Elgg/Views/HtmlFormatter.php b/engine/classes/Elgg/Views/HtmlFormatter.php
    index 4d9195fb78e..89c1dc5ad99 100644
    --- a/engine/classes/Elgg/Views/HtmlFormatter.php
    +++ b/engine/classes/Elgg/Views/HtmlFormatter.php
    @@ -188,7 +188,7 @@ public function parseMentions(string $text): string {
     			return $preceding_char . $replacement . $period;
     		};
     		
    -		return preg_replace_callback(self::MENTION_REGEX, $callback, $text);
    +		return preg_replace_callback(self::MENTION_REGEX, $callback, $text) ?? $text;
     	}
     
     	/**
    
    From 67277b2fe84201b43637cca001be55da5e5faff8 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Wed, 28 Jun 2023 14:02:42 +0200
    Subject: [PATCH 011/240] fix(thewire): improved hashtag matching
    
    ---
     mod/thewire/lib/functions.php | 10 +++++-----
     1 file changed, 5 insertions(+), 5 deletions(-)
    
    diff --git a/mod/thewire/lib/functions.php b/mod/thewire/lib/functions.php
    index c61ebd202a3..60e3f7d6ed8 100644
    --- a/mod/thewire/lib/functions.php
    +++ b/mod/thewire/lib/functions.php
    @@ -85,11 +85,11 @@ function thewire_save_post(string $text, int $userid, int $access_id, int $paren
      */
     function thewire_get_hashtags(string $text): array {
     	// beginning of text or white space followed by hashtag
    -	// hashtag must begin with # and contain at least one character not digit, space, or punctuation
    +	// the hashtag must begin with # and contain at least one character not digit, space, or punctuation
     	$matches = [];
    -	preg_match_all('/(^|[^\w])#(\w*[^\s\d!-\/:-@]+\w*)/', $text, $matches);
    +	preg_match_all('/(^|[^\w])#(\w+[^\s\d[:punct:]\x{2018}-\x{201F}]+\w*)/u', $text, $matches);
     	
    -	return $matches[2];
    +	return $matches[2] ?? [];
     }
     
     /**
    @@ -113,7 +113,7 @@ function thewire_filter(string $text): string {
     
     	// hashtags
     	$text = preg_replace_callback(
    -		'/(^|[^\w])#(\w*[^\s\d!-\/:-@]+\w*)/',
    +		'/(^|[^\w])#(\w+[^\s\d[:punct:]\x{2018}-\x{201F}]+\w*)/u',
     		function ($matches) {
     			$tag = elgg_extract(2, $matches);
     			$url = elgg_generate_url('collection:object:thewire:tag', [
    @@ -123,7 +123,7 @@ function ($matches) {
     			
     			return elgg_extract(1, $matches) . $link;
     		},
    -		$text);
    +		$text) ?? $text;
     
     	return trim($text);
     }
    
    From 72856546ba14139efa355398514e751b08c5c97b Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Wed, 28 Jun 2023 14:32:18 +0200
    Subject: [PATCH 012/240] fix(user): return correct type for getOwnerGuid
    
    ---
     engine/classes/ElggUser.php | 9 +++++----
     1 file changed, 5 insertions(+), 4 deletions(-)
    
    diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php
    index 554633cec1d..6fd4d3a34e3 100644
    --- a/engine/classes/ElggUser.php
    +++ b/engine/classes/ElggUser.php
    @@ -351,16 +351,17 @@ public function getObjects(array $options = []) {
     	/**
     	 * Get a user's owner GUID
     	 *
    -	 * Returns it's own GUID if the user is not owned.
    +	 * Returns its own GUID if the user is not owned.
     	 *
     	 * @return int
     	 */
     	public function getOwnerGUID(): int {
    -		if ($this->owner_guid == 0) {
    -			return $this->guid;
    +		$owner_guid = parent::getOwnerGUID();
    +		if ($owner_guid === 0) {
    +			$owner_guid = (int) $this->guid;
     		}
     
    -		return $this->owner_guid;
    +		return $owner_guid;
     	}
     
     	/**
    
    From 5d22944073b5cbdeb967e65d0e9b0332443fcdfb Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Mon, 3 Jul 2023 09:34:21 +0200
    Subject: [PATCH 013/240] chore(release): v5.0.2
    
    ---
     CHANGELOG.md  | 19 +++++++++++++++++++
     composer.json |  2 +-
     composer.lock | 29 +++++++++++++++++------------
     3 files changed, 37 insertions(+), 13 deletions(-)
    
    diff --git a/CHANGELOG.md b/CHANGELOG.md
    index bd75be537ec..14008e779fc 100644
    --- a/CHANGELOG.md
    +++ b/CHANGELOG.md
    @@ -1,3 +1,22 @@
    +
    +### 5.0.2  (2023-07-03)
    +
    +#### Contributors
    +
    +* Jerôme Bakker (5)
    +
    +#### Performance
    +
    +* **site_notifications:** simplify site_notification removal query ([ad8bd918](https://github.com/Elgg/Elgg/commit/ad8bd918edad2c312a4f6bbac042119b446cdc12))
    +
    +
    +#### Bug Fixes
    +
    +* **thewire:** improved hashtag matching ([67277b2f](https://github.com/Elgg/Elgg/commit/67277b2fe84201b43637cca001be55da5e5faff8))
    +* **user:** return correct type for getOwnerGuid ([72856546](https://github.com/Elgg/Elgg/commit/72856546ba14139efa355398514e751b08c5c97b))
    +* **views:** correctly handle errors in mention parsing ([92dc5d6d](https://github.com/Elgg/Elgg/commit/92dc5d6df4b1afdd5359211711ec9d66a1dcbc7e))
    +
    +
     
     ### 5.0.1  (2023-06-19)
     
    diff --git a/composer.json b/composer.json
    index 0c550cd8656..228fd0434ff 100644
    --- a/composer.json
    +++ b/composer.json
    @@ -1,6 +1,6 @@
     {
         "name": "elgg/elgg",
    -    "version": "5.0.1",
    +    "version": "5.0.2",
         "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.",
         "license": "GPL-2.0-only",
         "minimum-stability": "dev",
    diff --git a/composer.lock b/composer.lock
    index d96a4c42269..92b7a4b1652 100644
    --- a/composer.lock
    +++ b/composer.lock
    @@ -4,7 +4,7 @@
             "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
             "This file is @generated automatically"
         ],
    -    "content-hash": "9304615bfa30ab7f0cbf8e8a1567377a",
    +    "content-hash": "322b39d6f08ec2afc45d6066207de9c9",
         "packages": [
             {
                 "name": "cakephp/core",
    @@ -3645,7 +3645,7 @@
                 },
                 "conflict": {
                     "3f/pygmentize": "<1.2",
    -                "admidio/admidio": "<4.2.8",
    +                "admidio/admidio": "<4.2.9",
                     "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3",
                     "aheinze/cockpit": "<=2.2.1",
                     "akaunting/akaunting": "<2.1.13",
    @@ -3658,7 +3658,7 @@
                     "amphp/http-client": ">=4,<4.4",
                     "anchorcms/anchor-cms": "<=0.12.7",
                     "andreapollastri/cipi": "<=3.1.15",
    -                "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<=1.0.1|>=2,<=2.2.4",
    +                "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5",
                     "apereo/phpcas": "<1.6",
                     "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3",
                     "appwrite/server-ce": "<=1.2.1",
    @@ -3678,8 +3678,8 @@
                     "barzahlen/barzahlen-php": "<2.0.1",
                     "baserproject/basercms": "<4.7.5",
                     "bassjobsen/bootstrap-3-typeahead": ">4.0.2",
    -                "bigfork/silverstripe-form-capture": ">=3,<=3.1",
    -                "billz/raspap-webgui": "<=2.6.6",
    +                "bigfork/silverstripe-form-capture": ">=3,<3.1.1",
    +                "billz/raspap-webgui": "<2.8.9",
                     "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3",
                     "bmarshall511/wordpress_zero_spam": "<5.2.13",
                     "bolt/bolt": "<3.7.2",
    @@ -3716,7 +3716,7 @@
                     "contao/core-bundle": "<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4|= 4.10.0",
                     "contao/listing-bundle": ">=4,<4.4.8",
                     "contao/managed-edition": "<=1.5",
    -                "craftcms/cms": "<4.4.6|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1",
    +                "craftcms/cms": "<=4.4.9|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1",
                     "croogo/croogo": "<3.0.7",
                     "cuyz/valinor": "<0.12",
                     "czproject/git-php": "<4.0.3",
    @@ -3798,7 +3798,7 @@
                     "froala/wysiwyg-editor": "<3.2.7",
                     "froxlor/froxlor": "<2.1",
                     "fuel/core": "<1.8.1",
    -                "funadmin/funadmin": "<=3.2",
    +                "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3",
                     "gaoming13/wechat-php-sdk": "<=1.10.2",
                     "genix/cms": "<=1.1.11",
                     "getgrav/grav": "<1.7.42",
    @@ -3816,6 +3816,7 @@
                     "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5",
                     "harvesthq/chosen": "<1.8.7",
                     "helloxz/imgurl": "= 2.31|<=2.31",
    +                "hhxsv5/laravel-s": "<3.7.36",
                     "hillelcoren/invoice-ninja": "<5.3.35",
                     "himiklab/yii2-jqgrid-widget": "<1.0.8",
                     "hjue/justwriting": "<=1",
    @@ -3856,6 +3857,7 @@
                     "kazist/phpwhois": "<=4.2.6",
                     "kelvinmo/simplexrd": "<3.1.1",
                     "kevinpapst/kimai2": "<1.16.7",
    +                "khodakhah/nodcms": "<=3",
                     "kimai/kimai": "<1.1",
                     "kitodo/presentation": "<3.1.2",
                     "klaviyo/magento2-extension": ">=1,<3",
    @@ -3892,7 +3894,7 @@
                     "marcwillmann/turn": "<0.3.3",
                     "matyhtf/framework": "<3.0.6",
                     "mautic/core": "<4.3|= 2.13.1",
    -                "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35",
    +                "mediawiki/core": "<=1.39.3",
                     "mediawiki/matomo": "<2.4.3",
                     "melisplatform/melis-asset-manager": "<5.0.1",
                     "melisplatform/melis-cms": "<5.0.1",
    @@ -3906,7 +3908,7 @@
                     "modx/revolution": "<= 2.8.3-pl|<2.8",
                     "mojo42/jirafeau": "<4.4",
                     "monolog/monolog": ">=1.8,<1.12",
    -                "moodle/moodle": "<4.2-rc.2|= 3.11",
    +                "moodle/moodle": "<4.2-rc.2|= 4.2.0|= 3.11",
                     "mustache/mustache": ">=2,<2.14.1",
                     "namshi/jose": "<2.2",
                     "neoan3-apps/template": "<1.1.1",
    @@ -4010,10 +4012,11 @@
                     "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11",
                     "sensiolabs/connect": "<4.2.3",
                     "serluck/phpwhois": "<=4.2.6",
    +                "sheng/yiicms": "<=1.2",
                     "shopware/core": "<=6.4.20",
                     "shopware/platform": "<=6.4.20",
                     "shopware/production": "<=6.3.5.2",
    -                "shopware/shopware": "<=5.7.14",
    +                "shopware/shopware": "<=5.7.17",
                     "shopware/storefront": "<=6.4.8.1",
                     "shopxo/shopxo": "<2.2.6",
                     "showdoc/showdoc": "<2.10.4",
    @@ -4109,7 +4112,7 @@
                     "thelia/thelia": ">=2.1-beta.1,<2.1.3",
                     "theonedemon/phpwhois": "<=4.2.5",
                     "thinkcmf/thinkcmf": "<=5.1.7",
    -                "thorsten/phpmyfaq": "<3.2-beta",
    +                "thorsten/phpmyfaq": "<3.2-beta.2",
                     "tinymce/tinymce": "<5.10.7|>=6,<6.3.1",
                     "tinymighty/wiki-seo": "<1.2.2",
                     "titon/framework": ">=0,<9.9.99",
    @@ -4147,13 +4150,15 @@
                     "web-auth/webauthn-framework": ">=3.3,<3.3.4",
                     "webbuilders-group/silverstripe-kapost-bridge": "<0.4",
                     "webcoast/deferred-image-processing": "<1.0.2",
    +                "webklex/laravel-imap": "<5.3",
    +                "webklex/php-imap": "<5.3",
                     "webpa/webpa": "<3.1.2",
                     "wikimedia/parsoid": "<0.12.2",
                     "willdurand/js-translation-bundle": "<2.1.1",
                     "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1",
                     "woocommerce/woocommerce": "<6.6",
                     "wp-cli/wp-cli": "<2.5",
    -                "wp-graphql/wp-graphql": "<0.3.5",
    +                "wp-graphql/wp-graphql": "<=1.14.5",
                     "wpanel/wpanel4-cms": "<=4.3.1",
                     "wpcloud/wp-stateless": "<3.2",
                     "wwbn/avideo": "<=12.4",
    
    From 8667a251d4faa0539b44273ec62c5e863fffe196 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= 
    Date: Mon, 3 Jul 2023 15:34:51 +0200
    Subject: [PATCH 014/240] chore(seeding): prevent automatic seeding of object
     properties
    
    default values for title, description and tags can be disabled
    ---
     engine/classes/Elgg/Traits/Seeding.php        | 18 ++++-
     .../unit/Elgg/Traits/SeedingUnitTest.php      | 78 +++++++++++++++++++
     2 files changed, 93 insertions(+), 3 deletions(-)
     create mode 100644 engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php
    
    diff --git a/engine/classes/Elgg/Traits/Seeding.php b/engine/classes/Elgg/Traits/Seeding.php
    index 37335ceb9ad..9e1398c50d7 100644
    --- a/engine/classes/Elgg/Traits/Seeding.php
    +++ b/engine/classes/Elgg/Traits/Seeding.php
    @@ -381,6 +381,12 @@ public function createGroup(array $properties = [], array $options = []): \ElggG
     	 * @throws MaxAttemptsException
     	 */
     	public function createObject(array $properties = [], array $options = []): \ElggObject {
    +		$default_properties = [
    +			'title' => true,
    +			'description' => true,
    +			'tags' => true,
    +		];
    +		$properties = array_merge($default_properties, $properties);
     
     		$create = function () use ($properties, $options) {
     			$properties['__faker'] = true;
    @@ -389,20 +395,26 @@ public function createObject(array $properties = [], array $options = []): \Elgg
     				$properties['time_created'] = $this->getRandomCreationTimestamp();
     			}
     
    -			if (empty($properties['title'])) {
    +			if ($properties['title'] === true) {
     				$properties['title'] = $this->faker()->sentence();
    +			} elseif ($properties['title'] === false) {
    +				unset($properties['title']);
     			}
     
    -			if (empty($properties['description'])) {
    +			if ($properties['description'] === true) {
     				$properties['description'] = $this->faker()->text($this->faker()->numberBetween(500, 1000));
    +			} elseif ($properties['description'] === false) {
    +				unset($properties['description']);
     			}
     
     			if (empty($properties['subtype'])) {
     				$properties['subtype'] = $this->getRandomSubtype();
     			}
     
    -			if (empty($properties['tags'])) {
    +			if ($properties['tags'] === true) {
     				$properties['tags'] = $this->faker()->words(10);
    +			} elseif ($properties['tags'] === false) {
    +				unset($properties['tags']);
     			}
     
     			if (!isset($properties['owner_guid'])) {
    diff --git a/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php b/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php
    new file mode 100644
    index 00000000000..2aa6ea62571
    --- /dev/null
    +++ b/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php
    @@ -0,0 +1,78 @@
    +createSeededObject([
    +			'title' => $input,
    +		], ['save' => false]);
    +		$this->assertInstanceOf(\ElggObject::class, $object);
    +		
    +		if ($input === false) {
    +			$this->assertNull($object->title);
    +		} else {
    +			$this->assertIsString($object->title);
    +		}
    +		
    +		if (is_string($input)) {
    +			$this->assertEquals($input, $object->title);
    +		}
    +	}
    +	
    +	/**
    +	 * @dataProvider propertyProvider
    +	 */
    +	public function testCreateObjectDescription($input) {
    +		$object = $this->createSeededObject([
    +			'description' => $input,
    +		], ['save' => false]);
    +		$this->assertInstanceOf(\ElggObject::class, $object);
    +		
    +		if ($input === false) {
    +			$this->assertNull($object->description);
    +		} else {
    +			$this->assertIsString($object->description);
    +		}
    +		
    +		if (is_string($input)) {
    +			$this->assertEquals($input, $object->description);
    +		}
    +	}
    +	
    +	/**
    +	 * @dataProvider propertyProvider
    +	 */
    +	public function testCreateObjectTags($input) {
    +		$object = $this->createSeededObject([
    +			'tags' => $input,
    +		], ['save' => false]);
    +		$this->assertInstanceOf(\ElggObject::class, $object);
    +		
    +		if ($input === false) {
    +			$this->assertNull($object->tags);
    +		} elseif (is_string($input)) {
    +			$this->assertEquals($input, $object->tags);
    +		} else {
    +			$this->assertIsArray($object->tags);
    +		}
    +	}
    +	
    +	public function propertyProvider() {
    +		return [
    +			[true],
    +			[false],
    +			['hello world'],
    +		];
    +	}
    +}
    
    From f306388b51d08aeb2a28154a83793775315423a8 Mon Sep 17 00:00:00 2001
    From: Jeroen Dalsem 
    Date: Wed, 5 Jul 2023 12:37:07 +0200
    Subject: [PATCH 015/240] fix(email): image styles will be converted to
     attributes if possible
    
    This will help with email clients that do not allow or ignore styles.
    ---
     engine/classes/Elgg/Views/HtmlFormatter.php       | 6 ++++--
     mod/ckeditor/elgg-plugin.php                      | 3 +++
     mod/ckeditor/views/default/ckeditor/email_fix.css | 8 ++++++++
     3 files changed, 15 insertions(+), 2 deletions(-)
     create mode 100644 mod/ckeditor/views/default/ckeditor/email_fix.css
    
    diff --git a/engine/classes/Elgg/Views/HtmlFormatter.php b/engine/classes/Elgg/Views/HtmlFormatter.php
    index 4d9195fb78e..8b1d15a181b 100644
    --- a/engine/classes/Elgg/Views/HtmlFormatter.php
    +++ b/engine/classes/Elgg/Views/HtmlFormatter.php
    @@ -8,6 +8,7 @@
     use Elgg\Traits\Loggable;
     use Elgg\ViewsService;
     use Pelago\Emogrifier\CssInliner;
    +use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
     
     /**
      * Various helper method for formatting and sanitizing output
    @@ -424,9 +425,10 @@ public function inlineCss(string $html, string $css, bool $body_only = false): s
     			return $html;
     		}
     		
    -		$inliner = CssInliner::fromHtml($html)->disableStyleBlocksParsing()->inlineCss($css);
    +		$html_with_inlined_css = CssInliner::fromHtml($html)->disableStyleBlocksParsing()->inlineCss($css)->render();
    +		$inlined_attribute_converter = CssToAttributeConverter::fromHtml($html_with_inlined_css)->convertCssToVisualAttributes();
     		
    -		return $body_only ? $inliner->renderBodyContent() : $inliner->render();
    +		return $body_only ? $inlined_attribute_converter->renderBodyContent() : $inlined_attribute_converter->render();
     	}
     	
     	/**
    diff --git a/mod/ckeditor/elgg-plugin.php b/mod/ckeditor/elgg-plugin.php
    index dfd0d752342..146bb92ec9e 100644
    --- a/mod/ckeditor/elgg-plugin.php
    +++ b/mod/ckeditor/elgg-plugin.php
    @@ -17,6 +17,9 @@
     		'elgg.css' => [
     			'ckeditor/content.css' => [],
     		],
    +		'email/email.css' => [
    +			'ckeditor/email_fix.css' => [],
    +		],
     		'input/longtext' => [
     			'ckeditor/init' => [],
     		],
    diff --git a/mod/ckeditor/views/default/ckeditor/email_fix.css b/mod/ckeditor/views/default/ckeditor/email_fix.css
    new file mode 100644
    index 00000000000..00a53e1aa0a
    --- /dev/null
    +++ b/mod/ckeditor/views/default/ckeditor/email_fix.css
    @@ -0,0 +1,8 @@
    +/*
    + * this fix will make sure resized images from editor content have a set width
    + * the core htmlformatter will transform this style to an attribute which will help showing it correctly in some email clients like outlook
    + */
    +
    +figure.image_resized img {
    +	width: 100%;
    +}
    
    From 15e68df9056284cd3f6c4056be30081433a08dfd Mon Sep 17 00:00:00 2001
    From: Jeroen Dalsem 
    Date: Mon, 3 Jul 2023 13:51:22 +0200
    Subject: [PATCH 016/240] feat(widgets): the widget edit form now shows in a
     lightbox
    
    ---
     .../Elgg/Application/SystemEventHandlers.php  |  1 +
     engine/classes/Elgg/Menus/Widget.php          | 13 ++++++--
     views/default/elements/widgets.css            |  8 -----
     views/default/elgg/lightbox.js                |  2 ++
     views/default/elgg/widgets.js                 | 16 ++++-----
     views/default/forms/widgets/save.php          | 12 +++++--
     views/default/object/widget.php               |  8 +----
     views/default/object/widget/edit.php          | 33 +++++++++++++++++++
     .../object/widget/elements/content.php        |  2 +-
     .../object/widget/elements/controls.php       |  1 +
     .../object/widget/elements/settings.php       |  2 ++
     views/default/object/widget/header.php        |  1 +
     12 files changed, 69 insertions(+), 30 deletions(-)
     create mode 100644 views/default/object/widget/edit.php
    
    diff --git a/engine/classes/Elgg/Application/SystemEventHandlers.php b/engine/classes/Elgg/Application/SystemEventHandlers.php
    index fc4d6924fe8..fa984b7e759 100644
    --- a/engine/classes/Elgg/Application/SystemEventHandlers.php
    +++ b/engine/classes/Elgg/Application/SystemEventHandlers.php
    @@ -53,6 +53,7 @@ public static function init() {
     		elgg_register_ajax_view('navigation/menu/user_hover/contents');
     		elgg_register_ajax_view('notifications/subscriptions/details');
     		elgg_register_ajax_view('object/plugin/details');
    +		elgg_register_ajax_view('object/widget/edit');
     		elgg_register_ajax_view('page/elements/comments');
     		elgg_register_ajax_view('river/elements/responses');
     		
    diff --git a/engine/classes/Elgg/Menus/Widget.php b/engine/classes/Elgg/Menus/Widget.php
    index dd4a7b44106..218f987dfd3 100644
    --- a/engine/classes/Elgg/Menus/Widget.php
    +++ b/engine/classes/Elgg/Menus/Widget.php
    @@ -36,8 +36,17 @@ public static function registerEdit(\Elgg\Event $event) {
     			'name' => 'settings',
     			'text' => elgg_view_icon('settings-alt'),
     			'title' => elgg_echo('widget:edit'),
    -			'href' => "#widget-edit-{$widget->guid}",
    -			'link_class' => ['elgg-widget-edit-button', 'elgg-toggle'],
    +			'href' => elgg_http_add_url_query_elements('ajax/view/object/widget/edit', [
    +				'guid' => $widget->guid,
    +				'show_access' => $event->getParam('show_access', true),
    +			]),
    +			'data-colorbox-opts' => json_encode([
    +				'width' => 750,
    +				'max-height' => '80%',
    +				'trapFocus' => false,
    +				'fixed' => true,
    +			]),
    +			'link_class' => ['elgg-widget-edit-button', 'elgg-lightbox'],
     			'priority' => 800,
     		]);
     		
    diff --git a/views/default/elements/widgets.css b/views/default/elements/widgets.css
    index eb10545334a..12dab6e3eab 100644
    --- a/views/default/elements/widgets.css
    +++ b/views/default/elements/widgets.css
    @@ -97,14 +97,6 @@
     	}
     }
     
    -.elgg-widget-edit {
    -	display: none;
    -	width: auto;
    -	padding: 10px;
    -	border-bottom: 1px solid $(border-color-soft);
    -	background-color: $(background-color-mild);
    -}
    -
     .elgg-widget-content {
     	padding: 1rem;
     }
    diff --git a/views/default/elgg/lightbox.js b/views/default/elgg/lightbox.js
    index 2ae0b17111d..485d73af4c8 100644
    --- a/views/default/elgg/lightbox.js
    +++ b/views/default/elgg/lightbox.js
    @@ -149,6 +149,8 @@ define(['jquery', 'elgg', 'elgg/Ajax', 'elgg/hooks', 'jquery.colorbox'], functio
     				
     				// clear data so next fetch will refresh contents
     				currentOpts.html = undefined;
    +			}).fail(function() {
    +				$.colorbox.close();
     			});
     		},
     
    diff --git a/views/default/elgg/widgets.js b/views/default/elgg/widgets.js
    index c3d7e09980e..b0771cd220e 100644
    --- a/views/default/elgg/widgets.js
    +++ b/views/default/elgg/widgets.js
    @@ -1,4 +1,4 @@
    -define(['jquery', 'elgg/Ajax', 'jquery-ui/widgets/sortable'], function ($, Ajax) {
    +define(['jquery', 'elgg/Ajax', 'elgg/lightbox', 'jquery-ui/widgets/sortable'], function ($, Ajax, lightbox) {
     
     	/**
     	 * Persist the widget's new position
    @@ -55,17 +55,15 @@ define(['jquery', 'elgg/Ajax', 'jquery-ui/widgets/sortable'], function ($, Ajax)
     	 */
     	function saveWidgetSettings(event) {
     		event.preventDefault();
    -		
    -		$(this).parent().slideToggle('medium');
    -		var $widgetContent = $(this).parent().parent().children('.elgg-widget-content');
    -
    -		// stick the ajax loader in there
    -		$widgetContent.html('
    '); + + var $widgetContent = $('#elgg-widget-content-' + $(this).find('input[name="guid"]').val()); - var ajax = new Ajax(false); + var ajax = new Ajax(); ajax.action('widgets/save', { - data: $(this).serialize(), + data: ajax.objectify(this), success: function (result) { + lightbox.close(); + $widgetContent.html(result.content); if (result.title !== '') { var $widgetTitle = $widgetContent.parent().parent().find('.elgg-widget-title'); diff --git a/views/default/forms/widgets/save.php b/views/default/forms/widgets/save.php index a5802a3aaa0..7b01a2a134e 100644 --- a/views/default/forms/widgets/save.php +++ b/views/default/forms/widgets/save.php @@ -2,12 +2,18 @@ /** * Elgg widget edit settings * - * @uses $vars['widget'] - * @uses $vars['show_access'] + * @uses $vars['entity'] The widget entity + * @uses $vars['widget'] Deprecated; use 'entity' instead + * @uses $vars['show_access'] (bool) should widget access setting be available default: true */ $widget = elgg_extract('widget', $vars); -if (!$widget instanceof ElggWidget) { +if ($widget !== null) { + elgg_deprecated_notice('Passing the widget entity in $vars["widget"] is deprecated. Update your code to provide it in $vars["entity"].', '5.1'); +} + +$widget = elgg_extract('entity', $vars, $widget); +if (!$widget instanceof \ElggWidget) { return; } diff --git a/views/default/object/widget.php b/views/default/object/widget.php index c3623b6fb03..d2d4e8dccb2 100644 --- a/views/default/object/widget.php +++ b/views/default/object/widget.php @@ -19,13 +19,7 @@ if ($widget->canEdit()) { $widget_class[] = 'elgg-state-draggable'; - $settings = elgg_view('object/widget/elements/settings', [ - 'widget' => $widget, - 'show_access' => elgg_extract('show_access', $vars, true), - ]); - $body .= $settings; - - if (empty($settings)) { + if (!elgg_view_exists("widgets/{$widget->handler}/edit") && elgg_extract('show_access', $vars) === false) { // store for determining the edit menu item $vars['show_edit'] = false; } diff --git a/views/default/object/widget/edit.php b/views/default/object/widget/edit.php new file mode 100644 index 00000000000..c728bdd54b9 --- /dev/null +++ b/views/default/object/widget/edit.php @@ -0,0 +1,33 @@ +canEdit()) { + throw new EntityPermissionsException(); +} + +$form = elgg_view_form('widgets/save', [ + 'class' => [ + preg_replace('/[^a-z0-9-]/i', '-', "elgg-form-widgets-save-{$widget->handler}"), + ], + 'prevent_double_submit' => false, +], $vars); + +if (empty($form)) { + return; +} + +echo elgg_format_element('div', [ + 'class' => 'elgg-widget-edit', + 'id' => "widget-edit-{$widget->guid}", +], $form); diff --git a/views/default/object/widget/elements/content.php b/views/default/object/widget/elements/content.php index 80aba7b0fd6..58de850c640 100644 --- a/views/default/object/widget/elements/content.php +++ b/views/default/object/widget/elements/content.php @@ -6,7 +6,7 @@ } $widget = elgg_extract('entity', $vars); -if (!$widget instanceof ElggWidget) { +if (!$widget instanceof \ElggWidget) { return; } diff --git a/views/default/object/widget/elements/controls.php b/views/default/object/widget/elements/controls.php index 317045a0ae4..052d7d76f48 100644 --- a/views/default/object/widget/elements/controls.php +++ b/views/default/object/widget/elements/controls.php @@ -9,5 +9,6 @@ echo elgg_view_menu('widget', [ 'entity' => elgg_extract('widget', $vars), 'show_edit' => elgg_extract('show_edit', $vars, true), + 'show_access' => elgg_extract('show_access', $vars), 'class' => 'elgg-menu-hz', ]); diff --git a/views/default/object/widget/elements/settings.php b/views/default/object/widget/elements/settings.php index 2b2b3e1c73e..f2b1e48bdf9 100644 --- a/views/default/object/widget/elements/settings.php +++ b/views/default/object/widget/elements/settings.php @@ -5,6 +5,8 @@ * @uses $vars['widget'] */ +elgg_deprecated_notice('This view is no longer used and will be removed in the next major version.', '5.1'); + $widget = elgg_extract('widget', $vars); if (!$widget instanceof ElggWidget) { return; diff --git a/views/default/object/widget/header.php b/views/default/object/widget/header.php index 81ac6e2832d..22368533ed9 100644 --- a/views/default/object/widget/header.php +++ b/views/default/object/widget/header.php @@ -23,4 +23,5 @@ echo elgg_view('object/widget/elements/controls', [ 'widget' => $widget, 'show_edit' => elgg_extract('show_edit', $vars, $widget->canEdit()), + 'show_access' => elgg_extract('show_access', $vars), ]); From de1959ad580b6e4ea49fdd9f7a7560c0b02bea74 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Tue, 4 Jul 2023 10:32:58 +0200 Subject: [PATCH 017/240] feat(admin): reorganized admin and configure utilities menu items --- engine/classes/Elgg/Menus/AdminHeader.php | 109 +++++++++++++----- engine/events.php | 2 + languages/en.php | 6 +- .../Elgg/ExternalPages/Menus/AdminHeader.php | 2 +- .../Elgg/Profile/Menus/AdminHeader.php | 2 +- .../ReportedContent/Menus/AdminHeader.php | 2 +- .../Elgg/SystemLog/Menus/AdminHeader.php | 2 +- 7 files changed, 87 insertions(+), 38 deletions(-) diff --git a/engine/classes/Elgg/Menus/AdminHeader.php b/engine/classes/Elgg/Menus/AdminHeader.php index a5b253dfb44..a54fed3942e 100644 --- a/engine/classes/Elgg/Menus/AdminHeader.php +++ b/engine/classes/Elgg/Menus/AdminHeader.php @@ -107,7 +107,7 @@ public static function registerMaintenance(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminAdminister(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -118,6 +118,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { 'name' => 'administer', 'text' => elgg_echo('menu:page:header:administer'), 'href' => false, + 'priority' => 10, ]); $return[] = \ElggMenuItem::factory([ @@ -151,16 +152,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { 'priority' => 600, 'parent_name' => 'administer', ]); - - $return[] = \ElggMenuItem::factory([ - 'name' => 'administer_utilities', - 'text' => elgg_echo('admin:administer_utilities'), - 'href' => false, - 'priority' => 50, - 'parent_name' => 'administer', - 'show_with_empty_children' => false, - ]); - + return $return; } @@ -172,7 +164,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { * @return PreparedMenu|null */ public static function prepareAdminAdministerUsersChildren(\Elgg\Event $event): ?PreparedMenu { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return null; } @@ -231,7 +223,7 @@ public static function prepareAdminAdministerUsersChildren(\Elgg\Event $event): * @return void|MenuItems */ public static function registerAdminConfigure(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -242,6 +234,7 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'name' => 'configure', 'text' => elgg_echo('menu:page:header:configure'), 'href' => false, + 'priority' => 20, ]); $return[] = \ElggMenuItem::factory([ @@ -268,31 +261,52 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'parent_name' => 'configure', ]); - // Utilities - $return[] = \ElggMenuItem::factory([ - 'name' => 'configure_utilities', - 'text' => elgg_echo('admin:configure_utilities'), - 'href' => false, - 'priority' => 600, - 'parent_name' => 'configure', - ]); $return[] = \ElggMenuItem::factory([ 'name' => 'configure_utilities:maintenance', 'text' => elgg_echo('admin:configure_utilities:maintenance'), 'href' => 'admin/configure_utilities/maintenance', - 'parent_name' => 'configure_utilities', - ]); - $return[] = \ElggMenuItem::factory([ - 'name' => 'configure_utilities:menu_items', - 'text' => elgg_echo('admin:configure_utilities:menu_items'), - 'href' => 'admin/configure_utilities/menu_items', - 'parent_name' => 'configure_utilities', + 'priority' => 40, + 'parent_name' => 'configure', ]); + $return[] = \ElggMenuItem::factory([ 'name' => 'configure_utilities:robots', 'text' => elgg_echo('admin:configure_utilities:robots'), 'href' => 'admin/configure_utilities/robots', - 'parent_name' => 'configure_utilities', + 'priority' => 50, + 'parent_name' => 'configure', + ]); + + return $return; + } + + /** + * Add the utilities section to the admin page menu + * + * @param \Elgg\Event $event 'register', 'menu:admin_header' + * + * @return void|MenuItems + */ + public static function registerAdminUtilities(\Elgg\Event $event) { + if (!elgg_is_admin_logged_in()) { + return; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'utilities', + 'text' => elgg_echo('menu:page:header:utilities'), + 'href' => false, + 'priority' => 30, + ]); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'configure_utilities:menu_items', + 'text' => elgg_echo('admin:configure_utilities:menu_items'), + 'href' => 'admin/configure_utilities/menu_items', + 'parent_name' => 'utilities', ]); return $return; @@ -306,7 +320,7 @@ public static function registerAdminConfigure(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -321,7 +335,7 @@ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { 'name' => 'default_widgets', 'text' => elgg_echo('admin:configure_utilities:default_widgets'), 'href' => 'admin/configure_utilities/default_widgets', - 'parent_name' => 'configure_utilities', + 'parent_name' => 'utilities', ]); return $return; @@ -335,7 +349,7 @@ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminInformation(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -346,6 +360,7 @@ public static function registerAdminInformation(\Elgg\Event $event) { 'name' => 'information', 'text' => elgg_echo('menu:page:header:information'), 'href' => false, + 'priority' => 40, ]); $return[] = \ElggMenuItem::factory([ @@ -390,4 +405,34 @@ public static function registerAdminInformation(\Elgg\Event $event) { return $return; } + + /** + * Moves utility menu items to the new section + * + * @param \Elgg\Event $event 'register', 'menu:admin_header' + * + * @return void|MenuItems + */ + public static function moveUtilities(\Elgg\Event $event) { + if (!elgg_is_admin_logged_in()) { + return; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + /* @var $menu_item \ElggMenuItem */ + foreach ($return as $menu_item) { + if (in_array($menu_item->getParentName(), ['administer_utilities', 'configure_utilities'])) { + $message = 'The menu item ' . $menu_item->getName() . ' is using a deprecated parent.'; + $message .= ' Utilities have been moved to a dedicated top menu item (utilities) in the admin header.'; + + elgg_deprecated_notice($message, '5.1'); + + $menu_item->setParentName('utilities'); + } + } + + return $return; + } } diff --git a/engine/events.php b/engine/events.php index 461332bd896..9b97a78d769 100644 --- a/engine/events.php +++ b/engine/events.php @@ -250,12 +250,14 @@ 'Elgg\Menus\AdminControlPanel::register' => [], ], 'menu:admin_header' => [ + 'Elgg\Menus\AdminHeader::moveUtilities' => ['priority' => 9999], 'Elgg\Menus\AdminHeader::register' => [], 'Elgg\Menus\AdminHeader::registerMaintenance' => [], 'Elgg\Menus\AdminHeader::registerAdminAdminister' => [], 'Elgg\Menus\AdminHeader::registerAdminConfigure' => [], 'Elgg\Menus\AdminHeader::registerAdminDefaultWidgets' => [], 'Elgg\Menus\AdminHeader::registerAdminInformation' => [], + 'Elgg\Menus\AdminHeader::registerAdminUtilities' => [], ], 'menu:admin_footer' => [ 'Elgg\Menus\AdminFooter::registerHelpResources' => [], diff --git a/languages/en.php b/languages/en.php index c9b00250222..ae74dfc0632 100644 --- a/languages/en.php +++ b/languages/en.php @@ -475,6 +475,7 @@ */ 'menu:page:header:administer' => 'Administer', 'menu:page:header:configure' => 'Configure', + 'menu:page:header:utilities' => 'Utilities', 'menu:page:header:develop' => 'Develop', 'menu:page:header:information' => 'Information', 'menu:page:header:default' => 'Other', @@ -642,9 +643,10 @@ three sections:
    Administer
    Basic tasks like managing users, monitoring reported content and activating plugins.
    -
    Configure
    Occasional tasks like setting the site name or configuring settings of a plugin.
    +
    Configure
    Occasional tasks like setting the site name or configuring security preferences.
    +
    Utilities
    Various tools to support site maintenance.
    Information
    Information about your site like statistics.
    -
    Develop
    For developers who are building plugins or designing themes. (Requires a developer plugin.)
    +
    Develop
    For developers who are building plugins or debugging the site. (Requires a developer plugin.)
    ", // argh, this is ugly diff --git a/mod/externalpages/classes/Elgg/ExternalPages/Menus/AdminHeader.php b/mod/externalpages/classes/Elgg/ExternalPages/Menus/AdminHeader.php index 73608a0ed6a..8e48c4efd4f 100644 --- a/mod/externalpages/classes/Elgg/ExternalPages/Menus/AdminHeader.php +++ b/mod/externalpages/classes/Elgg/ExternalPages/Menus/AdminHeader.php @@ -29,7 +29,7 @@ public static function register(\Elgg\Event $event) { 'name' => 'configure_utilities:expages', 'text' => elgg_echo('admin:configure_utilities:expages'), 'href' => 'admin/configure_utilities/expages', - 'parent_name' => 'configure_utilities', + 'parent_name' => 'utilities', ]); return $return; diff --git a/mod/profile/classes/Elgg/Profile/Menus/AdminHeader.php b/mod/profile/classes/Elgg/Profile/Menus/AdminHeader.php index cd74f247b33..0de67fe51da 100644 --- a/mod/profile/classes/Elgg/Profile/Menus/AdminHeader.php +++ b/mod/profile/classes/Elgg/Profile/Menus/AdminHeader.php @@ -58,7 +58,7 @@ public static function registerAdminProfileFields(\Elgg\Event $event) { 'name' => 'configure_utilities:profile_fields', 'text' => elgg_echo('admin:configure_utilities:profile_fields'), 'href' => 'admin/configure_utilities/profile_fields', - 'parent_name' => 'configure_utilities', + 'parent_name' => 'utilities', ]); return $return; diff --git a/mod/reportedcontent/classes/Elgg/ReportedContent/Menus/AdminHeader.php b/mod/reportedcontent/classes/Elgg/ReportedContent/Menus/AdminHeader.php index 30cadcb00a0..ebf669b9ecf 100644 --- a/mod/reportedcontent/classes/Elgg/ReportedContent/Menus/AdminHeader.php +++ b/mod/reportedcontent/classes/Elgg/ReportedContent/Menus/AdminHeader.php @@ -27,7 +27,7 @@ public static function register(\Elgg\Event $event) { 'name' => 'administer_utilities:reportedcontent', 'text' => elgg_echo('admin:administer_utilities:reportedcontent'), 'href' => 'admin/administer_utilities/reportedcontent', - 'parent_name' => 'administer_utilities', + 'parent_name' => 'administer', ]); return $return; diff --git a/mod/system_log/classes/Elgg/SystemLog/Menus/AdminHeader.php b/mod/system_log/classes/Elgg/SystemLog/Menus/AdminHeader.php index b14af04fab5..034d8190559 100644 --- a/mod/system_log/classes/Elgg/SystemLog/Menus/AdminHeader.php +++ b/mod/system_log/classes/Elgg/SystemLog/Menus/AdminHeader.php @@ -27,7 +27,7 @@ public static function register(\Elgg\Event $event) { 'name' => 'administer_utilities:logbrowser', 'text' => elgg_echo('admin:administer_utilities:logbrowser'), 'href' => 'admin/administer_utilities/logbrowser', - 'parent_name' => 'administer_utilities', + 'parent_name' => 'utilities', ]); return $return; From 2709c2db45a455c1e52ec3cc1e438b2155a4627a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 6 Jul 2023 12:24:21 +0200 Subject: [PATCH 018/240] feat(security): add support for security.txt fixes #14315 --- actions/admin/security/security_txt.php | 33 +++++ engine/actions.php | 1 + engine/classes/Elgg/Config.php | 9 ++ .../classes/Elgg/Controllers/SecurityTxt.php | 61 ++++++++++ .../classes/Elgg/Forms/PrepareSecurityTxt.php | 39 ++++++ engine/events.php | 3 + engine/routes.php | 5 + languages/en.php | 22 ++++ views/default/admin/security/security_txt.php | 26 ++++ views/default/admin/security/tabs.php | 8 ++ .../forms/admin/security/security_txt.php | 114 ++++++++++++++++++ 11 files changed, 321 insertions(+) create mode 100644 actions/admin/security/security_txt.php create mode 100644 engine/classes/Elgg/Controllers/SecurityTxt.php create mode 100644 engine/classes/Elgg/Forms/PrepareSecurityTxt.php create mode 100644 views/default/admin/security/security_txt.php create mode 100644 views/default/forms/admin/security/security_txt.php diff --git a/actions/admin/security/security_txt.php b/actions/admin/security/security_txt.php new file mode 100644 index 00000000000..a95691d5e4c --- /dev/null +++ b/actions/admin/security/security_txt.php @@ -0,0 +1,33 @@ + true, + 'expires' => true, + 'encryption' => false, + 'acknowledgments' => false, + 'language' => false, + 'canonical' => false, + 'policy' => false, + 'hiring' => false, + 'csaf' => false, +]; + +// first validate all required inputs +foreach ($fields as $name => $required) { + $value = get_input($name); + if (!$required || !empty($value)) { + continue; + } + + return elgg_error_response(elgg_echo('error:missing_data')); +} + +// save all data +foreach ($fields as $name => $required) { + elgg_save_config("security_txt_{$name}", get_input($name) ?: null); +} + +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/engine/actions.php b/engine/actions.php index ceff5560563..ee15d5bea28 100644 --- a/engine/actions.php +++ b/engine/actions.php @@ -8,6 +8,7 @@ 'admin/plugins/deactivate' => ['access' => 'admin'], 'admin/plugins/deactivate_all' => ['access' => 'admin'], 'admin/plugins/set_priority' => ['access' => 'admin'], + 'admin/security/security_txt' => ['access' => 'admin'], 'admin/security/settings' => ['access' => 'admin'], 'admin/security/regenerate_site_secret' => ['access' => 'admin'], 'admin/site/cache/invalidate' => ['access' => 'admin'], diff --git a/engine/classes/Elgg/Config.php b/engine/classes/Elgg/Config.php index 38ed07ad458..0d66bdefcdd 100644 --- a/engine/classes/Elgg/Config.php +++ b/engine/classes/Elgg/Config.php @@ -95,6 +95,15 @@ * @property bool $remove_branding Is Elgg branding disabled * @property int $remove_unvalidated_users_days The number of days after which unvalidated users will be removed * @property bool $require_admin_validation + * @property string $security_txt_acknowledgments Security.txt link to acknowledgments + * @property string $security_txt_canonical Security.txt canonical url + * @property string $security_txt_contact Security.txt contact information (mailto or https) + * @property string $security_txt_csaf Security.txt link to CSAF provider + * @property string $security_txt_encryption Security.txt link to encryption key for communication + * @property int $security_txt_expires Security.txt expiration date + * @property string $security_txt_hiring Security.txt link to hiring page + * @property string $security_txt_language Security.txt preferred communication language + * @property string $security_txt_policy Security.txt link to security reporting policy * @property bool $security_disable_password_autocomplete * @property bool $security_email_require_password * @property bool $security_notify_admins diff --git a/engine/classes/Elgg/Controllers/SecurityTxt.php b/engine/classes/Elgg/Controllers/SecurityTxt.php new file mode 100644 index 00000000000..07d321c675b --- /dev/null +++ b/engine/classes/Elgg/Controllers/SecurityTxt.php @@ -0,0 +1,61 @@ +format(DATE_ATOM), + ]; + + $fields = [ + 'encryption' => 'Encryption', + 'acknowledgments' => 'Acknowledgments', + 'language' => 'Preferred-Languages', + 'canonical' => 'Canonical', + 'policy' => 'Policy', + 'hiring' => 'Hiring', + 'csaf' => 'CSAF', + ]; + foreach ($fields as $name => $output) { + $value = elgg_get_config("security_txt_{$name}"); + if (empty($value)) { + continue; + } + + $lines[] = "{$output}: {$value}"; + } + + $response = elgg_ok_response(implode(PHP_EOL, $lines)); + $response->setHeaders([ + 'Content-Type' => 'text/plain; charset=utf-8', + ]); + + return $response; + } +} diff --git a/engine/classes/Elgg/Forms/PrepareSecurityTxt.php b/engine/classes/Elgg/Forms/PrepareSecurityTxt.php new file mode 100644 index 00000000000..8d658ca9f33 --- /dev/null +++ b/engine/classes/Elgg/Forms/PrepareSecurityTxt.php @@ -0,0 +1,39 @@ +getValue(); + + $fields = [ + 'contact', + 'expires', + 'encryption', + 'acknowledgments', + 'language', + 'canonical', + 'policy', + 'hiring', + 'csaf', + ]; + foreach ($fields as $field) { + $body_vars[$field] = elgg_extract($field, $body_vars, elgg_get_config("security_txt_{$field}")); + } + + return $body_vars; + } +} diff --git a/engine/events.php b/engine/events.php index 9b97a78d769..b9c0dc3504f 100644 --- a/engine/events.php +++ b/engine/events.php @@ -163,6 +163,9 @@ ], ], 'form:prepare:fields' => [ + 'admin/security/security_txt' => [ + \Elgg\Forms\PrepareSecurityTxt::class => [], + ], 'all' => [ \Elgg\Forms\PrepareFields::class => ['priority' => 9999], ], diff --git a/engine/routes.php b/engine/routes.php index 3f21cba261c..ffedbd3eb42 100644 --- a/engine/routes.php +++ b/engine/routes.php @@ -150,6 +150,11 @@ 'match_on' => '\w+', ], ], + 'security.txt' => [ + 'path' => '/security.txt', + 'controller' => \Elgg\Controllers\SecurityTxt::class, + 'walled' => false, + ], 'settings:index' => [ 'path' => '/settings', 'resource' => 'settings/account', diff --git a/languages/en.php b/languages/en.php index ae74dfc0632..6334b7c68da 100644 --- a/languages/en.php +++ b/languages/en.php @@ -784,6 +784,28 @@ 'admin:security:settings:min_password_special' => "Minimal number of special characters in a password", 'admin:security:settings:min_password_special:help' => "Configure the minimal number of special (!@$%^&*()<>,.?/[]{}-=_+) characters that should be present in a password. 0 for not present at all, empty for no requirements.", + 'admin:security:security_txt' => "Security.txt", + 'admin:security:security_txt:description' => "When a security vulnerability is found in your website, where should it be reported? The security.txt is a standard to help structure the information the security researchers need in order to be able to contact the site administrators with the found vulnerability. More information about the standard can be found at %s. The contents of your security.txt can be found at %s.", + 'admin:security:security_txt:expired' => "The content of your security.txt is expired, please check if all the information is still up-to-date.", + 'admin:security:security_txt:contact' => "Contact", + 'admin:security:security_txt:contact:help' => "A link or e-mail address for people to contact you about security issues. Remember to include 'https://' for URLs, and 'mailto:' for e-mails. See %s", + 'admin:security:security_txt:expires' => "Expires", + 'admin:security:security_txt:expires:help' => "The date and time when the content of the security.txt file should be considered stale (so security researchers should then not trust it). Make sure you update this value periodically and keep your file under review. See %s", + 'admin:security:security_txt:encryption' => "Encryption", + 'admin:security:security_txt:encryption:help' => "A link to a key which security researchers should use to securely talk to you. Remember to include 'https://'. See %s", + 'admin:security:security_txt:acknowledgments' => "Acknowledgments", + 'admin:security:security_txt:acknowledgments:help' => "A link to a web page where you say thank you to security researchers who have helped you. Remember to include 'https://'. See %s", + 'admin:security:security_txt:language' => "Language", + 'admin:security:security_txt:language:help' => "A comma-separated list of language codes that your security team speaks. You may include more than one language. See %s", + 'admin:security:security_txt:canonical' => "Canonical", + 'admin:security:security_txt:canonical:help' => "The URLs for accessing your security.txt file. It is important to include this if you are digitally signing the security.txt file, so that the location of the security.txt file can be digitally signed too. See %s", + 'admin:security:security_txt:policy' => "Policy", + 'admin:security:security_txt:policy:help' => "A link to a policy detailing what security researchers should do when searching for or reporting security issues. Remember to include 'https://'. See %s", + 'admin:security:security_txt:hiring' => "Hiring", + 'admin:security:security_txt:hiring:help' => "A link to any security-related job openings in your organisation. Remember to include 'https://'. See %s", + 'admin:security:security_txt:csaf' => "CSAF", + 'admin:security:security_txt:csaf:help' => "A link to the provider-metadata.json of your CSAF (Common Security Advisory Framework) provider. Remember to include 'https://'. See %s", + 'admin:site:secret:regenerated' => "Your site secret has been regenerated", 'admin:site:secret:prevented' => "The regeneration of the site secret was prevented", diff --git a/views/default/admin/security/security_txt.php b/views/default/admin/security/security_txt.php new file mode 100644 index 00000000000..f7b1813b9d1 --- /dev/null +++ b/views/default/admin/security/security_txt.php @@ -0,0 +1,26 @@ + elgg_echo('admin:security:security_txt:description', [ + elgg_view_url('https://securitytxt.org/'), + elgg_view_url(elgg_generate_url('security.txt')), + ]), +]); + +$expires = elgg_get_config('security_txt_expires'); +if (!empty($expires) && $expires < time()) { + echo elgg_view_message('warning', elgg_echo('admin:security:security_txt:expired')); +} + +echo elgg_view_form('admin/security/security_txt', [ + 'enable_sticky' => true, +]); diff --git a/views/default/admin/security/tabs.php b/views/default/admin/security/tabs.php index fc351a1b38d..cf71189a8a6 100644 --- a/views/default/admin/security/tabs.php +++ b/views/default/admin/security/tabs.php @@ -16,6 +16,14 @@ ]), 'selected' => $selected === 'settings', ], + [ + 'name' => 'security_txt', + 'text' => elgg_echo('admin:security:security_txt'), + 'href' => elgg_generate_url('admin', [ + 'segments' => 'security/security_txt', + ]), + 'selected' => $selected === 'security_txt', + ], [ 'name' => 'information', 'text' => elgg_echo('admin:security:information'), diff --git a/views/default/forms/admin/security/security_txt.php b/views/default/forms/admin/security/security_txt.php new file mode 100644 index 00000000000..bc856649c2e --- /dev/null +++ b/views/default/forms/admin/security/security_txt.php @@ -0,0 +1,114 @@ + 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3', + 'expires' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5', + 'encryption' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.4', + 'acknowledgments' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.1', + 'language' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8', + 'canonical' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.2', + 'policy' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.7', + 'hiring' => 'https://www.rfc-editor.org/rfc/rfc9116#section-2.5.6', + 'csaf' => 'https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#718-requirement-8-securitytxt', +]; + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:contact'), + '#help' => elgg_echo('admin:security:security_txt:contact:help', [elgg_view_url($help_urls['contact'])]), + 'name' => 'contact', + 'value' => elgg_extract('contact', $vars), + 'required' => true, + 'placeholder' => 'mailto:security@' . elgg_get_site_entity()->getDomain(), +]); + +echo elgg_view_field([ + '#type' => 'date', + '#label' => elgg_echo('admin:security:security_txt:expires'), + '#help' => elgg_echo('admin:security:security_txt:expires:help', [elgg_view_url($help_urls['expires'])]), + 'name' => 'expires', + 'value' => elgg_extract('expires', $vars), + 'required' => true, + 'timestamp' => true, +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:encryption'), + '#help' => elgg_echo('admin:security:security_txt:encryption:help', [elgg_view_url($help_urls['encryption'])]), + 'name' => 'encryption', + 'value' => elgg_extract('encryption', $vars), + 'placeholder' => elgg_get_site_url() . 'pgp-key.txt', +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:acknowledgments'), + '#help' => elgg_echo('admin:security:security_txt:acknowledgments:help', [elgg_view_url($help_urls['acknowledgments'])]), + 'name' => 'acknowledgments', + 'value' => elgg_extract('acknowledgments', $vars), + 'placeholder' => elgg_get_site_url() . 'hall-of-fame.html', +]); + +$languages = [ + 'en', + elgg_get_config('language'), + elgg_get_current_language(), +]; +$languages = array_unique($languages); + +echo elgg_view_field([ + '#type' => 'text', + '#label' => elgg_echo('admin:security:security_txt:language'), + '#help' => elgg_echo('admin:security:security_txt:language:help', [elgg_view_url($help_urls['language'])]), + 'name' => 'language', + 'value' => elgg_extract('language', $vars), + 'placeholder' => implode(', ', $languages), +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:canonical'), + '#help' => elgg_echo('admin:security:security_txt:canonical:help', [elgg_view_url($help_urls['canonical'])]), + 'name' => 'canonical', + 'value' => elgg_extract('canonical', $vars), + 'placeholder' => elgg_generate_url('security.txt'), +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:policy'), + '#help' => elgg_echo('admin:security:security_txt:policy:help', [elgg_view_url($help_urls['policy'])]), + 'name' => 'policy', + 'value' => elgg_extract('policy', $vars), + 'placeholder' => elgg_get_site_url() . 'security-policy.html', +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:hiring'), + '#help' => elgg_echo('admin:security:security_txt:hiring:help', [elgg_view_url($help_urls['hiring'])]), + 'name' => 'hiring', + 'value' => elgg_extract('hiring', $vars), + 'placeholder' => elgg_get_site_url() . 'jobs.html', +]); + +echo elgg_view_field([ + '#type' => 'url', + '#label' => elgg_echo('admin:security:security_txt:csaf'), + '#help' => elgg_echo('admin:security:security_txt:csaf:help', [elgg_view_url($help_urls['csaf'])]), + 'name' => 'csaf', + 'value' => elgg_extract('csaf', $vars), + 'placeholder' => elgg_get_site_url() . '.well-known/csaf/provider-metadata.json', +]); + +$footer = elgg_view_field([ + '#type' => 'submit', + 'value' => elgg_echo('save'), +]); +elgg_set_form_footer($footer); From 9384d39ef4377f69092a2d6d6908d1d69ac60108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 6 Jul 2023 14:44:49 +0200 Subject: [PATCH 019/240] chore(seeder): improved stability of the seeders --- engine/classes/Elgg/Database/Seeds/Groups.php | 14 ++++---- engine/classes/Elgg/Database/Seeds/Users.php | 13 ++++---- engine/classes/Elgg/Traits/Seeding.php | 1 - mod/blog/classes/Elgg/Blog/Seeder.php | 32 +++++++++++-------- .../classes/Elgg/Bookmarks/Seeder.php | 21 +++++++----- .../classes/Elgg/Discussions/Seeder.php | 32 +++++++++++-------- mod/file/classes/Elgg/File/Seeder.php | 29 ++++++++--------- mod/pages/classes/Elgg/Pages/Seeder.php | 21 +++++++----- .../classes/Elgg/SiteNotifications/Seeder.php | 23 +++++++------ mod/thewire/classes/Elgg/TheWire/Seeder.php | 5 +-- 10 files changed, 106 insertions(+), 85 deletions(-) diff --git a/engine/classes/Elgg/Database/Seeds/Groups.php b/engine/classes/Elgg/Database/Seeds/Groups.php index 7925def35c9..40b565e3964 100644 --- a/engine/classes/Elgg/Database/Seeds/Groups.php +++ b/engine/classes/Elgg/Database/Seeds/Groups.php @@ -2,6 +2,8 @@ namespace Elgg\Database\Seeds; +use Elgg\Exceptions\Seeding\MaxAttemptsException; + /** * Seed users * @@ -34,7 +36,7 @@ public function seed() { } while ($this->getCount() < $this->limit) { - if ($this->create) { + try { $group = $this->createGroup([ 'access_id' => $this->getRandomGroupVisibility(), 'content_access_mode' => $this->getRandomGroupContentAccessMode(), @@ -43,11 +45,8 @@ public function seed() { 'profile_fields' => $profile_fields, 'group_tool_options' => _elgg_services()->group_tools->all(), ]); - } else { - $group = $this->getRandomGroup($exclude); - } - - if (!$group) { + } catch (MaxAttemptsException $e) { + // unable to create a group with the given options continue; } @@ -107,7 +106,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $groups \ElggBatch */ $groups = elgg_get_entities([ 'type' => 'group', @@ -123,6 +121,8 @@ public function unseed() { $this->log("Deleted group {$group->guid}"); } else { $this->log("Failed to delete group {$group->guid}"); + $groups->reportFailure(); + continue; } $this->advance(); diff --git a/engine/classes/Elgg/Database/Seeds/Users.php b/engine/classes/Elgg/Database/Seeds/Users.php index 72730589ae6..68b869ea144 100644 --- a/engine/classes/Elgg/Database/Seeds/Users.php +++ b/engine/classes/Elgg/Database/Seeds/Users.php @@ -3,6 +3,7 @@ namespace Elgg\Database\Seeds; use Elgg\Database\Update; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Seed users @@ -36,15 +37,12 @@ public function seed() { } while ($this->getCount() < $this->limit) { - if ($this->create) { + try { $user = $this->createUser([], [ 'profile_fields' => $profile_fields, ]); - } else { - $user = $this->getRandomUser($exclude); - } - - if (!$user) { + } catch (MaxAttemptsException $e) { + // unable to create a user with the given options continue; } @@ -113,7 +111,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $users \ElggBatch */ $users = elgg_get_entities([ 'type' => 'user', @@ -129,6 +126,8 @@ public function unseed() { $this->log("Deleted user {$user->guid}"); } else { $this->log("Failed to delete user {$user->guid}"); + $users->reportFailure(); + continue; } $this->advance(); diff --git a/engine/classes/Elgg/Traits/Seeding.php b/engine/classes/Elgg/Traits/Seeding.php index 37335ceb9ad..0dde27787cb 100644 --- a/engine/classes/Elgg/Traits/Seeding.php +++ b/engine/classes/Elgg/Traits/Seeding.php @@ -100,7 +100,6 @@ public function getRandomSubtype(): bool|string { * @param array $options Seeding options * * @return \ElggUser - * @throws Exception * @throws MaxAttemptsException */ public function createUser(array $properties = [], array $options = []): \ElggUser { diff --git a/mod/blog/classes/Elgg/Blog/Seeder.php b/mod/blog/classes/Elgg/Blog/Seeder.php index 3436ccb782b..db095fcf571 100644 --- a/mod/blog/classes/Elgg/Blog/Seeder.php +++ b/mod/blog/classes/Elgg/Blog/Seeder.php @@ -3,6 +3,7 @@ namespace Elgg\Blog; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add blog seed @@ -11,7 +12,7 @@ */ class Seeder extends Seed { - private $status = [ + protected array $status = [ 'draft', 'published', ]; @@ -23,15 +24,18 @@ public function seed() { $this->advance($this->getCount()); while ($this->getCount() < $this->limit) { - $properties = [ - 'subtype' => 'blog', - 'status' => $this->getRandomStatus(), - 'comments_on' => $this->faker()->boolean() ? 'On' : 'Off', - 'excerpt' => $this->faker()->sentence(), - ]; - - /* @var $blog \ElggBlog */ - $blog = $this->createObject($properties); + try { + /* @var $blog \ElggBlog */ + $blog = $this->createObject([ + 'subtype' => 'blog', + 'status' => $this->getRandomStatus(), + 'comments_on' => $this->faker()->boolean() ? 'On' : 'Off', + 'excerpt' => $this->faker()->sentence(), + ]); + } catch (MaxAttemptsException $e) { + // unable to create a blog with the given options + continue; + } $this->createComments($blog); $this->createLikes($blog); @@ -69,7 +73,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $blogs \ElggBatch */ $blogs = elgg_get_entities([ 'type' => 'object', @@ -86,6 +89,8 @@ public function unseed() { $this->log("Deleted blog {$blog->guid}"); } else { $this->log("Failed to delete blog {$blog->guid}"); + $blogs->reportFailure(); + continue; } $this->advance(); @@ -101,10 +106,11 @@ public static function getType() : string { /** * Returns random blog status + * * @return string */ - public function getRandomStatus() { - $key = array_rand($this->status, 1); + public function getRandomStatus(): string { + $key = array_rand($this->status); return $this->status[$key]; } diff --git a/mod/bookmarks/classes/Elgg/Bookmarks/Seeder.php b/mod/bookmarks/classes/Elgg/Bookmarks/Seeder.php index 74171022302..160b0b3bff4 100644 --- a/mod/bookmarks/classes/Elgg/Bookmarks/Seeder.php +++ b/mod/bookmarks/classes/Elgg/Bookmarks/Seeder.php @@ -3,6 +3,7 @@ namespace Elgg\Bookmarks; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add bookmarks seed @@ -18,13 +19,16 @@ public function seed() { $this->advance($this->getCount()); while ($this->getCount() < $this->limit) { - $properties = [ - 'subtype' => 'bookmarks', - 'address' => $this->faker()->url, - ]; - - /* @var $bookmark \ElggBookmark */ - $bookmark = $this->createObject($properties); + try { + /* @var $bookmark \ElggBookmark */ + $bookmark = $this->createObject([ + 'subtype' => 'bookmarks', + 'address' => $this->faker()->url, + ]); + } catch (MaxAttemptsException $e) { + // unable to create a bookmark with the given options + continue; + } $this->createComments($bookmark); $this->createLikes($bookmark); @@ -46,7 +50,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $bookmarks \ElggBatch */ $bookmarks = elgg_get_entities([ 'type' => 'object', @@ -63,6 +66,8 @@ public function unseed() { $this->log("Deleted bookmark {$bookmark->guid}"); } else { $this->log("Failed to delete bookmark {$bookmark->guid}"); + $bookmarks->reportFailure(); + continue; } $this->advance(); diff --git a/mod/discussions/classes/Elgg/Discussions/Seeder.php b/mod/discussions/classes/Elgg/Discussions/Seeder.php index 39bed426ae6..755a82bb624 100644 --- a/mod/discussions/classes/Elgg/Discussions/Seeder.php +++ b/mod/discussions/classes/Elgg/Discussions/Seeder.php @@ -3,6 +3,7 @@ namespace Elgg\Discussions; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add database seed @@ -11,7 +12,7 @@ */ class Seeder extends Seed { - private $status = [ + protected array $status = [ 'open', 'closed', ]; @@ -23,15 +24,18 @@ public function seed() { $this->advance($this->getCount()); while ($this->getCount() < $this->limit) { - $properties = [ - 'subtype' => 'discussion', - 'container_guid' => $this->getRandomGroup()->guid, - 'status' => $this->getRandomStatus(), - 'excerpt' => $this->faker()->sentence(), - ]; - - /* @var $discussion \ElggDiscussion */ - $discussion = $this->createObject($properties); + try { + /* @var $discussion \ElggDiscussion */ + $discussion = $this->createObject([ + 'subtype' => 'discussion', + 'container_guid' => $this->getRandomGroup()->guid, + 'status' => $this->getRandomStatus(), + 'excerpt' => $this->faker()->sentence(), + ]); + } catch (MaxAttemptsException $e) { + // unable to create a discussion with the given options + continue; + } $this->createComments($discussion); $this->createLikes($discussion); @@ -52,7 +56,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $discussions \ElggBatch */ $discussions = elgg_get_entities([ 'type' => 'object', @@ -69,6 +72,8 @@ public function unseed() { $this->log("Deleted discussion {$discussion->guid}"); } else { $this->log("Failed to delete discussion {$discussion->guid}"); + $discussions->reportFailure(); + continue; } $this->advance(); @@ -84,10 +89,11 @@ public static function getType() : string { /** * Returns random discussion status + * * @return string */ - public function getRandomStatus() { - $key = array_rand($this->status, 1); + public function getRandomStatus(): string { + $key = array_rand($this->status); return $this->status[$key]; } diff --git a/mod/file/classes/Elgg/File/Seeder.php b/mod/file/classes/Elgg/File/Seeder.php index a52604da6db..f412b7df95e 100644 --- a/mod/file/classes/Elgg/File/Seeder.php +++ b/mod/file/classes/Elgg/File/Seeder.php @@ -3,6 +3,7 @@ namespace Elgg\File; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add file seed @@ -17,31 +18,26 @@ class Seeder extends Seed { public function seed() { $this->advance($this->getCount()); - $attributes = [ - 'subtype' => 'file', - ]; - while ($this->getCount() < $this->limit) { - $path = $this->faker()->image(); - - $filename = pathinfo($path, PATHINFO_FILENAME); - - $file = $this->createObject($attributes); - if (!$file instanceof \ElggFile) { + try { + /* @var $file \ElggFile */ + $file = $this->createObject([ + 'subtype' => 'file', + ]); + } catch (MaxAttemptsException $e) { + // unable to create file with the given options continue; } + $path = $this->faker()->image(); + $filename = pathinfo($path, PATHINFO_FILENAME); + $file->setFilename("file/{$filename}"); $file->open('write'); $file->close(); copy($path, $file->getFilenameOnFilestore()); - if (!$file->save()) { - $file->delete(); - continue; - } - $this->createComments($file); $this->createLikes($file); @@ -61,7 +57,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $files \ElggBatch */ $files = elgg_get_entities([ 'type' => 'object', @@ -78,6 +73,8 @@ public function unseed() { $this->log("Deleted file {$file->guid}"); } else { $this->log("Failed to delete file {$file->guid}"); + $files->reportFailure(); + continue; } $this->advance(); diff --git a/mod/pages/classes/Elgg/Pages/Seeder.php b/mod/pages/classes/Elgg/Pages/Seeder.php index 3e6e1ca0fcd..571da777c79 100644 --- a/mod/pages/classes/Elgg/Pages/Seeder.php +++ b/mod/pages/classes/Elgg/Pages/Seeder.php @@ -3,6 +3,7 @@ namespace Elgg\Pages; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add page seed @@ -18,13 +19,16 @@ public function seed() { $this->advance($this->getCount()); $create_page = function () { - $properties = [ - 'subtype' => 'page', - 'write_access_id' => ACCESS_LOGGED_IN, - ]; - - /* @var $age \ElggPage */ - $page = $this->createObject($properties); + try { + /* @var $age \ElggPage */ + $page = $this->createObject([ + 'subtype' => 'page', + 'write_access_id' => ACCESS_LOGGED_IN, + ]); + } catch (MaxAttemptsException $e) { + // unable to create a page with the given options + return null; + } $this->createComments($page); $this->createLikes($page); @@ -66,7 +70,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $pages \ElggBatch */ $pages = elgg_get_entities([ 'type' => 'object', @@ -83,6 +86,8 @@ public function unseed() { $this->log("Deleted page {$page->guid}"); } else { $this->log("Failed to delete page {$page->guid}"); + $pages->reportFailure(); + continue; } $this->advance(); diff --git a/mod/site_notifications/classes/Elgg/SiteNotifications/Seeder.php b/mod/site_notifications/classes/Elgg/SiteNotifications/Seeder.php index f74dc7a15f8..3ef8cf8ea24 100644 --- a/mod/site_notifications/classes/Elgg/SiteNotifications/Seeder.php +++ b/mod/site_notifications/classes/Elgg/SiteNotifications/Seeder.php @@ -5,6 +5,7 @@ use Elgg\Database\Clauses\OrderByClause; use Elgg\Database\QueryBuilder; use Elgg\Database\Seeds\Seed; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Add site notification seed @@ -20,15 +21,16 @@ public function seed() { $this->advance($this->getCount()); while ($this->getCount() < $this->limit) { - $properties = [ - 'subtype' => 'site_notification', - 'access_id' => ACCESS_PRIVATE, - 'read' => $this->faker()->boolean(), - 'summary' => $this->faker()->sentence(), - ]; - - $notification = $this->createObject($properties); - if (!$notification instanceof \SiteNotification) { + try { + /* @var $notification \SiteNotification */ + $notification = $this->createObject([ + 'subtype' => 'site_notification', + 'access_id' => ACCESS_PRIVATE, + 'read' => $this->faker()->boolean(), + 'summary' => $this->faker()->sentence(), + ]); + } catch (MaxAttemptsException $e) { + // unable to create site notification with the given options continue; } @@ -56,7 +58,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $notifications \ElggBatch */ $notifications = elgg_get_entities([ 'type' => 'object', @@ -73,6 +74,8 @@ public function unseed() { $this->log("Deleted site notification {$notification->guid}"); } else { $this->log("Failed to delete site notification {$notification->guid}"); + $notifications->reportFailure(); + continue; } $this->advance(); diff --git a/mod/thewire/classes/Elgg/TheWire/Seeder.php b/mod/thewire/classes/Elgg/TheWire/Seeder.php index c0e2e3f998b..f34a4656d7c 100644 --- a/mod/thewire/classes/Elgg/TheWire/Seeder.php +++ b/mod/thewire/classes/Elgg/TheWire/Seeder.php @@ -57,7 +57,7 @@ public function seed() { }; while ($this->getCount() < $this->limit) { - $owner = $this->getRandomUser([], true); + $owner = $this->getRandomUser(); $wire_guid = thewire_save_post($this->faker()->text($max_chars), $owner->guid, $this->getRandomAccessId($owner)); if ($wire_guid === false) { @@ -95,7 +95,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $entities \ElggBatch */ $entities = elgg_get_entities([ 'type' => 'object', @@ -112,6 +111,8 @@ public function unseed() { $this->log("Deleted wire post {$entity->guid}"); } else { $this->log("Failed to delete wire post {$entity->guid}"); + $entities->reportFailure(); + continue; } $this->advance(); From c4ad5037bbaa04343c733358931f513765932a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 7 Jul 2023 10:00:44 +0200 Subject: [PATCH 020/240] fix(http): maintain set redirect code in response fixes #14346 --- engine/classes/Elgg/Http/ResponseFactory.php | 6 ++-- .../Http/ResponseFactoryIntegrationTest.php | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/engine/classes/Elgg/Http/ResponseFactory.php b/engine/classes/Elgg/Http/ResponseFactory.php index 045da16bc99..0e840786cfc 100644 --- a/engine/classes/Elgg/Http/ResponseFactory.php +++ b/engine/classes/Elgg/Http/ResponseFactory.php @@ -254,7 +254,7 @@ public function respond(ResponseBuilder $response) { $is_xhr = $this->request->isXmlHttpRequest(); - $is_action = str_starts_with($response_type, 'action:'); + $is_action = $this->isAction(); if ($is_action && $response->getForwardURL() === null) { // actions must always set a redirect url @@ -265,10 +265,10 @@ public function respond(ResponseBuilder $response) { $response->setForwardURL((string) $this->request->headers->get('Referer')); } - if ($response->getForwardURL() !== null && !$is_xhr) { + if ($response->getForwardURL() !== null && !$is_xhr && !$response->isRedirection()) { // non-xhr requests should issue a forward if redirect url is set // unless it's an error, in which case we serve an error page - if ($this->isAction() || (!$response->isClientError() && !$response->isServerError())) { + if ($is_action || (!$response->isClientError() && !$response->isServerError())) { $response->setStatusCode(ELGG_HTTP_FOUND); } } diff --git a/engine/tests/phpunit/integration/Elgg/Http/ResponseFactoryIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Http/ResponseFactoryIntegrationTest.php index 3f908533edb..ce59d07793b 100644 --- a/engine/tests/phpunit/integration/Elgg/Http/ResponseFactoryIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Http/ResponseFactoryIntegrationTest.php @@ -159,4 +159,33 @@ public function testRespondWithErrorPassesException() { $this->assertTrue($exception_found, 'No exception found in view vars of resource/error'); } + + /** + * @dataProvider redirectCodeProvider + */ + public function testRespondWithRedirectCode(int $status_code, int $expected_code) { + $request = $this->prepareHttpRequest('action/foo', 'POST', [], 0, true); + _elgg_services()->request = $request; + + $response = new OkResponse('', $status_code, '/forward'); + + ob_start(); + $result = $this->service->respond($response); + ob_end_clean(); + + $this->assertInstanceOf(Response::class, $result); + $this->assertEquals($expected_code, $result->getStatusCode()); + } + + public function redirectCodeProvider() { + return [ + [ELGG_HTTP_OK, ELGG_HTTP_FOUND], + [ELGG_HTTP_CREATED, ELGG_HTTP_CREATED], + [ELGG_HTTP_MOVED_PERMANENTLY, ELGG_HTTP_MOVED_PERMANENTLY], + [ELGG_HTTP_FOUND, ELGG_HTTP_FOUND], + [ELGG_HTTP_SEE_OTHER, ELGG_HTTP_SEE_OTHER], + [ELGG_HTTP_TEMPORARY_REDIRECT, ELGG_HTTP_TEMPORARY_REDIRECT], + [ELGG_HTTP_PERMANENTLY_REDIRECT, ELGG_HTTP_PERMANENTLY_REDIRECT], + ]; + } } From 337b1bd71040b0d83c41a70a745069b1fbe6f6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 6 Jul 2023 17:15:16 +0200 Subject: [PATCH 021/240] feat(cli): interactively set number of seeded items per seeder The seeders can now have their own default limit --- docs/intro/elgg-cli.rst | 2 +- .../classes/Elgg/Cli/DatabaseSeedCommand.php | 4 +- engine/classes/Elgg/Database/Seeder.php | 49 +++++++++++++++---- engine/classes/Elgg/Database/Seeds/Seed.php | 17 +++++-- languages/en.php | 1 + 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/docs/intro/elgg-cli.rst b/docs/intro/elgg-cli.rst index 3e4a4a045c2..390dc881233 100644 --- a/docs/intro/elgg-cli.rst +++ b/docs/intro/elgg-cli.rst @@ -42,7 +42,7 @@ Available commands vendor/bin/elgg-cli install [--no-plugins] [-c|--config CONFIG] # Seed the database with fake entities - # limit: (int) number of items to seed + # limit: (int) number of items to seed (will be asked interactively for each seeder unless the -n/--no-interaction is used or only one type is seeded) # type: (string) only seed given entity type # create_since: (string) a compatible PHP date/time string to set the lower bound entity time created (eg, '-5 months') # create_until: (string) a compatible PHP date/time string to set the upper bound entity time created (eg, 'yesterday') diff --git a/engine/classes/Elgg/Cli/DatabaseSeedCommand.php b/engine/classes/Elgg/Cli/DatabaseSeedCommand.php index 717f53cefc9..901514fde63 100644 --- a/engine/classes/Elgg/Cli/DatabaseSeedCommand.php +++ b/engine/classes/Elgg/Cli/DatabaseSeedCommand.php @@ -63,12 +63,14 @@ protected function command() { _elgg_services()->set('mailer', new \Laminas\Mail\Transport\InMemory()); $options = [ - 'limit' => (int) $this->option('limit') ?: 20, + 'limit' => $this->option('limit'), 'image_folder' => $this->option('image_folder'), 'type' => $this->option('type'), 'create_since' => $this->option('create_since'), 'create_until' => $this->option('create_until'), 'create' => (bool) $this->argument('create'), + 'interactive' => !(bool) $this->option('no-interaction'), + 'cli_command' => $this, ]; try { diff --git a/engine/classes/Elgg/Database/Seeder.php b/engine/classes/Elgg/Database/Seeder.php index 4163acfecb3..9492f616538 100644 --- a/engine/classes/Elgg/Database/Seeder.php +++ b/engine/classes/Elgg/Database/Seeder.php @@ -2,9 +2,11 @@ namespace Elgg\Database; +use Elgg\Cli\Command; use Elgg\Cli\Progress; use Elgg\Database\Seeds\Seed; use Elgg\EventsService; +use Elgg\I18n\Translator; use Elgg\Invoker; /** @@ -21,22 +23,27 @@ class Seeder { protected Progress $progress; protected Invoker $invoker; + + protected Translator $translator; /** * Seeder constructor. * - * @param EventsService $events Events service - * @param Progress $progress Progress helper - * @param Invoker $invoker Invoker service + * @param EventsService $events Events service + * @param Progress $progress Progress helper + * @param Invoker $invoker Invoker service + * @param Translator $translator Translator */ public function __construct( EventsService $events, Progress $progress, - Invoker $invoker + Invoker $invoker, + Translator $translator ) { $this->events = $events; $this->progress = $progress; $this->invoker = $invoker; + $this->translator = $translator; } /** @@ -55,17 +62,17 @@ public function __construct( public function seed(array $options = []): void { $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { $defaults = [ - 'limit' => max(elgg_get_config('default_limit'), 20), + 'limit' => null, 'image_folder' => elgg_get_config('seeder_local_image_folder'), 'type' => '', 'create' => false, 'create_since' => 'now', 'create_until' => 'now', + 'interactive' => true, + 'cli_command' => null, ]; $options = array_merge($defaults, $options); - $seeds = $this->getSeederClasses(); - // set global configuration if ($options['image_folder'] !== $defaults['image_folder']) { elgg_set_config('seeder_local_image_folder', $options['image_folder']); @@ -73,16 +80,38 @@ public function seed(array $options = []): void { unset($options['image_folder']); + // fetch CLI command + $cli_command = $options['cli_command']; + unset($options['cli_command']); + + // interactive mode + $interactive = $options['interactive'] && empty($options['type']); + unset($options['interactive']); + + $seeds = $this->getSeederClasses(); foreach ($seeds as $seed) { + $seed_options = $options; + // check for type limitation - if (!empty($options['type']) && $options['type'] !== $seed::getType()) { + if (!empty($seed_options['type']) && $seed_options['type'] !== $seed::getType()) { continue; } + // check the seed limit + $seed_options['limit'] = $seed_options['limit'] ?? $seed::getDefaultLimit(); + if ($interactive && $cli_command instanceof Command) { + $seed_options['limit'] = (int) $cli_command->ask($this->translator->translate('cli:database:seed:ask:limit', [$seed::getType()]), $seed_options['limit'], false, false); + } + + if ($seed_options['limit'] < 1) { + // skip seeding + continue; + } + /* @var $seeder Seed */ - $seeder = new $seed($options); + $seeder = new $seed($seed_options); - $progress_bar = $this->progress->start($seed, $options['limit']); + $progress_bar = $this->progress->start($seed, $seed_options['limit']); $seeder->setProgressBar($progress_bar); diff --git a/engine/classes/Elgg/Database/Seeds/Seed.php b/engine/classes/Elgg/Database/Seeds/Seed.php index f01c68e87df..af875f82cc6 100644 --- a/engine/classes/Elgg/Database/Seeds/Seed.php +++ b/engine/classes/Elgg/Database/Seeds/Seed.php @@ -21,17 +21,17 @@ abstract class Seed implements Seedable { /** * @var int Max number of items to be created by the seed */ - protected $limit = 20; + protected int $limit; /** * @var bool Create new entities */ - protected $create = false; + protected bool $create = false; /** * @var int Number of seeded entities */ - protected $seeded_counter = 0; + protected int $seeded_counter = 0; /** * Seed constructor. @@ -46,6 +46,8 @@ public function __construct(array $options = []) { $limit = (int) elgg_extract('limit', $options); if ($limit > 0) { $this->limit = $limit; + } else { + $this->limit = static::getDefaultLimit(); } $this->create = (bool) elgg_extract('create', $options, $this->create); @@ -98,6 +100,15 @@ public function advance(int $step = 1): void { $this->progressAdvance($step); } + + /** + * Get the default number of content to seed + * + * @return int + */ + public static function getDefaultLimit(): int { + return max(elgg_get_config('default_limit'), 20); + } /** * Populate database diff --git a/languages/en.php b/languages/en.php index 6334b7c68da..58be09ac0d7 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1809,6 +1809,7 @@ 'cli:database:seed:option:create_until' => "A PHP time string to set the upper bound creation time of seeded entities", 'cli:database:seed:log:error:faker' => "This is a developer tool currently intended for testing purposes only. Please refrain from using it.", 'cli:database:seed:log:error:logged_in' => "Database seeding should not be run with a logged in user", + 'cli:database:seed:ask:limit' => "How many items to seed for the '%s' seeder", 'cli:database:seeders:description' => "List all available database seeders with the current count of seeded entities", 'cli:database:seeders:handler' => "Seed handler", From 2d2f959ce74762b0d83cd9a9c48becf13866399b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 6 Jul 2023 17:13:27 +0200 Subject: [PATCH 022/240] chore(views): split userpicker into entity picker fixes #14399 --- docs/guides/actions.rst | 2 + docs/guides/search.rst | 2 +- .../elements/components/userpicker.css | 2 +- views/default/elements/forms.css.php | 2 +- views/default/elgg/UserPicker.js | 5 +- views/default/input/autocomplete/item.php | 2 +- views/default/input/entitypicker.css | 21 +++ views/default/input/entitypicker.js | 163 ++++++++++++++++++ views/default/input/entitypicker.php | 86 +++++++++ views/default/input/friendspicker.php | 3 - views/default/input/grouppicker.php | 4 +- views/default/input/objectpicker.php | 4 +- views/default/input/userpicker.php | 97 ++--------- 13 files changed, 297 insertions(+), 96 deletions(-) create mode 100644 views/default/input/entitypicker.css create mode 100644 views/default/input/entitypicker.js create mode 100644 views/default/input/entitypicker.php diff --git a/docs/guides/actions.rst b/docs/guides/actions.rst index ca70db72dcf..bc2f475d4c4 100644 --- a/docs/guides/actions.rst +++ b/docs/guides/actions.rst @@ -378,6 +378,8 @@ Elgg offers some helper input types * ``input/captcha`` - placeholder view for plugins to extend * ``input/friendspicker`` - renders an Elgg friend autocomplete * ``input/userpicker`` - renders an Elgg user autocomplete +* ``input/grouppicker`` - renders an Elgg group autocomplete +* ``input/objectpicker`` - renders an Elgg object autocomplete * ``input/location`` renders an Elgg location input Files and images diff --git a/docs/guides/search.rst b/docs/guides/search.rst index 3623859d7ce..e666bd41724 100644 --- a/docs/guides/search.rst +++ b/docs/guides/search.rst @@ -183,7 +183,7 @@ Elgg core only supports entity search. You can implement custom searches, e.g. u Autocomplete and livesearch endpoint ------------------------------------ -Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/userpicker`` views. +Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/entitypicker`` views. .. code-block:: php diff --git a/views/default/elements/components/userpicker.css b/views/default/elements/components/userpicker.css index b52c4797102..0fcf8083a2b 100644 --- a/views/default/elements/components/userpicker.css +++ b/views/default/elements/components/userpicker.css @@ -1,5 +1,5 @@ /* *************************************** - USER PICKER + USER PICKER This view is deprecated and replaced by input/entitypicker.css *************************************** */ .elgg-user-picker-list { > li { diff --git a/views/default/elements/forms.css.php b/views/default/elements/forms.css.php index d0f3b2a8202..52a21e03016 100644 --- a/views/default/elements/forms.css.php +++ b/views/default/elements/forms.css.php @@ -250,6 +250,6 @@ li { + padding: 0 1rem; + border-bottom: 1px solid $(border-color-soft); + + &:first-child { + border-top: 1px solid $(border-color-soft); + margin-top: 0.5rem; + } + } +} + +.elgg-entity-picker.elgg-state-disabled { + > input, + > label { + display: none; + } +} diff --git a/views/default/input/entitypicker.js b/views/default/input/entitypicker.js new file mode 100644 index 00000000000..a31b69b6348 --- /dev/null +++ b/views/default/input/entitypicker.js @@ -0,0 +1,163 @@ +define(['jquery', 'elgg', 'elgg/Ajax', 'jquery-ui/widgets/autocomplete', 'jquery.ui.autocomplete.html'], function($, elgg, Ajax) { + /** + * @param {HTMLElement} wrapper outer div + * @constructor + * @alias module:elgg/UserPicker + */ + function EntityPicker(wrapper) { + this.$wrapper = $(wrapper); + this.$input = $('.elgg-input-entity-picker', wrapper); + this.$ul = $('.elgg-entity-picker-list', wrapper); + + var EntityPicker = this, + data = this.$wrapper.data(); + + this.name = data.name || 'entities'; + this.matchOn = data.matchOn || 'entities'; + this.handler = data.handler || 'livesearch'; + this.limit = data.limit || 0; + this.minLength = data.minLength || 2; + this.isSealed = false; + + this.$input.autocomplete({ + source: function(request, response) { + // note: "this" below will not be bound to the input, but rather + // to an object created by the autocomplete component + var Autocomplete = this; + + if (EntityPicker.isSealed) { + return; + } + + var ajax = new Ajax(); + ajax.path(EntityPicker.handler, { + data: { + term: Autocomplete.term, + match_on: EntityPicker.getSearchType(), + name: EntityPicker.name + }, + method: 'GET', + success: function(data) { + response(data); + } + }); + }, + minLength: EntityPicker.minLength, + html: 'html', + select: function(event, ui) { + EntityPicker.addEntity(event, ui.item.guid, ui.item.html); + }, + // turn off experimental live help - no i18n support and a little buggy + messages: { + noResults: '', + results: function() {} + } + }); + + this.$wrapper.on('click', '.elgg-autocomplete-item-remove', function(event) { + EntityPicker.removeEntity(event); + }); + + this.enforceLimit(); + } + + EntityPicker.prototype = { + /** + * Adds an entity to the selected entity list + * + * @param {Object} event + * @param {Number} guid GUID of autocomplete item selected by user + * @param {String} html HTML for autocomplete item selected by user + */ + addEntity: function(event, guid, html) { + if (event.isDefaultPrevented()) { + return; + } + + // do not allow entities to be added multiple times + if (!$('li[data-guid="' + guid + '"]', this.$ul).length) { + this.$ul.append(html); + } + + this.$input.val(''); + + this.enforceLimit(); + + event.preventDefault(); + }, + + /** + * Removes an entity from the selected entities list + * + * @param {Object} event + */ + removeEntity: function(event) { + $(event.target).closest('.elgg-entity-picker-list > li').remove(); + + this.enforceLimit(); + + event.preventDefault(); + }, + + /** + * Make sure user can't add more than limit + */ + enforceLimit: function() { + if (this.limit) { + if ($('li[data-guid]', this.$ul).length >= this.limit) { + if (!this.isSealed) { + this.seal(); + } + } else { + if (this.isSealed) { + this.unseal(); + } + } + } + }, + + /** + * Don't allow user to add entities + */ + seal: function() { + this.$input.prop('disabled', true); + this.$wrapper.addClass('elgg-state-disabled'); + this.isSealed = true; + }, + + /** + * Allow user to add entities + */ + unseal: function() { + this.$input.prop('disabled', false); + this.$wrapper.removeClass('elgg-state-disabled'); + this.isSealed = false; + }, + + /** + * Get search type + */ + getSearchType: function() { + if (this.$wrapper.has('[type="checkbox"][name="match_on"]:checked').length) { + return $('[type="checkbox"][name=match_on]:checked', this.$wrapper).val(); + } + + return this.matchOn; + } + }; + + /** + * @param {String} selector + */ + EntityPicker.setup = function(selector) { + $(selector).each(function () { + // we only want to wrap each picker once + if (!$(this).data('initialized')) { + new EntityPicker(this); + $(this).data('initialized', 1); + } + }); + }; + + return EntityPicker; +}); diff --git a/views/default/input/entitypicker.php b/views/default/input/entitypicker.php new file mode 100644 index 00000000000..fe45bcb4c5c --- /dev/null +++ b/views/default/input/entitypicker.php @@ -0,0 +1,86 @@ +getToken(); +} + +$params['view'] = 'json'; // force json viewtype + +$wrapper_options = [ + 'class' => elgg_extract_class($vars, ['elgg-entity-picker']), + 'data-limit' => (int) elgg_extract('limit', $vars, 0), + 'data-name' => $name, + 'data-match-on' => elgg_extract('match_on', $vars, 'entities', false), + 'data-handler' => elgg_http_add_url_query_elements(elgg_extract('handler', $vars, 'livesearch'), $params), +]; + +$picker = elgg_format_element('input', [ + 'type' => 'text', + 'class' => [ + 'elgg-input-entity-picker', + 'elgg-input-user-picker', // relying on this class is deprecated in Elgg 5.1 + ], + 'size' => 30, + 'id' => elgg_extract('id', $vars), + 'placeholder' => elgg_extract('placeholder', $vars), +]); + +$picker .= elgg_view('input/hidden', ['name' => $name]); +$picker .= elgg_extract('picker_extras', $vars, ''); + +$item_view = elgg_extract('item_view', $vars, 'input/autocomplete/item'); +$items = ''; +foreach ($guids as $guid) { + $entity = get_entity((int) $guid); + if (!$entity instanceof \ElggEntity) { + continue; + } + + $items .= elgg_view($item_view, [ + 'entity' => $entity, + 'input_name' => $name, + ]); +} + +$picker .= elgg_format_element('ul', ['class' => [ + 'elgg-list', + 'elgg-entity-picker-list', + 'elgg-user-picker-list', // relying on this class is deprecated in Elgg 5.1 +]], $items); + +echo elgg_format_element('div', $wrapper_options, $picker); + +?> + diff --git a/views/default/input/friendspicker.php b/views/default/input/friendspicker.php index 7daa203ce66..d4a60e11242 100644 --- a/views/default/input/friendspicker.php +++ b/views/default/input/friendspicker.php @@ -2,10 +2,7 @@ /** * Elgg friends picker * - * @uses $vars['values'] Array of user guids for already selected users or null - * @uses $vars['limit'] Limit number of users (default 0 = no limit) * @uses $vars['name'] Name of the returned data array (default "friend") - * @uses $vars['handler'] Name of page handler used to power search (default "livesearch") */ if (!isset($vars['name'])) { diff --git a/views/default/input/grouppicker.php b/views/default/input/grouppicker.php index 4b58dadd4e0..59bb888da21 100644 --- a/views/default/input/grouppicker.php +++ b/views/default/input/grouppicker.php @@ -12,9 +12,7 @@ $vars['name'] = 'groups'; } -$vars['show_friends'] = false; $vars['match_on'] = elgg_extract('match_on', $vars, 'groups'); $vars['class'] = elgg_extract_class($vars, ['elgg-group-picker']); -// @todo don't abuse userpicker, make it into generic entity picker -echo elgg_view('input/userpicker', $vars); +echo elgg_view('input/entitypicker', $vars); diff --git a/views/default/input/objectpicker.php b/views/default/input/objectpicker.php index 620d013cf53..a019619c9f9 100644 --- a/views/default/input/objectpicker.php +++ b/views/default/input/objectpicker.php @@ -13,7 +13,6 @@ $vars['name'] = 'guids'; } -$vars['show_friends'] = false; $vars['match_on'] = elgg_extract('match_on', $vars, 'objects'); $vars['class'] = elgg_extract_class($vars, ['elgg-object-picker']); @@ -22,5 +21,4 @@ $vars['options'] = $options; -// @todo don't abuse userpicker, make it into generic entity picker -echo elgg_view('input/userpicker', $vars); +echo elgg_view('input/entitypicker', $vars); diff --git a/views/default/input/userpicker.php b/views/default/input/userpicker.php index b34edb836c1..e6a9694ee21 100644 --- a/views/default/input/userpicker.php +++ b/views/default/input/userpicker.php @@ -1,104 +1,37 @@ getToken(); -} - -$handler = elgg_extract('handler', $vars, 'livesearch'); -$params['view'] = 'json'; // force json viewtype - -$wrapper_options = [ - 'class' => elgg_extract_class($vars, ['elgg-user-picker']), - 'data-limit' => (int) elgg_extract('limit', $vars, 0), - 'data-name' => $name, - 'data-handler' => elgg_http_add_url_query_elements($handler, $params), -]; - -$picker = elgg_format_element('input', [ - 'type' => 'text', - 'class' => 'elgg-input-user-picker', - 'size' => 30, - 'id' => elgg_extract('id', $vars), - 'placeholder' => elgg_extract('placeholder', $vars), -]); - -$picker .= elgg_view('input/hidden', ['name' => $name]); - +$default_match_on = 'users'; if ($show_friends) { - $picker .= elgg_view('input/checkbox', [ + $vars['picker_extras'] = elgg_view('input/checkbox', [ 'name' => 'match_on', 'value' => 'friends', 'default' => elgg_extract('match_on', $vars, 'users', false), 'label' => elgg_echo('userpicker:only_friends'), ]); -} elseif ($friends_only) { - $wrapper_options['data-match-on'] = 'friends'; -} else { - $wrapper_options['data-match-on'] = elgg_extract('match_on', $vars, 'users', false); +} elseif ($options['friends_only']) { + $default_match_on = 'friends'; } -$item_view = elgg_extract('item_view', $vars, 'input/autocomplete/item'); -$items = ''; -foreach ($guids as $guid) { - $entity = get_entity((int) $guid); - if (!$entity instanceof \ElggEntity) { - continue; - } - - $items .= elgg_view($item_view, [ - 'entity' => $entity, - 'input_name' => $name, - ]); +if (!isset($vars['name'])) { + $vars['name'] = 'members'; } -$picker .= elgg_format_element('ul', ['class' => 'elgg-list elgg-user-picker-list'], $items); - -echo elgg_format_element('div', $wrapper_options, $picker); +$vars['match_on'] = elgg_extract('match_on', $vars, $default_match_on); +$vars['class'] = elgg_extract_class($vars, ['elgg-user-picker']); +$vars['options'] = $options; -?> - +echo elgg_view('input/entitypicker', $vars); From 25d039b258ad14f77b0193222193deaccc375f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Mon, 10 Jul 2023 16:15:41 +0200 Subject: [PATCH 023/240] fix(icons): make sure transparent images have a white background There was a difference between GD and Imagick --- engine/classes/Elgg/ImageService.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engine/classes/Elgg/ImageService.php b/engine/classes/Elgg/ImageService.php index 28c078e2ed1..6299ae89da5 100644 --- a/engine/classes/Elgg/ImageService.php +++ b/engine/classes/Elgg/ImageService.php @@ -118,7 +118,12 @@ public function resize(string $source, string $destination = null, array $params } $target_size = new Box($max_width, $max_height); - $thumbnail = $image->resize($target_size); + $image->resize($target_size); + + // create new canvas with a background (default: white) + $background_color = elgg_extract('background_color', $params, 'ffffff'); + $thumbnail = $this->imagine->create($image->getSize(), $image->palette()->color($background_color)); + $thumbnail->paste($image, new Point(0, 0)); if (pathinfo($destination, PATHINFO_EXTENSION) === 'webp') { $options = [ From a2ee148f954432c3ce876c257c9da15b5671ffaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 11 Jul 2023 10:07:30 +0200 Subject: [PATCH 024/240] fix(site_notifications): return correct actor and only allow one actor per notification --- .../classes/SiteNotification.php | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mod/site_notifications/classes/SiteNotification.php b/mod/site_notifications/classes/SiteNotification.php index 6f5a811fab8..a0f7da50867 100644 --- a/mod/site_notifications/classes/SiteNotification.php +++ b/mod/site_notifications/classes/SiteNotification.php @@ -11,7 +11,7 @@ * @property bool $read Has this notification been read yet * @property int $linked_entity_guid Entity linked to this notification */ -class SiteNotification extends ElggObject { +class SiteNotification extends \ElggObject { const HAS_ACTOR = 'hasActor'; @@ -47,7 +47,7 @@ public function getURL(): string { } $linked_entity = $this->getLinkedEntity(); - if ($linked_entity instanceof ElggEntity) { + if ($linked_entity instanceof \ElggEntity) { return $linked_entity->getURL(); } @@ -57,25 +57,31 @@ public function getURL(): string { /** * Get the actor involved in the notification * - * @return ElggEntity|null + * @return \ElggEntity|null */ public function getActor(): ?\ElggEntity { - $actor = $this->getEntitiesFromRelationship(['relationship' => self::HAS_ACTOR]); - if ($actor) { - $actor = $actor[0]; + $actor = $this->getEntitiesFromRelationship([ + 'relationship' => self::HAS_ACTOR, + 'limit' => 1, + ]); + if (empty($actor)) { + return null; } - return $actor; + return $actor[0]; } /** * Set the actor involved in the notification * - * @param ElggEntity $entity Actor + * @param \ElggEntity $entity Actor * * @return void */ public function setActor(\ElggEntity $entity): void { + // there can only be one actor + $this->removeAllRelationships(self::HAS_ACTOR); + $this->addRelationship($entity->guid, self::HAS_ACTOR); } From d2d2320984994cbfe0cdcd2ec42d6cf1f277f9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 11 Jul 2023 13:35:47 +0200 Subject: [PATCH 025/240] fix(database): execute delayed queries immediately during CLI To help prevent OOM issues --- engine/classes/Elgg/Database.php | 40 ++++++++++++++----- engine/classes/ElggInstaller.php | 2 +- .../Integration/ElggDataFunctionsTest.php | 30 ++++++++++++-- .../phpunit/unit/Elgg/DatabaseUnitTest.php | 3 +- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/engine/classes/Elgg/Database.php b/engine/classes/Elgg/Database.php index 7ea8416a0b8..90498037a61 100644 --- a/engine/classes/Elgg/Database.php +++ b/engine/classes/Elgg/Database.php @@ -64,18 +64,22 @@ class Database { /** * @var \Elgg\Database\DbConfig $config Database configuration */ - private $config; + private $db_config; + + protected Config $config; /** * Constructor * - * @param DbConfig $config DB configuration + * @param DbConfig $db_config DB configuration * @param QueryCache $query_cache Query Cache + * @param Config $config Elgg config */ - public function __construct(DbConfig $config, QueryCache $query_cache) { + public function __construct(DbConfig $db_config, QueryCache $query_cache, Config $config) { $this->query_cache = $query_cache; + $this->config = $config; - $this->resetConnections($config); + $this->resetConnections($db_config); } /** @@ -88,7 +92,7 @@ public function __construct(DbConfig $config, QueryCache $query_cache) { public function resetConnections(DbConfig $config) { $this->closeConnections(); - $this->config = $config; + $this->db_config = $config; $this->table_prefix = $config->getTablePrefix(); $this->query_cache->enable(); $this->query_cache->clear(); @@ -138,7 +142,7 @@ public function getConnection(string $type): Connection { * @return void */ public function setupConnections(): void { - if ($this->config->isDatabaseSplit()) { + if ($this->db_config->isDatabaseSplit()) { $this->connect('read'); $this->connect('write'); } else { @@ -157,7 +161,7 @@ public function setupConnections(): void { * @throws DatabaseException */ public function connect(string $type = 'readwrite'): void { - $conf = $this->config->getConnectionConfig($type); + $conf = $this->db_config->getConnectionConfig($type); $params = [ 'dbname' => $conf['database'], @@ -465,6 +469,24 @@ public function trackQuery(QueryBuilder $query, callable $callback) { * @return void */ public function registerDelayedQuery(QueryBuilder $query, $callback = null): void { + if (Application::isCli() && !$this->config->testing_mode) { + // during CLI execute delayed queries immediately (unless in testing mode, during PHPUnit) + // this should prevent OOM during long-running jobs + // @see Database::executeDelayedQueries() + try { + $stmt = $this->executeQuery($query); + + if (is_callable($callback)) { + call_user_func($callback, $stmt); + } + } catch (\Throwable $t) { + // Suppress all exceptions to not allow the application to crash + $this->getLogger()->error($t); + } + + return; + } + $this->delayed_queries[] = [ self::DELAYED_QUERY => $query, self::DELAYED_HANDLER => $callback, @@ -489,9 +511,9 @@ public function executeDelayedQueries(): void { if (is_callable($handler)) { call_user_func($handler, $stmt); } - } catch (\Exception $e) { + } catch (\Throwable $t) { // Suppress all exceptions since page already sent to requestor - $this->getLogger()->error($e); + $this->getLogger()->error($t); } } diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index e527208432e..98a4cb40de2 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -1239,7 +1239,7 @@ protected function checkDatabaseSettings($user, $password, $dbname, $host, $port 'dbname' => $dbname, 'dbencoding' => 'utf8mb4', ]); - $db = new Database($config, $app->internal_services->queryCache); + $db = new Database($config, $app->internal_services->queryCache, $app->internal_services->config); try { $db->getConnection('read')->executeQuery('SELECT 1'); diff --git a/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php b/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php index 8a3619dadc6..0af52662123 100644 --- a/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php +++ b/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php @@ -145,10 +145,34 @@ public function testCanDelayQuery() { $captured = $stmt; return $stmt; }; - _elgg_services()->db->registerDelayedQuery($qb, $callback); - - _elgg_services()->db->executeDelayedQueries(); + + // get a reflector to check the contents of the delayed queries property + $database = _elgg_services()->db; + $reflector = new \ReflectionClass($database); + $delayed_queries = $reflector->getProperty('delayed_queries'); + $delayed_queries->setAccessible(true); + + $delayed_value = $delayed_queries->getValue($database); // backup + $delayed_queries->setValue($database, []); + + $this->assertIsArray($delayed_queries->getValue($database)); + $this->assertEmpty($delayed_queries->getValue($database)); + + // add query + $database->registerDelayedQuery($qb, $callback); + + $this->assertIsArray($delayed_queries->getValue($database)); + $this->assertCount(1, $delayed_queries->getValue($database)); + // execute query + $database->executeDelayedQueries(); + + $this->assertIsArray($delayed_queries->getValue($database)); + $this->assertEmpty($delayed_queries->getValue($database)); + + // restore old value + $delayed_queries->setValue($database, $delayed_value); + /* @var \Doctrine\DBAL\Result $captured */ $this->assertInstanceOf(\Doctrine\DBAL\Result::class, $captured); diff --git a/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php b/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php index 224df798a5e..79cafc46126 100644 --- a/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php @@ -65,7 +65,8 @@ private function getDbMock() { ->onlyMethods(['updateData']) ->setConstructorArgs([ new \Elgg\Database\DbConfig((object) ['dbprefix' => 'test_']), - _elgg_services()->queryCache + _elgg_services()->queryCache, + _elgg_services()->config, ]) ->getMock(); } From ba28f760f562e1c493d757d49c2f7b36b1ccc8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 11 Jul 2023 15:13:12 +0200 Subject: [PATCH 026/240] fix(user): prevent logging of changes to last_login and prev_last_login To save on database queries --- engine/classes/ElggUser.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index 6fd4d3a34e3..442d3151835 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -238,7 +238,6 @@ public function removeAdmin(): bool { * @return void */ public function setLastLogin(): void { - $time = $this->getCurrentTime()->getTimestamp(); if ($this->last_login == $time) { @@ -246,9 +245,11 @@ public function setLastLogin(): void { return; } - // these writes actually work, we just type hint read-only. - $this->prev_last_login = $this->last_login; - $this->last_login = $time; + elgg_call(ELGG_IGNORE_ACCESS | ELGG_DISABLE_SYSTEM_LOG, function() use ($time) { + // these writes actually work, we just type hint read-only. + $this->prev_last_login = $this->last_login; + $this->last_login = $time; + }); } /** From f0c348c03973328f07918894d5cbe65ed8a0e9af Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 12 Jul 2023 14:31:19 +0200 Subject: [PATCH 027/240] fix(admin): admin layout now gets correct layout class --- views/default/page/layouts/admin.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/views/default/page/layouts/admin.php b/views/default/page/layouts/admin.php index 102e7cedb2d..e1f764b440b 100644 --- a/views/default/page/layouts/admin.php +++ b/views/default/page/layouts/admin.php @@ -9,7 +9,6 @@ $class = elgg_extract_class($vars, [ 'elgg-layout', - 'elgg-layout-one-sidebar', 'elgg-layout-admin', ]); unset($vars['class']); @@ -22,6 +21,12 @@ $sidebar = elgg_view('page/layouts/elements/sidebar', $vars); $body = elgg_view('page/layouts/elements/body', $vars); +if ($sidebar) { + $class[] = 'elgg-layout-one-sidebar'; +} else { + $class[] = 'elgg-layout-one-column'; +} + $layout = elgg_format_element('div', ['class' => 'elgg-layout-columns'], $sidebar . $body); echo elgg_format_element('div', ['class' => $class], $header . $layout); From 708cb7ff51e8a98b946124f2bcf0c7f38b67f01c Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 13 Jul 2023 09:42:42 +0200 Subject: [PATCH 028/240] fix(settings): prevent setting changes from being added to the systemlog --- engine/classes/Elgg/Traits/Entity/PluginSettings.php | 8 ++++++-- engine/classes/ElggPlugin.php | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/engine/classes/Elgg/Traits/Entity/PluginSettings.php b/engine/classes/Elgg/Traits/Entity/PluginSettings.php index 0626500411a..edc6da5654f 100644 --- a/engine/classes/Elgg/Traits/Entity/PluginSettings.php +++ b/engine/classes/Elgg/Traits/Entity/PluginSettings.php @@ -28,7 +28,9 @@ public function setPluginSetting(string $plugin_id, string $name, $value): bool $name = $this->getNamespacedPluginSettingName($plugin_id, $name); - return $this->setMetadata($name, $value); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) { + return $this->setMetadata($name, $value); + }); } /** @@ -57,7 +59,9 @@ public function getPluginSetting(string $plugin_id, string $name, $default = nul public function removePluginSetting(string $plugin_id, string $name): bool { $name = $this->getNamespacedPluginSettingName($plugin_id, $name); - return $this->deleteMetadata($name); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) { + return $this->deleteMetadata($name); + }); } /** diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index 32e735b061c..356d7d7e852 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -345,7 +345,9 @@ public function setSetting(string $name, $value): bool { return false; } - return $this->setMetadata($name, $value); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) { + return $this->setMetadata($name, $value); + }); } /** @@ -356,7 +358,9 @@ public function setSetting(string $name, $value): bool { * @return bool */ public function unsetSetting(string $name): bool { - return (bool) $this->deleteMetadata($name); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) { + return (bool) $this->deleteMetadata($name); + }); } /** From 5319f0eaf69071602b410a88857511ca80e8358a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 13 Jul 2023 15:31:55 +0200 Subject: [PATCH 029/240] fix(composer): no longer try to symlink the mods on Windows --- engine/classes/Elgg/Composer/PostInstall.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/engine/classes/Elgg/Composer/PostInstall.php b/engine/classes/Elgg/Composer/PostInstall.php index ee16e6fd0cf..9a9b55569b0 100644 --- a/engine/classes/Elgg/Composer/PostInstall.php +++ b/engine/classes/Elgg/Composer/PostInstall.php @@ -25,10 +25,12 @@ public static function execute(Event $event) { self::createProjectModFolder(); - $managed_plugins = \Elgg\Database\Plugins::BUNDLED_PLUGINS; - - foreach ($managed_plugins as $plugin) { - self::symlinkPluginFromRootToElgg($plugin); + if (stripos(PHP_OS, 'win') !== 0) { + // symlink the mods from Elgg /mod to the project /mod + $managed_plugins = \Elgg\Database\Plugins::BUNDLED_PLUGINS; + foreach ($managed_plugins as $plugin) { + self::symlinkPluginFromRootToElgg($plugin); + } } } From e2c52b9fd087b7fd36ee0c962a5f0306eb9fb5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 14 Jul 2023 08:24:36 +0200 Subject: [PATCH 030/240] chore(release): v5.0.3 --- CHANGELOG.md | 21 ++++++++++++++++++++ composer.json | 2 +- composer.lock | 55 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14008e779fc..8564125153c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ + +### 5.0.3 (2023-07-14) + +#### Contributors + +* Jerôme Bakker (7) +* Jeroen Dalsem (3) + +#### Bug Fixes + +* **admin:** admin layout now gets correct layout class ([f0c348c0](https://github.com/Elgg/Elgg/commit/f0c348c03973328f07918894d5cbe65ed8a0e9af)) +* **composer:** no longer try to symlink the mods on Windows ([5319f0ea](https://github.com/Elgg/Elgg/commit/5319f0eaf69071602b410a88857511ca80e8358a)) +* **database:** execute delayed queries immediately during CLI ([d2d23209](https://github.com/Elgg/Elgg/commit/d2d2320984994cbfe0cdcd2ec42d6cf1f277f9dc)) +* **email:** image styles will be converted to attributes if possible ([f306388b](https://github.com/Elgg/Elgg/commit/f306388b51d08aeb2a28154a83793775315423a8)) +* **http:** maintain set redirect code in response ([c4ad5037](https://github.com/Elgg/Elgg/commit/c4ad5037bbaa04343c733358931f513765932a19)) +* **icons:** make sure transparent images have a white background ([25d039b2](https://github.com/Elgg/Elgg/commit/25d039b258ad14f77b0193222193deaccc375f9b)) +* **settings:** prevent setting changes from being added to the systemlog ([708cb7ff](https://github.com/Elgg/Elgg/commit/708cb7ff51e8a98b946124f2bcf0c7f38b67f01c)) +* **site_notifications:** return correct actor ([a2ee148f](https://github.com/Elgg/Elgg/commit/a2ee148f954432c3ce876c257c9da15b5671ffaa)) +* **user:** prevent logging of changes to last_login and prev_last_login ([ba28f760](https://github.com/Elgg/Elgg/commit/ba28f760f562e1c493d757d49c2f7b36b1ccc8ba)) + + ### 5.0.2 (2023-07-03) diff --git a/composer.json b/composer.json index 228fd0434ff..7f5163f19ad 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "5.0.2", + "version": "5.0.3", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 92b7a4b1652..2f6e79a8647 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "322b39d6f08ec2afc45d6066207de9c9", + "content-hash": "9bdb13390b2a5080760718ae1bb23a3d", "packages": [ { "name": "cakephp/core", @@ -3648,6 +3648,7 @@ "admidio/admidio": "<4.2.9", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", "aheinze/cockpit": "<=2.2.1", + "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", "alextselegidis/easyappointments": "<1.5", @@ -3664,7 +3665,10 @@ "appwrite/server-ce": "<=1.2.1", "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", + "artesaos/seotools": "<0.17.2", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "athlon1600/php-proxy": "<=5.1", + "athlon1600/php-proxy-app": "<=3", "automad/automad": "<1.8", "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": ">=3,<3.2.1", @@ -3696,6 +3700,7 @@ "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", + "cardgate/woocommerce": "<=3.1.15", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", @@ -3716,6 +3721,7 @@ "contao/core-bundle": "<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", + "cosenary/instagram": "<=2.3", "craftcms/cms": "<=4.4.9|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", "croogo/croogo": "<3.0.7", "cuyz/valinor": "<0.12", @@ -3727,6 +3733,7 @@ "dcat/laravel-admin": "<=2.1.3-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "desperado/xml-bundle": "<=0.1.7", "directmailteam/direct-mail": "<5.2.4", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", @@ -3807,6 +3814,7 @@ "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", "globalpayments/php-sdk": "<2", + "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<2.2.1", @@ -3814,6 +3822,7 @@ "grumpydictator/firefly-iii": "<6", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", + "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", "helloxz/imgurl": "= 2.31|<=2.31", "hhxsv5/laravel-s": "<3.7.36", @@ -3835,7 +3844,7 @@ "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "impresscms/impresscms": "<=1.4.3", + "impresscms/impresscms": "<=1.4.5", "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.1", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", @@ -3859,7 +3868,7 @@ "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", "kimai/kimai": "<1.1", - "kitodo/presentation": "<3.1.2", + "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<1.4.2", "krayin/laravel-crm": "<1.2.2", @@ -3872,10 +3881,11 @@ "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", - "lavalite/cms": "<=9", + "lavalite/cms": "= 9.0.0|<=9", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", + "league/oauth2-server": ">=8.3.2,<8.5.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "librenms/librenms": "<22.10", "liftkit/database": "<2.13.2", @@ -3885,7 +3895,7 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", + "magento/community-edition": "<=2.4", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", @@ -3894,21 +3904,22 @@ "marcwillmann/turn": "<0.3.3", "matyhtf/framework": "<3.0.6", "mautic/core": "<4.3|= 2.13.1", - "mediawiki/core": "<=1.39.3", + "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", "mediawiki/matomo": "<2.4.3", "melisplatform/melis-asset-manager": "<5.0.1", "melisplatform/melis-cms": "<5.0.1", "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "<=1.3.4", + "microweber/microweber": "= 1.1.18|<=1.3.4", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", "modx/revolution": "<= 2.8.3-pl|<2.8", "mojo42/jirafeau": "<4.4", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.2-rc.2|= 4.2.0|= 3.11", + "moodle/moodle": "<4.2-rc.2|= 3.9|= 3.8|= 4.2.0|= 3.11", + "movim/moxl": ">=0.8,<=0.10", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", @@ -3920,7 +3931,7 @@ "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<3.0.9", + "nilsteampassnet/teampass": "<3.0.10", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", "nukeviet/nukeviet": "<4.5.2", @@ -3938,7 +3949,8 @@ "opencart/opencart": "<=3.0.3.7", "openid/php-openid": "<2.3", "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", - "orchid/platform": ">=9,<9.4.4", + "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", + "orchid/platform": ">=9,<9.4.4|>=14-alpha.4,<14.5", "oro/commerce": ">=4.1,<5.0.6", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", @@ -3951,11 +3963,12 @@ "paypal/merchant-sdk-php": "<3.12", "pear/archive_tar": "<1.4.14", "pear/crypt_gpg": "<1.6.7", + "pear/pear": "<=1.10.1", "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", "php-mod/curl": "<2.3.2", - "phpbb/phpbb": ">=3.2,<3.2.10|>=3.3,<3.3.1", + "phpbb/phpbb": "<3.2.10|>=3.3,<3.3.1", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", @@ -3964,13 +3977,15 @@ "phpoffice/phpexcel": "<1.8", "phpoffice/phpspreadsheet": "<1.16", "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.19", - "phpservermon/phpservermon": "<=3.5.2", + "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.2.5", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", - "pimcore/customer-management-framework-bundle": "<3.3.10", + "pi/pi": "<=2.5", + "pimcore/admin-ui-classic-bundle": "<1.0.3", + "pimcore/customer-management-framework-bundle": "<3.4.1", "pimcore/data-hub": "<1.2.4", "pimcore/perspective-editor": "<1.5.1", "pimcore/pimcore": "<10.5.23", @@ -3998,6 +4013,7 @@ "pyrocms/pyrocms": "<=3.9.1", "rainlab/debugbar-plugin": "<3.1", "rankmath/seo-by-rank-math": "<=1.0.95", + "rap2hpoutre/laravel-log-viewer": "<0.13", "react/http": ">=0.7,<1.9", "really-simple-plugins/complianz-gdpr": "<6.4.2", "remdex/livehelperchat": "<3.99", @@ -4008,7 +4024,7 @@ "s-cart/core": "<6.9", "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "sabre/dav": "<1.7.11|>=1.8,<1.8.9", "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", @@ -4054,9 +4070,10 @@ "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "ssddanbrown/bookstack": "<22.2.3", - "statamic/cms": "<3.2.39|>=3.3,<3.3.2", + "statamic/cms": "<4.10", "stormpath/sdk": ">=0,<9.9.99", "studio-42/elfinder": "<2.1.62", + "subhh/libconnect": "<7.0.8|>=8,<8.1", "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", @@ -4125,7 +4142,7 @@ "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<=6.2.38|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": "<8.7.51|>=9,<9.5.40|>=10,<10.4.36|>=11,<11.5.23|>=12,<12.2", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", @@ -4145,7 +4162,7 @@ "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<2.5.4", + "wallabag/wallabag": "<=2.5.4", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", @@ -4153,9 +4170,10 @@ "webklex/laravel-imap": "<5.3", "webklex/php-imap": "<5.3", "webpa/webpa": "<3.1.2", + "wikibase/wikibase": "<=1.39.3", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", - "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1", + "wintercms/winter": "<1.2.3", "woocommerce/woocommerce": "<6.6", "wp-cli/wp-cli": "<2.5", "wp-graphql/wp-graphql": "<=1.14.5", @@ -4179,6 +4197,7 @@ "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", "yourls/yourls": "<=1.8.2", + "zencart/zencart": "<1.5.8", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", From 6ee26b94637a384af133187afb9fab766ef324da Mon Sep 17 00:00:00 2001 From: Nikolai Shcherbin Date: Mon, 17 Jul 2023 14:36:04 +0300 Subject: [PATCH 031/240] fix(admin): use correct params for memcache and redis server information --- docs/admin/performance.rst | 10 ++++++++-- views/default/admin/server/memcache.php | 2 +- views/default/admin/server/redis.php | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/admin/performance.rst b/docs/admin/performance.rst index a560ecd6153..666cae47453 100644 --- a/docs/admin/performance.rst +++ b/docs/admin/performance.rst @@ -188,8 +188,14 @@ Uncomment and populate the following sections in ``settings.php`` $CONFIG->memcache = true; $CONFIG->memcache_servers = array ( - array('server1', 11211), - array('server2', 11211) + array ( + 'host' => 'server1', + 'port' => 11211 + ), + array ( + 'host' => 'server2', + 'port' => 11211 + ) ); Optionaly if you run multiple Elgg installations but use ony one Memcache server, you may want diff --git a/views/default/admin/server/memcache.php b/views/default/admin/server/memcache.php index f9810ba59a3..17870250fb2 100644 --- a/views/default/admin/server/memcache.php +++ b/views/default/admin/server/memcache.php @@ -15,7 +15,7 @@ } foreach ($servers as $server) { - $memcache->addserver($server[0], $server[1]); + $memcache->addserver($server['host'], $server['port']); } if ($memcache instanceof Memcache) { diff --git a/views/default/admin/server/redis.php b/views/default/admin/server/redis.php index 6fd52693f75..2bf8b2019dc 100644 --- a/views/default/admin/server/redis.php +++ b/views/default/admin/server/redis.php @@ -12,7 +12,7 @@ $redis = new Redis(); foreach ($servers as $server) { - $redis->connect($server[0], $server[1]); + $redis->connect($server['host'], $server['port']); } $password = elgg_extract('password', elgg_get_config('redis_options')); From 6fff94290017df4a9bf879236b73c1f0be92c62e Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 17 Jul 2023 14:23:56 +0200 Subject: [PATCH 032/240] fix(ckeditor): added all block level image alignments to toolbar --- mod/ckeditor/views/default/ckeditor/config/base.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mod/ckeditor/views/default/ckeditor/config/base.js b/mod/ckeditor/views/default/ckeditor/config/base.js index 6e2afb5859e..bf031603219 100644 --- a/mod/ckeditor/views/default/ckeditor/config/base.js +++ b/mod/ckeditor/views/default/ckeditor/config/base.js @@ -10,7 +10,16 @@ define(['elgg'], function(elgg) { } }, image: { - toolbar: ['toggleImageCaption', 'imageTextAlternative', 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side', 'linkImage'], + toolbar: ['toggleImageCaption', 'imageTextAlternative', { + title: '', + name: 'imageStyle:alignment', + items: [ + 'imageStyle:alignBlockLeft', + 'imageStyle:block', + 'imageStyle:alignBlockRight', + ], + defaultItem: 'imageStyle:alignBlockLeft' + }, 'imageStyle:side', 'linkImage'], resizeUnit: 'px' }, link: { From ffe94eab174e0984cf288585fd91d24ac8d07a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 18 Jul 2023 10:19:34 +0200 Subject: [PATCH 033/240] fix(views): only generate listing ID when using pagination Will help to prevent duplicate IDs in widgets --- views/default/page/components/list.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/views/default/page/components/list.php b/views/default/page/components/list.php index b165842bd1d..536be82eeb6 100644 --- a/views/default/page/components/list.php +++ b/views/default/page/components/list.php @@ -117,16 +117,20 @@ $base_url = elgg_http_add_url_query_elements($base_url, ['offset' => null, 'limit' => null]); } -$id = elgg_build_hmac([ - $list_classes, - $list_item_view, - elgg_extract('item_view', $vars), - elgg_extract('type', $vars), - elgg_extract('subtype', $vars), - elgg_extract('offset_key', $vars), - elgg_extract('pagination_class', $vars), - $base_url, -])->getToken(); +// make a unique ID for AJAX pagination +$id = null; +if ($pagination) { + $id = 'list-container-' . elgg_build_hmac([ + $list_classes, + $list_item_view, + elgg_extract('item_view', $vars), + elgg_extract('type', $vars), + elgg_extract('subtype', $vars), + elgg_extract('offset_key', $vars), + elgg_extract('pagination_class', $vars), + $base_url, + ])->getToken(); +} $container_classes = ['elgg-list-container']; if ($pagination && ($pagination_behaviour !== 'navigate')) { @@ -141,4 +145,4 @@ } } -echo elgg_format_element('div', ['class' => $container_classes, 'id' => "list-container-{$id}"], $result); +echo elgg_format_element('div', ['class' => $container_classes, 'id' => $id], $result); From e72f476eb62ce5e8253deaf7ea9ca71fe70c79c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 18 Jul 2023 11:06:19 +0200 Subject: [PATCH 034/240] fix(views): correctly set iframe width for PHPInfo --- views/default/admin/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/default/admin/server.php b/views/default/admin/server.php index 42f805e673f..ccb5ac606d6 100644 --- a/views/default/admin/server.php +++ b/views/default/admin/server.php @@ -25,7 +25,7 @@ 'text' => elgg_echo('admin:server:label:phpinfo'), 'content' => elgg_view('output/iframe', [ 'src' => elgg_generate_url('phpinfo'), - 'width' => '100%', + 'style' => 'width: 100%;', 'height' => '2000px', ]), ]; From 1cee1be17474da910172dd5cc829f10a67c7fd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 18 Jul 2023 11:28:53 +0200 Subject: [PATCH 035/240] fix(views): allow mobile devices to zoom --- engine/classes/Elgg/Page/AddMetasHandler.php | 2 +- views/installation/page/elements/head.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/classes/Elgg/Page/AddMetasHandler.php b/engine/classes/Elgg/Page/AddMetasHandler.php index 388f0ff76cd..7a0b0e970aa 100644 --- a/engine/classes/Elgg/Page/AddMetasHandler.php +++ b/engine/classes/Elgg/Page/AddMetasHandler.php @@ -35,7 +35,7 @@ public function __invoke(\Elgg\Event $event) { // https://developer.chrome.com/multidevice/android/installtohomescreen $head_params['metas']['viewport'] = [ 'name' => 'viewport', - 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0', + 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=1', ]; $head_params['metas']['mobile-web-app-capable'] = [ diff --git a/views/installation/page/elements/head.php b/views/installation/page/elements/head.php index eb65653d805..7791023ab40 100644 --- a/views/installation/page/elements/head.php +++ b/views/installation/page/elements/head.php @@ -18,7 +18,7 @@ echo elgg_format_element('meta', [ 'name' => 'viewport', - 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0', + 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=1', ]); echo elgg_format_element('link', [ From 0cc105c8b684ed756b4839c1d72df714f17a1865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 18 Jul 2023 11:53:06 +0200 Subject: [PATCH 036/240] fix(views): make sure the icon cropper img has an alt text --- languages/en.php | 1 + views/default/entity/edit/icon/crop.php | 1 + 2 files changed, 2 insertions(+) diff --git a/languages/en.php b/languages/en.php index b1d183d0ffe..4fb6c4d2fe0 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1072,6 +1072,7 @@ 'entity:edit:icon:crop_messages:generic' => "The selected image doesn't meet the recommended image dimensions. This could result in low quality icons.", 'entity:edit:icon:crop_messages:width' => "It's recommended to use an image with a minimal width of at least %dpx.", 'entity:edit:icon:crop_messages:height' => "It's recommended to use an image with a minimal height of at least %dpx.", + 'entity:edit:icon:crop:img:alt' => "Uploaded image", 'entity:edit:icon:file:label' => "Upload a new icon", 'entity:edit:icon:file:help' => "Leave blank to keep current icon.", 'entity:edit:icon:remove:label' => "Remove icon", diff --git a/views/default/entity/edit/icon/crop.php b/views/default/entity/edit/icon/crop.php index 35aa949b27e..952de195d93 100644 --- a/views/default/entity/edit/icon/crop.php +++ b/views/default/entity/edit/icon/crop.php @@ -129,6 +129,7 @@ $img = elgg_format_element('img', [ 'data-icon-cropper' => json_encode($cropper_data), 'src' => $img_url, + 'alt' => elgg_echo('entity:edit:icon:crop:img:alt'), ]); echo elgg_format_element('div', ['class' => ['elgg-entity-edit-icon-crop-wrapper', 'hidden', 'mbm']], $img); From 924b2cdcae2a97447a2094b7389fe9ebb1d2f74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 18 Jul 2023 17:11:14 +0200 Subject: [PATCH 037/240] fix(views): input/button and output/url must have discernible text --- engine/classes/Elgg/Menu/Service.php | 1 + engine/classes/Elgg/Menus/Title.php | 1 + mod/blog/views/default/forms/blog/save.php | 6 ++++-- .../views/default/forms/bookmarks/save.php | 2 +- mod/developers/views/default/developers/ajax.php | 2 +- .../default/forms/developers/entity_explorer.php | 2 +- .../views/default/forms/developers/settings.php | 2 +- .../views/default/theme_sandbox/buttons.php | 2 +- .../views/default/theme_sandbox/forms.php | 2 +- .../views/default/forms/discussion/save.php | 2 +- mod/file/views/default/forms/file/upload.php | 2 +- .../default/forms/friends/collections/edit.php | 2 +- mod/groups/views/default/forms/groups/edit.php | 2 +- mod/groups/views/default/forms/groups/find.php | 2 +- mod/groups/views/default/forms/groups/invite.php | 2 +- mod/groups/views/default/forms/groups/search.php | 2 +- .../forms/settings/notifications/groups.php | 2 +- .../views/default/forms/friends/invite.php | 2 +- .../views/default/forms/members/search.php | 2 +- .../views/default/forms/messageboard/add.php | 2 +- .../views/default/forms/messages/process.php | 2 +- .../views/default/forms/messages/reply.php | 2 +- .../views/default/forms/messages/send.php | 2 +- mod/pages/views/default/forms/pages/edit.php | 2 +- mod/profile/views/default/forms/profile/edit.php | 3 +-- .../views/default/forms/profile/edit/header.php | 2 +- .../views/default/forms/profile/fields/add.php | 2 +- .../views/default/forms/reportedcontent/add.php | 4 ++-- mod/search/views/default/forms/search.php | 3 ++- .../default/forms/site_notifications/process.php | 2 +- .../views/default/forms/logbrowser/refine.php | 2 +- .../default/forms/webservices/api_key/edit.php | 2 +- views/default/forms/admin/menu/save.php | 2 +- views/default/forms/admin/security/settings.php | 2 +- views/default/forms/admin/site/icons.php | 2 +- .../forms/admin/site/set_maintenance_mode.php | 2 +- views/default/forms/admin/site/set_robots.php | 2 +- views/default/forms/admin/site/settings.php | 2 +- views/default/forms/admin/user/change_email.php | 2 +- views/default/forms/avatar/upload.php | 2 +- views/default/forms/comment/save.php | 6 +++--- views/default/forms/login.php | 2 +- views/default/forms/notifications/mute.php | 2 +- views/default/forms/plugins/settings/save.php | 2 +- views/default/forms/register.php | 2 +- views/default/forms/settings/notifications.php | 2 +- .../forms/settings/notifications/users.php | 2 +- views/default/forms/user/changepassword.php | 2 +- views/default/forms/user/delete.php | 2 +- views/default/forms/user/requestnewpassword.php | 2 +- views/default/forms/useradd.php | 2 +- views/default/forms/usersettings/save.php | 2 +- views/default/forms/widgets/save.php | 2 +- views/default/icon/user/default.php | 2 +- views/default/input/button.php | 15 +++++++++++---- views/default/output/url.php | 8 ++++++-- views/installation/forms/install/template.php | 2 +- 57 files changed, 79 insertions(+), 64 deletions(-) diff --git a/engine/classes/Elgg/Menu/Service.php b/engine/classes/Elgg/Menu/Service.php index 4466d2bcb2f..5b6b365ce8b 100644 --- a/engine/classes/Elgg/Menu/Service.php +++ b/engine/classes/Elgg/Menu/Service.php @@ -229,6 +229,7 @@ protected function prepareDropdownMenu(PreparedMenu $menu, array $params): Prepa 'icon' => 'ellipsis-v', 'href' => false, 'text' => '', + 'title' => elgg_echo('more'), 'child_menu' => [ 'display' => 'dropdown', 'data-position' => json_encode([ diff --git a/engine/classes/Elgg/Menus/Title.php b/engine/classes/Elgg/Menus/Title.php index dddda2a7bb8..1f27d7d2aca 100644 --- a/engine/classes/Elgg/Menus/Title.php +++ b/engine/classes/Elgg/Menus/Title.php @@ -99,6 +99,7 @@ public static function registerEntityToTitle(\Elgg\Event $event) { 'icon' => 'ellipsis-v', 'href' => false, 'text' => '', + 'title' => elgg_echo('more'), 'child_menu' => [ 'display' => 'dropdown', 'data-position' => json_encode([ diff --git a/mod/blog/views/default/forms/blog/save.php b/mod/blog/views/default/forms/blog/save.php index c514610b443..54911002337 100644 --- a/mod/blog/views/default/forms/blog/save.php +++ b/mod/blog/views/default/forms/blog/save.php @@ -101,15 +101,17 @@ $footer = elgg_format_element('div', ['class' => ['elgg-subtext', 'mbm']], elgg_echo('blog:save_status') . ' ' . $saved); $footer .= elgg_view('input/submit', [ - 'value' => elgg_echo('save'), 'name' => 'save', + 'value' => 1, + 'text' => elgg_echo('save'), ]); // published blogs do not get the preview button if (!$blog instanceof \ElggBlog || $blog->status != 'published') { $footer .= elgg_view('input/button', [ - 'value' => elgg_echo('preview'), 'name' => 'preview', + 'value' => 1, + 'text' => elgg_echo('preview'), 'class' => 'elgg-button-action mls', ]); } diff --git a/mod/bookmarks/views/default/forms/bookmarks/save.php b/mod/bookmarks/views/default/forms/bookmarks/save.php index 40abde73ee3..c717c528a56 100644 --- a/mod/bookmarks/views/default/forms/bookmarks/save.php +++ b/mod/bookmarks/views/default/forms/bookmarks/save.php @@ -64,6 +64,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/developers/views/default/developers/ajax.php b/mod/developers/views/default/developers/ajax.php index deb3f8024b9..399dd4b8b32 100644 --- a/mod/developers/views/default/developers/ajax.php +++ b/mod/developers/views/default/developers/ajax.php @@ -8,7 +8,7 @@ $resize_button = elgg_view('input/button', [ 'id' => 'elgg-lightbox-test-resize', 'class' => 'elgg-button elgg-button-action', - 'value' => 'Add extra content and resize', + 'text' => 'Add extra content and resize', ]); echo '
    '; diff --git a/mod/developers/views/default/forms/developers/entity_explorer.php b/mod/developers/views/default/forms/developers/entity_explorer.php index 3fda16e3b87..fb22ec277c5 100644 --- a/mod/developers/views/default/forms/developers/entity_explorer.php +++ b/mod/developers/views/default/forms/developers/entity_explorer.php @@ -9,7 +9,7 @@ ]); $footer = elgg_view('input/submit', [ - 'value' => elgg_echo('submit'), + 'text' => elgg_echo('submit'), ]); elgg_set_form_footer($footer); diff --git a/mod/developers/views/default/forms/developers/settings.php b/mod/developers/views/default/forms/developers/settings.php index d6fa4140b30..08af9ccca5e 100644 --- a/mod/developers/views/default/forms/developers/settings.php +++ b/mod/developers/views/default/forms/developers/settings.php @@ -33,7 +33,7 @@ // form footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('developers:label:submit'), + 'text' => elgg_echo('developers:label:submit'), ]); elgg_set_form_footer($footer); diff --git a/mod/developers/views/default/theme_sandbox/buttons.php b/mod/developers/views/default/theme_sandbox/buttons.php index e2213d784d2..8e41c39460e 100644 --- a/mod/developers/views/default/theme_sandbox/buttons.php +++ b/mod/developers/views/default/theme_sandbox/buttons.php @@ -13,7 +13,7 @@ $getButton = function(array $options = []) { $vars = [ - 'value' => elgg_echo('submit'), + 'text' => elgg_echo('submit'), ]; return elgg_view('input/button', array_merge($vars, $options)); diff --git a/mod/developers/views/default/theme_sandbox/forms.php b/mod/developers/views/default/theme_sandbox/forms.php index 3b056be9f6f..041eadf7e9e 100644 --- a/mod/developers/views/default/theme_sandbox/forms.php +++ b/mod/developers/views/default/theme_sandbox/forms.php @@ -722,7 +722,7 @@ ]); $body .= elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('submit'), + 'text' => elgg_echo('submit'), ]); echo elgg_view('input/form', [ diff --git a/mod/discussions/views/default/forms/discussion/save.php b/mod/discussions/views/default/forms/discussion/save.php index ba026ed9c95..87d47a32ad5 100644 --- a/mod/discussions/views/default/forms/discussion/save.php +++ b/mod/discussions/views/default/forms/discussion/save.php @@ -111,6 +111,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/file/views/default/forms/file/upload.php b/mod/file/views/default/forms/file/upload.php index b6072909765..50cc9d0b145 100644 --- a/mod/file/views/default/forms/file/upload.php +++ b/mod/file/views/default/forms/file/upload.php @@ -82,6 +82,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => $submit_label, + 'text' => $submit_label, ]); elgg_set_form_footer($footer); diff --git a/mod/friends_collections/views/default/forms/friends/collections/edit.php b/mod/friends_collections/views/default/forms/friends/collections/edit.php index 78dd1b568e5..5b83d939dda 100644 --- a/mod/friends_collections/views/default/forms/friends/collections/edit.php +++ b/mod/friends_collections/views/default/forms/friends/collections/edit.php @@ -32,6 +32,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/groups/views/default/forms/groups/edit.php b/mod/groups/views/default/forms/groups/edit.php index 35697ea07ff..eeedc2564de 100644 --- a/mod/groups/views/default/forms/groups/edit.php +++ b/mod/groups/views/default/forms/groups/edit.php @@ -82,7 +82,7 @@ '#type' => 'button', 'id' => 'elgg-groups-edit-footer-navigate-next', 'icon_alt' => 'chevron-right', - 'value' => elgg_echo('next'), + 'text' => elgg_echo('next'), 'class' => 'elgg-button-action', ], ], diff --git a/mod/groups/views/default/forms/groups/find.php b/mod/groups/views/default/forms/groups/find.php index ca6f9ad1a4f..4a285ecf2d1 100644 --- a/mod/groups/views/default/forms/groups/find.php +++ b/mod/groups/views/default/forms/groups/find.php @@ -13,7 +13,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('search:go'), + 'text' => elgg_echo('search:go'), ]); elgg_set_form_footer($footer); diff --git a/mod/groups/views/default/forms/groups/invite.php b/mod/groups/views/default/forms/groups/invite.php index 53b46e4e599..3a38ed9d991 100644 --- a/mod/groups/views/default/forms/groups/invite.php +++ b/mod/groups/views/default/forms/groups/invite.php @@ -50,7 +50,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('invite'), + 'text' => elgg_echo('invite'), ]); elgg_set_form_footer($footer); diff --git a/mod/groups/views/default/forms/groups/search.php b/mod/groups/views/default/forms/groups/search.php index 63027f26fb3..07bfc1f3233 100644 --- a/mod/groups/views/default/forms/groups/search.php +++ b/mod/groups/views/default/forms/groups/search.php @@ -25,7 +25,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('search:go'), + 'text' => elgg_echo('search:go'), ]); elgg_set_form_footer($footer); diff --git a/mod/groups/views/default/forms/settings/notifications/groups.php b/mod/groups/views/default/forms/settings/notifications/groups.php index f811f173fa2..e84b9c9650f 100644 --- a/mod/groups/views/default/forms/settings/notifications/groups.php +++ b/mod/groups/views/default/forms/settings/notifications/groups.php @@ -70,7 +70,7 @@ function(QueryBuilder $qb) { // form footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/invitefriends/views/default/forms/friends/invite.php b/mod/invitefriends/views/default/forms/friends/invite.php index e2aca4b6496..9c7af06ba98 100644 --- a/mod/invitefriends/views/default/forms/friends/invite.php +++ b/mod/invitefriends/views/default/forms/friends/invite.php @@ -30,7 +30,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('send'), + 'text' => elgg_echo('send'), ]); elgg_set_form_footer($footer); diff --git a/mod/members/views/default/forms/members/search.php b/mod/members/views/default/forms/members/search.php index 0f6e07e8d85..a93abd49368 100644 --- a/mod/members/views/default/forms/members/search.php +++ b/mod/members/views/default/forms/members/search.php @@ -9,7 +9,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('search'), + 'text' => elgg_echo('search'), ]); $footer .= elgg_format_element('p', [ diff --git a/mod/messageboard/views/default/forms/messageboard/add.php b/mod/messageboard/views/default/forms/messageboard/add.php index d7b681b04ea..2b50eb0b16a 100644 --- a/mod/messageboard/views/default/forms/messageboard/add.php +++ b/mod/messageboard/views/default/forms/messageboard/add.php @@ -20,7 +20,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('post'), + 'text' => elgg_echo('post'), ]); elgg_set_form_footer($footer); diff --git a/mod/messages/views/default/forms/messages/process.php b/mod/messages/views/default/forms/messages/process.php index bcbc1a61a31..8bee87332ea 100644 --- a/mod/messages/views/default/forms/messages/process.php +++ b/mod/messages/views/default/forms/messages/process.php @@ -35,7 +35,7 @@ $buttons[] = [ '#type' => 'button', - 'value' => elgg_echo('messages:toggle'), + 'text' => elgg_echo('messages:toggle'), 'class' => 'elgg-button-cancel', 'id' => 'messages-toggle', ]; diff --git a/mod/messages/views/default/forms/messages/reply.php b/mod/messages/views/default/forms/messages/reply.php index 08074fad75d..3a997de6c0e 100644 --- a/mod/messages/views/default/forms/messages/reply.php +++ b/mod/messages/views/default/forms/messages/reply.php @@ -49,7 +49,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('send'), + 'text' => elgg_echo('send'), ]); elgg_set_form_footer($footer); diff --git a/mod/messages/views/default/forms/messages/send.php b/mod/messages/views/default/forms/messages/send.php index 875f4e36782..e06db99f3b0 100644 --- a/mod/messages/views/default/forms/messages/send.php +++ b/mod/messages/views/default/forms/messages/send.php @@ -44,7 +44,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('send'), + 'text' => elgg_echo('send'), ]); elgg_set_form_footer($footer); diff --git a/mod/pages/views/default/forms/pages/edit.php b/mod/pages/views/default/forms/pages/edit.php index ff14ba0fca2..63c219b341b 100644 --- a/mod/pages/views/default/forms/pages/edit.php +++ b/mod/pages/views/default/forms/pages/edit.php @@ -68,6 +68,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/profile/views/default/forms/profile/edit.php b/mod/profile/views/default/forms/profile/edit.php index 82e385a057a..7bff16d8e20 100644 --- a/mod/profile/views/default/forms/profile/edit.php +++ b/mod/profile/views/default/forms/profile/edit.php @@ -75,7 +75,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), - '#class' => 'elgg-foot', + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/profile/views/default/forms/profile/edit/header.php b/mod/profile/views/default/forms/profile/edit/header.php index deaa3b7b1ec..13fcb8b68b3 100644 --- a/mod/profile/views/default/forms/profile/edit/header.php +++ b/mod/profile/views/default/forms/profile/edit/header.php @@ -24,7 +24,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/profile/views/default/forms/profile/fields/add.php b/mod/profile/views/default/forms/profile/fields/add.php index a9b7e106c84..9b2da6f4ee8 100644 --- a/mod/profile/views/default/forms/profile/fields/add.php +++ b/mod/profile/views/default/forms/profile/fields/add.php @@ -46,7 +46,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/mod/reportedcontent/views/default/forms/reportedcontent/add.php b/mod/reportedcontent/views/default/forms/reportedcontent/add.php index f9d8d9158c2..7bc9461bb01 100644 --- a/mod/reportedcontent/views/default/forms/reportedcontent/add.php +++ b/mod/reportedcontent/views/default/forms/reportedcontent/add.php @@ -45,11 +45,11 @@ } $footer = elgg_view('input/submit', [ - 'value' => elgg_echo('reportedcontent:report'), + 'text' => elgg_echo('reportedcontent:report'), ]); $footer .= elgg_view('input/button', [ 'class' => 'elgg-button-cancel', - 'value' => elgg_echo('cancel'), + 'text' => elgg_echo('cancel'), ]); elgg_set_form_footer($footer); diff --git a/mod/search/views/default/forms/search.php b/mod/search/views/default/forms/search.php index c44cf03a7dc..4af56cb74a6 100644 --- a/mod/search/views/default/forms/search.php +++ b/mod/search/views/default/forms/search.php @@ -22,7 +22,8 @@ echo elgg_view_field([ '#type' => 'submit', - 'value' => elgg_view_icon('search'), + 'icon' => 'search', + 'aria-label' => elgg_echo('search'), ]); $values = [ diff --git a/mod/site_notifications/views/default/forms/site_notifications/process.php b/mod/site_notifications/views/default/forms/site_notifications/process.php index 0a119f33e28..4f16d0273a4 100644 --- a/mod/site_notifications/views/default/forms/site_notifications/process.php +++ b/mod/site_notifications/views/default/forms/site_notifications/process.php @@ -6,7 +6,7 @@ $fields = [ [ '#type' => 'button', - 'value' => elgg_echo('site_notifications:toggle_all'), + 'text' => elgg_echo('site_notifications:toggle_all'), 'class' => 'elgg-button elgg-button-cancel', 'id' => 'site-notifications-toggle', ], diff --git a/mod/system_log/views/default/forms/logbrowser/refine.php b/mod/system_log/views/default/forms/logbrowser/refine.php index 8e9914a5dea..1c7874e7329 100644 --- a/mod/system_log/views/default/forms/logbrowser/refine.php +++ b/mod/system_log/views/default/forms/logbrowser/refine.php @@ -64,7 +64,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('search'), + 'text' => elgg_echo('search'), ]); elgg_set_form_footer($footer); diff --git a/mod/web_services/views/default/forms/webservices/api_key/edit.php b/mod/web_services/views/default/forms/webservices/api_key/edit.php index 4fba979f88a..b3f2e27a8fa 100644 --- a/mod/web_services/views/default/forms/webservices/api_key/edit.php +++ b/mod/web_services/views/default/forms/webservices/api_key/edit.php @@ -30,7 +30,7 @@ // footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/menu/save.php b/views/default/forms/admin/menu/save.php index 8338b7c5c76..62dff945a12 100644 --- a/views/default/forms/admin/menu/save.php +++ b/views/default/forms/admin/menu/save.php @@ -88,7 +88,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/security/settings.php b/views/default/forms/admin/security/settings.php index da573949f27..df860a71125 100644 --- a/views/default/forms/admin/security/settings.php +++ b/views/default/forms/admin/security/settings.php @@ -11,7 +11,7 @@ // footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/site/icons.php b/views/default/forms/admin/site/icons.php index 20a2fb7e527..f528230f20b 100644 --- a/views/default/forms/admin/site/icons.php +++ b/views/default/forms/admin/site/icons.php @@ -34,6 +34,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/site/set_maintenance_mode.php b/views/default/forms/admin/site/set_maintenance_mode.php index de7aa1b28b4..09689612718 100644 --- a/views/default/forms/admin/site/set_maintenance_mode.php +++ b/views/default/forms/admin/site/set_maintenance_mode.php @@ -29,7 +29,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/site/set_robots.php b/views/default/forms/admin/site/set_robots.php index 2ea4c792e77..53630426cd3 100644 --- a/views/default/forms/admin/site/set_robots.php +++ b/views/default/forms/admin/site/set_robots.php @@ -21,7 +21,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/site/settings.php b/views/default/forms/admin/site/settings.php index abb9f73648c..610a4845a12 100644 --- a/views/default/forms/admin/site/settings.php +++ b/views/default/forms/admin/site/settings.php @@ -14,5 +14,5 @@ echo elgg_view('forms/admin/site/settings/email', $vars); echo elgg_view('forms/admin/site/settings/other', $vars); -$footer = elgg_view('input/submit', ['value' => elgg_echo('save')]); +$footer = elgg_view('input/submit', ['text' => elgg_echo('save')]); elgg_set_form_footer($footer); diff --git a/views/default/forms/admin/user/change_email.php b/views/default/forms/admin/user/change_email.php index 829b848b3a9..ccdc5d1d431 100644 --- a/views/default/forms/admin/user/change_email.php +++ b/views/default/forms/admin/user/change_email.php @@ -32,6 +32,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/avatar/upload.php b/views/default/forms/avatar/upload.php index f687ae83336..87ff1734c99 100644 --- a/views/default/forms/avatar/upload.php +++ b/views/default/forms/avatar/upload.php @@ -23,7 +23,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/comment/save.php b/views/default/forms/comment/save.php index b3655facc3b..fead4fdd373 100644 --- a/views/default/forms/comment/save.php +++ b/views/default/forms/comment/save.php @@ -36,11 +36,11 @@ 'value' => $comment->guid, ]); $comment_label = elgg_echo('generic_comments:edit'); - $footer .= elgg_view('input/submit', ['value' => elgg_echo('save')]); + $footer .= elgg_view('input/submit', ['text' => elgg_echo('save')]); $comment_text = $comment->description; } else { $comment_label = elgg_echo('generic_comments:add'); - $footer .= elgg_view('input/submit', ['value' => elgg_echo('comment')]); + $footer .= elgg_view('input/submit', ['text' => elgg_echo('comment')]); } if ($inline) { @@ -66,7 +66,7 @@ if ($comment) { $footer .= elgg_view('input/button', [ - 'value' => elgg_echo('cancel'), + 'text' => elgg_echo('cancel'), 'class' => 'elgg-button-cancel mlm', 'href' => $entity ? $entity->getURL() : '#', ]); diff --git a/views/default/forms/login.php b/views/default/forms/login.php index 47cbfa5f273..f0ee967f0f9 100644 --- a/views/default/forms/login.php +++ b/views/default/forms/login.php @@ -39,7 +39,7 @@ elgg_echo('login')]); + echo elgg_view('input/submit', ['text' => elgg_echo('login')]); ?>
    'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/plugins/settings/save.php b/views/default/forms/plugins/settings/save.php index 1f4f7b352cf..1f096653c06 100644 --- a/views/default/forms/plugins/settings/save.php +++ b/views/default/forms/plugins/settings/save.php @@ -38,7 +38,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/register.php b/views/default/forms/register.php index 3f7fcefcfc6..57a27a8ba5e 100644 --- a/views/default/forms/register.php +++ b/views/default/forms/register.php @@ -67,7 +67,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('register'), + 'text' => elgg_echo('register'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/settings/notifications.php b/views/default/forms/settings/notifications.php index 278984465f9..34d20dce036 100644 --- a/views/default/forms/settings/notifications.php +++ b/views/default/forms/settings/notifications.php @@ -31,7 +31,7 @@ // form footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/settings/notifications/users.php b/views/default/forms/settings/notifications/users.php index 0e06eca6e08..778b6126c6b 100644 --- a/views/default/forms/settings/notifications/users.php +++ b/views/default/forms/settings/notifications/users.php @@ -69,7 +69,7 @@ function(QueryBuilder $qb) { // form footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/user/changepassword.php b/views/default/forms/user/changepassword.php index 54ea08b1055..158b9b5e295 100644 --- a/views/default/forms/user/changepassword.php +++ b/views/default/forms/user/changepassword.php @@ -40,6 +40,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('changepassword'), + 'text' => elgg_echo('changepassword'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/user/delete.php b/views/default/forms/user/delete.php index 425022bcd6a..5cb3fb05aad 100644 --- a/views/default/forms/user/delete.php +++ b/views/default/forms/user/delete.php @@ -22,6 +22,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('delete'), + 'text' => elgg_echo('delete'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/user/requestnewpassword.php b/views/default/forms/user/requestnewpassword.php index d33e91f233e..2507ad6a9ae 100644 --- a/views/default/forms/user/requestnewpassword.php +++ b/views/default/forms/user/requestnewpassword.php @@ -19,6 +19,6 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('request'), + 'text' => elgg_echo('request'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/useradd.php b/views/default/forms/useradd.php index d26e5585f5a..330f940554e 100644 --- a/views/default/forms/useradd.php +++ b/views/default/forms/useradd.php @@ -67,7 +67,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('register'), + 'text' => elgg_echo('register'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/usersettings/save.php b/views/default/forms/usersettings/save.php index 12551e5c9e4..080e3222ed3 100644 --- a/views/default/forms/usersettings/save.php +++ b/views/default/forms/usersettings/save.php @@ -22,7 +22,7 @@ // form footer $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/forms/widgets/save.php b/views/default/forms/widgets/save.php index a5802a3aaa0..aab22f4af04 100644 --- a/views/default/forms/widgets/save.php +++ b/views/default/forms/widgets/save.php @@ -50,7 +50,7 @@ $footer = elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('save'), + 'text' => elgg_echo('save'), ]); elgg_set_form_footer($footer); diff --git a/views/default/icon/user/default.php b/views/default/icon/user/default.php index 477af8b7286..53326cd6d5d 100644 --- a/views/default/icon/user/default.php +++ b/views/default/icon/user/default.php @@ -46,7 +46,6 @@ $icon = elgg_view('output/img', [ 'src' => $user->getIconURL($size), 'alt' => $name, - 'title' => $name, 'class' => elgg_extract_class($vars, [], 'img_class'), ]); @@ -70,6 +69,7 @@ $content .= elgg_view('output/url', [ 'href' => elgg_extract('href', $vars, $user->getURL()), 'text' => $icon, + 'title' => $name, 'is_trusted' => true, 'class' => elgg_extract_class($vars, [], 'link_class'), ]); diff --git a/views/default/input/button.php b/views/default/input/button.php index e8e9646e2c8..3dc49ed3325 100644 --- a/views/default/input/button.php +++ b/views/default/input/button.php @@ -1,5 +1,4 @@ * @@ -15,6 +14,8 @@ if (!isset($vars['text']) && isset($vars['value'])) { // Keeping this to ease the transition to 3.0 $vars['text'] = elgg_extract('value', $vars); + + elgg_deprecated_notice('Only providing a value to a button is deprecated, please also provide a text: ' . $vars['value'], '5.0'); } if (!empty($vars['confirm'])) { @@ -32,9 +33,15 @@ $text = (string) elgg_extract('text', $vars); unset($vars['text']); -$text = elgg_format_element('span', [ - 'class' => 'elgg-button-label', -], $text); +if (!isset($vars['aria-label']) && !isset($vars['aria-labelledby']) && !isset($vars['title']) && empty(elgg_strip_tags($text))) { + elgg_log('An input/button should have a discernible text (text, title, aria-label or aria-labelledby)', 'NOTICE'); +} + +if (!elgg_is_empty($text)) { + $text = elgg_format_element('span', [ + 'class' => 'elgg-button-label', + ], $text); +} $icon = (string) elgg_extract('icon', $vars); unset($vars['icon']); diff --git a/views/default/output/url.php b/views/default/output/url.php index f0af0df5293..e5e3d5b2b8e 100644 --- a/views/default/output/url.php +++ b/views/default/output/url.php @@ -62,7 +62,7 @@ if (isset($vars['text'])) { if (elgg_extract('encode_text', $vars, false)) { - $text = htmlspecialchars($vars['text'], ENT_QUOTES, 'UTF-8', false); + $text = htmlspecialchars((string) $vars['text'], ENT_QUOTES, 'UTF-8', false); } else { $text = elgg_extract('text', $vars); } @@ -117,7 +117,11 @@ $vars['class'] = elgg_extract_class($vars, 'elgg-anchor'); -if ($text !== false && $text !== '') { +if (!isset($vars['aria-label']) && !isset($vars['aria-labelledby']) && !isset($vars['title']) && empty(elgg_strip_tags((string) $text))) { + elgg_log('An output/url should have a discernible text (text, title, aria-label or aria-labelledby)', 'NOTICE'); +} + +if (!elgg_is_empty($text)) { $text = elgg_format_element('span', [ 'class' => 'elgg-anchor-label', ], $text); diff --git a/views/installation/forms/install/template.php b/views/installation/forms/install/template.php index f268b4b4906..501ea03f432 100644 --- a/views/installation/forms/install/template.php +++ b/views/installation/forms/install/template.php @@ -22,5 +22,5 @@ 'class' => 'elgg-install-nav', ], elgg_view_field([ '#type' => 'submit', - 'value' => elgg_echo('install:next'), + 'text' => elgg_echo('install:next'), ])); From 0a23cd09b2d388a300b48f928b560a36fd9dcc5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 19 Jul 2023 11:53:51 +0200 Subject: [PATCH 038/240] feat(blog): prevent double submit of the blog form --- mod/blog/actions/blog/save.php | 8 ++++---- mod/blog/views/default/forms/blog/save.js | 3 +++ mod/blog/views/default/resources/blog/add.php | 1 - mod/blog/views/default/resources/blog/edit.php | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mod/blog/actions/blog/save.php b/mod/blog/actions/blog/save.php index 68d9c2804aa..eb27ab2e261 100644 --- a/mod/blog/actions/blog/save.php +++ b/mod/blog/actions/blog/save.php @@ -10,7 +10,7 @@ */ // save or preview -$save = (bool) get_input('save'); +$preview = (bool) get_input('preview'); // edit or create a new entity $guid = (int) get_input('guid'); @@ -86,8 +86,8 @@ } } -// if preview, force status to be draft -if (!$save) { +// if this is a preview, force status to be draft +if ($preview) { $values['status'] = 'draft'; } @@ -138,7 +138,7 @@ ]); } -if ($blog->status == 'published' || !$save) { +if ($blog->status == 'published' || $preview) { $forward_url = $blog->getURL(); } else { $forward_url = elgg_generate_url('edit:object:blog', [ diff --git a/mod/blog/views/default/forms/blog/save.js b/mod/blog/views/default/forms/blog/save.js index 56e1ca44595..6182ba0008a 100644 --- a/mod/blog/views/default/forms/blog/save.js +++ b/mod/blog/views/default/forms/blog/save.js @@ -13,6 +13,9 @@ define(['jquery', 'elgg/Ajax'], function($, Ajax) { return false; } + // tell the action this a preview save + formData.append('preview', 1); + // open preview in blank window ajax.action('blog/save', { data: formData, diff --git a/mod/blog/views/default/resources/blog/add.php b/mod/blog/views/default/resources/blog/add.php index c28d46c921a..6b2d9f60ffa 100644 --- a/mod/blog/views/default/resources/blog/add.php +++ b/mod/blog/views/default/resources/blog/add.php @@ -11,7 +11,6 @@ echo elgg_view_page(elgg_echo('add:object:blog'), [ 'content' => elgg_view_form('blog/save', [ - 'prevent_double_submit' => false, // action is using the submit buttons to determine type of submission, disabled buttons are not submitted 'sticky_enabled' => true, ]), 'filter_id' => 'blog/edit', diff --git a/mod/blog/views/default/resources/blog/edit.php b/mod/blog/views/default/resources/blog/edit.php index 4a148f7f560..26947ef63ad 100644 --- a/mod/blog/views/default/resources/blog/edit.php +++ b/mod/blog/views/default/resources/blog/edit.php @@ -28,7 +28,6 @@ } $form_vars = [ - 'prevent_double_submit' => false, // action is using the submit buttons to determine type of submission, disabled buttons are not submitted 'sticky_enabled' => true, ]; From 45003d6b99cea64b2d6d06bee351a25024f4b1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 19 Jul 2023 14:17:00 +0200 Subject: [PATCH 039/240] chore(views): input/button and output/url must have discernible text ref #14431 --- mod/messages/views/default/forms/messages/process.php | 5 +++-- .../views/default/forms/site_notifications/process.php | 6 ++---- mod/thewire/views/default/forms/thewire/add.php | 2 +- views/default/icon/default.php | 1 + 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mod/messages/views/default/forms/messages/process.php b/mod/messages/views/default/forms/messages/process.php index 8bee87332ea..d15d66c7608 100644 --- a/mod/messages/views/default/forms/messages/process.php +++ b/mod/messages/views/default/forms/messages/process.php @@ -18,8 +18,9 @@ $buttons = []; $buttons[] = [ '#type' => 'submit', - 'value' => elgg_echo('delete'), 'name' => 'delete', + 'value' => 1, + 'text' => elgg_echo('delete'), 'class' => 'elgg-button-delete', 'title' => elgg_echo('deleteconfirm:plural'), 'data-confirm' => elgg_echo('deleteconfirm:plural'), @@ -28,8 +29,8 @@ if (elgg_extract('folder', $vars) == 'inbox') { $buttons[] = [ '#type' => 'submit', - 'value' => elgg_echo('messages:markread'), 'name' => 'read', + 'text' => elgg_echo('messages:markread'), ]; } diff --git a/mod/site_notifications/views/default/forms/site_notifications/process.php b/mod/site_notifications/views/default/forms/site_notifications/process.php index 4f16d0273a4..46caf61b8c6 100644 --- a/mod/site_notifications/views/default/forms/site_notifications/process.php +++ b/mod/site_notifications/views/default/forms/site_notifications/process.php @@ -12,8 +12,7 @@ ], [ '#type' => 'submit', - 'value' => elgg_echo('delete'), - 'name' => 'delete', + 'text' => elgg_echo('delete'), 'class' => 'elgg-button-delete', 'data-confirm' => elgg_echo('site_notifications:delete:confirm'), 'disabled' => true, @@ -22,8 +21,7 @@ if ((bool) elgg_extract('mark_read', $vars, true)) { $fields[] = [ '#type' => 'submit', - 'value' => elgg_echo('site_notifications:mark_read'), - 'name' => 'mark_read', + 'text' => elgg_echo('site_notifications:mark_read'), 'data-confirm' => elgg_echo('site_notifications:mark_read:confirm'), 'formaction' => elgg_generate_action_url('site_notifications/mark_read', [], false), 'disabled' => true, diff --git a/mod/thewire/views/default/forms/thewire/add.php b/mod/thewire/views/default/forms/thewire/add.php index e61fd9aca11..3d59f54ab77 100644 --- a/mod/thewire/views/default/forms/thewire/add.php +++ b/mod/thewire/views/default/forms/thewire/add.php @@ -48,7 +48,7 @@ $fields = [ [ '#type' => 'submit', - 'value' => $text, + 'text' => $text, ], ]; diff --git a/views/default/icon/default.php b/views/default/icon/default.php index a6a28a83218..acbd737d85d 100644 --- a/views/default/icon/default.php +++ b/views/default/icon/default.php @@ -67,6 +67,7 @@ $params = [ 'href' => $url, 'text' => $img, + 'title' => $entity->getDisplayName(), 'is_trusted' => true, ]; $link_class = elgg_extract_class($vars, [], 'link_class'); From bef997f252701598a30b723aed99d9b5a5b4a1e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 20 Jul 2023 13:51:13 +0200 Subject: [PATCH 040/240] chore(views): output/url should have a discernible text --- views/default/admin/cron.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/views/default/admin/cron.php b/views/default/admin/cron.php index 2f573959f81..76d5728e595 100644 --- a/views/default/admin/cron.php +++ b/views/default/admin/cron.php @@ -28,6 +28,7 @@ // cron output $msg = $cron_service->getLog('output', $period); + $msg_class = []; if (!empty($msg)) { $msg = nl2br($msg); @@ -36,14 +37,17 @@ $msg = elgg_view('output/url', [ 'href' => false, 'text' => false, + 'title' => elgg_echo('more_info'), 'icon' => 'info', 'class' => ['elgg-lightbox'], 'data-colorbox-opts' => json_encode(['html' => $msg]), ]); + + $msg_class[] = 'center'; } } - $row[] = elgg_format_element('td', [], $msg); + $row[] = elgg_format_element('td', ['class' => $msg_class], $msg); $table_content .= elgg_format_element('tr', [], implode(PHP_EOL, $row)); } From 972f4087373cc5700a7cd7bd707d29f7193d522a Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 20 Jul 2023 14:31:08 +0200 Subject: [PATCH 041/240] fix(views): do not use rel to track related hover menu placeholders fixes #14430 --- views/default/icon/user/default.js | 8 ++++---- .../navigation/menu/user_hover/placeholder.php | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/views/default/icon/user/default.js b/views/default/icon/user/default.js index 29ca13274b3..063a7034792 100644 --- a/views/default/icon/user/default.js +++ b/views/default/icon/user/default.js @@ -10,7 +10,7 @@ define(['jquery'], function ($) { * @param {Function} callback a callback function to call when the loading of het menu was succesfull */ function loadMenu(mac, callback) { - var $all_placeholders = $(".elgg-menu-hover[rel='" + mac + "']"); + var $all_placeholders = $(".elgg-menu-hover[data-menu-id='" + mac + "']"); if (!$all_placeholders.length) { return; @@ -31,7 +31,7 @@ define(['jquery'], function ($) { } }, complete: function() { - $all_placeholders.removeAttr('data-menu-placeholder data-elgg-menu-data'); + $all_placeholders.removeAttr('data-menu-id data-elgg-menu-data'); } }); }); @@ -72,10 +72,10 @@ define(['jquery'], function ($) { var $icon = $(this); - var $placeholder = $icon.parent().find('.elgg-menu-hover[data-menu-placeholder]'); + var $placeholder = $icon.parent().find('.elgg-menu-hover[data-menu-id]'); if ($placeholder.length) { - loadMenu($placeholder.attr('rel'), function() { + loadMenu($placeholder.attr('data-menu-id'), function() { showPopup($icon); }); } else { diff --git a/views/default/navigation/menu/user_hover/placeholder.php b/views/default/navigation/menu/user_hover/placeholder.php index 030acf19c2d..3d14fe8ca09 100644 --- a/views/default/navigation/menu/user_hover/placeholder.php +++ b/views/default/navigation/menu/user_hover/placeholder.php @@ -1,12 +1,12 @@ guid; -$page_owner_guid = (int) elgg_get_page_owner_guid(); +$guid = $user->guid; +$page_owner_guid = elgg_get_page_owner_guid(); $contexts = elgg_get_context_stack(); $input = (array) elgg_get_config('input'); @@ -15,9 +15,8 @@ $mac = elgg_build_hmac($data)->getToken(); echo elgg_format_element('ul', [ - 'rel' => $mac, - 'class' => 'elgg-menu elgg-menu-hover', - 'data-menu-placeholder' => '1', // flag for the JS to know this menu isn't fully loaded yet + 'class' => ['elgg-menu', 'elgg-menu-hover'], + 'data-menu-id' => $mac, 'data-elgg-menu-data' => json_encode([ 'g' => $guid, 'pog' => $page_owner_guid, From b499352814c45d8fbfc1eefa3fa5294e27de68cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 20 Jul 2023 16:30:00 +0200 Subject: [PATCH 042/240] fix(icons): prevent racing condition when saving cropping coordinates --- engine/classes/Elgg/EntityIconService.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index 6b28557fe1a..28c00dfcfba 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -269,6 +269,12 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a } } + // first invalidate entity metadata cache, because of a high risk of racing condition to save the coordinates + // the racing condition occurs with 2 (or more) icon save calls and the time between clearing + // the coordinates in deleteIcon() and the new save here + $entity->invalidateCache(); + + // save cropping coordinates if ($type == 'icon') { $entity->icontime = time(); if ($x1 || $y1 || $x2 || $y2) { From 5e0fcab17eb701474d1d121933474eefa52b7aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 25 Jul 2023 16:54:53 +0200 Subject: [PATCH 043/240] fix(notifications): processing delayed emails could cause OOM issues On active communities the delayed email queue could contain to many items to process at once causing Out-Of-Memory issues. --- .../Elgg/Database/DelayedEmailQueueTable.php | 62 +++++++++----- .../Elgg/Email/DelayedEmailService.php | 59 +++++++------- .../Mocks/Database/DelayedEmailQueueTable.php | 81 +++++-------------- .../DelayedEmailQueueTableIntegrationTest.php | 80 ++++++++++++++---- .../DelayedEmailQueueTableUnitTest.php | 27 ------- 5 files changed, 157 insertions(+), 152 deletions(-) diff --git a/engine/classes/Elgg/Database/DelayedEmailQueueTable.php b/engine/classes/Elgg/Database/DelayedEmailQueueTable.php index 4c7ae762c4b..5aff8f7ca7c 100644 --- a/engine/classes/Elgg/Database/DelayedEmailQueueTable.php +++ b/engine/classes/Elgg/Database/DelayedEmailQueueTable.php @@ -50,7 +50,7 @@ public function queueEmail(int $recipient_guid, string $delivery_interval, $item 'timestamp' => $insert->param($this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP), ]); - return $this->db->insertData($insert) !== false; + return $this->db->insertData($insert) !== 0; } /** @@ -71,39 +71,52 @@ public function getRow(int $id): ?DatabaseRecord { /** * Get all the rows in the queue for a given recipient * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) + * @param int $recipient_guid the recipient + * @param string $delivery_interval the interval for the recipient + * @param null|int $timestamp (optional) all queue items before time (default: now) + * @param int $max_results (optional) maximum number of rows to return * * @return DatabaseRecord[] database rows */ - public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): array { + public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_results = 0): array { $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('recipient_guid', '=', $recipient_guid, ELGG_VALUE_GUID)) ->andWhere($select->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) - ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP)); + ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP)) + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC'); + + if ($max_results > 0) { + $select->setMaxResults($max_results); + } return $this->db->getData($select, [$this, 'rowToRecord']); } /** - * Get the queued items from the database for a given interval + * Fetch the GUID of the next recipient to process * - * @param string $delivery_interval the delivery interval to get - * @param int $timestamp (optional) all queue items before time (default: now) + * @param string $delivery_interval the delivery interval to get + * @param null|int $timestamp (optional) based on queue items before time (default: now) * - * @return DatabaseRecord[] + * @return null|int */ - public function getIntervalRows(string $delivery_interval, int $timestamp = null): array { + public function getNextRecipientGUID(string $delivery_interval, int $timestamp = null): ?int { $select = Select::fromTable(self::TABLE_NAME); - $select->select('*') + $select->select('recipient_guid') ->where($select->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp())) - ->orderBy('recipient_guid', 'ASC') - ->addOrderBy('timestamp', 'ASC'); + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC') + ->setMaxResults(1); - return $this->db->getData($select, [$this, 'rowToRecord']); + $row = $this->db->getDataRow($select); + if (empty($row)) { + return null; + } + + return (int) $row->recipient_guid; } /** @@ -123,17 +136,24 @@ public function deleteRow(int $id): int { /** * Delete all the queue items from the database for the given recipient and interval * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) + * @param int $recipient_guid the recipient + * @param string $delivery_interval the interval for the recipient + * @param null|int $timestamp (optional) all queue items before time (default: now) + * @param int $max_id (optional) the max row ID to remove (this includes the given row ID) * * @return int number of deleted rows */ - public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): int { + public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_id = 0): int { $delete = Delete::fromTable(self::TABLE_NAME); $delete->where($delete->compare('recipient_guid', '=', $recipient_guid, ELGG_VALUE_GUID)) ->andWhere($delete->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) - ->andWhere($delete->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_INTEGER)); + ->andWhere($delete->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_INTEGER)) + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC'); + + if ($max_id > 0) { + $delete->andWhere($delete->compare('id', '<=', $max_id, ELGG_VALUE_ID)); + } return $this->db->deleteData($delete); } @@ -169,7 +189,7 @@ public function updateRecipientInterval(int $recipient_guid, string $delivery_in } /** - * Convert a database row to a managable object + * Convert a database row to a manageable object * * @param \stdClass $row the database record * diff --git a/engine/classes/Elgg/Email/DelayedEmailService.php b/engine/classes/Elgg/Email/DelayedEmailService.php index 913a5b2bb58..d97f314d13d 100644 --- a/engine/classes/Elgg/Email/DelayedEmailService.php +++ b/engine/classes/Elgg/Email/DelayedEmailService.php @@ -23,6 +23,8 @@ class DelayedEmailService { use Loggable; + protected const NOTIFICATIONS_BATCH_SIZE = 500; + /** * @var DelayedEmailQueueTable */ @@ -100,46 +102,47 @@ public function processQueuedNotifications(string $delivery_interval, int $times return ($this->invoker->call(ELGG_IGNORE_ACCESS, function() use ($delivery_interval, $timestamp) { $count = 0; - $last_recipient_guid = null; - $notifications = []; // process one recipient - $processRecipient = function($row = null) use (&$last_recipient_guid, &$notifications, $delivery_interval, $timestamp) { + $processRecipient = function(int $recipient_guid, array $notifications, int $max_id) use ($delivery_interval, $timestamp) { try { - $this->processRecipientNotifications($last_recipient_guid, $notifications, $delivery_interval); + $this->processRecipientNotifications($recipient_guid, $notifications, $delivery_interval); } catch (\Throwable $t) { $this->getLogger()->error($t); } // cleanup the queue for this recipient - $this->queue_table->deleteRecipientRows($last_recipient_guid, $delivery_interval, $timestamp); - - // start collecting data for the new recipient - $last_recipient_guid = $row ? $row->recipient_guid : null; - $notifications = []; + return $this->queue_table->deleteRecipientRows($recipient_guid, $delivery_interval, $timestamp, $max_id); }; - $rows = $this->queue_table->getIntervalRows($delivery_interval, $timestamp); - foreach ($rows as $row) { - $count++; - - if (!isset($last_recipient_guid)) { - $last_recipient_guid = $row->recipient_guid; - } elseif ($last_recipient_guid !== $row->recipient_guid) { - // process one recipient - $processRecipient($row); + // get the next recipient to process + $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp); + while ($recipient_guid > 0) { + // get a notification batch to process for this recipient + $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, self::NOTIFICATIONS_BATCH_SIZE); + while (!empty($rows)) { + $notifications = []; + $max_id = 0; + foreach ($rows as $row) { + $max_id = max($max_id, $row->id); + + $notification = $row->getNotification(); + if (!$notification instanceof Notification) { + continue; + } + + $notifications[] = $notification; + } + + // send all notifications in this batch + $count += $processRecipient($recipient_guid, $notifications, $max_id); + + // get next batch + $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, static::NOTIFICATIONS_BATCH_SIZE); } - $notfication = $row->getNotification(); - if (!$notfication instanceof Notification) { - continue; - } - - $notifications[] = $notfication; - } - - if (isset($last_recipient_guid)) { - $processRecipient(); + // get next recipient to process + $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp); } return $count; diff --git a/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php b/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php index 1ffcd541c1d..b22be088f35 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php @@ -32,13 +32,7 @@ class DelayedEmailQueueTable extends DbDelayedEmailQueueTable{ protected static $iterator = 100; /** - * Insert a delayed email into the queue - * - * @param int $recipient_guid the recipient of the email - * @param string $delivery_interval the desired interval of the recipient - * @param mixed $item the email to queue - * - * @return bool + * {@inheritdoc} */ public function queueEmail(int $recipient_guid, string $delivery_interval, $item): bool { self::$iterator++; @@ -65,15 +59,9 @@ public function queueEmail(int $recipient_guid, string $delivery_interval, $item } /** - * Get all the rows in the queue for a given recipient - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return DatabaseRecord[] database rows + * {@inheritdoc} */ - public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): array { + public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_results = 0): array { $result = []; $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); @@ -94,49 +82,23 @@ public function getRecipientRows(int $recipient_guid, string $delivery_interval, $result[] = $this->rowToRecord($row); } - return $result; - } - - /** - * Get the queued items from the database for a given interval - * - * @param string $delivery_interval the delivery interval to get - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return DatabaseRecord[] - */ - public function getIntervalRows(string $delivery_interval, int $timestamp = null): array { - $result = []; - - $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); - - foreach ($this->rows as $row) { - if ($row->delivery_interval !== $delivery_interval) { - continue; - } + if ($max_results > 0) { + // first order + usort($result, function($row_a, $row_b) { + // this should be based on timestamp and id, but that's harder + return $row_a->id - $row_b->id; + }); - if ($row->timestamp >= $timestamp) { - continue; - } - - $result[$row->timestamp . '_' . $row->recipient_guid] = $this->rowToRecord($row); + return array_slice($result, 0, $max_results); } - uksort($result, 'strnatcasecmp'); - - return array_values($result); + return $result; } /** - * Delete all the queue items from the database for the given recipient and interval - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return int number of deleted rows + * {@inheritdoc} */ - public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): int { + public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_id = 0): int { $result = 0; $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); @@ -154,6 +116,10 @@ public function deleteRecipientRows(int $recipient_guid, string $delivery_interv continue; } + if ($max_id > 0 && $id > $max_id) { + continue; + } + $this->clearQuerySpecs($row); unset($this->rows[$id]); @@ -164,11 +130,7 @@ public function deleteRecipientRows(int $recipient_guid, string $delivery_interv } /** - * Delete all the queue items from the database for the given recipient and interval - * - * @param int $recipient_guid the recipient - * - * @return int number of deleted rows + * {@inheritdoc} */ public function deleteAllRecipientRows(int $recipient_guid): int { $result = 0; @@ -188,12 +150,7 @@ public function deleteAllRecipientRows(int $recipient_guid): int { } /** - * Update the queued notifications for the recipient to a new delivery interval - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the new delivery interval - * - * @return bool + * {@inheritdoc} */ public function updateRecipientInterval(int $recipient_guid, string $delivery_interval): bool { foreach ($this->rows as $row) { diff --git a/engine/tests/phpunit/integration/Elgg/Database/DelayedEmailQueueTableIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Database/DelayedEmailQueueTableIntegrationTest.php index 593f684fdb3..8be3d002445 100644 --- a/engine/tests/phpunit/integration/Elgg/Database/DelayedEmailQueueTableIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Database/DelayedEmailQueueTableIntegrationTest.php @@ -5,6 +5,7 @@ use Elgg\Email\DelayedQueue\DatabaseRecord; use Elgg\IntegrationTestCase; use Elgg\Notifications\Notification; +use Elgg\Values; class DelayedEmailQueueTableIntegrationTest extends IntegrationTestCase { @@ -32,7 +33,7 @@ protected function getTestNotification(): Notification { return new Notification($sender, $recipient, 'en', 'Test subject', 'Test body'); } - public function testqueueEmail() { + public function testQueueEmail() { $notification = $this->getTestNotification(); $recipient = $notification->getRecipient(); @@ -67,31 +68,50 @@ public function testqueueEmail() { $this->assertEmpty($this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp())); } - public function testGetIntervalRows() { + public function testGetRecipientRowsWithMaxResults() { + $notification = $this->getTestNotification(); + $recipient = $notification->getRecipient(); - // add testing rows + // insert for ($i = 0; $i < 5; $i++) { - $notification = $this->getTestNotification(); - $recipient = $notification->getRecipient(); - - // insert $this->assertTrue($this->table->queueEmail($recipient->guid, 'daily', $notification)); } - // different interval + $dt = $this->table->getCurrentTime('+10 seconds'); + + $rows = $this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp(), 2); + $this->assertNotEmpty($rows); + $this->assertCount(2, $rows); + + $same_rows = $this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp(), 2); + $this->assertNotEmpty($same_rows); + $this->assertCount(2, $same_rows); + $this->assertEquals($rows, $same_rows); + + // fetch too much + $rows = $this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp(), 100); + $this->assertNotEmpty($rows); + $this->assertCount(5, $rows); + } + + public function testGetNextRecipientGUID() { + $recipients = []; + + // insert rows in reverse order for ($i = 0; $i < 5; $i++) { $notification = $this->getTestNotification(); $recipient = $notification->getRecipient(); + $recipients[] = $recipient->guid; - // insert - $this->assertTrue($this->table->queueEmail($recipient->guid, 'weekly', $notification)); + $this->table->setCurrentTime(Values::normalizeTime("-{$i} minutes")); + $this->table->queueEmail($recipient->guid, 'daily', $notification); } - $dt = $this->table->getCurrentTime('+10 seconds'); + $this->table->resetCurrentTime(); - // retrieve - $this->assertCount(5, $this->table->getIntervalRows('daily', $dt->getTimestamp())); - $this->assertCount(5, $this->table->getIntervalRows('weekly', $dt->getTimestamp())); + $next_recipient = $this->table->getNextRecipientGUID('daily'); + $this->assertNotEmpty($next_recipient); + $this->assertEquals(end($recipients), $next_recipient); } public function testDeleteRecipientRows() { @@ -115,6 +135,38 @@ public function testDeleteRecipientRows() { $this->assertEmpty($this->table->getRecipientRows($recipient->guid, 'weekly', $dt->getTimestamp())); } + public function testDeleteRecipientRowsWithMaxID() { + $notification = $this->getTestNotification(); + $recipient = $notification->getRecipient(); + + // insert + for ($i = 0; $i < 5; $i++) { + $this->assertTrue($this->table->queueEmail($recipient->guid, 'daily', $notification)); + } + + $dt = $this->table->getCurrentTime('+10 seconds'); + + $rows = $this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp(), 2); + $max_id = 0; + foreach ($rows as $row) { + $max_id = max($max_id, $row->id); + } + + // delete + $this->assertEquals(2, $this->table->deleteRecipientRows($recipient->guid, 'daily', $dt->getTimestamp(), $max_id)); + + // verify still rows left + $rows = $this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp()); + $this->assertNotEmpty($rows); + $this->assertCount(3, $rows); + + // delete the rest + $this->assertEquals(3, $this->table->deleteRecipientRows($recipient->guid, 'daily', $dt->getTimestamp())); + + // verify all is now removed + $this->assertEmpty($this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp())); + } + public function testDeleteAllRecipientRows() { $notification = $this->getTestNotification(); $recipient = $notification->getRecipient(); diff --git a/engine/tests/phpunit/unit/Elgg/Database/DelayedEmailQueueTableUnitTest.php b/engine/tests/phpunit/unit/Elgg/Database/DelayedEmailQueueTableUnitTest.php index cd10a521499..b44332cccf6 100644 --- a/engine/tests/phpunit/unit/Elgg/Database/DelayedEmailQueueTableUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Database/DelayedEmailQueueTableUnitTest.php @@ -73,33 +73,6 @@ public function testqueueEmail() { $this->assertEmpty($this->table->getRecipientRows($recipient->guid, 'daily', $dt->getTimestamp())); } - public function testGetIntervalRows() { - - // add testing rows - for ($i = 0; $i < 5; $i++) { - $notification = $this->getTestNotification(); - $recipient = $notification->getRecipient(); - - // insert - $this->assertTrue($this->table->queueEmail($recipient->guid, 'daily', $notification)); - } - - // different interval - for ($i = 0; $i < 5; $i++) { - $notification = $this->getTestNotification(); - $recipient = $notification->getRecipient(); - - // insert - $this->assertTrue($this->table->queueEmail($recipient->guid, 'weekly', $notification)); - } - - $dt = $this->table->getCurrentTime('+10 seconds'); - - // retrieve - $this->assertCount(5, $this->table->getIntervalRows('daily', $dt->getTimestamp())); - $this->assertCount(5, $this->table->getIntervalRows('weekly', $dt->getTimestamp())); - } - public function testDeleteRecipientRows() { $notification = $this->getTestNotification(); $recipient = $notification->getRecipient(); From 58a714fff56de64414e419d4bc9bec6ad8777ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 26 Jul 2023 10:14:38 +0200 Subject: [PATCH 044/240] chore(composer): composer update to solve security issue in guzzle In preparation for release of 4.3.9 --- composer.lock | 674 +++++++++++++++++++++++++++----------------------- 1 file changed, 361 insertions(+), 313 deletions(-) diff --git a/composer.lock b/composer.lock index 303d79821e5..31aa5065354 100644 --- a/composer.lock +++ b/composer.lock @@ -8,22 +8,25 @@ "packages": [ { "name": "cakephp/core", - "version": "4.4.10", + "version": "4.4.15", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "20e50de2f461b5983a1a1296fe5c3762857b9edd" + "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/20e50de2f461b5983a1a1296fe5c3762857b9edd", - "reference": "20e50de2f461b5983a1a1296fe5c3762857b9edd", + "url": "https://api.github.com/repos/cakephp/core/zipball/ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", + "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", "shasum": "" }, "require": { "cakephp/utility": "^4.0", "php": ">=7.4.0" }, + "provide": { + "psr/container-implementation": "^1.0 || ^2.0" + }, "suggest": { "cakephp/cache": "To use Configure::store() and restore().", "cakephp/event": "To use PluginApplicationInterface or plugin applications.", @@ -61,20 +64,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2022-10-07T16:40:13+00:00" + "time": "2023-05-16T13:58:50+00:00" }, { "name": "cakephp/database", - "version": "4.4.10", + "version": "4.4.15", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "c12a8f30f802968a885774e2ac3c099f470bf07c" + "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/c12a8f30f802968a885774e2ac3c099f470bf07c", - "reference": "c12a8f30f802968a885774e2ac3c099f470bf07c", + "url": "https://api.github.com/repos/cakephp/database/zipball/752e3dfa61be055bf9d360880f00ab4ccfea6d1e", + "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e", "shasum": "" }, "require": { @@ -117,20 +120,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2023-01-03T20:29:38+00:00" + "time": "2023-04-28T21:24:39+00:00" }, { "name": "cakephp/datasource", - "version": "4.4.10", + "version": "4.4.15", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "cb58adb0e6f52f26fa61d03776b07c157e328c1e" + "reference": "faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/cb58adb0e6f52f26fa61d03776b07c157e328c1e", - "reference": "cb58adb0e6f52f26fa61d03776b07c157e328c1e", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13", + "reference": "faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13", "shasum": "" }, "require": { @@ -175,20 +178,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2022-11-26T11:46:41+00:00" + "time": "2023-04-22T08:15:33+00:00" }, { "name": "cakephp/utility", - "version": "4.4.10", + "version": "4.4.15", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "aa7bba6c39b56751f5c917464f113c924d4ba10f" + "reference": "a6a17c556d02c57259e21127a4f3d3ec5cd8481f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/aa7bba6c39b56751f5c917464f113c924d4ba10f", - "reference": "aa7bba6c39b56751f5c917464f113c924d4ba10f", + "url": "https://api.github.com/repos/cakephp/utility/zipball/a6a17c556d02c57259e21127a4f3d3ec5cd8481f", + "reference": "a6a17c556d02c57259e21127a4f3d3ec5cd8481f", "shasum": "" }, "require": { @@ -234,7 +237,7 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2022-11-06T06:40:44+00:00" + "time": "2023-02-24T22:07:16+00:00" }, { "name": "ckeditor/ckeditor", @@ -631,25 +634,29 @@ }, { "name": "doctrine/deprecations", - "version": "v1.0.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -668,9 +675,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" }, - "time": "2022-05-02T15:47:09+00:00" + "time": "2023-06-03T09:27:29+00:00" }, { "name": "doctrine/event-manager", @@ -1189,16 +1196,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.5.2", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "b94b2807d85443f9719887892882d0329d1e2598" + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", - "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", "shasum": "" }, "require": { @@ -1208,11 +1215,6 @@ "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } - }, "autoload": { "files": [ "src/functions_include.php" @@ -1253,7 +1255,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.2" + "source": "https://github.com/guzzle/promises/tree/1.5.3" }, "funding": [ { @@ -1269,26 +1271,26 @@ "type": "tidelift" } ], - "time": "2022-08-28T14:55:35+00:00" + "time": "2023-05-21T12:31:43+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.4.3", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "67c26b443f348a51926030c83481b85718457d3d" + "reference": "b635f279edd83fc275f822a1188157ffea568ff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", - "reference": "67c26b443f348a51926030c83481b85718457d3d", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", + "reference": "b635f279edd83fc275f822a1188157ffea568ff6", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1 || ^2.0", "ralouphie/getallheaders": "^3.0" }, "provide": { @@ -1308,9 +1310,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "2.4-dev" } }, "autoload": { @@ -1372,7 +1371,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.3" + "source": "https://github.com/guzzle/psr7/tree/2.5.0" }, "funding": [ { @@ -1388,7 +1387,7 @@ "type": "tidelift" } ], - "time": "2022-10-26T14:07:24+00:00" + "time": "2023-04-17T16:11:26+00:00" }, { "name": "hackzilla/password-generator", @@ -1436,16 +1435,16 @@ }, { "name": "imagine/imagine", - "version": "1.3.3", + "version": "1.3.5", "source": { "type": "git", "url": "https://github.com/php-imagine/Imagine.git", - "reference": "a6e6da93ea0f76aba33b0e8ed1325523c0413da2" + "reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/a6e6da93ea0f76aba33b0e8ed1325523c0413da2", - "reference": "a6e6da93ea0f76aba33b0e8ed1325523c0413da2", + "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/7151d553edec4dc2bbac60419f7a74ff34700e7f", + "reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f", "shasum": "" }, "require": { @@ -1492,9 +1491,9 @@ ], "support": { "issues": "https://github.com/php-imagine/Imagine/issues", - "source": "https://github.com/php-imagine/Imagine/tree/1.3.3" + "source": "https://github.com/php-imagine/Imagine/tree/1.3.5" }, - "time": "2022-11-16T13:09:11+00:00" + "time": "2023-06-07T14:49:52+00:00" }, { "name": "justinrainbow/json-schema", @@ -2002,16 +2001,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902", + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902", "shasum": "" }, "require": { @@ -2058,7 +2057,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-01-30T18:31:20+00:00" + "time": "2023-07-14T13:56:28+00:00" }, { "name": "league/flysystem", @@ -2253,16 +2252,16 @@ }, { "name": "matthiasmullie/minify", - "version": "1.3.70", + "version": "1.3.71", "source": { "type": "git", "url": "https://github.com/matthiasmullie/minify.git", - "reference": "2807d9f9bece6877577ad44acb5c801bb3ae536b" + "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/2807d9f9bece6877577ad44acb5c801bb3ae536b", - "reference": "2807d9f9bece6877577ad44acb5c801bb3ae536b", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", + "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", "shasum": "" }, "require": { @@ -2312,7 +2311,7 @@ ], "support": { "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.70" + "source": "https://github.com/matthiasmullie/minify/tree/1.3.71" }, "funding": [ { @@ -2320,7 +2319,7 @@ "type": "github" } ], - "time": "2022-12-09T12:56:44+00:00" + "time": "2023-04-25T20:33:03+00:00" }, { "name": "matthiasmullie/path-converter", @@ -2595,10 +2594,10 @@ }, { "name": "npm-asset/jquery", - "version": "3.6.3", + "version": "3.6.4", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/jquery/-/jquery-3.6.3.tgz" + "url": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz" }, "type": "npm-asset", "license": [ @@ -3031,16 +3030,16 @@ }, { "name": "phpfastcache/phpfastcache", - "version": "8.1.3", + "version": "8.1.4", "source": { "type": "git", "url": "https://github.com/PHPSocialNetwork/phpfastcache.git", - "reference": "babf654c1618edeb4f9d592d6837b1da661b5107" + "reference": "ad4ac950b63fd2d3368fb1204e80413969c3c2b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPSocialNetwork/phpfastcache/zipball/babf654c1618edeb4f9d592d6837b1da661b5107", - "reference": "babf654c1618edeb4f9d592d6837b1da661b5107", + "url": "https://api.github.com/repos/PHPSocialNetwork/phpfastcache/zipball/ad4ac950b63fd2d3368fb1204e80413969c3c2b8", + "reference": "ad4ac950b63fd2d3368fb1204e80413969c3c2b8", "shasum": "" }, "require": { @@ -3133,7 +3132,7 @@ ], "support": { "issues": "https://github.com/PHPSocialNetwork/phpfastcache/issues", - "source": "https://github.com/PHPSocialNetwork/phpfastcache/tree/8.1.3" + "source": "https://github.com/PHPSocialNetwork/phpfastcache/tree/8.1.4" }, "funding": [ { @@ -3145,7 +3144,7 @@ "type": "patreon" } ], - "time": "2022-05-25T11:52:43+00:00" + "time": "2023-02-11T23:32:28+00:00" }, { "name": "psr/cache", @@ -3246,21 +3245,21 @@ }, { "name": "psr/http-client", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", "shasum": "" }, "require": { "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -3280,7 +3279,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP clients", @@ -3292,27 +3291,27 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/master" + "source": "https://github.com/php-fig/http-client/tree/1.0.2" }, - "time": "2020-06-29T06:28:15+00:00" + "time": "2023-04-10T20:12:12+00:00" }, { "name": "psr/http-factory", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -3332,7 +3331,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for PSR-7 HTTP message factories", @@ -3347,31 +3346,31 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" }, - "time": "2019-04-30T12:38:16+00:00" + "time": "2023-04-10T20:10:41+00:00" }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -3386,7 +3385,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -3400,9 +3399,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", @@ -3551,23 +3550,23 @@ }, { "name": "react/promise", - "version": "v2.9.0", + "version": "v2.10.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910" + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910", - "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { @@ -3611,19 +3610,15 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.9.0" + "source": "https://github.com/reactphp/promise/tree/v2.10.0" }, "funding": [ { - "url": "https://github.com/WyriHaximus", - "type": "github" - }, - { - "url": "https://github.com/clue", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2022-02-11T10:27:51+00:00" + "time": "2023-05-02T15:15:43+00:00" }, { "name": "roave/security-advisories", @@ -3631,19 +3626,20 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "c0e29643df152bd7fbe3de189f6c2c16c7d4c2a2" + "reference": "69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/c0e29643df152bd7fbe3de189f6c2c16c7d4c2a2", - "reference": "c0e29643df152bd7fbe3de189f6c2c16c7d4c2a2", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7", + "reference": "69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", - "admidio/admidio": "<4.1.9", + "admidio/admidio": "<4.2.10", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", - "aheinze/cockpit": "<=2.2.1", + "aheinze/cockpit": "<2.2", + "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", "alextselegidis/easyappointments": "<1.5", @@ -3654,17 +3650,22 @@ "amphp/http-client": ">=4,<4.4", "anchorcms/anchor-cms": "<=0.12.7", "andreapollastri/cipi": "<=3.1.15", - "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<=1.0.1|>=2,<=2.2.4", + "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", "apereo/phpcas": "<1.6", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3", - "appwrite/server-ce": "<0.11.1|>=0.12,<0.12.2", + "appwrite/server-ce": "<=1.2.1", "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", + "artesaos/seotools": "<0.17.2", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "athlon1600/php-proxy": "<=5.1", + "athlon1600/php-proxy-app": "<=3", "automad/automad": "<1.8", "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": ">=3,<3.2.1", - "backdrop/backdrop": "<=1.23", + "azuracast/azuracast": "<0.18.3", + "backdrop/backdrop": "<1.24.2", + "backpack/crud": "<3.4.9", "badaso/core": "<2.7", "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", @@ -3673,8 +3674,8 @@ "barzahlen/barzahlen-php": "<2.0.1", "baserproject/basercms": "<4.7.5", "bassjobsen/bootstrap-3-typeahead": ">4.0.2", - "bigfork/silverstripe-form-capture": ">=3,<=3.1", - "billz/raspap-webgui": "<=2.6.6", + "bigfork/silverstripe-form-capture": ">=3,<3.1.1", + "billz/raspap-webgui": "<2.8.9", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bmarshall511/wordpress_zero_spam": "<5.2.13", "bolt/bolt": "<3.7.2", @@ -3691,27 +3692,29 @@ "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", + "cardgate/woocommerce": "<=3.1.15", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", "centreon/centreon": "<22.10-beta.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "cockpit-hq/cockpit": "<2.4.1", + "cockpit-hq/cockpit": "<2.6", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<=3.0.6", - "codeigniter4/framework": "<4.2.11", + "codeigniter4/framework": "<4.3.5", "codeigniter4/shield": "<1-beta.4|= 1.0.0-beta", "codiad/codiad": "<=2.8.4", "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<=9.1.3|>= 9.0.0RC1, < 9.1.3", + "concrete5/concrete5": "<9.2|>= 9.0.0RC1, < 9.1.3", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3", + "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3|= 4.10.0", + "contao/core-bundle": "<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", - "craftcms/cms": "<3.7.64|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", + "cosenary/instagram": "<=2.3", + "craftcms/cms": "<=4.4.9|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", "croogo/croogo": "<3.0.7", "cuyz/valinor": "<0.12", "czproject/git-php": "<4.0.3", @@ -3719,8 +3722,10 @@ "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", + "dcat/laravel-admin": "<=2.1.3-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "desperado/xml-bundle": "<=0.1.7", "directmailteam/direct-mail": "<5.2.4", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", @@ -3731,9 +3736,9 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<16|>=16.0.1,<16.0.3|= 12.0.5|>= 3.3.beta1, < 13.0.2", + "dolibarr/dolibarr": "<17.0.1|= 12.0.5|>= 3.3.beta1, < 13.0.2", "dompdf/dompdf": "<2.0.2|= 2.0.2", - "drupal/core": ">=7,<7.91|>=8,<9.3.19|>=9.4,<9.4.3", + "drupal/core": ">=7,<7.96|>=8,<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "dweeves/magmi": "<=0.7.24", "ecodev/newsletter": "<=4", @@ -3774,6 +3779,7 @@ "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", "flarum/core": "<1.7", + "flarum/framework": "<=0.1-beta.7.1", "flarum/mentions": "<1.6.3", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", @@ -3783,42 +3789,48 @@ "fooman/tcpdf": "<6.2.22", "forkcms/forkcms": "<5.11.1", "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<10.8.2", + "francoisjacquet/rosariosis": "<11", "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "froala/wysiwyg-editor": "<3.2.7", - "froxlor/froxlor": "<2.0.13", + "froxlor/froxlor": "<2.1", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=3.2", + "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", - "getgrav/grav": "<1.7.34", + "getgrav/grav": "<=1.7.42.1", "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", + "getkirby/kirby": "<=2.5.12", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", "globalpayments/php-sdk": "<2", + "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", "grumpydictator/firefly-iii": "<6", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", - "guzzlehttp/psr7": "<1.8.4|>=2,<2.1.1", + "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", + "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", "helloxz/imgurl": "= 2.31|<=2.31", + "hhxsv5/laravel-s": "<3.7.36", "hillelcoren/invoice-ninja": "<5.3.35", "himiklab/yii2-jqgrid-widget": "<1.0.8", "hjue/justwriting": "<=1", "hov/jobfair": "<1.0.13|>=2,<2.0.2", + "httpsoft/http-message": "<1.0.12", "hyn/multi-tenant": ">=5.6,<5.7.2", "ibexa/admin-ui": ">=4.2,<4.2.3", "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3", "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", "ibexa/post-install": "<=1.0.4", + "ibexa/user": ">=4,<4.4.3", "icecoder/icecoder": "<=8.1", "idno/known": "<=1.3.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", @@ -3826,8 +3838,9 @@ "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "impresscms/impresscms": "<=1.4.3", + "impresscms/impresscms": "<=1.4.5", "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.1", + "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", "innologi/typo3-appointments": "<2.0.6", "intelliants/subrion": "<=4.2.1", @@ -3839,7 +3852,9 @@ "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", + "joomla/framework": ">=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", + "joomla/joomla-cms": ">=3,<3.9.12", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", @@ -3847,24 +3862,26 @@ "kazist/phpwhois": "<=4.2.6", "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", + "khodakhah/nodcms": "<=3", "kimai/kimai": "<1.1", - "kitodo/presentation": "<3.1.2", + "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<=1.4.1", + "knplabs/knp-snappy": "<1.4.2", "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-diactoros": "<2.11.1", + "laminas/laminas-diactoros": "<2.18.1|>=2.24,<2.24.2|>=2.25,<2.25.2|= 2.23.0|= 2.22.0|= 2.21.0|= 2.20.0|= 2.19.0", "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", "laravel/fortify": "<1.11.1", - "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "laravel/framework": "<6.20.44|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", - "lavalite/cms": "<=5.8", + "lavalite/cms": "= 9.0.0|<=9", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", + "league/oauth2-server": ">=8.3.2,<8.5.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "librenms/librenms": "<22.10", "liftkit/database": "<2.13.2", @@ -3874,7 +3891,7 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", + "magento/community-edition": "= 2.4.0|<=2.4", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", @@ -3890,14 +3907,16 @@ "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "<=1.3.2", + "microweber/microweber": "<=1.3.4|= 1.1.18", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<= 2.8.3-pl|<2.8", + "modx/revolution": "<2.8|<= 2.8.3-pl", "mojo42/jirafeau": "<4.4", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.0.7|>=4.1-beta,<4.1.2|= 3.11", + "moodle/moodle": "<4.2-rc.2|= 3.4.3|= 3.5|= 3.7|= 3.9|= 3.8|= 4.2.0|= 3.11", + "movim/moxl": ">=0.8,<=0.10", + "mpdf/mpdf": "<=7.1.7", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", @@ -3909,15 +3928,16 @@ "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<3.0.0.23", + "nilsteampassnet/teampass": "<3.0.10", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", "nukeviet/nukeviet": "<4.5.2", + "nyholm/psr7": "<1.6.1", "nystudio107/craft-seomatic": "<3.4.12", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466|>=2.1,<2.1.12", + "october/october": "<1.0.466|>=2.1,<2.1.12", "october/rain": "<1.0.472|>=1.1,<1.1.2", "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", "onelogin/php-saml": "<2.10.4", @@ -3926,7 +3946,8 @@ "opencart/opencart": "<=3.0.3.7", "openid/php-openid": "<2.3", "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", - "orchid/platform": ">=9,<9.4.4", + "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", + "orchid/platform": ">=9,<9.4.4|>=14-alpha.4,<14.5", "oro/commerce": ">=4.1,<5.0.6", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", @@ -3939,10 +3960,12 @@ "paypal/merchant-sdk-php": "<3.12", "pear/archive_tar": "<1.4.14", "pear/crypt_gpg": "<1.6.7", + "pear/pear": "<=1.10.1", "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", "php-mod/curl": "<2.3.2", + "phpbb/phpbb": "<3.2.10|>=3.3,<3.3.1", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", @@ -3951,24 +3974,27 @@ "phpoffice/phpexcel": "<1.8", "phpoffice/phpspreadsheet": "<1.16", "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.19", - "phpservermon/phpservermon": "<=3.5.2", + "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.2.5", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", + "pi/pi": "<=2.5", + "pimcore/admin-ui-classic-bundle": "<1.0.3", + "pimcore/customer-management-framework-bundle": "<3.4.1", "pimcore/data-hub": "<1.2.4", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.5.20", + "pimcore/pimcore": "<10.6.4", "pixelfed/pixelfed": "<=0.11.4", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.12.5|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.0.1", + "prestashop/prestashop": "<8.0.4", "prestashop/productcomments": "<5.0.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", @@ -3984,7 +4010,8 @@ "pyrocms/pyrocms": "<=3.9.1", "rainlab/debugbar-plugin": "<3.1", "rankmath/seo-by-rank-math": "<=1.0.95", - "react/http": ">=0.7,<1.7", + "rap2hpoutre/laravel-log-viewer": "<0.13", + "react/http": ">=0.7,<1.9", "really-simple-plugins/complianz-gdpr": "<6.4.2", "remdex/livehelperchat": "<3.99", "rmccue/requests": ">=1.6,<1.8", @@ -3994,25 +4021,29 @@ "s-cart/core": "<6.9", "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "sabre/dav": "<1.7.11|>=1.8,<1.8.9", "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.4.18", - "shopware/platform": "<=6.4.18", + "sfroemken/url_redirect": "<=1.2.1", + "sheng/yiicms": "<=1.2", + "shopware/core": "<=6.4.20", + "shopware/platform": "<=6.4.20", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.7.14", + "shopware/shopware": "<=5.7.17", "shopware/storefront": "<=6.4.8.1", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", - "silverstripe/admin": ">=1,<1.11.3", + "silverstripe-australia/advancedreports": ">=1,<=2", + "silverstripe/admin": "<1.12.7", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.11.14", + "silverstripe/framework": "<4.12.5", "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3|= 4.0.0-alpha1", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", + "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", @@ -4028,6 +4059,8 @@ "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", + "sjbr/sr-freecap": "<=2.5.2", + "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.48|>=4,<4.3.1", "snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5", @@ -4035,12 +4068,14 @@ "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", "spipu/html2pdf": "<5.2.4", + "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "ssddanbrown/bookstack": "<22.2.3", - "statamic/cms": "<3.2.39|>=3.3,<3.3.2", + "statamic/cms": "<4.10", "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.59", + "studio-42/elfinder": "<2.1.62", + "subhh/libconnect": "<7.0.8|>=8,<8.1", "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", @@ -4089,13 +4124,14 @@ "t3/dce": ">=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", "tastyigniter/tastyigniter": "<3.3", + "tcg/voyager": "<=1.4", "tecnickcom/tcpdf": "<6.2.22", "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<=5.1.7", - "thorsten/phpmyfaq": "<3.1.12", + "thorsten/phpmyfaq": "<3.2-beta.2", "tinymce/tinymce": "<5.10.7|>=6,<6.3.1", "tinymighty/wiki-seo": "<1.2.2", "titon/framework": ">=0,<9.9.99", @@ -4103,16 +4139,17 @@ "topthink/framework": "<6.0.14", "topthink/think": "<=6.1.1", "topthink/thinkphp": "<=3.2.3", + "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", "tribalsystems/zenario": "<=9.3.57595", "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<=6.2.38|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": "<8.7.51|>=9,<9.5.40|>=10,<10.4.36|>=11,<11.5.23|>=12,<12.2", + "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<1.5|>=2,<2.1.1", + "typo3/html-sanitizer": ">=1,<1.5.1|>=2,<2.1.2", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", @@ -4121,27 +4158,30 @@ "unisharp/laravel-filemanager": "<=2.5.1", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "uvdesk/community-skeleton": "<1.1", + "uvdesk/community-skeleton": "<=1.1.1", "vanilla/safecurl": "<0.9.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<2.5.4", + "wallabag/wallabag": "<=2.5.4", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", "webcoast/deferred-image-processing": "<1.0.2", + "webklex/laravel-imap": "<5.3", + "webklex/php-imap": "<5.3", "webpa/webpa": "<3.1.2", + "wikibase/wikibase": "<=1.39.3", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", - "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1", + "wintercms/winter": "<1.2.3", "woocommerce/woocommerce": "<6.6", "wp-cli/wp-cli": "<2.5", - "wp-graphql/wp-graphql": "<0.3.5", + "wp-graphql/wp-graphql": "<=1.14.5", "wpanel/wpanel4-cms": "<=4.3.1", "wpcloud/wp-stateless": "<3.2", - "wwbn/avideo": "<12.4", + "wwbn/avideo": "<=12.4", "xataface/xataface": "<3", "xpressengine/xpressengine": "<3.0.15", "yeswiki/yeswiki": "<4.1", @@ -4159,6 +4199,7 @@ "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", "yourls/yourls": "<=1.8.2", + "zencart/zencart": "<1.5.8", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", @@ -4181,6 +4222,7 @@ "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", + "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", @@ -4222,7 +4264,7 @@ "type": "tidelift" } ], - "time": "2023-02-09T20:04:23+00:00" + "time": "2023-07-25T19:04:12+00:00" }, { "name": "robmorgan/phinx", @@ -4365,16 +4407,16 @@ }, { "name": "symfony/config", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179" + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9bd60843443cda9638efdca7c41eb82ed0026179", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179", + "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", "shasum": "" }, "require": { @@ -4424,7 +4466,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.19" + "source": "https://github.com/symfony/config/tree/v5.4.21" }, "funding": [ { @@ -4440,20 +4482,20 @@ "type": "tidelift" } ], - "time": "2023-01-08T13:23:55+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/console", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" + "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", + "url": "https://api.github.com/repos/symfony/console/zipball/560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", + "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", "shasum": "" }, "require": { @@ -4518,12 +4560,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.19" + "source": "https://github.com/symfony/console/tree/v5.4.24" }, "funding": [ { @@ -4539,20 +4581,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-26T05:13:16+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f4a7d150f5b9e8f974f6f127d8167e420d11fc62" + "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4a7d150f5b9e8f974f6f127d8167e420d11fc62", - "reference": "f4a7d150f5b9e8f974f6f127d8167e420d11fc62", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/95f3c7468db1da8cc360b24fa2a26e7cefcb355d", + "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d", "shasum": "" }, "require": { @@ -4589,7 +4631,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.19" + "source": "https://github.com/symfony/css-selector/tree/v5.4.21" }, "funding": [ { @@ -4605,7 +4647,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4676,16 +4718,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.19", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8" + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", "shasum": "" }, "require": { @@ -4720,7 +4762,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.19" + "source": "https://github.com/symfony/filesystem/tree/v5.4.25" }, "funding": [ { @@ -4736,20 +4778,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-05-31T13:04:02+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.20", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a" + "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0435363362a47c14e9cf50663cb8ffbf491875a", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f66be2706075c5f6325d2fe2b743a57fb5d23f6b", + "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b", "shasum": "" }, "require": { @@ -4796,7 +4838,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.20" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.25" }, "funding": [ { @@ -4812,20 +4854,20 @@ "type": "tidelift" } ], - "time": "2023-01-29T11:11:52+00:00" + "time": "2023-06-22T08:06:06+00:00" }, { "name": "symfony/mime", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "a858429a9c704edc53fe057228cf9ca282ba48eb" + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/a858429a9c704edc53fe057228cf9ca282ba48eb", - "reference": "a858429a9c704edc53fe057228cf9ca282ba48eb", + "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", "shasum": "" }, "require": { @@ -4880,7 +4922,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.19" + "source": "https://github.com/symfony/mime/tree/v5.4.23" }, "funding": [ { @@ -4896,7 +4938,7 @@ "type": "tidelift" } ], - "time": "2023-01-09T05:43:46+00:00" + "time": "2023-04-19T09:49:13+00:00" }, { "name": "symfony/polyfill-ctype", @@ -5634,16 +5676,16 @@ }, { "name": "symfony/routing", - "version": "v5.4.19", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5" + "reference": "56bfc1394f7011303eb2e22724f9b422d3f14649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", + "url": "https://api.github.com/repos/symfony/routing/zipball/56bfc1394f7011303eb2e22724f9b422d3f14649", + "reference": "56bfc1394f7011303eb2e22724f9b422d3f14649", "shasum": "" }, "require": { @@ -5704,7 +5746,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.19" + "source": "https://github.com/symfony/routing/tree/v5.4.25" }, "funding": [ { @@ -5720,7 +5762,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-06-05T14:18:47+00:00" }, { "name": "symfony/service-contracts", @@ -5807,16 +5849,16 @@ }, { "name": "symfony/string", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", + "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", "shasum": "" }, "require": { @@ -5873,7 +5915,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.19" + "source": "https://github.com/symfony/string/tree/v5.4.22" }, "funding": [ { @@ -5889,20 +5931,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T06:11:53+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.19", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b" + "reference": "82269f73c0f0f9859ab9b6900eebacbe54954ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82269f73c0f0f9859ab9b6900eebacbe54954ede", + "reference": "82269f73c0f0f9859ab9b6900eebacbe54954ede", "shasum": "" }, "require": { @@ -5911,7 +5953,6 @@ "symfony/polyfill-php80": "^1.16" }, "conflict": { - "phpunit/phpunit": "<5.4.3", "symfony/console": "<4.4" }, "require-dev": { @@ -5962,7 +6003,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.19" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.25" }, "funding": [ { @@ -5978,7 +6019,7 @@ "type": "tidelift" } ], - "time": "2023-01-16T10:52:33+00:00" + "time": "2023-06-20T20:56:26+00:00" }, { "name": "vanilla/htmlawed", @@ -6343,16 +6384,16 @@ }, { "name": "jms/metadata", - "version": "2.7.0", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/metadata.git", - "reference": "283c714831d272d78ddd6e52e08ac16d76be30fd" + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/283c714831d272d78ddd6e52e08ac16d76be30fd", - "reference": "283c714831d272d78ddd6e52e08ac16d76be30fd", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", "shasum": "" }, "require": { @@ -6363,7 +6404,7 @@ "doctrine/coding-standard": "^8.0", "mikey179/vfsstream": "^1.6.7", "phpunit/phpunit": "^8.5|^9.0", - "psr/container": "^1.0", + "psr/container": "^1.0|^2.0", "symfony/cache": "^3.1|^4.0|^5.0", "symfony/dependency-injection": "^3.1|^4.0|^5.0" }, @@ -6401,28 +6442,28 @@ ], "support": { "issues": "https://github.com/schmittjoh/metadata/issues", - "source": "https://github.com/schmittjoh/metadata/tree/2.7.0" + "source": "https://github.com/schmittjoh/metadata/tree/2.8.0" }, - "time": "2022-09-13T19:18:27+00:00" + "time": "2023-02-15T13:44:18+00:00" }, { "name": "jms/serializer", - "version": "3.22.0", + "version": "3.26.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "576d226178697534e214531dbf80058637a10ebc" + "reference": "926a7d57438fa1ff4ab794551c5ae26e68536853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/576d226178697534e214531dbf80058637a10ebc", - "reference": "576d226178697534e214531dbf80058637a10ebc", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/926a7d57438fa1ff4ab794551c5ae26e68536853", + "reference": "926a7d57438fa1ff4ab794551c5ae26e68536853", "shasum": "" }, "require": { "doctrine/annotations": "^1.13 || ^2.0", - "doctrine/instantiator": "^1.0.3", - "doctrine/lexer": "^1.1 || ^2", + "doctrine/instantiator": "^1.0.3 || ^2.0", + "doctrine/lexer": "^2", "jms/metadata": "^2.6", "php": "^7.2||^8.0", "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" @@ -6437,8 +6478,8 @@ "ocramius/proxy-manager": "^1.0|^2.0", "phpbench/phpbench": "^1.0", "phpstan/phpstan": "^1.0.2", - "phpunit/phpunit": "^8.5.21||^9.0", - "psr/container": "^1.0", + "phpunit/phpunit": "^8.5.21||^9.0||^10.0", + "psr/container": "^1.0|^2.0", "symfony/dependency-injection": "^3.0|^4.0|^5.0|^6.0", "symfony/expression-language": "^3.2|^4.0|^5.0|^6.0", "symfony/filesystem": "^3.0|^4.0|^5.0|^6.0", @@ -6491,7 +6532,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.22.0" + "source": "https://github.com/schmittjoh/serializer/tree/3.26.0" }, "funding": [ { @@ -6499,20 +6540,20 @@ "type": "github" } ], - "time": "2023-02-03T04:58:11+00:00" + "time": "2023-06-24T19:25:58+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -6550,7 +6591,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -6558,20 +6599,20 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.3", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -6612,9 +6653,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-01-16T22:05:37+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "phar-io/manifest", @@ -6839,24 +6880,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -6888,30 +6932,30 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-05-30T18:13:47+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8", - "phpunit/phpunit": "^8.5.28 || ^9.5.21" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" }, "type": "library", "extra": { @@ -6953,7 +6997,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" }, "funding": [ { @@ -6965,26 +7009,28 @@ "type": "tidelift" } ], - "time": "2022-07-30T15:51:26+00:00" + "time": "2023-02-25T19:38:58+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.16.1", + "version": "1.23.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + "reference": "a2b24135c35852b348894320d47b3902a94bc494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", + "reference": "a2b24135c35852b348894320d47b3902a94bc494", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", @@ -7008,29 +7054,29 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.0" }, - "time": "2023-02-07T18:11:17+00:00" + "time": "2023-07-23T22:17:56+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.24", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -7045,8 +7091,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -7079,7 +7125,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -7087,7 +7133,7 @@ "type": "github" } ], - "time": "2023-01-26T08:26:55+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -7332,16 +7378,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.3", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -7374,8 +7420,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -7414,7 +7460,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -7430,7 +7477,7 @@ "type": "tidelift" } ], - "time": "2023-02-04T13:37:15+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "scrutinizer/ocular", @@ -7777,16 +7824,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -7831,7 +7878,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -7839,7 +7886,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", @@ -8443,16 +8490,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.1", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, "require": { @@ -8488,27 +8535,28 @@ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2022-06-18T07:21:10+00:00" + "time": "2023-02-22T23:07:41+00:00" }, { "name": "symfony/process", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" + "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", + "url": "https://api.github.com/repos/symfony/process/zipball/e3c46cc5689c8782944274bb30702106ecbe3b64", + "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64", "shasum": "" }, "require": { @@ -8541,7 +8589,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.19" + "source": "https://github.com/symfony/process/tree/v5.4.24" }, "funding": [ { @@ -8557,7 +8605,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-17T11:26:05+00:00" }, { "name": "theseer/tokenizer", From d3ac96dc7cb68dea49aa82c4f46822d9c24262d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 26 Jul 2023 10:56:55 +0200 Subject: [PATCH 045/240] chore(release): v4.3.9 --- CHANGELOG.md | 13 +++++++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf61e9d176e..e515687d1fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ + +### 4.3.9 (2023-07-26) + +#### Contributors + +* Jerôme Bakker (2) +* Nikolai Shcherbin (1) + +#### Bug Fixes + +* **admin:** use correct params for memcache and redis server information ([6ee26b94](https://github.com/Elgg/Elgg/commit/6ee26b94637a384af133187afb9fab766ef324da)) + + ### 4.3.8 (2023-04-04) diff --git a/composer.json b/composer.json index d5ecf33955a..37c959b622d 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "4.3.8", + "version": "4.3.9", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 31aa5065354..a80b69590e5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e83d7f801ce5abb6f62a72990b98ce13", + "content-hash": "642f069c3c1990b47ed210c4f6444791", "packages": [ { "name": "cakephp/core", From d3c8d6f359c4ac5dc590d1f6e338e553072b7777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 26 Jul 2023 12:09:02 +0200 Subject: [PATCH 046/240] chore(release): v5.0.4 --- CHANGELOG.md | 21 +++++++++++++++++++++ composer.json | 2 +- composer.lock | 44 ++++++++++++++++++++++++++++---------------- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66934dab513..c90b02fd4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ + +### 5.0.4 (2023-07-26) + +#### Contributors + +* Jerôme Bakker (9) +* Jeroen Dalsem (1) + +#### Bug Fixes + +* **ckeditor:** added all block level image alignments to toolbar ([6fff9429](https://github.com/Elgg/Elgg/commit/6fff94290017df4a9bf879236b73c1f0be92c62e)) +* **icons:** prevent racing condition when saving cropping coordinates ([b4993528](https://github.com/Elgg/Elgg/commit/b499352814c45d8fbfc1eefa3fa5294e27de68cb)) +* **notifications:** processing delayed emails could cause OOM issues ([5e0fcab1](https://github.com/Elgg/Elgg/commit/5e0fcab17eb701474d1d121933474eefa52b7aca)) +* **views:** + * input/button and output/url must have discernible text ([924b2cdc](https://github.com/Elgg/Elgg/commit/924b2cdcae2a97447a2094b7389fe9ebb1d2f74e)) + * make sure the icon cropper img has an alt text ([0cc105c8](https://github.com/Elgg/Elgg/commit/0cc105c8b684ed756b4839c1d72df714f17a1865)) + * allow mobile devices to zoom ([1cee1be1](https://github.com/Elgg/Elgg/commit/1cee1be17474da910172dd5cc829f10a67c7fd0b)) + * correctly set iframe width for PHPInfo ([e72f476e](https://github.com/Elgg/Elgg/commit/e72f476eb62ce5e8253deaf7ea9ca71fe70c79c5)) + * only generate listing ID when using pagination ([ffe94eab](https://github.com/Elgg/Elgg/commit/ffe94eab174e0984cf288585fd91d24ac8d07a55)) + + ### 5.0.3 (2023-07-14) diff --git a/composer.json b/composer.json index 7f5163f19ad..ef9a16ecee6 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "5.0.3", + "version": "5.0.4", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 2f6e79a8647..681946d0230 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9bdb13390b2a5080760718ae1bb23a3d", + "content-hash": "61fb31bb7bef904f2188ed4a2ae549cb", "packages": [ { "name": "cakephp/core", @@ -3645,9 +3645,9 @@ }, "conflict": { "3f/pygmentize": "<1.2", - "admidio/admidio": "<4.2.9", + "admidio/admidio": "<4.2.10", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", - "aheinze/cockpit": "<=2.2.1", + "aheinze/cockpit": "<2.2", "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", @@ -3674,6 +3674,7 @@ "aws/aws-sdk-php": ">=3,<3.2.1", "azuracast/azuracast": "<0.18.3", "backdrop/backdrop": "<1.24.2", + "backpack/crud": "<3.4.9", "badaso/core": "<2.7", "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", @@ -3706,7 +3707,7 @@ "catfan/medoo": "<1.7.5", "centreon/centreon": "<22.10-beta.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "cockpit-hq/cockpit": "<2.4.1", + "cockpit-hq/cockpit": "<2.6", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<=3.0.6", "codeigniter4/framework": "<4.3.5", @@ -3718,7 +3719,7 @@ "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4|= 4.10.0", + "contao/core-bundle": "<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", "cosenary/instagram": "<=2.3", @@ -3787,6 +3788,7 @@ "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", "flarum/core": "<1.7", + "flarum/framework": "<=0.1-beta.7.1", "flarum/mentions": "<1.6.3", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", @@ -3808,8 +3810,9 @@ "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", - "getgrav/grav": "<1.7.42", + "getgrav/grav": "<=1.7.42.1", "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", + "getkirby/kirby": "<=2.5.12", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", @@ -3858,7 +3861,9 @@ "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", + "joomla/framework": ">=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", + "joomla/joomla-cms": ">=3,<3.9.12", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", @@ -3878,7 +3883,7 @@ "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", "laravel/fortify": "<1.11.1", - "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "laravel/framework": "<6.20.44|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", "lavalite/cms": "= 9.0.0|<=9", @@ -3895,7 +3900,7 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": "<=2.4", + "magento/community-edition": "= 2.4.0|<=2.4", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", @@ -3911,15 +3916,16 @@ "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "= 1.1.18|<=1.3.4", + "microweber/microweber": "<=1.3.4|= 1.1.18", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<= 2.8.3-pl|<2.8", + "modx/revolution": "<2.8|<= 2.8.3-pl", "mojo42/jirafeau": "<4.4", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.2-rc.2|= 3.9|= 3.8|= 4.2.0|= 3.11", + "moodle/moodle": "<4.2-rc.2|= 3.4.3|= 3.5|= 3.7|= 3.9|= 3.8|= 4.2.0|= 3.11", "movim/moxl": ">=0.8,<=0.10", + "mpdf/mpdf": "<=7.1.7", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", @@ -3940,7 +3946,7 @@ "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466|>=2.1,<2.1.12", + "october/october": "<1.0.466|>=2.1,<2.1.12", "october/rain": "<1.0.472|>=1.1,<1.1.2", "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", "onelogin/php-saml": "<2.10.4", @@ -3988,10 +3994,10 @@ "pimcore/customer-management-framework-bundle": "<3.4.1", "pimcore/data-hub": "<1.2.4", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.5.23", + "pimcore/pimcore": "<10.6.4", "pixelfed/pixelfed": "<=0.11.4", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.20.5|>=4.21,<4.21.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", @@ -4028,6 +4034,7 @@ "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", + "sfroemken/url_redirect": "<=1.2.1", "sheng/yiicms": "<=1.2", "shopware/core": "<=6.4.20", "shopware/platform": "<=6.4.20", @@ -4036,6 +4043,7 @@ "shopware/storefront": "<=6.4.8.1", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", + "silverstripe-australia/advancedreports": ">=1,<=2", "silverstripe/admin": "<1.12.7", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", @@ -4044,6 +4052,7 @@ "silverstripe/framework": "<4.12.5", "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3|= 4.0.0-alpha1", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", + "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", @@ -4059,6 +4068,7 @@ "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", + "sjbr/sr-freecap": "<=2.5.2", "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.48|>=4,<4.3.1", @@ -4067,6 +4077,7 @@ "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", "spipu/html2pdf": "<5.2.4", + "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "ssddanbrown/bookstack": "<22.2.3", @@ -4144,10 +4155,10 @@ "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<=6.2.38|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": "<8.7.51|>=9,<9.5.40|>=10,<10.4.36|>=11,<11.5.23|>=12,<12.2", + "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<1.5|>=2,<2.1.1", + "typo3/html-sanitizer": ">=1,<1.5.1|>=2,<2.1.2", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", @@ -4220,6 +4231,7 @@ "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", + "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", From 1856f30b0f8a0a33c38e855ff280e3546626a72e Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 26 Jul 2023 15:33:41 +0200 Subject: [PATCH 047/240] chore(breadcrumbs): log a notice for a breadcrumb without a link --- engine/classes/Elgg/Menus/Breadcrumbs.php | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/classes/Elgg/Menus/Breadcrumbs.php b/engine/classes/Elgg/Menus/Breadcrumbs.php index e6b9fbac0c3..f94f8531d7a 100644 --- a/engine/classes/Elgg/Menus/Breadcrumbs.php +++ b/engine/classes/Elgg/Menus/Breadcrumbs.php @@ -36,6 +36,7 @@ public static function cleanupBreadcrumbs(\Elgg\Event $event) { // remove last crumb if it has no link if (empty($last->getHref())) { + elgg_log("Having a breadcrumb at the end of the list without a link makes no sense. Please update your code for the '{$last->getText()}[{$last->getID()}]' breadcrumb.", 'NOTICE'); $breadcrumbs->getSection('default')->remove($last->getID()); } } From 7a44a533c2d68f7402abb0b124698934e6626b75 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 26 Jul 2023 15:34:56 +0200 Subject: [PATCH 048/240] fix(breadcrumbs): no longer add a breadcrumb if link to self is false --- engine/lib/breadcrumbs.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/engine/lib/breadcrumbs.php b/engine/lib/breadcrumbs.php index 1834657e4fe..3239834e07f 100644 --- a/engine/lib/breadcrumbs.php +++ b/engine/lib/breadcrumbs.php @@ -27,7 +27,7 @@ function elgg_push_breadcrumb(string $text, string|false $href = false): void { * Resolves and pushes entity breadcrumbs based on named routes * * @param \ElggEntity $entity Entity - * @param bool $link_self Use entity link in the last crumb + * @param bool $link_self Add a link to the entity * * @return void */ @@ -35,11 +35,13 @@ function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = tru elgg_push_collection_breadcrumbs($entity->type, $entity->subtype, $entity->getContainerEntity()); - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'entity', - 'text' => $entity->getDisplayName(), - 'href' => $link_self ? $entity->getURL() : false, - ]); + if ($link_self) { + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'entity', + 'text' => $entity->getDisplayName(), + 'href' => $entity->getURL(), + ]); + } } /** From e78e7ee68519cd44c07721c9a1c95fd6080eea17 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 26 Jul 2023 17:00:23 +0200 Subject: [PATCH 049/240] feat(breadcrumbs): added a home icon as a first item --- engine/classes/Elgg/Menus/Breadcrumbs.php | 39 +++++++++++++++++++++-- engine/events.php | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/engine/classes/Elgg/Menus/Breadcrumbs.php b/engine/classes/Elgg/Menus/Breadcrumbs.php index f94f8531d7a..eb82db31df3 100644 --- a/engine/classes/Elgg/Menus/Breadcrumbs.php +++ b/engine/classes/Elgg/Menus/Breadcrumbs.php @@ -17,9 +17,9 @@ class Breadcrumbs { * * @param \Elgg\Event $event 'prepare', 'menu:breadcrumbs' * - * @return void|PreparedMenu + * @return void */ - public static function cleanupBreadcrumbs(\Elgg\Event $event) { + public static function cleanupBreadcrumbs(\Elgg\Event $event): void { /* @var $breadcrumbs PreparedMenu */ $breadcrumbs = $event->getValue(); @@ -40,4 +40,39 @@ public static function cleanupBreadcrumbs(\Elgg\Event $event) { $breadcrumbs->getSection('default')->remove($last->getID()); } } + + /** + * Adds a home item + * + * @param \Elgg\Event $event 'prepare', 'menu:breadcrumbs' + * + * @return null|PreparedMenu + */ + public static function addHomeItem(\Elgg\Event $event): ?PreparedMenu { + /* @var $return PreparedMenu */ + $return = $event->getValue(); + + /* @var $items \ElggMenuItem[] */ + $items = $return->getItems('default'); + if (empty($items)) { + return null; + } + + $href = elgg_get_site_url(); + if (elgg_in_context('admin')) { + $href = elgg_generate_url('admin'); + } + + array_unshift($items, \ElggMenuItem::factory([ + 'name' => 'home', + 'icon' => 'home', + 'text' => false, + 'title' => elgg_get_site_entity()->getDisplayName(), + 'href' => $href, + ])); + + $return->getSection('default')->fill($items); + + return $return; + } } diff --git a/engine/events.php b/engine/events.php index b9c0dc3504f..50102f89e08 100644 --- a/engine/events.php +++ b/engine/events.php @@ -226,6 +226,7 @@ 'Elgg\Menus\AdminUsersBulk::disableItems' => [], ], 'menu:breadcrumbs' => [ + '\Elgg\Menus\Breadcrumbs::addHomeItem' => ['priority' => 10000], '\Elgg\Menus\Breadcrumbs::cleanupBreadcrumbs' => ['priority' => 9999], ], 'menu:site' => [ From 95b3054585ca07c85de328a28e0346a51385ead6 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 27 Jul 2023 08:29:58 +0200 Subject: [PATCH 050/240] feat(breadcrumbs): last item pointing to current page will be removed --- engine/classes/Elgg/Menus/Breadcrumbs.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/classes/Elgg/Menus/Breadcrumbs.php b/engine/classes/Elgg/Menus/Breadcrumbs.php index eb82db31df3..52507fa8c94 100644 --- a/engine/classes/Elgg/Menus/Breadcrumbs.php +++ b/engine/classes/Elgg/Menus/Breadcrumbs.php @@ -38,6 +38,9 @@ public static function cleanupBreadcrumbs(\Elgg\Event $event): void { if (empty($last->getHref())) { elgg_log("Having a breadcrumb at the end of the list without a link makes no sense. Please update your code for the '{$last->getText()}[{$last->getID()}]' breadcrumb.", 'NOTICE'); $breadcrumbs->getSection('default')->remove($last->getID()); + } elseif (!$last->getChildren() && elgg_http_url_is_identical(elgg_get_current_url(), $last->getHref())) { + elgg_log("Having a breadcrumb at the end of the list which links to the current page makes no sense. Please update your code for the '{$last->getText()}[{$last->getID()}]' breadcrumb.", 'NOTICE'); + $breadcrumbs->getSection('default')->remove($last->getID()); } } From 68c6d069e785eeb56446b1db84c4f4bf402e471c Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 27 Jul 2023 14:58:38 +0200 Subject: [PATCH 051/240] feat(breadcrumbs): improved usability of elgg_push_collection_breadcrumb --- engine/lib/breadcrumbs.php | 57 +++++++++++++------ .../default/resources/activity/friends.php | 1 - .../default/resources/activity/group.php | 2 - .../default/resources/activity/owner.php | 1 - .../views/default/resources/blog/view.php | 2 +- .../default/resources/bookmarks/view.php | 2 +- .../default/resources/discussion/view.php | 2 +- .../views/default/resources/file/view.php | 2 +- .../resources/friends/collections/add.php | 3 - .../resources/friends/collections/edit.php | 7 +-- .../resources/friends/collections/owner.php | 4 -- .../resources/friends/collections/view.php | 5 +- .../views/default/resources/groups/add.php | 2 +- .../views/default/resources/groups/edit.php | 3 +- .../default/resources/groups/invitations.php | 2 +- .../views/default/resources/groups/invite.php | 3 +- .../default/resources/groups/invites.php | 3 +- .../views/default/resources/groups/member.php | 2 +- .../default/resources/groups/members.php | 3 +- .../views/default/resources/groups/owner.php | 2 +- .../default/resources/groups/profile.php | 2 +- .../default/resources/groups/requests.php | 3 +- .../views/default/resources/groups/search.php | 2 +- .../settings/notifications/groups.php | 6 +- .../default/resources/friends/invite.php | 1 - mod/pages/lib/pages.php | 6 +- .../views/default/resources/pages/add.php | 1 - .../views/default/resources/pages/edit.php | 6 +- .../views/default/resources/pages/history.php | 7 +-- .../default/resources/pages/revision.php | 2 +- .../views/default/resources/profile/edit.php | 2 +- .../default/resources/profile/edit_header.php | 4 +- .../views/default/resources/thewire/reply.php | 2 +- .../views/default/resources/thewire/view.php | 8 +-- views/default/page/layouts/admin.php | 2 - views/default/page/layouts/default.php | 9 ++- views/default/page/layouts/elements/body.php | 14 ++--- .../page/layouts/elements/breadcrumbs.php | 2 +- views/default/page/layouts/error.php | 1 - views/default/resources/avatar/edit.php | 2 +- views/default/resources/comments/edit.php | 2 +- views/default/resources/settings/account.php | 2 - .../resources/settings/notifications.php | 6 +- .../settings/notifications/users.php | 6 +- .../default/resources/settings/statistics.php | 4 -- views/default/resources/settings/tools.php | 2 - 46 files changed, 87 insertions(+), 125 deletions(-) diff --git a/engine/lib/breadcrumbs.php b/engine/lib/breadcrumbs.php index 3239834e07f..4988887172c 100644 --- a/engine/lib/breadcrumbs.php +++ b/engine/lib/breadcrumbs.php @@ -27,14 +27,20 @@ function elgg_push_breadcrumb(string $text, string|false $href = false): void { * Resolves and pushes entity breadcrumbs based on named routes * * @param \ElggEntity $entity Entity - * @param bool $link_self Add a link to the entity + * @param bool $link_self (deprecated) Add a link to the entity * * @return void */ -function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = true): void { +function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = null): void { elgg_push_collection_breadcrumbs($entity->type, $entity->subtype, $entity->getContainerEntity()); + if (isset($link_self)) { + elgg_deprecated_notice('Using link_self argument is deprecated. A link to self will always be added if not on the "view" route of the entity.', '5.1'); + } else { + $link_self = elgg_get_current_route_name() !== "view:{$entity->type}:{$entity->subtype}"; + } + if ($link_self) { elgg_register_menu_item('breadcrumbs', [ 'name' => 'entity', @@ -55,9 +61,9 @@ function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = tru * @return void */ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_subtype, \ElggEntity $container = null, bool $friends = false): void { - + if ($container) { - if (!$container instanceof \ElggSite) { + if (!$container instanceof \ElggSite && $entity_type !== 'group') { elgg_register_menu_item('breadcrumbs', [ 'name' => 'container', 'text' => $container->getDisplayName(), @@ -67,15 +73,21 @@ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_su if ($friends) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:friends"; - } else if ($container instanceof ElggUser) { + } elseif ($entity_type === 'group') { + $collection_route = "collection:{$entity_type}:{$entity_subtype}:all"; + } elseif ($container instanceof \ElggUser) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:owner"; - } else if ($container instanceof ElggGroup) { + } elseif ($container instanceof \ElggGroup) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:group"; - } else if ($container instanceof ElggSite) { + } elseif ($container instanceof \ElggSite) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:all"; } else { $collection_route = "collection:{$entity_type}:{$entity_subtype}:container"; } + + if ($collection_route === elgg_get_current_route_name()) { + return; + } $parameters = _elgg_services()->routes->resolveRouteParameters($collection_route, $container); if ($parameters !== false) { @@ -88,17 +100,26 @@ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_su } } - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'collection', - 'text' => $label, - 'href' => elgg_generate_url($collection_route, $parameters), - ]); + if (elgg_route_exists($collection_route)) { + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'collection', + 'text' => $label, + 'href' => elgg_generate_url($collection_route, $parameters), + ]); + } } - } else { - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'collection', - 'text' => elgg_echo("collection:{$entity_type}:{$entity_subtype}"), - 'href' => elgg_generate_url("collection:{$entity_type}:{$entity_subtype}:all"), - ]); + + return; } + + $all_route_name = "collection:{$entity_type}:{$entity_subtype}:all"; + if (!elgg_route_exists($all_route_name) || ($all_route_name === elgg_get_current_route_name())) { + return; + } + + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'collection', + 'text' => elgg_echo("collection:{$entity_type}:{$entity_subtype}"), + 'href' => elgg_generate_url($all_route_name), + ]); } diff --git a/mod/activity/views/default/resources/activity/friends.php b/mod/activity/views/default/resources/activity/friends.php index 3e8dd57058f..4ed1a98f842 100644 --- a/mod/activity/views/default/resources/activity/friends.php +++ b/mod/activity/views/default/resources/activity/friends.php @@ -6,7 +6,6 @@ $page_owner = elgg_get_page_owner_entity(); elgg_push_breadcrumb($page_owner->getDisplayName(), $page_owner->getURL()); -elgg_push_breadcrumb(elgg_echo('river:friends'), elgg_generate_url('collection:river:friends', ['username' => $page_owner->username])); $content = elgg_view('river/listing/friends', [ 'entity' => $page_owner, diff --git a/mod/activity/views/default/resources/activity/group.php b/mod/activity/views/default/resources/activity/group.php index 519d543f8b1..1b8aa4e73a7 100644 --- a/mod/activity/views/default/resources/activity/group.php +++ b/mod/activity/views/default/resources/activity/group.php @@ -4,9 +4,7 @@ elgg_group_tool_gatekeeper('activity'); -// can't use elgg_push_collection_breadcrumbs() because of the routenames for river elgg_push_breadcrumb($page_owner->getDisplayName(), $page_owner->getURL()); -elgg_push_breadcrumb(elgg_echo('collection:river'), elgg_generate_url('collection:river:group', ['guid' => $page_owner->guid])); $content = elgg_view('river/listing/group', [ 'entity' => $page_owner, diff --git a/mod/activity/views/default/resources/activity/owner.php b/mod/activity/views/default/resources/activity/owner.php index 67c0511bd3f..8a421a0707d 100644 --- a/mod/activity/views/default/resources/activity/owner.php +++ b/mod/activity/views/default/resources/activity/owner.php @@ -14,7 +14,6 @@ } elgg_push_breadcrumb($page_owner->getDisplayName(), $page_owner->getURL()); -elgg_push_breadcrumb($title, elgg_generate_url('collection:river:owner', ['username' => $page_owner->username])); $content = elgg_view('river/listing/owner', [ 'entity' => $page_owner, diff --git a/mod/blog/views/default/resources/blog/view.php b/mod/blog/views/default/resources/blog/view.php index d1c8640cfff..7718839e91b 100644 --- a/mod/blog/views/default/resources/blog/view.php +++ b/mod/blog/views/default/resources/blog/view.php @@ -5,7 +5,7 @@ $entity = get_entity($guid); -elgg_push_entity_breadcrumbs($entity, false); +elgg_push_entity_breadcrumbs($entity); echo elgg_view_page($entity->getDisplayName(), [ 'content' => elgg_view_entity($entity, [ diff --git a/mod/bookmarks/views/default/resources/bookmarks/view.php b/mod/bookmarks/views/default/resources/bookmarks/view.php index cf1b5c0bfc2..662d55c2473 100644 --- a/mod/bookmarks/views/default/resources/bookmarks/view.php +++ b/mod/bookmarks/views/default/resources/bookmarks/view.php @@ -9,7 +9,7 @@ $entity = get_entity($guid); -elgg_push_entity_breadcrumbs($entity, false); +elgg_push_entity_breadcrumbs($entity); echo elgg_view_page($entity->getDisplayName(), [ 'content' => elgg_view_entity($entity, [ diff --git a/mod/discussions/views/default/resources/discussion/view.php b/mod/discussions/views/default/resources/discussion/view.php index 0ecb5042b8f..818df757d52 100644 --- a/mod/discussions/views/default/resources/discussion/view.php +++ b/mod/discussions/views/default/resources/discussion/view.php @@ -6,7 +6,7 @@ $topic = get_entity($guid); -elgg_push_entity_breadcrumbs($topic, false); +elgg_push_entity_breadcrumbs($topic); $content = elgg_view_entity($topic, [ 'full_view' => true, diff --git a/mod/file/views/default/resources/file/view.php b/mod/file/views/default/resources/file/view.php index 1bc7000f3fe..3d7daf28f11 100644 --- a/mod/file/views/default/resources/file/view.php +++ b/mod/file/views/default/resources/file/view.php @@ -10,7 +10,7 @@ /* @var $file \ElggFile */ $file = get_entity($guid); -elgg_push_entity_breadcrumbs($file, false); +elgg_push_entity_breadcrumbs($file); if ($file->canDownload()) { elgg_register_menu_item('title', [ diff --git a/mod/friends_collections/views/default/resources/friends/collections/add.php b/mod/friends_collections/views/default/resources/friends/collections/add.php index 31bebe0e187..731f4836b95 100644 --- a/mod/friends_collections/views/default/resources/friends/collections/add.php +++ b/mod/friends_collections/views/default/resources/friends/collections/add.php @@ -5,12 +5,9 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); -elgg_push_breadcrumb(elgg_echo('friends'), elgg_generate_url('collection:friends:owner', ['username' => $user->username])); elgg_push_breadcrumb(elgg_echo('friends:collections'), elgg_generate_url('collection:access_collection:friends:owner', ['username' => $user->username])); echo elgg_view_page(elgg_echo('friends:collections:add'), [ 'content' => elgg_view_form('friends/collections/edit', ['sticky_enabled' => true]), - 'show_owner_block_menu' => false, 'filter_id' => 'friends_collections/edit', ]); diff --git a/mod/friends_collections/views/default/resources/friends/collections/edit.php b/mod/friends_collections/views/default/resources/friends/collections/edit.php index 93b35147bb9..53b4aac55b3 100644 --- a/mod/friends_collections/views/default/resources/friends/collections/edit.php +++ b/mod/friends_collections/views/default/resources/friends/collections/edit.php @@ -14,22 +14,19 @@ } $user = $collection->getOwnerEntity(); -if (!$user instanceof ElggUser) { +if (!$user instanceof \ElggUser) { throw new EntityNotFoundException(); } elgg_set_page_owner_guid($user->guid); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); -elgg_push_breadcrumb(elgg_echo('friends'), elgg_generate_url('collection:friends:owner', ['username' => $user->username])); elgg_push_breadcrumb(elgg_echo('friends:collections'), elgg_generate_url('collection:access_collection:friends:owner', ['username' => $user->username])); -elgg_push_breadcrumb($collection->name, $collection->getURL()); +elgg_push_breadcrumb($collection->getDisplayName(), $collection->getURL()); echo elgg_view_page(elgg_echo('friends:collections:edit'), [ 'content' => elgg_view_form('friends/collections/edit', ['sticky_enabled' => true], [ 'collection_id' => $collection->id, 'collection_name' => $collection->name, ]), - 'show_owner_block_menu' => false, 'filter_id' => 'friends_collections/edit', ]); diff --git a/mod/friends_collections/views/default/resources/friends/collections/owner.php b/mod/friends_collections/views/default/resources/friends/collections/owner.php index ba59f52eb05..00616135f72 100644 --- a/mod/friends_collections/views/default/resources/friends/collections/owner.php +++ b/mod/friends_collections/views/default/resources/friends/collections/owner.php @@ -5,9 +5,6 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); -elgg_push_breadcrumb(elgg_echo('friends'), elgg_generate_url('collection:friends:owner', ['username' => $user->username])); - elgg_register_menu_item('title', [ 'name' => 'add', 'icon' => 'plus', @@ -22,6 +19,5 @@ 'content' => elgg_view('collections/listing/owner', [ 'entity' => $user, ]), - 'show_owner_block_menu' => false, 'filter_id' => 'friends_collections', ]); diff --git a/mod/friends_collections/views/default/resources/friends/collections/view.php b/mod/friends_collections/views/default/resources/friends/collections/view.php index b1f78d33c94..97ab2f9cc11 100644 --- a/mod/friends_collections/views/default/resources/friends/collections/view.php +++ b/mod/friends_collections/views/default/resources/friends/collections/view.php @@ -15,14 +15,12 @@ } $user = $collection->getOwnerEntity(); -if (!$user instanceof ElggUser) { +if (!$user instanceof \ElggUser) { throw new EntityNotFoundException(); } elgg_set_page_owner_guid($user->guid); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); -elgg_push_breadcrumb(elgg_echo('friends'), elgg_generate_url('collection:friends:owner', ['username' => $user->username])); elgg_push_breadcrumb(elgg_echo('friends:collections'), elgg_generate_url('collection:access_collection:friends:owner', ['username' => $user->username])); echo elgg_view_page($collection->getDisplayName(), [ @@ -30,6 +28,5 @@ 'full_view' => true, 'item' => $collection, ]), - 'show_owner_block_menu' => false, 'filter_id' => 'friends_collections/view', ]); diff --git a/mod/groups/views/default/resources/groups/add.php b/mod/groups/views/default/resources/groups/add.php index dcbc72410a9..22a3ad05866 100644 --- a/mod/groups/views/default/resources/groups/add.php +++ b/mod/groups/views/default/resources/groups/add.php @@ -7,7 +7,7 @@ throw new EntityPermissionsException(); } -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); +elgg_push_collection_breadcrumbs('group', 'group'); echo elgg_view_page(elgg_echo('groups:add'), [ 'content' => elgg_view('groups/edit'), diff --git a/mod/groups/views/default/resources/groups/edit.php b/mod/groups/views/default/resources/groups/edit.php index 4695c38684d..33e5fb44c14 100644 --- a/mod/groups/views/default/resources/groups/edit.php +++ b/mod/groups/views/default/resources/groups/edit.php @@ -2,8 +2,7 @@ $group = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); -elgg_push_breadcrumb($group->getDisplayName(), $group->getURL()); +elgg_push_entity_breadcrumbs($group); echo elgg_view_page(elgg_echo('groups:edit'), [ 'content' => elgg_view('groups/edit', ['entity' => $group]), diff --git a/mod/groups/views/default/resources/groups/invitations.php b/mod/groups/views/default/resources/groups/invitations.php index b6be8b7a183..aa6493e1f49 100644 --- a/mod/groups/views/default/resources/groups/invitations.php +++ b/mod/groups/views/default/resources/groups/invitations.php @@ -2,7 +2,7 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); +elgg_push_collection_breadcrumbs('group', 'group'); $content = elgg_call(ELGG_IGNORE_ACCESS, function() use ($user) { return elgg_list_relationships([ diff --git a/mod/groups/views/default/resources/groups/invite.php b/mod/groups/views/default/resources/groups/invite.php index 90358e25daa..530578a8f70 100644 --- a/mod/groups/views/default/resources/groups/invite.php +++ b/mod/groups/views/default/resources/groups/invite.php @@ -2,8 +2,7 @@ $group = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); -elgg_push_breadcrumb($group->getDisplayName(), $group->getURL()); +elgg_push_entity_breadcrumbs($group); $content = elgg_view_form('groups/invite', [ 'id' => 'invite_to_group', diff --git a/mod/groups/views/default/resources/groups/invites.php b/mod/groups/views/default/resources/groups/invites.php index 4b31607359a..046fc0bd568 100644 --- a/mod/groups/views/default/resources/groups/invites.php +++ b/mod/groups/views/default/resources/groups/invites.php @@ -5,8 +5,7 @@ $group = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); -elgg_push_breadcrumb($group->getDisplayName(), $group->getURL()); +elgg_push_entity_breadcrumbs($group); if (elgg_is_active_plugin('friends')) { elgg_register_menu_item('title', [ diff --git a/mod/groups/views/default/resources/groups/member.php b/mod/groups/views/default/resources/groups/member.php index f8ff14991b9..2e388c36a12 100644 --- a/mod/groups/views/default/resources/groups/member.php +++ b/mod/groups/views/default/resources/groups/member.php @@ -8,7 +8,7 @@ $title = elgg_echo('groups:user', [$page_owner->getDisplayName()]); } -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); +elgg_push_collection_breadcrumbs('group', 'group'); if (elgg_get_plugin_setting('limited_groups', 'groups') !== 'yes' || elgg_is_admin_logged_in()) { elgg_register_title_button('add', 'group', 'group'); diff --git a/mod/groups/views/default/resources/groups/members.php b/mod/groups/views/default/resources/groups/members.php index 24d70e441a1..233e3b2688a 100644 --- a/mod/groups/views/default/resources/groups/members.php +++ b/mod/groups/views/default/resources/groups/members.php @@ -5,8 +5,7 @@ $group = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); -elgg_push_breadcrumb($group->getDisplayName(), $group->getURL()); +elgg_push_entity_breadcrumbs($group); if ($group->canEdit() && elgg_is_active_plugin('friends')) { elgg_register_menu_item('title', [ diff --git a/mod/groups/views/default/resources/groups/owner.php b/mod/groups/views/default/resources/groups/owner.php index 0001b9db81f..e5d8f06c742 100644 --- a/mod/groups/views/default/resources/groups/owner.php +++ b/mod/groups/views/default/resources/groups/owner.php @@ -8,7 +8,7 @@ $title = elgg_echo('groups:owned:user', [$page_owner->getDisplayName()]); } -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); +elgg_push_collection_breadcrumbs('group', 'group'); if (elgg_get_plugin_setting('limited_groups', 'groups') != 'yes' || elgg_is_admin_logged_in()) { elgg_register_title_button('add', 'group', 'group'); diff --git a/mod/groups/views/default/resources/groups/profile.php b/mod/groups/views/default/resources/groups/profile.php index 90238a826ba..99199ee8177 100644 --- a/mod/groups/views/default/resources/groups/profile.php +++ b/mod/groups/views/default/resources/groups/profile.php @@ -7,7 +7,7 @@ elgg_push_context('group_profile'); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); +elgg_push_entity_breadcrumbs($group); $sidebar = ''; if ($group->canAccessContent()) { diff --git a/mod/groups/views/default/resources/groups/requests.php b/mod/groups/views/default/resources/groups/requests.php index 5b3a3ea67cf..43960e7cc8d 100644 --- a/mod/groups/views/default/resources/groups/requests.php +++ b/mod/groups/views/default/resources/groups/requests.php @@ -7,8 +7,7 @@ $group = elgg_get_page_owner_entity(); -elgg_push_breadcrumb(elgg_echo('groups'), elgg_generate_url('collection:group:group:all')); -elgg_push_breadcrumb($group->getDisplayName(), $group->getURL()); +elgg_push_entity_breadcrumbs($group); $content = elgg_list_relationships([ 'relationship' => 'membership_request', diff --git a/mod/groups/views/default/resources/groups/search.php b/mod/groups/views/default/resources/groups/search.php index c908cb200fc..01c8a39f25a 100644 --- a/mod/groups/views/default/resources/groups/search.php +++ b/mod/groups/views/default/resources/groups/search.php @@ -1,6 +1,6 @@ $user->username])); - echo elgg_view_page(elgg_echo('groups:usersettings:notifications:title'), [ 'content' => elgg_view_form('settings/notifications/groups', [ 'action' => 'action/settings/notifications/subscriptions', ], [ - 'entity' => $user, + 'entity' => elgg_get_page_owner_entity(), ]), 'show_owner_block_menu' => false, 'filter_id' => 'settings/notifications', diff --git a/mod/invitefriends/views/default/resources/friends/invite.php b/mod/invitefriends/views/default/resources/friends/invite.php index ade5a53a511..2e51368b24e 100644 --- a/mod/invitefriends/views/default/resources/friends/invite.php +++ b/mod/invitefriends/views/default/resources/friends/invite.php @@ -5,7 +5,6 @@ echo elgg_view_page(elgg_echo('friends:invite'), [ 'content' => elgg_view_form('friends/invite', ['sticky_enabled' => true]), - 'show_owner_block_menu' => false, 'filter_id' => 'friends', 'filter_value' => 'invite', ]); diff --git a/mod/pages/lib/pages.php b/mod/pages/lib/pages.php index 4d1afcbd2d0..600a72ee643 100644 --- a/mod/pages/lib/pages.php +++ b/mod/pages/lib/pages.php @@ -21,7 +21,11 @@ function pages_prepare_parent_breadcrumbs(\ElggPage $page): void { $page = $page->getParentEntity(); } - array_shift($crumbs); + if (elgg_http_url_is_identical(elgg_get_current_url(), $crumbs[0]['href'])) { + // do not add breadcrumb to self + array_shift($crumbs); + } + $crumbs = array_reverse($crumbs); foreach ($crumbs as $crumb) { diff --git a/mod/pages/views/default/resources/pages/add.php b/mod/pages/views/default/resources/pages/add.php index 9f420f4e5ce..8d356f2da81 100644 --- a/mod/pages/views/default/resources/pages/add.php +++ b/mod/pages/views/default/resources/pages/add.php @@ -31,7 +31,6 @@ if ($parent instanceof \ElggPage) { pages_prepare_parent_breadcrumbs($parent); - elgg_push_breadcrumb($parent->getDisplayName(), $parent->getURL()); } echo elgg_view_page(elgg_echo('add:object:page'), [ diff --git a/mod/pages/views/default/resources/pages/edit.php b/mod/pages/views/default/resources/pages/edit.php index d2485138dc0..83079e245a3 100644 --- a/mod/pages/views/default/resources/pages/edit.php +++ b/mod/pages/views/default/resources/pages/edit.php @@ -10,13 +10,9 @@ /* @var $page \ElggPage */ $page = get_entity($page_guid); -$container = $page->getContainerEntity(); -if ($container) { - elgg_push_collection_breadcrumbs('object', 'page', $container); -} +elgg_push_collection_breadcrumbs('object', 'page', $page->getContainerEntity()); pages_prepare_parent_breadcrumbs($page); -elgg_push_breadcrumb($page->getDisplayName(), $page->getURL()); echo elgg_view_page(elgg_echo('edit:object:page'), [ 'content' => elgg_view_form('pages/edit', ['sticky_enabled' => true], [ diff --git a/mod/pages/views/default/resources/pages/history.php b/mod/pages/views/default/resources/pages/history.php index 1167b8237d7..d1ecafadf60 100644 --- a/mod/pages/views/default/resources/pages/history.php +++ b/mod/pages/views/default/resources/pages/history.php @@ -7,16 +7,13 @@ elgg_entity_gatekeeper($page_guid, 'object', 'page', true); +/* @var $page \ElggPage */ $page = get_entity($page_guid); -$container = elgg_get_page_owner_entity(); - -elgg_push_collection_breadcrumbs('object', 'page', $container); +elgg_push_collection_breadcrumbs('object', 'page', elgg_get_page_owner_entity()); pages_prepare_parent_breadcrumbs($page); -elgg_push_breadcrumb($page->getDisplayName(), $page->getURL()); - $title = "{$page->getDisplayName()}: " . elgg_echo('pages:history'); $content = elgg_list_annotations([ diff --git a/mod/pages/views/default/resources/pages/revision.php b/mod/pages/views/default/resources/pages/revision.php index 2021292acbd..7fa33258352 100644 --- a/mod/pages/views/default/resources/pages/revision.php +++ b/mod/pages/views/default/resources/pages/revision.php @@ -26,7 +26,7 @@ elgg_push_collection_breadcrumbs('object', 'page', $page->getContainerEntity()); pages_prepare_parent_breadcrumbs($page); -elgg_push_breadcrumb($page->getDisplayName(), $page->getURL()); + elgg_push_breadcrumb(elgg_echo('pages:history'), elgg_generate_url('history:object:page', ['guid' => $page->guid])); echo elgg_view_page($title, [ diff --git a/mod/profile/views/default/resources/profile/edit.php b/mod/profile/views/default/resources/profile/edit.php index f16c53a56d7..3d8401bf5f6 100644 --- a/mod/profile/views/default/resources/profile/edit.php +++ b/mod/profile/views/default/resources/profile/edit.php @@ -5,7 +5,7 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); +elgg_push_entity_breadcrumbs($user); echo elgg_view_page(elgg_echo('profile:edit'), [ 'content' => elgg_view_form('profile/edit', [], ['entity' => $user]), diff --git a/mod/profile/views/default/resources/profile/edit_header.php b/mod/profile/views/default/resources/profile/edit_header.php index 0732ee8c530..db853db49a3 100644 --- a/mod/profile/views/default/resources/profile/edit_header.php +++ b/mod/profile/views/default/resources/profile/edit_header.php @@ -5,9 +5,9 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); +elgg_push_entity_breadcrumbs($user); -echo elgg_view_page(elgg_echo('profile:edit'), [ +echo elgg_view_page(elgg_echo('profile:edit:header'), [ 'content' => elgg_view_form('profile/edit/header', [], ['entity' => $user]), 'show_owner_block_menu' => false, 'filter_id' => 'profile/edit', diff --git a/mod/thewire/views/default/resources/thewire/reply.php b/mod/thewire/views/default/resources/thewire/reply.php index b2931a3b814..cbd0e3c0065 100644 --- a/mod/thewire/views/default/resources/thewire/reply.php +++ b/mod/thewire/views/default/resources/thewire/reply.php @@ -9,7 +9,7 @@ /* @var $post ElggWire */ $post = get_entity($guid); -elgg_push_entity_breadcrumbs($post, true); +elgg_push_entity_breadcrumbs($post); $content = elgg_view('thewire/reply', ['post' => $post]); diff --git a/mod/thewire/views/default/resources/thewire/view.php b/mod/thewire/views/default/resources/thewire/view.php index e1b9ec8a2c8..cb735982958 100644 --- a/mod/thewire/views/default/resources/thewire/view.php +++ b/mod/thewire/views/default/resources/thewire/view.php @@ -6,14 +6,12 @@ $guid = (int) elgg_extract('guid', $vars); elgg_entity_gatekeeper($guid, 'object', 'thewire'); -/* @var $post ElggWire */ +/* @var $post \ElggWire */ $post = get_entity($guid); -$title = elgg_echo('thewire:by', [$post->getOwnerEntity()->getDisplayName()]); +elgg_push_entity_breadcrumbs($post); -elgg_push_entity_breadcrumbs($post, false); - -echo elgg_view_page($title, [ +echo elgg_view_page(elgg_echo('thewire:by', [$post->getOwnerEntity()->getDisplayName()]), [ 'content' => elgg_view_entity($post), 'entity' => $post, 'filter_id' => 'thewire/view', diff --git a/views/default/page/layouts/admin.php b/views/default/page/layouts/admin.php index e1f764b440b..9ad34e9cc3f 100644 --- a/views/default/page/layouts/admin.php +++ b/views/default/page/layouts/admin.php @@ -13,8 +13,6 @@ ]); unset($vars['class']); -$vars['breadcrumbs'] = false; - $vars['sidebar'] = elgg_view('admin/sidebar', $vars); $header = elgg_view('page/layouts/elements/header', $vars); diff --git a/views/default/page/layouts/default.php b/views/default/page/layouts/default.php index 611b568c5bb..ae1de518607 100644 --- a/views/default/page/layouts/default.php +++ b/views/default/page/layouts/default.php @@ -7,7 +7,7 @@ * @uses $vars['class'] Additional CSS classes to apply to the layout * * @uses $vars['breadcrumbs'] Breadcrumbs - * Will no be rendered if the value is 'false' + * Will not be rendered if the value is 'false' * Will render 'navigation/breadcrumbs' view if * not set or is an array of breadcrumbs * Will override breadcrumbs view if set to a string @@ -70,12 +70,11 @@ $layout_attrs['class'] = elgg_extract_class($layout_attrs, $class); -$breadcrumbs = elgg_view('page/layouts/elements/breadcrumbs', $vars); -$header = elgg_view('page/layouts/elements/header', $vars); +$layout = elgg_view('page/layouts/elements/breadcrumbs', $vars); +$layout .= elgg_view('page/layouts/elements/header', $vars); + $body = elgg_view('page/layouts/elements/body', $vars); -$layout = $breadcrumbs; -$layout .= $header; $layout .= elgg_format_element('div', [ 'class' => 'elgg-layout-columns', ], $sidebar_alt . $body . $sidebar); diff --git a/views/default/page/layouts/elements/body.php b/views/default/page/layouts/elements/body.php index 4e9ad310da2..4930513381e 100644 --- a/views/default/page/layouts/elements/body.php +++ b/views/default/page/layouts/elements/body.php @@ -2,16 +2,10 @@ /** * Layout body * - * @uses $vars['breadcrumbs'] Breadcrumbs - * Will no be rendered if the value is 'false' - * Will render 'navigation/breadcrumbs' view if - * not set or is an array of breadcrumbs - * Will override breadcrumbs view if set to a string - * - * @uses $vars['title'] Optional title for main content area - * @uses $vars['header'] Optional override for the header - * @uses $vars['content'] Content - * @uses $vars['footer'] Optional footer + * @uses $vars['title'] Optional title for main content area + * @uses $vars['header'] Optional override for the header + * @uses $vars['content'] Content + * @uses $vars['footer'] Optional footer */ $filter = elgg_view('page/layouts/elements/filter', $vars); $content = elgg_view('page/layouts/elements/content', $vars); diff --git a/views/default/page/layouts/elements/breadcrumbs.php b/views/default/page/layouts/elements/breadcrumbs.php index 2342a13c926..94d7158bd2b 100644 --- a/views/default/page/layouts/elements/breadcrumbs.php +++ b/views/default/page/layouts/elements/breadcrumbs.php @@ -3,7 +3,7 @@ * Layout breadcrumbs * * @uses $vars['breadcrumbs'] Breadcrumbs - * Will no be rendered if the value is 'false' + * Will not be rendered if the value is 'false' * Will override breadcrumbs view if set to a string * Will render 'navigation/breadcrumbs' view if * not set or is an array of breadcrumbs diff --git a/views/default/page/layouts/error.php b/views/default/page/layouts/error.php index ff6f746a4d1..d60684ff7ec 100644 --- a/views/default/page/layouts/error.php +++ b/views/default/page/layouts/error.php @@ -14,7 +14,6 @@ ]); unset($vars['class']); -$vars['breadcrumbs'] = false; $vars['filter'] = false; $header = elgg_view('page/layouts/elements/header', $vars); diff --git a/views/default/resources/avatar/edit.php b/views/default/resources/avatar/edit.php index 3b46dce06f1..11d481fbbd8 100644 --- a/views/default/resources/avatar/edit.php +++ b/views/default/resources/avatar/edit.php @@ -5,7 +5,7 @@ $user = elgg_get_page_owner_entity(); -elgg_push_breadcrumb($user->getDisplayName(), $user->getURL()); +elgg_push_entity_breadcrumbs($user); echo elgg_view_page(elgg_echo('avatar:edit'), [ 'content' => elgg_view('core/avatar/upload', ['entity' => $user]), diff --git a/views/default/resources/comments/edit.php b/views/default/resources/comments/edit.php index 93f3b08848c..cc86f72253a 100644 --- a/views/default/resources/comments/edit.php +++ b/views/default/resources/comments/edit.php @@ -15,7 +15,7 @@ throw new EntityNotFoundException(elgg_echo('generic_comment:notfound')); } -elgg_push_breadcrumb($target->getDisplayName(), $target->getURL()); +elgg_push_entity_breadcrumbs($target); echo elgg_view_page(elgg_echo('generic_comments:edit'), [ 'content' => elgg_view_form('comment/save', [], [ diff --git a/views/default/resources/settings/account.php b/views/default/resources/settings/account.php index 91386e25676..3878675be90 100644 --- a/views/default/resources/settings/account.php +++ b/views/default/resources/settings/account.php @@ -15,8 +15,6 @@ throw new EntityPermissionsException(); } -elgg_push_breadcrumb(elgg_echo('settings'), elgg_generate_url('settings:account', ['username' => $user->username])); - $title = elgg_echo('usersettings:user', [$user->getDisplayName()]); echo elgg_view_page($title, [ diff --git a/views/default/resources/settings/notifications.php b/views/default/resources/settings/notifications.php index 7ad50877e9e..671409410cf 100644 --- a/views/default/resources/settings/notifications.php +++ b/views/default/resources/settings/notifications.php @@ -3,13 +3,9 @@ * Notification settings page */ -$user = elgg_get_page_owner_entity(); - -elgg_push_breadcrumb(elgg_echo('settings'), elgg_generate_url('settings:account', ['username' => $user->username])); - echo elgg_view_page(elgg_echo('usersettings:notifications:title'), [ 'content' => elgg_view_form('settings/notifications', [], [ - 'entity' => $user, + 'entity' => elgg_get_page_owner_entity(), ]), 'show_owner_block_menu' => false, 'filter_id' => 'settings/notifications', diff --git a/views/default/resources/settings/notifications/users.php b/views/default/resources/settings/notifications/users.php index 73f6189ba88..da03caf53c1 100644 --- a/views/default/resources/settings/notifications/users.php +++ b/views/default/resources/settings/notifications/users.php @@ -3,15 +3,11 @@ * Manage user notification subscriptions */ -$user = elgg_get_page_owner_entity(); - -elgg_push_breadcrumb(elgg_echo('settings'), elgg_generate_url('settings:account', ['username' => $user->username])); - echo elgg_view_page(elgg_echo('usersettings:notifications:users:title'), [ 'content' => elgg_view_form('settings/notifications/users', [ 'action' => 'action/settings/notifications/subscriptions', ], [ - 'entity' => $user, + 'entity' => elgg_get_page_owner_entity(), ]), 'show_owner_block_menu' => false, 'filter_id' => 'settings/notifications', diff --git a/views/default/resources/settings/statistics.php b/views/default/resources/settings/statistics.php index da005e480e3..e4f0726ec86 100644 --- a/views/default/resources/settings/statistics.php +++ b/views/default/resources/settings/statistics.php @@ -15,10 +15,6 @@ throw new EntityPermissionsException(); } -elgg_push_breadcrumb(elgg_echo('settings'), elgg_generate_url('settings:account', [ - 'username' => $user->username, -])); - if ($user->guid === elgg_get_logged_in_user_guid()) { $title = elgg_echo('usersettings:statistics'); } else { diff --git a/views/default/resources/settings/tools.php b/views/default/resources/settings/tools.php index 83346309d19..548b151795f 100644 --- a/views/default/resources/settings/tools.php +++ b/views/default/resources/settings/tools.php @@ -20,8 +20,6 @@ $title = $plugin->getDisplayName(); } -elgg_push_breadcrumb(elgg_echo('settings'), elgg_generate_url('settings:account', ['username' => $user->username])); - $form_vars = []; if (elgg_action_exists("{$plugin_id}/usersettings/save")) { $form_vars['action'] = "action/{$plugin_id}/usersettings/save"; From 0467cf8703bb3ea4936bd73bfbb3813a434d9275 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Fri, 28 Jul 2023 11:29:51 +0200 Subject: [PATCH 052/240] fixed(rss): invalid atom link href in rss channel --- views/rss/page/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/rss/page/default.php b/views/rss/page/default.php index 30543075bf3..94ec365ccc4 100644 --- a/views/rss/page/default.php +++ b/views/rss/page/default.php @@ -42,7 +42,7 @@ <![CDATA[<?= $title; ?>}]]> - + }]]> From 84deb0e54ed887c883f67c5538f0d8d095efd19b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Fri, 28 Jul 2023 11:13:58 +0200 Subject: [PATCH 053/240] deprecated(views): resource and route for comment edit are not in use --- docs/appendix/upgrade-notes.rst | 1 + docs/appendix/upgrade-notes/5.0-to-5.1.rst | 17 +++++++++ engine/classes/Elgg/Menus/Entity.php | 41 +++++++++++++++++++--- engine/events.php | 3 ++ engine/routes.php | 1 + views/default/elgg/comments.js | 2 +- views/default/resources/comments/edit.php | 2 ++ 7 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 docs/appendix/upgrade-notes/5.0-to-5.1.rst diff --git a/docs/appendix/upgrade-notes.rst b/docs/appendix/upgrade-notes.rst index 6e7907e62ab..b65b7efe35a 100644 --- a/docs/appendix/upgrade-notes.rst +++ b/docs/appendix/upgrade-notes.rst @@ -8,6 +8,7 @@ See the administrator guides for :doc:`how to upgrade a live site getValue(); + if ($return->get('edit')) { + // a menu item for editting already exists + return; + } + + $edit_url = elgg_generate_entity_url($entity, 'edit'); if (empty($edit_url) || !$entity->canEdit()) { return; } - /* @var $return MenuItems */ - $return = $event->getValue(); - $return[] = \ElggMenuItem::factory([ 'name' => 'edit', 'icon' => 'edit', @@ -88,6 +92,35 @@ public static function registerDelete(\Elgg\Event $event) { return $return; } + /** + * Registers menu items for the entity menu of a comment + * + * @param \Elgg\Event $event 'register', 'menu:entity:object:comment' + * + * @return void|MenuItems + */ + public static function registerComment(\Elgg\Event $event) { + $entity = $event->getEntityParam(); + if (!$entity instanceof \ElggComment || !$entity->canEdit()) { + return; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'edit', + 'icon' => 'edit', + 'text' => elgg_echo('edit'), + 'title' => elgg_echo('edit:this'), + 'href' => false, + 'priority' => 900, + 'data-comment-guid' => $entity->guid, + ]); + + return $return; + } + /** * Registers menu items for the entity menu of a plugin * diff --git a/engine/events.php b/engine/events.php index 50102f89e08..cd9f57dee07 100644 --- a/engine/events.php +++ b/engine/events.php @@ -278,6 +278,9 @@ 'Elgg\Menus\Entity::registerUserHoverAdminSection' => [], 'Elgg\Menus\UserHover::registerLoginAs' => [], ], + 'menu:entity:object:comment' => [ + 'Elgg\Menus\Entity::registerComment' => [], + ], 'menu:entity:object:elgg_upgrade' => [ 'Elgg\Menus\Entity::registerUpgrade' => [], ], diff --git a/engine/routes.php b/engine/routes.php index ffedbd3eb42..a2072413781 100644 --- a/engine/routes.php +++ b/engine/routes.php @@ -220,6 +220,7 @@ 'middleware' => [ \Elgg\Router\Middleware\Gatekeeper::class, ], + 'deprecated' => true, ], 'view:user' => [ 'path' => '/user/{guid}', diff --git a/views/default/elgg/comments.js b/views/default/elgg/comments.js index b786a16d727..615d66cb750 100644 --- a/views/default/elgg/comments.js +++ b/views/default/elgg/comments.js @@ -95,7 +95,7 @@ define(['jquery', 'elgg'], function ($, elgg) { // store object as data in the edit link var dc = $(this).data('Comment'); if (!dc) { - var guid = this.href.split('/').pop(); + var guid = $(this).data().commentGuid; dc = new Comment(guid, $trigger.closest('.elgg-item-object-comment')); $(this).data('Comment', dc); } diff --git a/views/default/resources/comments/edit.php b/views/default/resources/comments/edit.php index cc86f72253a..7beed419897 100644 --- a/views/default/resources/comments/edit.php +++ b/views/default/resources/comments/edit.php @@ -3,6 +3,8 @@ use Elgg\Exceptions\Http\EntityNotFoundException; use Elgg\Exceptions\Http\EntityPermissionsException; +elgg_deprecated_notice('The resource "comments/edit" is deprecated. Do not use this view.', '5.1'); + $guid = (int) elgg_extract('guid', $vars); $comment = get_entity($guid); From f2567c5c543dae9189459e9d645a6f3e40d8b485 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Fri, 28 Jul 2023 11:37:12 +0200 Subject: [PATCH 054/240] chore(views): only issue missing notice on default views by default --- engine/classes/Elgg/ViewsService.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 6d20e9984a9..55001a63fa3 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -385,7 +385,7 @@ public function getViewList(string $view): array { * * @see elgg_view() */ - public function renderView(string $view, array $vars = [], string $viewtype = '', bool $issue_missing_notice = true, array $extensions_tree = []): string { + public function renderView(string $view, array $vars = [], string $viewtype = '', bool $issue_missing_notice = null, array $extensions_tree = []): string { $view = self::canonicalizeViewName($view); // basic checking for bad paths @@ -406,6 +406,10 @@ public function renderView(string $view, array $vars = [], string $viewtype = '' if ($viewtype === '' || !$this->isValidViewtype($viewtype)) { $viewtype = $this->getViewtype(); } + + if (!isset($issue_missing_notice)) { + $issue_missing_notice = $viewtype === 'default'; + } // allow altering $vars $vars_event_params = [ From bbc00ec5127c02e84e5d761730dff654fb8a765d Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 7 Aug 2023 11:08:53 +0200 Subject: [PATCH 055/240] chore(views): no longer check for old format in views cache --- engine/classes/Elgg/ViewsService.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 55001a63fa3..7e815fba60d 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -795,11 +795,6 @@ public function configureFromCache(SystemCache $cache): bool { return false; } - // format changed, check version - if (empty($data['version']) || $data['version'] !== '2.0') { - return false; - } - $this->locations = $data['locations']; $this->cache = $cache; @@ -819,10 +814,7 @@ public function cacheConfiguration(SystemCache $cache): void { return; } - $cache->save('view_locations', [ - 'version' => '2.0', - 'locations' => $this->locations, - ]); + $cache->save('view_locations', ['locations' => $this->locations]); // this is saved just for the inspector and is not loaded in loadAll() $cache->save('view_overrides', $this->overrides); From ca2ab5fa3627da3517a47e0a17e62c97d271be42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Mon, 7 Aug 2023 14:34:28 +0200 Subject: [PATCH 056/240] chore(views): input/button must have discernible text --- views/default/forms/admin/users/search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/default/forms/admin/users/search.php b/views/default/forms/admin/users/search.php index 995ab9954c1..011c07c4bc5 100644 --- a/views/default/forms/admin/users/search.php +++ b/views/default/forms/admin/users/search.php @@ -23,7 +23,7 @@ ], [ '#type' => 'submit', - 'value' => elgg_echo('search'), + 'text' => elgg_echo('search'), ], ], 'align' => 'horizontal', From 41585508a030b8dda38b2c0f1e0be295d4faf59c Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 7 Aug 2023 13:11:26 +0200 Subject: [PATCH 057/240] chore(views): removed the need to clamp the viewtype on boot --- .../classes/Elgg/Application/BootHandler.php | 1 - engine/classes/Elgg/ViewsService.php | 16 +---- .../unit/Elgg/ViewsServiceUnitTest.php | 66 ++++++++++++++++--- .../phpunit/unit/ElggCoreViewtypeUnitTest.php | 56 ---------------- 4 files changed, 59 insertions(+), 80 deletions(-) delete mode 100644 engine/tests/phpunit/unit/ElggCoreViewtypeUnitTest.php diff --git a/engine/classes/Elgg/Application/BootHandler.php b/engine/classes/Elgg/Application/BootHandler.php index e9a088ef8e8..d1a49fddf76 100644 --- a/engine/classes/Elgg/Application/BootHandler.php +++ b/engine/classes/Elgg/Application/BootHandler.php @@ -133,7 +133,6 @@ public function bootApplication(): void { $events = $this->app->internal_services->events; - $this->app->internal_services->views->clampViewtypeToPopulatedViews(); $this->app->allowPathRewrite(); // Complete the boot process for both engine and plugins diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 7e815fba60d..1191dc6c7c9 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -130,18 +130,6 @@ public function getViewtype(): string { return $this->viewtype; } - /** - * If the current viewtype has no views, reset it to "default" - * - * @return void - */ - public function clampViewtypeToPopulatedViews(): void { - $viewtype = $this->getViewtype(); - if (empty($this->locations[$viewtype])) { - $this->viewtype = 'default'; - } - } - /** * Resolve the initial viewtype * @@ -150,13 +138,13 @@ public function clampViewtypeToPopulatedViews(): void { private function resolveViewtype(): string { if ($this->request) { $view = $this->request->getParam('view', '', false); - if ($this->isValidViewtype($view)) { + if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { return $view; } } $view = (string) elgg_get_config('view'); - if ($this->isValidViewtype($view)) { + if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { return $view; } diff --git a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php index 7fcdc1256b4..5ff0306232b 100644 --- a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php @@ -25,7 +25,14 @@ public function up() { $this->views = new ViewsService($this->events, _elgg_services()->request); $this->views->setLogger($logger); - $this->views->autoregisterViews('', "$this->viewsDir/default", 'default'); + $this->views->autoregisterViews('', "{$this->viewsDir}/default", 'default'); + $this->views->autoregisterViews('', "{$this->viewsDir}/json", 'json'); + $this->views->setViewtype(''); + } + + public function down() { + set_input('view', ''); + elgg_set_config('view', null); } public function testCanExtendViews() { @@ -75,9 +82,7 @@ public function testRegistersStaticFilesAsViews() { } public function testUsesPhpToRenderNonStaticViews() { - $this->assertEquals("// PHPin", $this->views->renderView('js/interpreted.js', array( - 'in' => 'in', - ))); + $this->assertEquals("// PHPin", $this->views->renderView('js/interpreted.js', ['in' => 'in'])); } public function testDoesNotUsePhpToRenderStaticViews() { @@ -103,9 +108,7 @@ public function testCanSetViewPathsViaSpec() { $expected = file_get_contents("$this->viewsDir/default/js/static.js"); $this->assertEquals($expected, $this->views->renderView('hello.js')); - $this->assertEquals("// PHPin", $this->views->renderView('hello/world.js', array( - 'in' => 'in', - ))); + $this->assertEquals("// PHPin", $this->views->renderView('hello/world.js', ['in' => 'in'])); } public function testCanSetViewsDirs() { @@ -201,7 +204,7 @@ public function testCanGetViewRenderingList() { $list = $this->views->getViewList('foo'); $this->assertEquals([ 500 => 'foo', - ], $list); + ], $list); $this->views->extendView('foo', 'bar'); $this->views->extendView('foo', 'bing', 499); @@ -211,7 +214,7 @@ public function testCanGetViewRenderingList() { 499 => 'bing', 500 => 'foo', 501 => 'bar', - ], $list); + ], $list); } public function testPreventExtensionOnSelf() { @@ -253,4 +256,49 @@ public function getExampleNormalizedViews() { ['view.jpg', 'css/view.jpg'], ]; } + + public function testSetViewtype() { + $this->assertTrue($this->views->setViewtype('test')); + $this->assertEquals('test', $this->views->getViewtype()); + } + + public function testDefaultViewtype() { + $this->assertEquals('default', $this->views->getViewtype()); + } + + public function testInputSetsInitialViewtype() { + set_input('view', 'json'); + $this->assertEquals('json', $this->views->getViewtype()); + } + + public function testConfigSetsInitialViewtype() { + elgg_set_config('view', 'json'); + + $this->assertEquals('json', $this->views->getViewtype()); + } + + public function testSettingInputDoesNotChangeViewtype() { + $this->assertEquals('default', $this->views->getViewtype()); + + set_input('view', 'json'); + $this->assertEquals('default', $this->views->getViewtype()); + } + + public function testSettingConfigDoesNotChangeViewtype() { + $this->assertEquals('default', $this->views->getViewtype()); + + elgg_set_config('view', 'json'); + $this->assertEquals('default', $this->views->getViewtype()); + } + + public function testIsValidViewtype() { + $this->assertTrue($this->views->isValidViewtype('valid')); + $this->assertTrue($this->views->isValidViewtype('valid_viewtype')); + $this->assertTrue($this->views->isValidViewtype('0')); + $this->assertTrue($this->views->isValidViewtype(123)); // will be autocasted to string + + $this->assertFalse($this->views->isValidViewtype('a;b')); + $this->assertFalse($this->views->isValidViewtype('invalid-viewtype')); + $this->assertFalse($this->views->isValidViewtype('')); + } } diff --git a/engine/tests/phpunit/unit/ElggCoreViewtypeUnitTest.php b/engine/tests/phpunit/unit/ElggCoreViewtypeUnitTest.php deleted file mode 100644 index c1679d4fcd3..00000000000 --- a/engine/tests/phpunit/unit/ElggCoreViewtypeUnitTest.php +++ /dev/null @@ -1,56 +0,0 @@ -assertTrue(elgg_set_viewtype('test')); - $this->assertEquals('test', elgg_get_viewtype()); - } - - public function testDefaultViewtype() { - $this->assertEquals('default', elgg_get_viewtype()); - } - - public function testInputSetsInitialViewtype() { - set_input('view', 'foo'); - $this->assertEquals('foo', elgg_get_viewtype()); - } - - public function testConfigSetsInitialViewtype() { - elgg_set_config('view', 'bar'); - - $this->assertEquals('bar', elgg_get_viewtype()); - } - - public function testSettingInputDoesNotChangeViewtype() { - $this->assertEquals('default', elgg_get_viewtype()); - - set_input('view', 'foo'); - $this->assertEquals('default', elgg_get_viewtype()); - } - - public function testSettingConfigDoesNotChangeViewtype() { - $this->assertEquals('default', elgg_get_viewtype()); - - elgg_set_config('view', 'foo'); - $this->assertEquals('default', elgg_get_viewtype()); - elgg_set_config('view', null); - } - - public function testElggIsValidViewtype() { - $this->assertTrue(_elgg_services()->views->isValidViewtype('valid')); - $this->assertTrue(_elgg_services()->views->isValidViewtype('valid_viewtype')); - $this->assertTrue(_elgg_services()->views->isValidViewtype('0')); - $this->assertTrue(_elgg_services()->views->isValidViewtype(123)); // will be autocasted to string - - $this->assertFalse(_elgg_services()->views->isValidViewtype('a;b')); - $this->assertFalse(_elgg_services()->views->isValidViewtype('invalid-viewtype')); - $this->assertFalse(_elgg_services()->views->isValidViewtype('')); - } -} From 2ebfccb096dba500bf2f496bd1807b923ca9cb63 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Tue, 8 Aug 2023 14:00:11 +0200 Subject: [PATCH 058/240] feat(views): support a title on an imprint element --- views/default/object/elements/imprint/element.php | 1 + 1 file changed, 1 insertion(+) diff --git a/views/default/object/elements/imprint/element.php b/views/default/object/elements/imprint/element.php index 2d35ffb684c..8cef663c791 100644 --- a/views/default/object/elements/imprint/element.php +++ b/views/default/object/elements/imprint/element.php @@ -16,4 +16,5 @@ echo elgg_format_element('span', [ 'class' => elgg_extract_class($vars), + 'title' => elgg_extract('title', $vars), ], $result); From 5ec2f3a5d5b3e0e7aead63d67122494abe0281af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 27 Jul 2023 17:03:21 +0200 Subject: [PATCH 059/240] chore(cron): improved stability of cron interval handling ref #14381 --- engine/classes/Elgg/Cron.php | 106 ++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/engine/classes/Elgg/Cron.php b/engine/classes/Elgg/Cron.php index 2f0defb3e13..0403b952a05 100644 --- a/engine/classes/Elgg/Cron.php +++ b/engine/classes/Elgg/Cron.php @@ -3,6 +3,8 @@ namespace Elgg; use Elgg\Exceptions\CronException; +use Elgg\Exceptions\Exception; +use Elgg\I18n\Translator; use Elgg\Traits\Loggable; use Elgg\Traits\TimeUsing; use GO\Job; @@ -18,10 +20,7 @@ class Cron { use Loggable; use TimeUsing; - /** - * @var array - */ - protected $default_intervals = [ + protected array $default_intervals = [ 'minute' => '* * * * *', 'fiveminute' => '*/5 * * * *', 'fifteenmin' => '*/15 * * * *', @@ -33,30 +32,31 @@ class Cron { 'yearly' => '0 0 1 1 *', ]; - /** - * @var EventsService - */ - protected $events; + protected EventsService $events; + + protected Translator $translator; /** * Constructor * - * @param EventsService $events Events service + * @param EventsService $events Events service + * @param Translator $translator Translator service */ - public function __construct(EventsService $events) { + public function __construct(EventsService $events, Translator $translator) { $this->events = $events; + $this->translator = $translator; } /** * Executes handlers for periods that have elapsed since last cron * - * @param array $intervals Interval names to run - * @param bool $force Force cron jobs to run even they are not yet due + * @param null|array $intervals Interval names to run (default: all cron intervals) + * @param bool $force Force cron jobs to run even they are not yet due * * @return Job[] * @throws CronException */ - public function run(array $intervals = null, $force = false) { + public function run(array $intervals = null, bool $force = false): array { if (!isset($intervals)) { $intervals = array_keys($this->default_intervals); @@ -69,7 +69,7 @@ public function run(array $intervals = null, $force = false) { foreach ($intervals as $interval) { if (!array_key_exists($interval, $allowed_intervals)) { - throw new CronException("$interval is not a recognized cron interval"); + throw new CronException("{$interval} is not a recognized cron interval"); } $cron_interval = $force ? $allowed_intervals['minute'] : $allowed_intervals[$interval]; @@ -93,26 +93,30 @@ public function run(array $intervals = null, $force = false) { /** * Execute commands before cron interval is run * - * @param string $interval Interval name - * @param \DateTime $time Time of the cron initialization + * @param string $interval Interval name + * @param null|\DateTime $time Time of the cron initialization (default: current service time) * * @return void */ - protected function before($interval, \DateTime $time = null) { + protected function before(string $interval, \DateTime $time = null): void { if (!isset($time)) { $time = $this->getCurrentTime(); } - $this->events->triggerBefore('cron', $interval, $time); + try { + $this->events->triggerBefore('cron', $interval, $time); + } catch (\Throwable $t) { + $this->getLogger()->error($t); + } // give every period at least 'max_execution_time' (PHP ini setting) set_time_limit((int) ini_get('max_execution_time')); $now = new \DateTime(); - $msg = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL; - $msg .= elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL; + $msg = $this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL; + $msg .= $this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL; $this->cronLog('output', $interval, $msg); } @@ -120,12 +124,12 @@ protected function before($interval, \DateTime $time = null) { /** * Execute handlers attached to a specific cron interval * - * @param string $interval Cron interval to execute - * @param \DateTime $time Time of cron initialization + * @param string $interval Cron interval to execute + * @param null|\DateTime $time Time of cron initialization (default: current service time) * * @return string */ - protected function execute($interval, \DateTime $time = null) { + protected function execute(string $interval, \DateTime $time = null): string { if (!isset($time)) { $time = $this->getCurrentTime(); @@ -135,22 +139,28 @@ protected function execute($interval, \DateTime $time = null) { $output = []; - $output[] = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]); - $output[] = elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]); - - ob_start(); + $output[] = $this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]); + $output[] = $this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]); - $old_stdout = $this->events->triggerResults('cron', $interval, [ - 'time' => $time->getTimestamp(), - 'dt' => $time, - ], ''); - - $output[] = ob_get_clean(); - $output[] = $old_stdout; + try { + ob_start(); + + $old_stdout = $this->events->triggerResults('cron', $interval, [ + 'time' => $time->getTimestamp(), + 'dt' => $time, + ], ''); + + $output[] = ob_get_clean(); + $output[] = $old_stdout; + } catch (\Throwable $t) { + $output[] = ob_get_clean(); + + $this->getLogger()->error($t); + } $now = new \DateTime(); - $output[] = elgg_echo('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); + $output[] = $this->translator->translate('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); return implode(PHP_EOL, array_filter($output)); } @@ -163,16 +173,19 @@ protected function execute($interval, \DateTime $time = null) { * * @return void */ - protected function after($output, $interval) { - + protected function after(string $output, string $interval): void { $time = new \DateTime(); $this->cronLog('output', $interval, $output); $this->cronLog('completion', $interval, $time->getTimestamp()); $this->getLogger()->info($output); - - $this->events->triggerAfter('cron', $interval, $time); + + try { + $this->events->triggerAfter('cron', $interval, $time); + } catch (\Throwable $t) { + $this->getLogger()->error($t); + } } /** @@ -184,15 +197,20 @@ protected function after($output, $interval) { * * @return void */ - protected function cronLog($setting, $interval, $msg = '') { + protected function cronLog(string $setting, string $interval, string $msg = ''): void { $suffix = $setting ?: 'output'; $fh = new \ElggFile(); $fh->owner_guid = elgg_get_site_entity()->guid; $fh->setFilename("{$interval}-{$suffix}.log"); - $fh->open('write'); - $fh->write($msg); + try { + $fh->open('write'); + $fh->write($msg); + } catch (Exception $e) { + // don't do anything + } + $fh->close(); } @@ -204,7 +222,7 @@ protected function cronLog($setting, $interval, $msg = '') { * * @return string */ - public function getLog($setting, $interval) { + public function getLog(string $setting, string $interval): string { $suffix = $setting ?: 'output'; $fh = new \ElggFile(); @@ -231,7 +249,7 @@ public function getLog($setting, $interval) { * @return array * @since 3.2 */ - public function getConfiguredIntervals(bool $only_names = false) { + public function getConfiguredIntervals(bool $only_names = false): array { $result = $this->events->triggerResults('cron:intervals', 'system', [], $this->default_intervals); if (!is_array($result)) { $this->getLogger()->warning("The event 'cron:intervals', 'system' should return an array, " . gettype($result) . ' given'); From 61315fe7edbb11a13f049517ac13631c57859ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 8 Aug 2023 17:01:07 +0200 Subject: [PATCH 060/240] feat(a11y): added header, main, footer aria landmarks ref #5087 --- docs/appendix/upgrade-notes/5.0-to-5.1.rst | 11 +++++++++-- views/default/page/elements/section.php | 18 +++++++++++++----- .../page/elements/walled_garden/body.php | 12 ++++++------ views/default/page/maintenance.php | 2 +- views/default/walled_garden.css.php | 8 ++++---- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/docs/appendix/upgrade-notes/5.0-to-5.1.rst b/docs/appendix/upgrade-notes/5.0-to-5.1.rst index 6d6b9df8580..b8210087dad 100644 --- a/docs/appendix/upgrade-notes/5.0-to-5.1.rst +++ b/docs/appendix/upgrade-notes/5.0-to-5.1.rst @@ -5,13 +5,20 @@ From 5.0 to 5.1 :local: :depth: 1 +Changes in the DOM structure +---------------------------- + +In order to improve accessibility the HTML DOM structure has been changed slightly. Some sections of the page have been +changed from a ``div`` to ``header``, ``main`` or ``footer``. The classes or place in the DOM has not been changed. + Deprecated Views ---------------- + * ``page/elements/
    /after`` is deprecated: Extend the correct ``page/elements/
    `` + * ``page/elements/
    /before`` is deprecated: Prepend the correct ``page/elements/
    `` * ``resources/comments/edit`` is deprecated: This resource is no longer in use Deprecated Routes ----------------- - * ``edit:object:comment`` is deprecated: Editting comments uses an inline form - \ No newline at end of file + * ``edit:object:comment`` is deprecated: Editing comments uses an inline form diff --git a/views/default/page/elements/section.php b/views/default/page/elements/section.php index 96e7ea45d3b..042dbb97fcf 100644 --- a/views/default/page/elements/section.php +++ b/views/default/page/elements/section.php @@ -10,20 +10,28 @@ $html = elgg_extract('html', $vars); if (!empty($section) && elgg_view_exists("page/elements/{$section}/before")) { - echo elgg_view("page/elements/{$section}/before", $vars); + echo elgg_view_deprecated("page/elements/{$section}/before", $vars, 'Prepend the correct page/elements/
    ', '5.1'); } if (!empty($html)) { + $section_elements = [ + 'body' => 'main', + 'topbar' => 'header', + 'footer' => 'footer', + ]; + $class = ['elgg-page-section']; if (!empty($section)) { $class[] = "elgg-page-{$section}"; } - + $inner = elgg_format_element('div', ['class' => 'elgg-inner'], $html); - - echo elgg_format_element('div', ['class' => $class], $inner); + + $element = elgg_extract($section, $section_elements, 'div'); + + echo elgg_format_element($element, ['class' => $class], $inner); } if (!empty($section) && elgg_view_exists("page/elements/{$section}/after")) { - echo elgg_view("page/elements/{$section}/after", $vars); + echo elgg_view_deprecated("page/elements/{$section}/after", $vars, 'Append the correct page/elements/
    ', '5.1'); } diff --git a/views/default/page/elements/walled_garden/body.php b/views/default/page/elements/walled_garden/body.php index ae5c9aabb2a..cfc26edd26f 100644 --- a/views/default/page/elements/walled_garden/body.php +++ b/views/default/page/elements/walled_garden/body.php @@ -14,20 +14,20 @@
    -
    +
    -
    -
    + +
    -
    - +
    diff --git a/views/default/page/maintenance.php b/views/default/page/maintenance.php index ca5c743db5b..30e191f959a 100644 --- a/views/default/page/maintenance.php +++ b/views/default/page/maintenance.php @@ -15,7 +15,7 @@ elgg_load_external_file('css', 'maintenance'); $body = elgg_format_element('div', ['class' => 'elgg-page-messages'], $messages); -$body .= elgg_format_element('div', ['class' => 'elgg-body-maintenance'], $content); +$body .= elgg_format_element('main', ['class' => 'elgg-body-maintenance'], $content); $body = elgg_format_element('div', ['class' => ['elgg-page', 'elgg-page-maintenance'], 'id' => 'elgg-maintenance-page-wrapper'], $body); $head = elgg_view('page/elements/head', elgg_extract('head', $vars, [])); diff --git a/views/default/walled_garden.css.php b/views/default/walled_garden.css.php index e2a5b41ca3b..26ab481df58 100644 --- a/views/default/walled_garden.css.php +++ b/views/default/walled_garden.css.php @@ -43,16 +43,16 @@ min-height: 100%; } -.elgg-page-walled-garden > .elgg-inner > div { - &.elgg-page-body { +.elgg-page-walled-garden > .elgg-inner { + > .elgg-page-body { padding: 1.5rem 3rem; background: #fff; box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3), -1px -1px 1px rgba(0, 0, 0, 0.3); } - &.elgg-page-header { + > .elgg-page-header { padding: 3rem 0; } - &.elgg-page-footer { + > .elgg-page-footer { background: none; a { color: $(text-color-strong); From 091202e4a0445d7d2fc37c3b217628f8e0e2f022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 9 Aug 2023 11:08:51 +0200 Subject: [PATCH 061/240] feat(a11y): added aria search forms ref #5087 --- languages/en.php | 13 ++++++++++--- mod/groups/languages/en.php | 4 ++++ mod/groups/views/default/forms/groups/find.php | 3 ++- mod/groups/views/default/forms/groups/search.php | 7 ++++--- mod/groups/views/default/groups/sidebar/find.php | 4 +++- mod/groups/views/default/groups/sidebar/search.php | 8 +++++++- mod/members/languages/en.php | 1 + mod/members/views/default/forms/members/search.php | 4 +++- mod/members/views/default/members/sidebar.php | 10 +++++----- mod/search/languages/en.php | 2 ++ mod/search/views/default/forms/search.php | 5 +++-- mod/search/views/default/resources/search/index.php | 2 ++ mod/search/views/default/search/search.css | 2 +- mod/search/views/default/search/search_box.php | 2 ++ views/default/admin/users/header.php | 2 ++ views/default/forms/admin/users/search.php | 3 ++- 16 files changed, 53 insertions(+), 19 deletions(-) diff --git a/languages/en.php b/languages/en.php index 994e0dc97b6..f1e49f1c160 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1782,7 +1782,13 @@ * Miscellaneous */ 'elgg:powered' => "Powered by Elgg", - + 'field:required' => "Required", + +/** + * Accessibility + */ + 'aria:label:admin:users:search' => "User search", + /** * Cli commands */ @@ -2006,8 +2012,9 @@ "zh_hans" => "Chinese Simplified", "zu" => "Zulu", - "field:required" => 'Required', - +/** + * Upgrades + */ "core:upgrade:2017080900:title" => "Alter database encoding for multi-byte support", "core:upgrade:2017080900:description" => "Alters database and table encoding to utf8mb4, in order to support multi-byte characters such as emoji", diff --git a/mod/groups/languages/en.php b/mod/groups/languages/en.php index d3961685c89..44b51e65bdc 100644 --- a/mod/groups/languages/en.php +++ b/mod/groups/languages/en.php @@ -178,4 +178,8 @@ 'groups:usersettings:notifications:title' => 'Group notifications', 'groups:usersettings:notifications:description' => 'To receive notifications when new content is added to a group you are a member of, find it below and select the notification method(s) you would like to use.', + + // accessibility + 'groups:aria:label:group_search' => "Search for groups", + 'groups:aria:label:search_in_group' => "Search in this group", ); diff --git a/mod/groups/views/default/forms/groups/find.php b/mod/groups/views/default/forms/groups/find.php index 4a285ecf2d1..764a0e62817 100644 --- a/mod/groups/views/default/forms/groups/find.php +++ b/mod/groups/views/default/forms/groups/find.php @@ -4,11 +4,12 @@ */ echo elgg_view_field([ - '#type' => 'text', + '#type' => 'search', 'name' => 'tag', 'required' => true, 'class' => 'elgg-input-search', 'placeholder' => elgg_echo('groups:search'), + 'aria-label' => elgg_echo('groups:search'), // because we don't add #label ]); $footer = elgg_view_field([ diff --git a/mod/groups/views/default/forms/groups/search.php b/mod/groups/views/default/forms/groups/search.php index 07bfc1f3233..8c6c7eeaa3a 100644 --- a/mod/groups/views/default/forms/groups/search.php +++ b/mod/groups/views/default/forms/groups/search.php @@ -6,15 +6,16 @@ */ $group = elgg_extract('entity', $vars); -if (!($group instanceof \ElggGroup)) { +if (!$group instanceof \ElggGroup) { return; } echo elgg_view_field([ - '#type' => 'text', + '#type' => 'search', 'name' => 'q', 'required' => true, - 'class' => 'elgg-input-search', + 'placeholder' => elgg_echo('groups:search_in_group'), + 'aria-label' => elgg_echo('groups:search_in_group'), // because we don't add #label ]); echo elgg_view_field([ diff --git a/mod/groups/views/default/groups/sidebar/find.php b/mod/groups/views/default/groups/sidebar/find.php index 40ca1926114..72618935130 100644 --- a/mod/groups/views/default/groups/sidebar/find.php +++ b/mod/groups/views/default/groups/sidebar/find.php @@ -4,9 +4,11 @@ */ $body = elgg_view_form('groups/find', [ - 'action' => 'groups/search', + 'action' => elgg_generate_url('collection:group:group:search'), 'method' => 'get', 'disable_security' => true, + 'role' => 'search', + 'aria-label' => elgg_echo('groups:aria:label:group_search'), ]); echo elgg_view_module('aside', elgg_echo('groups:search'), $body); diff --git a/mod/groups/views/default/groups/sidebar/search.php b/mod/groups/views/default/groups/sidebar/search.php index 01975e28164..58e35e2b85a 100644 --- a/mod/groups/views/default/groups/sidebar/search.php +++ b/mod/groups/views/default/groups/sidebar/search.php @@ -3,10 +3,16 @@ * Search for content in this group */ +if (!elgg_is_active_plugin('search')) { + return; +} + $body = elgg_view_form('groups/search', [ - 'action' => 'search', + 'action' => elgg_generate_url('default:search'), 'method' => 'get', 'disable_security' => true, + 'role' => 'search', + 'aria-label' => elgg_echo('groups:aria:label:search_in_group'), ], $vars); echo elgg_view_module('aside', elgg_echo('groups:search_in_group'), $body); diff --git a/mod/members/languages/en.php b/mod/members/languages/en.php index 4eeef905561..dc8b9a7d575 100644 --- a/mod/members/languages/en.php +++ b/mod/members/languages/en.php @@ -9,6 +9,7 @@ 'members:label:online' => 'Online', 'members:label:search' => 'Search results', 'members:search' => 'Search members', + 'members:aria:label:member_search' => "Search for members", 'members:title:search' => "Member search for '%s'", 'members:total' => 'Total members: %s', 'members:title:all' => 'All members', diff --git a/mod/members/views/default/forms/members/search.php b/mod/members/views/default/forms/members/search.php index a93abd49368..5e229314a09 100644 --- a/mod/members/views/default/forms/members/search.php +++ b/mod/members/views/default/forms/members/search.php @@ -1,10 +1,12 @@ 'text', + '#type' => 'search', 'name' => 'member_query', 'value' => get_input('member_query'), 'required' => true, + 'placeholder' => elgg_echo('members:search'), + 'aria-label' => elgg_echo('members:search'), // because we don't use #label ]); $footer = elgg_view_field([ diff --git a/mod/members/views/default/members/sidebar.php b/mod/members/views/default/members/sidebar.php index 153eebb92cf..8ba44a37d94 100644 --- a/mod/members/views/default/members/sidebar.php +++ b/mod/members/views/default/members/sidebar.php @@ -3,12 +3,12 @@ * Members sidebar */ -$params = [ +$body = elgg_view_form('members/search', [ 'method' => 'get', - 'action' => 'members/search', + 'action' => elgg_generate_url('search:user:user'), 'disable_security' => true, -]; - -$body = elgg_view_form('members/search', $params); + 'role' => 'search', + 'aria-label' => elgg_echo('members:aria:label:member_search'), +]); echo elgg_view_module('aside', elgg_echo('members:search'), $body); diff --git a/mod/search/languages/en.php b/mod/search/languages/en.php index add48e73f5a..6e5ac700104 100644 --- a/mod/search/languages/en.php +++ b/mod/search/languages/en.php @@ -12,4 +12,6 @@ 'search:comment_on' => 'Comment on "%s"', 'search:unknown_entity' => 'Unknown Entity type', 'search:empty_query' => 'Please provide a valid search query', + + 'search:aria:label:site_search' => "Search on the site", ); diff --git a/mod/search/views/default/forms/search.php b/mod/search/views/default/forms/search.php index 4af56cb74a6..b40e5449a9e 100644 --- a/mod/search/views/default/forms/search.php +++ b/mod/search/views/default/forms/search.php @@ -8,7 +8,7 @@ $value = (string) elgg_extract('value', $vars, get_input('q', get_input('tag'))); echo elgg_view_field([ - '#type' => 'text', + '#type' => 'search', 'class' => 'search-input', 'size' => '21', 'name' => 'q', @@ -18,12 +18,13 @@ 'required' => true, 'value' => _elgg_get_display_query($value), 'placeholder' => elgg_echo('search'), + 'aria-label' => elgg_echo('search'), // because we don't add #label ]); echo elgg_view_field([ '#type' => 'submit', 'icon' => 'search', - 'aria-label' => elgg_echo('search'), + 'aria-label' => elgg_echo('search'), // because we don't add text ]); $values = [ diff --git a/mod/search/views/default/resources/search/index.php b/mod/search/views/default/resources/search/index.php index 2b7bf6b4da3..a7c8f410032 100644 --- a/mod/search/views/default/resources/search/index.php +++ b/mod/search/views/default/resources/search/index.php @@ -27,6 +27,8 @@ 'action' => elgg_generate_url('default:search'), 'method' => 'get', 'disable_security' => true, + 'role' => 'search', + 'aria-label' => elgg_echo('search:aria:label:site_search'), ], $params); if (!preg_match('/[\pL\pN]+/', $query)) { diff --git a/mod/search/views/default/search/search.css b/mod/search/views/default/search/search.css index 9135a7e98ee..3fba85ce15f 100644 --- a/mod/search/views/default/search/search.css +++ b/mod/search/views/default/search/search.css @@ -39,7 +39,7 @@ Search plugin width: 100%; } - [type="text"] { + [type="search"] { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1); border: none; background: transparent; diff --git a/mod/search/views/default/search/search_box.php b/mod/search/views/default/search/search_box.php index 58a0aa94e1b..a15609d569d 100644 --- a/mod/search/views/default/search/search_box.php +++ b/mod/search/views/default/search/search_box.php @@ -18,4 +18,6 @@ 'method' => 'get', 'disable_security' => true, 'class' => $class, + 'role' => 'search', + 'aria-label' => elgg_echo('search:aria:label:site_search'), ], $vars); diff --git a/views/default/admin/users/header.php b/views/default/admin/users/header.php index 838545cf91f..b5556ccdda3 100644 --- a/views/default/admin/users/header.php +++ b/views/default/admin/users/header.php @@ -33,6 +33,8 @@ 'action' => elgg_get_current_url(), 'disable_security' => true, 'class' => $search_class, + 'role' => 'search', + 'aria-label' => elgg_echo('aria:label:admin:users:search'), ], [ 'additional_search_fields' => elgg_extract('additional_search_fields', $vars, []), ]); diff --git a/views/default/forms/admin/users/search.php b/views/default/forms/admin/users/search.php index 995ab9954c1..aa436719b94 100644 --- a/views/default/forms/admin/users/search.php +++ b/views/default/forms/admin/users/search.php @@ -15,9 +15,10 @@ '#type' => 'fieldset', 'fields' => [ [ - '#type' => 'text', + '#type' => 'search', '#class' => 'elgg-field-stretch', 'name' => 'q', + 'aria-label' => elgg_echo('search'), // because we don't have a #label 'placeholder' => elgg_echo('search'), 'value' => get_input('q'), ], From 8772e2ae6ff6090ea1d5fd8a311b3df8b2e405ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 9 Aug 2023 14:06:11 +0200 Subject: [PATCH 062/240] chore(css): remove unused definition --- views/default/elements/components/list.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/views/default/elements/components/list.css b/views/default/elements/components/list.css index b856a94586c..a33c33375f0 100644 --- a/views/default/elements/components/list.css +++ b/views/default/elements/components/list.css @@ -22,10 +22,6 @@ .elgg-content { margin: 0.5rem 0; } - - > .elgg-subtext { - margin-bottom: 0.25rem; - } } .elgg-content { From 19869cfc9f3e1ddc90f5e15babcb3974dad083be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 9 Aug 2023 14:57:17 +0200 Subject: [PATCH 063/240] feat(a11y): added menu aria labels ref #5087 --- docs/guides/menus.rst | 21 ++++++++++++++++++- languages/en.php | 25 +++++++++++++++++++++++ mod/blog/languages/en.php | 1 + mod/developers/languages/en.php | 2 ++ mod/externalpages/languages/en.php | 2 ++ mod/friends_collections/languages/en.php | 1 + mod/pages/languages/en.php | 1 + mod/profile/languages/en.php | 1 + views/default/navigation/menu/default.php | 7 +++++++ 9 files changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/guides/menus.rst b/docs/guides/menus.rst index 95084c95fda..9917abd1025 100644 --- a/docs/guides/menus.rst +++ b/docs/guides/menus.rst @@ -44,7 +44,7 @@ Admin menu You can also register ``page`` menu items to the admin backend menu. When registering for the admin menu you can set the context of the menu items to ``admin`` so the menu items only show in the ``admin`` context. There are 3 default sections to add your menu items to. - - ``administer`` for daily tasks, usermanagement and other actionable tasks + - ``administer`` for daily tasks, user management and other actionable tasks - ``configure`` for settings, configuration and utilities that configure stuff - ``information`` for statistics, overview of information or status @@ -52,6 +52,25 @@ the menu items to ``admin`` so the menu items only show in the ``admin`` context Advanced usage ============== +Headers +------- + +For accessibility reasons each menu will get an ``aria-label`` which defaults to the menu name, but can be translated by making sure +the language key ``menu::header`` is available. + +It's also possible to show menu section headers by setting ``show_section_headers`` to ``true`` in ``elgg_view_menu()`` + +.. code-block:: php + + echo elgg_view_menu('my_menu', [ + 'show_section_headers' => true, + ]); + +The headers have a magic language key available ``menu::header:
    `` in order to be able to translate the headers. + +Events +------ + You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class. diff --git a/languages/en.php b/languages/en.php index f1e49f1c160..8e37be05c10 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1789,6 +1789,31 @@ */ 'aria:label:admin:users:search' => "User search", + 'menu:admin_footer:header' => "Admin footer", + 'menu:admin_header:header' => "Admin header", + 'menu:admin:users:bulk:header' => "Users bulk actions", + 'menu:annotation:header' => "Annotation", + 'menu:breadcrumbs:header' => "Breadcrumbs", + 'menu:comments:header' => "Comments", + 'menu:entity:header' => "Entity", + 'menu:entity_navigation:header' => "Entity navigation", + 'menu:filter:header' => "Filter", + 'menu:footer:header' => "Footer", + 'menu:login:header' => "Login", + 'menu:owner_block:header' => "Owner block", + 'menu:page:header' => "Page", + 'menu:relationship:header' => "Relationship", + 'menu:river:header' => "River", + 'menu:site:header' => "Site", + 'menu:social:header' => "Social", + 'menu:title:header' => "Title", + 'menu:title:widgets:header' => "Widget administration", + 'menu:topbar:header' => "Topbar", + 'menu:user_hover:header' => "User hover", + 'menu:user:unvalidated:header' => "Unvalidated user", + 'menu:walled_garden:header' => "Walled garden", + 'menu:widget:header' => "Widget controls", + /** * Cli commands */ diff --git a/mod/blog/languages/en.php b/mod/blog/languages/en.php index 513ea7e21ec..5cc989a6974 100644 --- a/mod/blog/languages/en.php +++ b/mod/blog/languages/en.php @@ -16,6 +16,7 @@ 'edit:object:blog' => 'Edit blog post', 'notification:object:blog:publish' => "Send a notification when a blog is published", 'notifications:mute:object:blog' => "about the blog '%s'", + 'menu:blog_archive:header' => "Blog archive", 'blog:revisions' => 'Revisions', 'blog:archives' => 'Archives', diff --git a/mod/developers/languages/en.php b/mod/developers/languages/en.php index fcbed1b86fe..0f95cd8338f 100644 --- a/mod/developers/languages/en.php +++ b/mod/developers/languages/en.php @@ -15,6 +15,8 @@ 'admin:develop_tools:entity_explorer' => 'Entity Explorer', 'admin:developers' => 'Developers', 'admin:developers:settings' => 'Settings', + 'menu:entity_explorer:header' => 'Entity explorer', + 'menu:developers_inspect_viewtype:header' => 'Inspect view types', // settings 'elgg_dev_tools:settings:explanation' => 'Control your development and debugging settings below. Some of these settings are also available on other admin pages.', diff --git a/mod/externalpages/languages/en.php b/mod/externalpages/languages/en.php index 79ebaf53ea1..f515a6790f5 100644 --- a/mod/externalpages/languages/en.php +++ b/mod/externalpages/languages/en.php @@ -11,6 +11,8 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Site Pages", + 'menu:expages:header' => "Site pages", + 'expages:edit:viewpage' => "View page on site", 'expages:about' => "About", 'expages:terms' => "Terms", diff --git a/mod/friends_collections/languages/en.php b/mod/friends_collections/languages/en.php index f3120857cd8..5e967e57cec 100644 --- a/mod/friends_collections/languages/en.php +++ b/mod/friends_collections/languages/en.php @@ -6,6 +6,7 @@ */ return array( + 'menu:friends:collection:header' => 'Collection', 'friends:collections' => 'Collections', 'friends:collections:no_results' => 'You haven\'t created any collections yet', 'friends:collection:members:no_results' => 'This collection doesn\'t have any members yet', diff --git a/mod/pages/languages/en.php b/mod/pages/languages/en.php index 852ce99ef4e..e84374cb20c 100644 --- a/mod/pages/languages/en.php +++ b/mod/pages/languages/en.php @@ -19,6 +19,7 @@ 'collection:object:page:group' => "Group pages", 'add:object:page' => "Add a page", 'edit:object:page' => "Edit this page", + 'menu:pages_nav:header' => "Sub-pages", 'notification:object:page:create' => "Send a notification when a page is created", 'notifications:mute:object:page' => "about the page '%s'", diff --git a/mod/profile/languages/en.php b/mod/profile/languages/en.php index 9f576cafc0d..73a5ff56ba4 100644 --- a/mod/profile/languages/en.php +++ b/mod/profile/languages/en.php @@ -10,6 +10,7 @@ 'profile:notfound' => 'Sorry. We could not find the requested profile.', 'admin:configure_utilities:profile_fields' => 'Edit Profile Fields', + 'menu:profile_admin:header' => 'Profile administration', 'profile:edit' => 'Edit profile', 'profile:edit:header' => 'Edit profile header', diff --git a/views/default/navigation/menu/default.php b/views/default/navigation/menu/default.php index 53fe8137772..39322cb933e 100644 --- a/views/default/navigation/menu/default.php +++ b/views/default/navigation/menu/default.php @@ -54,10 +54,17 @@ return; } +// make an ARIA label +$aria_label = $name; +if (elgg_language_key_exists("menu:{$name}:header")) { + $aria_label = elgg_echo("menu:{$name}:header"); +} + echo elgg_format_element('nav', [ 'class' => [ 'elgg-menu-container', "elgg-menu-{$name_class_selector}-container", ], 'data-menu-name' => $name, + 'aria-label' => $aria_label, ], $menu_view); From 7b4aa0e751a8e8126c16b9c9d3bfdca42f2b8d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 16 Aug 2023 10:23:50 +0200 Subject: [PATCH 064/240] chore(release): v5.0.5 --- CHANGELOG.md | 13 ++++ composer.json | 2 +- composer.lock | 173 +++++++++++++++++++++++++++----------------------- 3 files changed, 107 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c90b02fd4d2..84c271ed639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ + +### 5.0.5 (2023-08-16) + +#### Contributors + +* Jeroen Dalsem (1) +* Jerôme Bakker (1) + +#### Bug Fixes + +* **rss:** invalid atom link href in rss channel ([0467cf87](https://github.com/Elgg/Elgg/commit/0467cf8703bb3ea4936bd73bfbb3813a434d9275)) + + ### 5.0.4 (2023-07-26) diff --git a/composer.json b/composer.json index ef9a16ecee6..0c77b8c55dc 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "5.0.4", + "version": "5.0.5", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 681946d0230..d5f0b7dd6d4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "61fb31bb7bef904f2188ed4a2ae549cb", + "content-hash": "72403bc849acc68d3593f27c8a15b6a3", "packages": [ { "name": "cakephp/core", @@ -887,6 +887,7 @@ "issues": "https://github.com/eloquent/composer-config-reader/issues", "source": "https://github.com/eloquent/composer-config-reader/tree/3.0.0" }, + "abandoned": true, "time": "2020-11-16T06:11:04+00:00" }, { @@ -940,6 +941,7 @@ "issues": "https://github.com/eloquent/enumeration/issues", "source": "https://github.com/eloquent/enumeration/tree/master" }, + "abandoned": true, "time": "2018-11-22T02:45:56+00:00" }, { @@ -3645,7 +3647,7 @@ }, "conflict": { "3f/pygmentize": "<1.2", - "admidio/admidio": "<4.2.10", + "admidio/admidio": "<4.2.11", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", "aheinze/cockpit": "<2.2", "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", @@ -3666,9 +3668,10 @@ "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", "artesaos/seotools": "<0.17.2", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "asymmetricrypt/asymmetricrypt": "<9.9.99", "athlon1600/php-proxy": "<=5.1", "athlon1600/php-proxy-app": "<=3", + "austintoddj/canvas": "<=3.4.2", "automad/automad": "<1.8", "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": ">=3,<3.2.1", @@ -3684,7 +3687,7 @@ "baserproject/basercms": "<4.7.5", "bassjobsen/bootstrap-3-typeahead": ">4.0.2", "bigfork/silverstripe-form-capture": ">=3,<3.1.1", - "billz/raspap-webgui": "<2.8.9", + "billz/raspap-webgui": "<=2.9.2", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bmarshall511/wordpress_zero_spam": "<5.2.13", "bolt/bolt": "<3.7.2", @@ -3698,40 +3701,41 @@ "bugsnag/bugsnag-laravel": ">=2,<2.0.2", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", "cardgate/woocommerce": "<=3.1.15", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", - "centreon/centreon": "<22.10-beta.1", + "centreon/centreon": "<22.10.0.0-beta1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "cockpit-hq/cockpit": "<2.6", + "chriskacerguis/codeigniter-restserver": "<=2.7.1", + "cockpit-hq/cockpit": "<2.6.3", "codeception/codeception": "<3.1.3|>=4,<4.1.22", - "codeigniter/framework": "<=3.0.6", + "codeigniter/framework": "<3.1.9", "codeigniter4/framework": "<4.3.5", - "codeigniter4/shield": "<1-beta.4|= 1.0.0-beta", + "codeigniter4/shield": "<1.0.0.0-beta4", "codiad/codiad": "<=2.8.4", - "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<9.2|>= 9.0.0RC1, < 9.1.3", + "composer/composer": "<1.10.26|>=2,<2.2.12|>=2.3,<2.3.5", + "concrete5/concrete5": "<9.2", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10|= 4.10.0", + "contao/core-bundle": "<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", "cosenary/instagram": "<=2.3", - "craftcms/cms": "<=4.4.9|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", - "croogo/croogo": "<3.0.7", + "craftcms/cms": "<4.4.12", + "croogo/croogo": "<4", "cuyz/valinor": "<0.12", "czproject/git-php": "<4.0.3", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3-beta", + "dcat/laravel-admin": "<=2.1.3.0-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", "desperado/xml-bundle": "<=0.1.7", @@ -3745,14 +3749,14 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<17.0.1|= 12.0.5|>= 3.3.beta1, < 13.0.2", - "dompdf/dompdf": "<2.0.2|= 2.0.2", + "dolibarr/dolibarr": "<17.0.1", + "dompdf/dompdf": "<2.0.2|==2.0.2", "drupal/core": ">=7,<7.96|>=8,<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", - "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "drupal/drupal": ">=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "dweeves/magmi": "<=0.7.24", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", - "elefant/cms": "<1.3.13", + "elefant/cms": "<2.0.7", "elgg/elgg": "<3.3.24|>=4,<4.0.5", "encore/laravel-admin": "<=1.8.19", "endroid/qr-code-bundle": "<3.4.2", @@ -3760,26 +3764,26 @@ "erusev/parsedown": "<1.7.2", "ether/logs": "<3.0.4", "exceedone/exment": "<4.4.3|>=5,<5.0.3", - "exceedone/laravel-admin": "= 3.0.0|<2.2.3", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", + "exceedone/laravel-admin": "<2.2.3|==3", + "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.26", "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-graphql": ">=1-rc.1,<1.0.13|>=2-beta.1,<2.3.12", - "ezsystems/ezplatform-kernel": "<1.2.5.1|>=1.3,<1.3.26", + "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", + "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.26", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<6.13.8.2|>=7,<7.5.30", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.3.5.1", + "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.30", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.06,<=2019.03.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1|>=2.5,<2.5.15", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<4.1.1", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2022.8", + "facturascripts/facturascripts": "<=2022.08", "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", "fenom/fenom": "<=2.12.1", @@ -3788,12 +3792,12 @@ "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", "flarum/core": "<1.7", - "flarum/framework": "<=0.1-beta.7.1", + "flarum/framework": "<=0.1.0.0-beta7.1", "flarum/mentions": "<1.6.3", - "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", - "flarum/tags": "<=0.1-beta.13", + "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", + "flarum/tags": "<=0.1.0.0-beta13", "fluidtypo3/vhs": "<5.1.1", - "fof/byobu": ">=0.3-beta.2,<1.1.7", + "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", "fof/upload": "<1.2.3", "fooman/tcpdf": "<6.2.22", "forkcms/forkcms": "<5.11.1", @@ -3811,11 +3815,12 @@ "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", "getgrav/grav": "<=1.7.42.1", - "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", + "getkirby/cms": "<3.5.8.3-dev|>=3.6,<3.6.6.3-dev|>=3.7,<3.7.5.2-dev|>=3.8,<3.8.4.1-dev|>=3.9,<3.9.6", "getkirby/kirby": "<=2.5.12", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", + "gleez/cms": "<=1.2", "globalpayments/php-sdk": "<2", "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", @@ -3827,7 +3832,7 @@ "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", - "helloxz/imgurl": "= 2.31|<=2.31", + "helloxz/imgurl": "<=2.31", "hhxsv5/laravel-s": "<3.7.36", "hillelcoren/invoice-ninja": "<5.3.35", "himiklab/yii2-jqgrid-widget": "<1.0.8", @@ -3858,12 +3863,13 @@ "jackalope/jackalope-doctrine-dbal": "<1.7.4", "james-heinrich/getid3": "<1.9.21", "jasig/phpcas": "<1.3.3", + "jcbrand/converse.js": "<3.3.3", "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", "joomla/framework": ">=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", - "joomla/joomla-cms": ">=3,<3.9.12", + "joomla/joomla-cms": "<3.9.12", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", @@ -3879,20 +3885,20 @@ "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-diactoros": "<2.18.1|>=2.24,<2.24.2|>=2.25,<2.25.2|= 2.23.0|= 2.22.0|= 2.21.0|= 2.20.0|= 2.19.0", + "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", "laravel/fortify": "<1.11.1", "laravel/framework": "<6.20.44|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", - "lavalite/cms": "= 9.0.0|<=9", + "lavalite/cms": "<=9", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", - "league/oauth2-server": ">=8.3.2,<8.5.3", + "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<22.10", + "librenms/librenms": "<2017.08.18", "liftkit/database": "<2.13.2", "limesurvey/limesurvey": "<3.27.19", "livehelperchat/livehelperchat": "<=3.91", @@ -3900,15 +3906,15 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": "= 2.4.0|<=2.4", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "magento/community-edition": "<=2.4", + "magento/magento1ce": "<1.9.4.3-dev", + "magento/magento1ee": ">=1,<1.14.4.3-dev", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2.0-patch2", "maikuolan/phpmussel": ">=1,<1.6", "mantisbt/mantisbt": "<=2.25.5", "marcwillmann/turn": "<0.3.3", "matyhtf/framework": "<3.0.6", - "mautic/core": "<4.3|= 2.13.1", + "mautic/core": "<4.3", "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", "mediawiki/matomo": "<2.4.3", "melisplatform/melis-asset-manager": "<5.0.1", @@ -3916,20 +3922,20 @@ "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "<=1.3.4|= 1.1.18", + "microweber/microweber": "<=1.3.4", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<2.8|<= 2.8.3-pl", + "modx/revolution": "<=2.8.3.0-patch", "mojo42/jirafeau": "<4.4", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.2-rc.2|= 3.4.3|= 3.5|= 3.7|= 3.9|= 3.8|= 4.2.0|= 3.11", + "moodle/moodle": "<4.2.0.0-RC2-dev|==4.2", "movim/moxl": ">=0.8,<=0.10", "mpdf/mpdf": "<=7.1.7", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", - "neorazorx/facturascripts": "<2022.4", + "neorazorx/facturascripts": "<2022.04", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", @@ -3940,13 +3946,13 @@ "nilsteampassnet/teampass": "<3.0.10", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", - "nukeviet/nukeviet": "<4.5.2", + "nukeviet/nukeviet": "<4.5.02", "nyholm/psr7": "<1.6.1", "nystudio107/craft-seomatic": "<3.4.12", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", - "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": "<1.0.466|>=2.1,<2.1.12", + "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", + "october/october": "<=3.4.4", "october/rain": "<1.0.472|>=1.1,<1.1.2", "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", "onelogin/php-saml": "<2.10.4", @@ -3956,13 +3962,14 @@ "openid/php-openid": "<2.3", "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", - "orchid/platform": ">=9,<9.4.4|>=14-alpha.4,<14.5", + "orchid/platform": ">=9,<9.4.4|>=14.0.0.0-alpha4,<14.5", "oro/commerce": ">=4.1,<5.0.6", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", + "oxid-esales/oxideshop-ce": "<4.5", "packbackbooks/lti-1-3-php-library": "<5", "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", + "pagarme/pagarme-php": "<3", "pagekit/pagekit": "<=1.0.18", "paragonie/random_compat": "<2", "passbolt/passbolt_api": "<2.11", @@ -3991,33 +3998,35 @@ "phpxmlrpc/phpxmlrpc": "<4.9.2", "pi/pi": "<=2.5", "pimcore/admin-ui-classic-bundle": "<1.0.3", - "pimcore/customer-management-framework-bundle": "<3.4.1", + "pimcore/customer-management-framework-bundle": "<3.4.2", "pimcore/data-hub": "<1.2.4", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.6.4", + "pimcore/pimcore": "<10.6.7", "pixelfed/pixelfed": "<=0.11.4", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.0.4", + "prestashop/prestashop": "<=8.1", "prestashop/productcomments": "<5.0.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_linklist": "<3.1", "privatebin/privatebin": "<1.4", "processwire/processwire": "<=3.0.200", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", + "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pterodactyl/panel": "<1.7", + "ptheofan/yii2-statemachine": ">=2", "ptrofimov/beanstalk_console": "<1.7.14", "pusher/pusher-php-server": "<2.2.1", - "pwweb/laravel-core": "<=0.3.6-beta", + "pwweb/laravel-core": "<=0.3.6.0-beta", "pyrocms/pyrocms": "<=3.9.1", "rainlab/debugbar-plugin": "<3.1", + "rainlab/user-plugin": "<=1.4.5", "rankmath/seo-by-rank-math": "<=1.0.95", "rap2hpoutre/laravel-log-viewer": "<0.13", "react/http": ">=0.7,<1.9", @@ -4031,7 +4040,7 @@ "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", "sabre/dav": "<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", + "scheb/two-factor-bundle": "<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", "sfroemken/url_redirect": "<=1.2.1", @@ -4044,13 +4053,13 @@ "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", "silverstripe-australia/advancedreports": ">=1,<=2", - "silverstripe/admin": "<1.12.7", + "silverstripe/admin": "<1.13.6", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.12.5", - "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3|= 4.0.0-alpha1", + "silverstripe/framework": "<4.13.14|>=5,<5.0.13", + "silverstripe/graphql": "<3.5.2|>=4.0.0.0-alpha1,<4.0.0.0-alpha2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", @@ -4061,7 +4070,7 @@ "silverstripe/userforms": "<3", "silverstripe/versioned-admin": ">=1,<1.11.1", "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/saml2": "<1.15.4|>=2,<2.3.8|>=3,<3.1.4", "simplesamlphp/simplesamlphp": "<1.18.6", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplesamlphp/simplesamlphp-module-openid": "<1", @@ -4071,8 +4080,9 @@ "sjbr/sr-freecap": "<=2.5.2", "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", + "slub/slub-events": "<3.0.3", "smarty/smarty": "<3.1.48|>=4,<4.3.1", - "snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5", + "snipe/snipe-it": "<=6.0.14", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", @@ -4080,14 +4090,14 @@ "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<22.2.3", + "ssddanbrown/bookstack": "<22.02.3", "statamic/cms": "<4.10", - "stormpath/sdk": ">=0,<9.9.99", + "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<2.1.62", "subhh/libconnect": "<7.0.8|>=8,<8.1", "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", - "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", + "sulu/sulu": "<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8|==2.4.0.0-RC1|>=2.5,<2.5.10", "sumocoders/framework-user-bundle": "<1.4", "swag/paypal": "<5.4.4", "swiftmailer/swiftmailer": ">=4,<5.4.5", @@ -4106,7 +4116,7 @@ "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3|= 6.0.3|= 5.4.3|= 5.3.14", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3", "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", @@ -4124,27 +4134,28 @@ "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.3.2", "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", + "symfony/symfony": "<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "t3/dce": ">=2.2,<2.6.2", + "t3/dce": "<0.11.5|>=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", "tastyigniter/tastyigniter": "<3.3", "tcg/voyager": "<=1.4", "tecnickcom/tcpdf": "<6.2.22", "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", + "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<=5.1.7", - "thorsten/phpmyfaq": "<3.2-beta.2", + "thorsten/phpmyfaq": "<3.2.0.0-beta2", + "tikiwiki/tiki-manager": "<=17.1", "tinymce/tinymce": "<5.10.7|>=6,<6.3.1", "tinymighty/wiki-seo": "<1.2.2", - "titon/framework": ">=0,<9.9.99", - "tobiasbg/tablepress": "<= 2.0-RC1", + "titon/framework": "<9.9.99", + "tobiasbg/tablepress": "<=2.0.0.0-RC1", "topthink/framework": "<6.0.14", "topthink/think": "<=6.1.1", "topthink/thinkphp": "<=3.2.3", @@ -4153,10 +4164,12 @@ "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<=6.2.38|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", + "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "typo3/html-sanitizer": ">=1,<1.5.1|>=2,<2.1.2", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", @@ -4208,7 +4221,7 @@ "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", "yourls/yourls": "<=1.8.2", - "zencart/zencart": "<1.5.8", + "zencart/zencart": "<=1.5.7.0-beta", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", @@ -4230,7 +4243,7 @@ "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", + "zendframework/zendxml": "<1.0.1", "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", From 68a5eb28989d8d3c6736c1222ccc4844bce99ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 16 Aug 2023 16:06:08 +0200 Subject: [PATCH 065/240] chore(seeder): set correct access for comments/likes --- engine/classes/Elgg/Traits/Seeding.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/classes/Elgg/Traits/Seeding.php b/engine/classes/Elgg/Traits/Seeding.php index 0dde27787cb..f4a34e3069d 100644 --- a/engine/classes/Elgg/Traits/Seeding.php +++ b/engine/classes/Elgg/Traits/Seeding.php @@ -822,6 +822,7 @@ public function createComments(\ElggEntity $entity, $limit = null): int { $comment->container_guid = $entity->guid; $comment->description = $this->faker()->paragraph; $comment->time_created = $this->getRandomCreationTimestamp(); + $comment->access_id = $entity->access_id; $tries++; if ($comment->save()) { @@ -857,7 +858,7 @@ public function createLikes(\ElggEntity $entity, $limit = null): int { } while ($success < $limit) { - if ($entity->annotate('likes', true, $entity->access_id, $this->getRandomUser()->guid)) { + if ($entity->annotate('likes', true, ACCESS_PUBLIC, $this->getRandomUser()->guid)) { $success++; } } From b397601cd21212698c16e0ab00eb96d0e9f9679f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 25 Aug 2023 09:55:20 +0200 Subject: [PATCH 066/240] fix(ckeditor): early abort object mentions on closing bracket --- mod/ckeditor/views/default/ckeditor/config/mentions.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/ckeditor/views/default/ckeditor/config/mentions.js b/mod/ckeditor/views/default/ckeditor/config/mentions.js index 5ecb202ab55..9224b912ef6 100644 --- a/mod/ckeditor/views/default/ckeditor/config/mentions.js +++ b/mod/ckeditor/views/default/ckeditor/config/mentions.js @@ -61,6 +61,12 @@ define(['elgg/Ajax'], function(Ajax) { } function findObjects(queryText) { + if (queryText.includes(']')) { + // to allow the use of 'some [text] more text' + // without triggering the mentions functionality + return []; + } + return getLivesearch(queryText, 'objects'); } From e9ba84a15c4aeaeb9892ec252bdb5543135251fe Mon Sep 17 00:00:00 2001 From: Nikolai Shcherbin Date: Tue, 29 Aug 2023 09:35:04 +0300 Subject: [PATCH 067/240] fix(docs): document correct function --- docs/appendix/upgrade-notes/4.x-to-5.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/appendix/upgrade-notes/4.x-to-5.0.rst b/docs/appendix/upgrade-notes/4.x-to-5.0.rst index 7a729b7699a..c60731a7dd5 100644 --- a/docs/appendix/upgrade-notes/4.x-to-5.0.rst +++ b/docs/appendix/upgrade-notes/4.x-to-5.0.rst @@ -440,7 +440,7 @@ Deprecated APIs * ``elgg_clear_plugin_hook_handlers`` use ``elgg_clear_event_handlers`` * ``elgg_register_plugin_hook_handler`` use ``elgg_register_event_handler`` -* ``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_result`` +* ``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_results`` * ``elgg_unregister_plugin_hook_handler`` use ``elgg_unregister_event_handler`` * ``get_user_by_email`` use ``elgg_get_user_by_email`` * ``get_user_by_username`` use ``elgg_get_user_by_username`` From efe03d6ed65fdeb426fc6c9ae0934447a6943173 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 7 Sep 2023 11:17:15 +0200 Subject: [PATCH 068/240] chore(composer): updated tagify version --- composer.json | 2 +- composer.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 758f038af63..29fb940f7cc 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "npm-asset/requirejs": "^2.3.6", "npm-asset/requirejs-text": "^2.0.4", "npm-asset/sprintf-js": "~1.1.2", - "npm-asset/yaireo--tagify": "~4.16.0", + "npm-asset/yaireo--tagify": "~4.17.0", "pelago/emogrifier": "~7.0.0", "peppeocchi/php-cron-scheduler": "~4.0", "php-di/php-di": "~6.4.0", diff --git a/composer.lock b/composer.lock index 303ab43d285..fb13b11d001 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c5c74ce4725ce7409108819b63c73b8b", + "content-hash": "f2042d27bc1ea712ba38d5122cb47e13", "packages": [ { "name": "cakephp/core", @@ -2718,10 +2718,10 @@ }, { "name": "npm-asset/yaireo--tagify", - "version": "4.16.4", + "version": "4.17.9", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.16.4.tgz" + "url": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.17.9.tgz" }, "type": "npm-asset", "license": [ From 7fda4ab8a94f0cd4a070dc64d56cccd7987fb325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 7 Sep 2023 14:27:54 +0200 Subject: [PATCH 069/240] chore(release): v5.0.6 --- CHANGELOG.md | 14 ++++++++++++++ composer.json | 2 +- composer.lock | 26 +++++++++++++++++--------- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84c271ed639..cec87873c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + +### 5.0.6 (2023-09-07) + +#### Contributors + +* Jerôme Bakker (2) +* Nikolai Shcherbin (1) + +#### Bug Fixes + +* **ckeditor:** early abort object mentions on closing bracket ([b397601c](https://github.com/Elgg/Elgg/commit/b397601cd21212698c16e0ab00eb96d0e9f9679f)) +* **docs:** document correct function ([e9ba84a1](https://github.com/Elgg/Elgg/commit/e9ba84a15c4aeaeb9892ec252bdb5543135251fe)) + + ### 5.0.5 (2023-08-16) diff --git a/composer.json b/composer.json index 0c77b8c55dc..d03ccd0c1fc 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "5.0.5", + "version": "5.0.6", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index d5f0b7dd6d4..d3ed657f33f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "72403bc849acc68d3593f27c8a15b6a3", + "content-hash": "af9353b501835f6af7ac449138aad273", "packages": [ { "name": "cakephp/core", @@ -3662,6 +3662,7 @@ "anchorcms/anchor-cms": "<=0.12.7", "andreapollastri/cipi": "<=3.1.15", "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", + "apache-solr-for-typo3/solr": "<2.8.3", "apereo/phpcas": "<1.6", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3", "appwrite/server-ce": "<=1.2.1", @@ -3711,7 +3712,8 @@ "centreon/centreon": "<22.10.0.0-beta1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1", - "cockpit-hq/cockpit": "<2.6.3", + "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", + "cockpit-hq/cockpit": "<=2.6.3", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<3.1.9", "codeigniter4/framework": "<4.3.5", @@ -3727,7 +3729,7 @@ "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", "cosenary/instagram": "<=2.3", - "craftcms/cms": "<4.4.12", + "craftcms/cms": "<=4.4.14", "croogo/croogo": "<4", "cuyz/valinor": "<0.12", "czproject/git-php": "<4.0.3", @@ -3791,8 +3793,8 @@ "firebase/php-jwt": "<6", "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<1.7", - "flarum/framework": "<=0.1.0.0-beta7.1", + "flarum/core": "<1.8", + "flarum/framework": "<1.8", "flarum/mentions": "<1.6.3", "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", "flarum/tags": "<=0.1.0.0-beta13", @@ -3808,6 +3810,7 @@ "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", "froala/wysiwyg-editor": "<3.2.7", "froxlor/froxlor": "<2.1", "fuel/core": "<1.8.1", @@ -3862,6 +3865,7 @@ "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", "james-heinrich/getid3": "<1.9.21", + "james-heinrich/phpthumb": "<1.7.12", "jasig/phpcas": "<1.3.3", "jcbrand/converse.js": "<3.3.3", "joomla/archive": "<1.1.12|>=2,<2.0.1", @@ -3882,6 +3886,7 @@ "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<1.4.2", + "kohana/core": "<3.3.3", "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", @@ -3928,6 +3933,7 @@ "mobiledetect/mobiledetectlib": "<2.8.32", "modx/revolution": "<=2.8.3.0-patch", "mojo42/jirafeau": "<4.4", + "mongodb/mongodb": ">=1,<1.9.2", "monolog/monolog": ">=1.8,<1.12", "moodle/moodle": "<4.2.0.0-RC2-dev|==4.2", "movim/moxl": ">=0.8,<=0.10", @@ -4001,7 +4007,7 @@ "pimcore/customer-management-framework-bundle": "<3.4.2", "pimcore/data-hub": "<1.2.4", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.6.7", + "pimcore/pimcore": "<10.6.8", "pixelfed/pixelfed": "<=0.11.4", "pocketmine/bedrock-protocol": "<8.0.2", "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1", @@ -4086,7 +4092,7 @@ "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", - "spipu/html2pdf": "<5.2.4", + "spipu/html2pdf": "<5.2.8", "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", @@ -4177,6 +4183,7 @@ "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", + "uasoft-indonesia/badaso": "<=2.9.7", "unisharp/laravel-filemanager": "<=2.5.1", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", @@ -4185,8 +4192,9 @@ "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", + "waldhacker/hcaptcha": "<2.1.2", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<=2.5.4", + "wallabag/wallabag": "<=2.6.2", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", @@ -8700,5 +8708,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 6535d386b22d27e8631e59c6cbcaf258e63f7b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 3 Aug 2023 16:00:28 +0200 Subject: [PATCH 070/240] feat(cron): added custom cron logger class The provided logger will allow developers to log to the cron log directly, so it's easier to debug issue or long-running tasks. --- docs/guides/events-list.rst | 6 + engine/classes/Elgg/Cron.php | 289 +++++++++++++----- engine/classes/Elgg/EventsService.php | 121 ++++++-- engine/classes/Elgg/Logger/Cron.php | 65 ++++ .../Elgg/EventsServiceResultsUnitTest.php | 30 -- .../unit/Elgg/EventsServiceUnitTest.php | 133 +++++++- .../Elgg/GarbageCollector/CronRunner.php | 29 +- .../GarbageCollector/GarbageCollector.php | 118 ++++--- .../classes/Elgg/SiteNotifications/Cron.php | 37 ++- views/default/admin/cron.php | 59 ++-- 10 files changed, 615 insertions(+), 272 deletions(-) create mode 100644 engine/classes/Elgg/Logger/Cron.php diff --git a/docs/guides/events-list.rst b/docs/guides/events-list.rst index 83c587a9902..acb1f12d1c8 100644 --- a/docs/guides/events-list.rst +++ b/docs/guides/events-list.rst @@ -41,6 +41,12 @@ System events **cron, ** |results| Triggered by cron for each period. + The ``$params`` array will contain: + + * ``time`` - the timestamp of when the cron command was started + * ``dt`` - the ``\DateTime`` object of when the cron command was started + * ``logger`` - instance of ``\Elgg\Logger\Cron`` to log any information to the cron log + **cron:intervals, system** |results| Allow the configuration of custom cron intervals diff --git a/engine/classes/Elgg/Cron.php b/engine/classes/Elgg/Cron.php index 0403b952a05..a0a91725281 100644 --- a/engine/classes/Elgg/Cron.php +++ b/engine/classes/Elgg/Cron.php @@ -3,7 +3,7 @@ namespace Elgg; use Elgg\Exceptions\CronException; -use Elgg\Exceptions\Exception; +use Elgg\I18n\DateTime; use Elgg\I18n\Translator; use Elgg\Traits\Loggable; use Elgg\Traits\TimeUsing; @@ -20,6 +20,8 @@ class Cron { use Loggable; use TimeUsing; + protected const LOG_FILES_TO_KEEP = 5; + protected array $default_intervals = [ 'minute' => '* * * * *', 'fiveminute' => '*/5 * * * *', @@ -57,7 +59,6 @@ public function __construct(EventsService $events, Translator $translator) { * @throws CronException */ public function run(array $intervals = null, bool $force = false): array { - if (!isset($intervals)) { $intervals = array_keys($this->default_intervals); } @@ -73,17 +74,23 @@ public function run(array $intervals = null, bool $force = false): array { } $cron_interval = $force ? $allowed_intervals['minute'] : $allowed_intervals[$interval]; - + $filename = $this->getLogFilename($interval, $time); + + $cron_logger = \Elgg\Logger\Cron::factory([ + 'interval' => $interval, + 'filename' => $filename, + ]); + $scheduler - ->call(function () use ($interval, $time) { - return $this->execute($interval, $time); + ->call(function () use ($interval, $time, $cron_logger, $filename) { + return $this->execute($interval, $cron_logger, $filename, $time); }) ->at($cron_interval) - ->before(function () use ($interval, $time) { - $this->before($interval, $time); + ->before(function () use ($interval, $time, $cron_logger) { + $this->before($interval, $cron_logger, $time); }) - ->then(function ($output) use ($interval) { - $this->after($output, $interval); + ->then(function ($output) use ($interval, $cron_logger) { + $this->after($output, $interval, $cron_logger); }); } @@ -93,13 +100,13 @@ public function run(array $intervals = null, bool $force = false): array { /** * Execute commands before cron interval is run * - * @param string $interval Interval name - * @param null|\DateTime $time Time of the cron initialization (default: current service time) + * @param string $interval Interval name + * @param \Elgg\Logger\Cron $cron_logger Cron logger + * @param null|\DateTime $time Time of the cron initialization (default: current service time) * * @return void */ - protected function before(string $interval, \DateTime $time = null): void { - + protected function before(string $interval, \Elgg\Logger\Cron $cron_logger, \DateTime $time = null): void { if (!isset($time)) { $time = $this->getCurrentTime(); } @@ -112,133 +119,185 @@ protected function before(string $interval, \DateTime $time = null): void { // give every period at least 'max_execution_time' (PHP ini setting) set_time_limit((int) ini_get('max_execution_time')); - - $now = new \DateTime(); - - $msg = $this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL; - $msg .= $this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL; - - $this->cronLog('output', $interval, $msg); + + $now = new DateTime(); + + $cron_logger->notice($this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)])); + $cron_logger->notice($this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)])); } /** * Execute handlers attached to a specific cron interval * - * @param string $interval Cron interval to execute - * @param null|\DateTime $time Time of cron initialization (default: current service time) + * @param string $interval Cron interval to execute + * @param \Elgg\Logger\Cron $cron_logger Cron logger + * @param string $filename Filename of the cron log + * @param null|\DateTime $time Time of cron initialization (default: current service time) * * @return string */ - protected function execute(string $interval, \DateTime $time = null): string { - + protected function execute(string $interval, \Elgg\Logger\Cron $cron_logger, string $filename, \DateTime $time = null): string { if (!isset($time)) { $time = $this->getCurrentTime(); } - - $now = new \DateTime(); - - $output = []; - - $output[] = $this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]); - $output[] = $this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]); - + try { ob_start(); + $begin_callback = function (array $params) use ($cron_logger) { + $readable_callable = (string) elgg_extract('readable_callable', $params); + + $cron_logger->notice("Starting {$readable_callable}"); + }; + + $end_callback = function (array $params) use ($cron_logger) { + $readable_callable = (string) elgg_extract('readable_callable', $params); + + $cron_logger->notice("Finished {$readable_callable}"); + }; + $old_stdout = $this->events->triggerResults('cron', $interval, [ 'time' => $time->getTimestamp(), 'dt' => $time, - ], ''); + 'logger' => $cron_logger, + ], '', [ + EventsService::OPTION_BEGIN_CALLBACK => $begin_callback, + EventsService::OPTION_END_CALLBACK => $end_callback, + ]); + + $ob_output = ob_get_clean(); + + if (!empty($ob_output)) { + elgg_deprecated_notice('Direct output (echo, print) in a CRON event will be removed, use the provided "logger"', '5.1'); + + $cron_logger->notice($ob_output, ['ob_output']); + } - $output[] = ob_get_clean(); - $output[] = $old_stdout; + if (!empty($old_stdout)) { + elgg_deprecated_notice('Output in a CRON event result will be removed, use the provided "logger"', '5.1'); + + $cron_logger->notice($old_stdout, ['event_result']); + } } catch (\Throwable $t) { - $output[] = ob_get_clean(); + $ob_output = ob_get_clean(); + + if (!empty($ob_output)) { + elgg_deprecated_notice('Direct output (echo, print) in a CRON event will be removed, use the provided "logger"', '5.1'); + + $cron_logger->notice($ob_output, ['ob_output', 'throwable']); + } $this->getLogger()->error($t); } - $now = new \DateTime(); - - $output[] = $this->translator->translate('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); + $now = new DateTime(); - return implode(PHP_EOL, array_filter($output)); + $complete = $this->translator->translate('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); + $cron_logger->notice($complete); + + if (file_exists($filename) && is_readable($filename)) { + return file_get_contents($filename); + } + + return ''; } /** * Printers handler result * - * @param string $output Output string - * @param string $interval Interval name + * @param string $output Output string + * @param string $interval Interval name + * @param \Elgg\Logger\Cron $cron_logger Cron logger * * @return void */ - protected function after(string $output, string $interval): void { - $time = new \DateTime(); - - $this->cronLog('output', $interval, $output); - $this->cronLog('completion', $interval, $time->getTimestamp()); - + protected function after(string $output, string $interval, \Elgg\Logger\Cron $cron_logger): void { $this->getLogger()->info($output); try { - $this->events->triggerAfter('cron', $interval, $time); + $this->events->triggerAfter('cron', $interval, new \DateTime()); } catch (\Throwable $t) { $this->getLogger()->error($t); } + + $cron_logger->close(); + $this->rotateLogs($interval); + $this->logCompletion($interval); } - + /** - * Log the results of a cron interval + * Get the log files for a given cron interval * - * @param string $setting 'output'|'completion' - * @param string $interval Interval name - * @param string $msg Logged message + * The results are sorted so the newest log is the first in the array * - * @return void + * @param string $interval cron interval + * @param bool $filenames_only only return the filenames (default: false) + * + * @return array */ - protected function cronLog(string $setting, string $interval, string $msg = ''): void { - $suffix = $setting ?: 'output'; - + public function getLogs(string $interval, bool $filenames_only = false): array { $fh = new \ElggFile(); $fh->owner_guid = elgg_get_site_entity()->guid; - $fh->setFilename("{$interval}-{$suffix}.log"); + $fh->setFilename("cron/{$interval}/dummy.log"); - try { - $fh->open('write'); - $fh->write($msg); - } catch (Exception $e) { - // don't do anything + $dir = pathinfo($fh->getFilenameOnFilestore(), PATHINFO_DIRNAME); + if (!is_dir($dir) || !is_readable($dir)) { + return []; } - $fh->close(); + $dh = new \DirectoryIterator($dir); + $files = []; + /* @var $file \DirectoryIterator */ + foreach ($dh as $file) { + if ($file->isDot() || !$file->isFile()) { + continue; + } + + if ($filenames_only) { + $files[] = $file->getFilename(); + } else { + $files[$file->getFilename()] = file_get_contents($file->getPathname()); + } + } + + if ($filenames_only) { + natcasesort($files); + } else { + uksort($files, 'strnatcasecmp'); + } + + return array_reverse($files); } /** - * Get the log contents of a cron interval + * Get the time of the last completion of a cron interval * - * @param string $setting 'output'|'completion' - * @param string $interval Interval name + * @param string $interval cron interval * - * @return string + * @return null|DateTime */ - public function getLog(string $setting, string $interval): string { - $suffix = $setting ?: 'output'; - + public function getLastCompletion(string $interval): ?DateTime { $fh = new \ElggFile(); $fh->owner_guid = elgg_get_site_entity()->guid; - $fh->setFilename("{$interval}-{$suffix}.log"); + $fh->setFilename("cron/{$interval}.complete"); if (!$fh->exists()) { - return ''; + return null; + } + + $date = $fh->grabFile(); + if (empty($date)) { + // how?? + return null; } - $contents = $fh->grabFile(); - if (!is_string($contents)) { - $contents = ''; + try { + return Values::normalizeTime($date); + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + $this->getLogger()->warning($e); } - return $contents; + return null; } /** @@ -263,4 +322,78 @@ public function getConfiguredIntervals(bool $only_names = false): array { return $result; } + + /** + * Get a filename to log in + * + * @param string $interval cron interval to log + * @param \DateTime|null $time start time of the cron + * + * @return string + */ + protected function getLogFilename(string $interval, \DateTime $time = null): string { + if (!isset($time)) { + $time = $this->getCurrentTime(); + } + + $date = $time->format(\DateTimeInterface::ATOM); + $date = str_replace('+', 'p', $date); + $date = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $date); + + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + $fh->setFilename("cron/{$interval}/{$date}.log"); + + return $fh->getFilenameOnFilestore(); + } + + /** + * Rotate the log files + * + * @param string $interval cron interval + * + * @return void + */ + protected function rotateLogs(string $interval): void { + $files = $this->getLogs($interval, true); + if (count($files) <= self::LOG_FILES_TO_KEEP) { + return; + } + + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + + while (count($files) > self::LOG_FILES_TO_KEEP) { + $filename = array_pop($files); + + $fh->setFilename("cron/{$interval}/{$filename}"); + $fh->delete(); + } + } + + /** + * Log the completion time of a cron interval + * + * @param string $interval cron interval + * + * @return void + */ + protected function logCompletion(string $interval): void { + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + $fh->setFilename("cron/{$interval}.complete"); + + try { + if ($fh->open('write') === false) { + return; + } + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + $this->getLogger()->warning($e); + return; + } + + $now = new DateTime(); + $fh->write($now->format(\DateTimeInterface::ATOM)); + $fh->close(); + } } diff --git a/engine/classes/Elgg/EventsService.php b/engine/classes/Elgg/EventsService.php index 5c3a5c9d26a..582045652e9 100644 --- a/engine/classes/Elgg/EventsService.php +++ b/engine/classes/Elgg/EventsService.php @@ -22,6 +22,10 @@ class EventsService { const REG_KEY_HANDLER = 2; const OPTION_STOPPABLE = 'stoppable'; + const OPTION_USE_TIMER = 'use_timer'; + const OPTION_TIMER_KEYS = 'timer_keys'; + const OPTION_BEGIN_CALLBACK = 'begin_callback'; + const OPTION_END_CALLBACK = 'end_callback'; /** * @var HandlersService @@ -70,7 +74,13 @@ public function trigger(string $name, string $type, $object = null, array $optio $options = array_merge([ self::OPTION_STOPPABLE => true, ], $options); - + + // allow for the profiling of system events (when enabled) + if ($this->hasTimer() && $type === 'system' && $name !== 'shutdown') { + $options[self::OPTION_USE_TIMER] = true; + $options[self::OPTION_TIMER_KEYS] = ["[{$name},{$type}]"]; + } + // get registered handlers $handlers = $this->getOrderedHandlers($name, $type); @@ -79,26 +89,17 @@ public function trigger(string $name, string $type, $object = null, array $optio // creating objects for every triggering is expensive. /* @var $event Event|string */ $event = 'event'; + $event_args = [ + $name, + $type, + null, + [ + 'object' => $object, + '_elgg_sequence_id' => elgg_extract('_elgg_sequence_id', $options), + ], + ]; foreach ($handlers as $handler) { - $handler_description = false; - if ($this->hasTimer() && $type === 'system' && $name !== 'shutdown') { - $handler_description = $this->handlers->describeCallable($handler) . '()'; - $this->beginTimer(["[{$name},{$type}]", $handler_description]); - } - - list($success, $return, $event) = $this->handlers->call($handler, $event, [ - $name, - $type, - null, - [ - 'object' => $object, - '_elgg_sequence_id' => elgg_extract('_elgg_sequence_id', $options), - ], - ]); - - if ($handler_description) { - $this->endTimer(["[{$name},{$type}]", $handler_description]); - } + list($success, $return, $event) = $this->callHandler($handler, $event, $event_args, $options); if (!$success) { continue; @@ -115,23 +116,26 @@ public function trigger(string $name, string $type, $object = null, array $optio /** * Triggers a event that is allowed to return a mixed result * - * @param string $name The name of the event - * @param string $type The type of the event - * @param mixed $params Supplied params for the event - * @param mixed $value The value of the event, this can be altered by registered callbacks + * @param string $name The name of the event + * @param string $type The type of the event + * @param mixed $params Supplied params for the event + * @param mixed $value The value of the event, this can be altered by registered callbacks + * @param array $options (internal) options for triggering the event * * @return mixed * * @see elgg_trigger_event_results() */ - public function triggerResults(string $name, string $type, array $params = [], $value = null) { + public function triggerResults(string $name, string $type, array $params = [], $value = null, array $options = []) { // This starts as a string, but if a handler type-hints an object we convert it on-demand inside // \Elgg\HandlersService::call and keep it alive during all handler calls. We do this because // creating objects for every triggering is expensive. /* @var $event Event|string */ $event = 'event'; foreach ($this->getOrderedHandlers($name, $type) as $handler) { - list($success, $return, $event) = $this->handlers->call($handler, $event, [$name, $type, $value, $params]); + $event_args = [$name, $type, $value, $params]; + + list($success, $return, $event) = $this->callHandler($handler, $event, $event_args, $options); if (!$success) { continue; @@ -194,7 +198,7 @@ public function triggerAfter(string $name, string $type, $object = null, array $ } /** - * Trigger an sequence of :before, , and :after handlers. + * Trigger a sequence of :before, , and :after handlers. * Allows :before to terminate the sequence by returning false from a handler * Allows running a callable on successful before :after is triggered * Returns the result of the callable or bool @@ -253,7 +257,7 @@ public function triggerResultsSequence(string $name, string $type, array $params return false; } - $result = $this->triggerResults($name, $type, $params, $value); + $result = $this->triggerResults($name, $type, $params, $value, $options); if ($result === false) { return false; } @@ -275,16 +279,17 @@ public function triggerResultsSequence(string $name, string $type, array $params * @param mixed $object The object involved in the event * @param string $message The deprecation message * @param string $version Human-readable *release* version: 1.9, 1.10, ... + * @param array $options (internal) options for triggering the event * * @return bool * * @see elgg_trigger_deprecated_event() */ - public function triggerDeprecated(string $name, string $type, $object = null, string $message = '', string $version = ''): bool { + public function triggerDeprecated(string $name, string $type, $object = null, string $message = '', string $version = '', array $options = []): bool { $message = "The '{$name}', '{$type}' event is deprecated. {$message}"; $this->checkDeprecation($name, $type, $message, $version); - return $this->trigger($name, $type, $object); + return $this->trigger($name, $type, $object, $options); } /** @@ -296,16 +301,17 @@ public function triggerDeprecated(string $name, string $type, $object = null, st * @param mixed $returnvalue The return value * @param string $message The deprecation message * @param string $version Human-readable *release* version: 1.9, 1.10, ... + * @param array $options (internal) options for triggering the event * * @return mixed * * @see elgg_trigger_deprecated_event_results() */ - public function triggerDeprecatedResults(string $name, string $type, array $params = [], $returnvalue = null, string $message = '', string $version = '') { + public function triggerDeprecatedResults(string $name, string $type, array $params = [], $returnvalue = null, string $message = '', string $version = '', array $options = []) { $message = "The '{$name}', '{$type}' event is deprecated. {$message}"; $this->checkDeprecation($name, $type, $message, $version); - return $this->triggerResults($name, $type, $params, $returnvalue); + return $this->triggerResults($name, $type, $params, $returnvalue, $options); } /** @@ -567,4 +573,55 @@ protected function checkDeprecation(string $name, string $type, string $message, $this->logDeprecatedMessage($message, $version); } + + /** + * @param callable $callable Callable + * @param mixed $event Event object + * @param array $args Event arguments + * @param array $options (internal) options for triggering the event + * + * @return array [success, result, object] + */ + protected function callHandler($callable, $event, array $args, array $options = []): array { + // call a function before the actual callable + $begin_callback = elgg_extract(self::OPTION_BEGIN_CALLBACK, $options); + if (is_callable($begin_callback)) { + call_user_func($begin_callback, [ + 'callable' => $callable, + 'readable_callable' => $this->handlers->describeCallable($callable), + 'event' => $event, + 'arguments' => $args, + ]); + } + + // time the callable function + $use_timer = (bool) elgg_extract(self::OPTION_USE_TIMER, $options, false); + $timer_keys = (array) elgg_extract(self::OPTION_TIMER_KEYS, $options, []); + if ($use_timer) { + $timer_keys[] = $this->handlers->describeCallable($callable); + $this->beginTimer($timer_keys); + } + + // execute the callable function + $results = $this->handlers->call($callable, $event, $args); + + // end the timer + if ($use_timer) { + $this->endTimer($timer_keys); + } + + // call a function after the actual callable + $end_callback = elgg_extract(self::OPTION_END_CALLBACK, $options); + if (is_callable($end_callback)) { + call_user_func($end_callback, [ + 'callable' => $callable, + 'readable_callable' => $this->handlers->describeCallable($callable), + 'event' => $event, + 'arguments' => $args, + 'results' => $results, + ]); + } + + return $results; + } } diff --git a/engine/classes/Elgg/Logger/Cron.php b/engine/classes/Elgg/Logger/Cron.php new file mode 100644 index 00000000000..26498ed40f8 --- /dev/null +++ b/engine/classes/Elgg/Logger/Cron.php @@ -0,0 +1,65 @@ +cron; + if (empty($interval) || !in_array($interval, $cron->getConfiguredIntervals(true))) { + throw new InvalidArgumentException('Please specify a valid cron interval'); + } + + $filename = elgg_extract('filename', $params); + if (empty($filename)) { + throw new InvalidArgumentException('Please provide a log filename'); + } + + $logger = new static(self::CHANNEL); + + $handler = new StreamHandler($filename); + + $formatter = new ElggLogFormatter(); + $formatter->allowInlineLineBreaks(); + $formatter->ignoreEmptyContextAndExtra(); + + $handler->setFormatter($formatter); + + $handler->pushProcessor(new MemoryUsageProcessor()); + $handler->pushProcessor(new MemoryPeakUsageProcessor()); + $handler->pushProcessor(new ProcessIdProcessor()); + $handler->pushProcessor(new TagProcessor([$interval])); + $handler->pushProcessor(new PsrLogMessageProcessor()); + + $logger->pushHandler($handler); + + return $logger; + } +} diff --git a/engine/tests/phpunit/unit/Elgg/EventsServiceResultsUnitTest.php b/engine/tests/phpunit/unit/Elgg/EventsServiceResultsUnitTest.php index 1f801f29f50..6666a4cefbe 100644 --- a/engine/tests/phpunit/unit/Elgg/EventsServiceResultsUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/EventsServiceResultsUnitTest.php @@ -93,36 +93,6 @@ public function testHookTypeHintReceivesObject() { TestEventResultsHandler::$invocations = []; } - - public function testDeprecatedWithoutRegisteredHandlers() { - - _elgg_services()->logger->disable(); - - $this->assertEquals(2, $this->events->triggerDeprecated('foo', 'bar', ['foo' => 1], 2, 'The plugin hook "foo":"bar" has been deprecated', '1.0')); - - $logged = _elgg_services()->logger->enable(); - - $this->assertEquals([], $logged); - } - - public function testDeprecatedWithRegisteredHandlers() { - $handler = new TestEventResultsHandler(); - $this->events->registerHandler('foo', 'bar', $handler); - - _elgg_services()->logger->disable(); - - $this->assertEquals(3, $this->events->triggerDeprecatedResults('foo', 'bar', ['foo' => 1], 2, 'Do not use it!', '1.0')); - - $logged = _elgg_services()->logger->enable(); - $this->assertCount(1, $logged); - - $message_details = $logged[0]; - - $this->assertArrayHasKey('message', $message_details); - $this->assertArrayHasKey('level', $message_details); - $this->assertStringStartsWith("Deprecated in 1.0: The 'foo', 'bar' event is deprecated. Do not use it!", $message_details['message']); - $this->assertEquals(LogLevel::WARNING, $message_details['level']); - } public static function returnTwo() { return 2; diff --git a/engine/tests/phpunit/unit/Elgg/EventsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/EventsServiceUnitTest.php index aed5256aefb..8c620cd611a 100644 --- a/engine/tests/phpunit/unit/Elgg/EventsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/EventsServiceUnitTest.php @@ -8,18 +8,26 @@ class EventsServiceUnitTest extends \Elgg\UnitTestCase { - public $counter = 0; - - /** - * @var EventsService - */ - public $events; + protected int $counter = 0; + protected int $counter2 = 0; + protected EventsService $events; public function up() { $this->counter = 0; + $this->counter2 = 0; $this->events = new EventsService(new HandlersService()); } + public function incrementCounter(): bool { + $this->counter++; + return true; + } + + public function incrementCounter2(): bool { + $this->counter2++; + return true; + } + public function testTriggerCallsRegisteredHandlersAndReturnsTrue() { $this->events->registerHandler('foo', 'bar', array($this, 'incrementCounter')); $this->events->registerHandler('foo', 'bar', array($this, 'incrementCounter')); @@ -143,7 +151,7 @@ public function testInvokableFunctionTypeHintHook() { $this->assertEquals(2, $this->events->trigger('foo', 'bar', 1)); } - public function testDeprecatedWithoutRegisteredHandlers() { + public function testTriggerDeprecatedWithoutRegisteredHandlers() { _elgg_services()->logger->disable(); @@ -154,7 +162,7 @@ public function testDeprecatedWithoutRegisteredHandlers() { $this->assertEquals([], $logged); } - public function testDeprecatedWithRegisteredHandlers() { + public function testTriggerDeprecatedWithRegisteredHandlers() { $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter']); @@ -173,12 +181,113 @@ public function testDeprecatedWithRegisteredHandlers() { $this->assertStringStartsWith("Deprecated in 1.0: The 'foo', 'bar' event is deprecated. Do not use it!", $message_details['message']); $this->assertEquals(LogLevel::WARNING, $message_details['level']); } - - public function incrementCounter() { - $this->counter++; - return true; + + public function testTriggerDeprecatedResultsWithoutRegisteredHandlers() { + + _elgg_services()->logger->disable(); + + $this->assertTrue($this->events->triggerDeprecatedResults('foo', 'bar', [], true, 'The event "foo":"bar" has been deprecated', '1.0')); + + $logged = _elgg_services()->logger->enable(); + + $this->assertEquals([], $logged); + } + + public function testTriggerDeprecatedResultsWithRegisteredHandlers() { + + $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter']); + + _elgg_services()->logger->disable(); + + $this->assertTrue($this->events->triggerDeprecatedResults('foo', 'bar', [], false, 'Do not use it!', '1.0')); + $this->assertEquals(1, $this->counter); + + $logged = _elgg_services()->logger->enable(); + $this->assertCount(1, $logged); + + $message_details = $logged[0]; + + $this->assertArrayHasKey('message', $message_details); + $this->assertArrayHasKey('level', $message_details); + $this->assertStringStartsWith("Deprecated in 1.0: The 'foo', 'bar' event is deprecated. Do not use it!", $message_details['message']); + $this->assertEquals(LogLevel::WARNING, $message_details['level']); + } + + public function testTriggerWithBeforeCallbackNotCalledWithoutRegisteredHandlers() { + $this->assertTrue($this->events->trigger('foo', 'bar', [], [ + EventsService::OPTION_BEGIN_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEmpty($this->counter); + } + + public function testTriggerWithBeforeCallbackCalledWithRegisteredHandlers() { + $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter2']); + + $this->assertTrue($this->events->trigger('foo', 'bar', [], [ + EventsService::OPTION_BEGIN_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEquals(1, $this->counter); + $this->assertEquals(1, $this->counter2); + } + + public function testTriggerResultsWithBeforeCallbackNotCalledWithoutRegisteredHandlers() { + $this->assertTrue($this->events->triggerResults('foo', 'bar', [], true, [ + EventsService::OPTION_BEGIN_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEmpty($this->counter); + } + + public function testTriggerResultsWithBeforeCallbackCalledWithRegisteredHandlers() { + $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter2']); + + $this->assertTrue($this->events->triggerResults('foo', 'bar', [], false, [ + EventsService::OPTION_BEGIN_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEquals(1, $this->counter); + $this->assertEquals(1, $this->counter2); + } + + public function testTriggerWithEndCallbackNotCalledWithoutRegisteredHandlers() { + $this->assertTrue($this->events->trigger('foo', 'bar', [], [ + EventsService::OPTION_END_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEmpty($this->counter); } + public function testTriggerWithEndCallbackCalledWithRegisteredHandlers() { + $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter2']); + + $this->assertTrue($this->events->trigger('foo', 'bar', [], [ + EventsService::OPTION_END_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEquals(1, $this->counter); + $this->assertEquals(1, $this->counter2); + } + + public function testTriggerResultsWithEndCallbackNotCalledWithoutRegisteredHandlers() { + $this->assertTrue($this->events->triggerResults('foo', 'bar', [], true, [ + EventsService::OPTION_END_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEmpty($this->counter); + } + + public function testTriggerResultsWithEndCallbackCalledWithRegisteredHandlers() { + $this->events->registerHandler('foo', 'bar', [$this, 'incrementCounter2']); + + $this->assertTrue($this->events->triggerResults('foo', 'bar', [], false, [ + EventsService::OPTION_END_CALLBACK => [$this, 'incrementCounter'], + ])); + + $this->assertEquals(1, $this->counter); + $this->assertEquals(1, $this->counter2); + } public function testCanRegisterHandlers() { $f = function () { diff --git a/mod/garbagecollector/classes/Elgg/GarbageCollector/CronRunner.php b/mod/garbagecollector/classes/Elgg/GarbageCollector/CronRunner.php index bbab07c48d9..19489108191 100644 --- a/mod/garbagecollector/classes/Elgg/GarbageCollector/CronRunner.php +++ b/mod/garbagecollector/classes/Elgg/GarbageCollector/CronRunner.php @@ -14,25 +14,24 @@ class CronRunner { * * @return void */ - public function __invoke(\Elgg\Event $event) { - + public function __invoke(\Elgg\Event $event): void { $period = $event->getType(); - if ($period !== elgg_get_plugin_setting('period', 'garbagecollector')) { return; } - + + /* @var $cron_logger \Elgg\Logger\Cron */ + $cron_logger = $event->getParam('logger'); + // Now, because we are nice, trigger an event to let other plugins do some GC - elgg_trigger_event_results('gc', 'system', ['period' => $period]); - - $ops = GarbageCollector::instance()->optimize(); - - $output = []; - foreach ($ops as $op) { - $ok = $op->result ? 'ok' : 'err'; - $output[] = $op->operation . ': ' . $ok . '. Completed: ' . $op->completed->format(DATE_ATOM); - } - - echo implode(PHP_EOL, $output) . PHP_EOL; + $params = $event->getParams(); + $params['period'] = $period; + elgg_trigger_event_results('gc', 'system', $params); + + // optimize database tables + $instance = GarbageCollector::instance(); + $instance->setLogger($cron_logger); + + $instance->optimize(true); } } diff --git a/mod/garbagecollector/classes/Elgg/GarbageCollector/GarbageCollector.php b/mod/garbagecollector/classes/Elgg/GarbageCollector/GarbageCollector.php index 83b5d18518b..213edfbe7f3 100644 --- a/mod/garbagecollector/classes/Elgg/GarbageCollector/GarbageCollector.php +++ b/mod/garbagecollector/classes/Elgg/GarbageCollector/GarbageCollector.php @@ -6,6 +6,7 @@ use Elgg\Database\Delete; use Elgg\I18n\Translator; use Elgg\Traits\Di\ServiceFacade; +use Elgg\Traits\Loggable; /** * Garbage collecting service @@ -13,6 +14,7 @@ class GarbageCollector { use ServiceFacade; + use Loggable; /** * @var Database @@ -52,38 +54,52 @@ public static function name() { /** * Optimize the database * + * @param bool $use_logger Add the results to the log (default: false) + * * @return \stdClass[] */ - public function optimize(): array { + public function optimize(bool $use_logger = false): array { $dbprefix = $this->db->prefix; $output = []; - + $output[] = (object) [ 'operation' => $this->translator->translate('garbagecollector:start'), 'result' => true, 'completed' => new \DateTime(), ]; - + + if ($use_logger) { + $this->getLogger()->notice($this->translator->translate('garbagecollector:start')); + } + foreach ($this->tables() as $table) { if (stripos($table, "{$dbprefix}system_log_") === 0) { // rotated system_log tables don't need to be optimized continue; } - + $result = $this->optimizeTable($table) !== 0; $output[] = (object) [ 'operation' => $this->translator->translate('garbagecollector:optimize', [$table]), 'result' => $result, 'completed' => new \DateTime(), ]; + + if ($use_logger) { + $this->getLogger()->notice($this->translator->translate('garbagecollector:optimize', [$table]) . ' ' . $result ? 'OK' : 'FAILED'); + } } - + $output[] = (object) [ 'operation' => $this->translator->translate('garbagecollector:done'), 'result' => true, 'completed' => new \DateTime(), ]; - + + if ($use_logger) { + $this->getLogger()->notice($this->translator->translate('garbagecollector:done')); + } + return $output; } @@ -95,31 +111,27 @@ public function optimize(): array { * @return void */ public static function gcCallback(\Elgg\Event $event): void { - $results = self::instance()->cleanupOrphanedData(); + $cron_logger = $event->getParam('logger'); - foreach ($results as $result) { - echo $result->operation . ': ' . $result->num_rows . '. Completed: ' . $result->completed->format(DATE_ATOM) . PHP_EOL; - } + $instance = self::instance(); + $instance->setLogger($cron_logger); + $instance->cleanupOrphanedData(); - echo elgg_echo('garbagecollector:orphaned:done') . PHP_EOL . PHP_EOL; + $cron_logger->notice(elgg_echo('garbagecollector:orphaned:done')); } /** * Go through the database tables and remove orphaned data * - * @return \stdClass[] + * @return void */ - public function cleanupOrphanedData(): array { - $output = []; - - $output[] = $this->cleanupAccessCollections(); - $output[] = $this->cleanupAccessCollectionMembership(); - $output[] = $this->cleanupAnnotations(); - $output[] = $this->cleanupDelayedEmailQueue(); - $output[] = $this->cleanupEntityRelationships(); - $output[] = $this->cleanupMetadata(); - - return $output; + public function cleanupOrphanedData(): void { + $this->cleanupAccessCollections(); + $this->cleanupAccessCollectionMembership(); + $this->cleanupAnnotations(); + $this->cleanupDelayedEmailQueue(); + $this->cleanupEntityRelationships(); + $this->cleanupMetadata(); } /** @@ -169,9 +181,9 @@ protected function optimizeTable(string $table): int { * - id is not used in the entities table as access_id * - id is not used in the annotations table as access_id * - * @return \stdClass + * @return void */ - protected function cleanupAccessCollections(): \stdClass { + protected function cleanupAccessCollections(): void { $delete = Delete::fromTable('access_collections'); $owner_sub = $delete->subquery('entities'); @@ -189,11 +201,7 @@ protected function cleanupAccessCollections(): \stdClass { $delete->compare('id', 'not in', $annotations_access_id_sub->getSQL()), ], 'AND')); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['access_collections']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['access_collections']) . ': ' . $this->db->deleteData($delete)); } /** @@ -201,9 +209,9 @@ protected function cleanupAccessCollections(): \stdClass { * - user_guid no longer exists in the entities table * - access_collection_id no longer exists in the access_collections table * - * @return \stdClass + * @return void */ - protected function cleanupAccessCollectionMembership(): \stdClass { + protected function cleanupAccessCollectionMembership(): void { $delete = Delete::fromTable('access_collection_membership'); $user_sub = $delete->subquery('entities'); @@ -217,20 +225,16 @@ protected function cleanupAccessCollectionMembership(): \stdClass { $delete->compare('access_collection_id', 'not in', $access_collection_sub->getSQL()), ], 'OR')); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['access_collection_membership']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['access_collection_membership']) . ': ' . $this->db->deleteData($delete)); } /** * Remove annotations where: * - entity_guid no longer exists in the entities table * - * @return \stdClass + * @return void */ - protected function cleanupAnnotations(): \stdClass { + protected function cleanupAnnotations(): void { $delete = Delete::fromTable('annotations'); $entity_sub = $delete->subquery('entities'); @@ -238,20 +242,16 @@ protected function cleanupAnnotations(): \stdClass { $delete->where($delete->compare('entity_guid', 'not in', $entity_sub->getSQL())); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['annotations']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['annotations']) . ': ' . $this->db->deleteData($delete)); } /** * Remove delayed emails where: * - recipient_guid no longer exists in the entities table * - * @return \stdClass + * @return void */ - protected function cleanupDelayedEmailQueue(): \stdClass { + protected function cleanupDelayedEmailQueue(): void { $delete = Delete::fromTable('delayed_email_queue'); $entity_sub = $delete->subquery('entities'); @@ -259,11 +259,7 @@ protected function cleanupDelayedEmailQueue(): \stdClass { $delete->where($delete->compare('recipient_guid', 'not in', $entity_sub->getSQL())); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['delayed_email_queue']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['delayed_email_queue']) . ': ' . $this->db->deleteData($delete)); } /** @@ -271,9 +267,9 @@ protected function cleanupDelayedEmailQueue(): \stdClass { * - guid_one no longer exists in the entities table * - guid_two no longer exists in the entities table * - * @return \stdClass + * @return void */ - protected function cleanupEntityRelationships(): \stdClass { + protected function cleanupEntityRelationships(): void { $delete = Delete::fromTable('entity_relationships'); $guid_sub = $delete->subquery('entities'); @@ -284,20 +280,16 @@ protected function cleanupEntityRelationships(): \stdClass { $delete->compare('guid_two', 'not in', $guid_sub->getSQL()), ], 'OR')); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['entity_relationships']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['entity_relationships']) . ': ' . $this->db->deleteData($delete)); } /** * Remove metadata where: * - entity_guid no longer exists in the entities table * - * @return \stdClass + * @return void */ - protected function cleanupMetadata(): \stdClass { + protected function cleanupMetadata(): void { $delete = Delete::fromTable('metadata'); $entity_guid_sub = $delete->subquery('entities'); @@ -305,10 +297,6 @@ protected function cleanupMetadata(): \stdClass { $delete->where($delete->compare('entity_guid', 'not in', $entity_guid_sub->getSQL())); - return (object) [ - 'operation' => $this->translator->translate('garbagecollector:orphaned', ['metadata']), - 'num_rows' => $this->db->deleteData($delete), - 'completed' => new \DateTime(), - ]; + $this->getLogger()->notice($this->translator->translate('garbagecollector:orphaned', ['metadata']) . ': ' . $this->db->deleteData($delete)); } } diff --git a/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php b/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php index e6391a439b0..b4e324fbba0 100644 --- a/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php +++ b/mod/site_notifications/classes/Elgg/SiteNotifications/Cron.php @@ -26,13 +26,13 @@ class Cron { * * @param \Elgg\Event $event 'cron', 'fiveminute' * - * @return string + * @return void */ - public static function cleanupSiteNotificationsWithRemovedLinkedEntities(\Elgg\Event $event) { + public static function cleanupSiteNotificationsWithRemovedLinkedEntities(\Elgg\Event $event): void { set_time_limit(0); - $result = $event->getValue(); - $result .= elgg_echo('site_notifications:cron:linked_cleanup:start') . PHP_EOL; + /* @var $cron_logger \Elgg\Logger\Cron */ + $cron_logger = $event->getParam('logger'); $count = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() { $count = 0; @@ -80,8 +80,7 @@ function (QueryBuilder $qb, $main_alias) { return $count; }); - $result .= elgg_echo('site_notifications:cron:linked_cleanup:end', [$count]) . PHP_EOL; - return $result; + $cron_logger->notice(elgg_echo('site_notifications:cron:linked_cleanup:end', [$count])); } /** @@ -89,9 +88,9 @@ function (QueryBuilder $qb, $main_alias) { * * @param \Elgg\Event $event 'cron', 'daily' * - * @return void|string + * @return void */ - public static function cleanupUnreadSiteNotifications(\Elgg\Event $event) { + public static function cleanupUnreadSiteNotifications(\Elgg\Event $event): void { set_time_limit(0); $days = (int) elgg_get_plugin_setting('unread_cleanup_days', 'site_notifications'); @@ -100,10 +99,10 @@ public static function cleanupUnreadSiteNotifications(\Elgg\Event $event) { return; } - $max_runtime = static::CLEANUP_MAX_DURATION[$event->getType()]; + /* @var $cron_logger \Elgg\Logger\Cron */ + $cron_logger = $event->getParam('logger'); - $result = $event->getValue(); - $result .= elgg_echo('site_notifications:cron:unread_cleanup:start', [$days]) . PHP_EOL; + $max_runtime = static::CLEANUP_MAX_DURATION[$event->getType()]; $count = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($days, $max_runtime) { $count = 0; @@ -150,8 +149,7 @@ public static function cleanupUnreadSiteNotifications(\Elgg\Event $event) { return $count; }); - $result .= elgg_echo('site_notifications:cron:unread_cleanup:end', [$count]) . PHP_EOL; - return $result; + $cron_logger->notice(elgg_echo('site_notifications:cron:unread_cleanup:end', [$count])); } /** @@ -159,9 +157,9 @@ public static function cleanupUnreadSiteNotifications(\Elgg\Event $event) { * * @param \Elgg\Event $event 'cron', 'daily' * - * @return void|string + * @return void */ - public static function cleanupReadSiteNotifications(\Elgg\Event $event) { + public static function cleanupReadSiteNotifications(\Elgg\Event $event): void { set_time_limit(0); $days = (int) elgg_get_plugin_setting('read_cleanup_days', 'site_notifications'); @@ -170,10 +168,10 @@ public static function cleanupReadSiteNotifications(\Elgg\Event $event) { return; } - $max_runtime = static::CLEANUP_MAX_DURATION[$event->getType()]; + /* @var $cron_logger \Elgg\Logger\Cron */ + $cron_logger = $event->getParam('logger'); - $result = $event->getValue(); - $result .= elgg_echo('site_notifications:cron:read_cleanup:start', [$days]) . PHP_EOL; + $max_runtime = static::CLEANUP_MAX_DURATION[$event->getType()]; $count = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($days, $max_runtime) { $count = 0; @@ -220,8 +218,7 @@ public static function cleanupReadSiteNotifications(\Elgg\Event $event) { return $count; }); - $result .= elgg_echo('site_notifications:cron:read_cleanup:end', [$count]) . PHP_EOL; - return $result; + $cron_logger->notice(elgg_echo('site_notifications:cron:read_cleanup:end', [$count])); } /** diff --git a/views/default/admin/cron.php b/views/default/admin/cron.php index 76d5728e595..1984cc29b01 100644 --- a/views/default/admin/cron.php +++ b/views/default/admin/cron.php @@ -3,22 +3,26 @@ * Cron statistics */ +use Elgg\Values; + $cron_service = _elgg_services()->cron; $periods = $cron_service->getConfiguredIntervals(true); +$in_widget = elgg_in_context('widgets'); + $table_content = ''; foreach ($periods as $period) { $row = []; // name - $row[] = elgg_format_element('td', [], elgg_echo("interval:$period")); + $row[] = elgg_format_element('td', [], elgg_echo("interval:{$period}")); // last completed (friendly) and full date - $ts = $cron_service->getLog('completion', $period); - if (!elgg_is_empty($ts)) { - $row[] = elgg_format_element('td', [], elgg_view_friendly_time((int) $ts)); + $date = $cron_service->getLastCompletion($period); + if (!elgg_is_empty($date)) { + $row[] = elgg_format_element('td', [], elgg_view_friendly_time($date)); $row[] = elgg_format_element('td', [], elgg_view('output/date', [ - 'value' => $ts, + 'value' => $date, 'format' => DATE_RFC2822, ])); } else { @@ -27,27 +31,44 @@ } // cron output - $msg = $cron_service->getLog('output', $period); + $logs = $cron_service->getLogs($period); $msg_class = []; - if (!empty($msg)) { - $msg = nl2br($msg); + $log_output = ' '; + if (!empty($logs)) { + $log_output = ''; - if (elgg_in_context('widgets')) { - $msg = elgg_format_element('div', [], $msg); - $msg = elgg_view('output/url', [ - 'href' => false, - 'text' => false, - 'title' => elgg_echo('more_info'), + foreach ($logs as $filename => $contents) { + $matches = []; + preg_match('/(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})T(?[0-9]{2})-(?[0-9]{2})-(?[0-9]{2})(?[-p])(?[0-9]{2})-(?[0-9]{2})\S+/', $filename, $matches); + if ($matches['offset'] === 'p') { + $matches['offset'] = '+'; + } + + $date_string = "{$matches['year']}-{$matches['month']}-{$matches['day']}T{$matches['hour']}:{$matches['minute']}:{$matches['second']}{$matches['offset']}{$matches['offset_hour']}:{$matches['offset_minute']}"; + $date = Values::normalizeTime($date_string); + + $contents = nl2br($contents); + $contents = elgg_format_element('div', [], $contents); + + $log_output .= elgg_view('output/url', [ 'icon' => 'info', + 'text' => !$in_widget ? $date->format(DATE_RFC2822) : false, + 'title' => elgg_echo('more_info'), + 'href' => "#{$period}-{$date->getTimestamp()}", 'class' => ['elgg-lightbox'], - 'data-colorbox-opts' => json_encode(['html' => $msg]), + 'data-colorbox-opts' => json_encode(['html' => $contents]), ]); - $msg_class[] = 'center'; + if ($in_widget) { + $msg_class[] = 'center'; + break; + } + + $log_output .= '
    '; } } - $row[] = elgg_format_element('td', ['class' => $msg_class], $msg); + $row[] = elgg_format_element('td', ['class' => $msg_class], $log_output); $table_content .= elgg_format_element('tr', [], implode(PHP_EOL, $row)); } @@ -61,6 +82,4 @@ $table_content = elgg_format_element('tbody', [], $table_content); -$table = elgg_format_element('table', ['class' => 'elgg-table'], $header . $table_content); - -echo elgg_view_module('info', elgg_echo('admin:cron:record'), $table); +echo elgg_format_element('table', ['class' => 'elgg-table'], $header . $table_content); From 5b0bd6a8d72e2872e447fb3e331356aa5b4f095b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 14 Sep 2023 10:33:59 +0200 Subject: [PATCH 071/240] feat(ckeditor): ctrl+enter in the editor field will submit the form --- mod/ckeditor/views/default/ckeditor/editor.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mod/ckeditor/views/default/ckeditor/editor.js b/mod/ckeditor/views/default/ckeditor/editor.js index eaeed04622d..84d1ee9a826 100644 --- a/mod/ckeditor/views/default/ckeditor/editor.js +++ b/mod/ckeditor/views/default/ckeditor/editor.js @@ -44,6 +44,15 @@ define(['jquery', 'elgg', 'elgg/hooks', 'ckeditor/ckeditor'], function ($, elgg, $(editor.sourceElement).trigger('change'); }); + editor.keystrokes.set('Ctrl+Enter', (event, cancel ) => { + $submit_button = $(editor.sourceElement).closest('form').find('button[type="submit"]').eq(0); + if ($submit_button.length) { + $submit_button.trigger('click'); + } + + cancel(); + }); + $(window).on('beforeunload.ckeditor', function(event) { if ($(editor.sourceElement).data('dirty') && $(editor.sourceElement).closest('form').is(':visible')) { return true; From 3eb7fe3549ef2c7758541c4080d6914bf131815d Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 13 Sep 2023 16:06:41 +0200 Subject: [PATCH 072/240] feat(css): allow theme variables to be configured by the site admin --- actions/admin/site/icons.php | 2 +- actions/admin/site/theme.php | 34 +++++++++++++ engine/actions.php | 1 + engine/classes/Elgg/Assets/CssCompiler.php | 47 +++++++++++------- engine/classes/Elgg/Menus/AdminHeader.php | 8 ++++ engine/theme.php | 2 +- languages/en.php | 5 ++ views/default/admin/theme.php | 3 ++ views/default/forms/admin/site/theme.js | 8 ++++ views/default/forms/admin/site/theme.php | 56 ++++++++++++++++++++++ 10 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 actions/admin/site/theme.php create mode 100644 views/default/admin/theme.php create mode 100644 views/default/forms/admin/site/theme.js create mode 100644 views/default/forms/admin/site/theme.php diff --git a/actions/admin/site/icons.php b/actions/admin/site/icons.php index d3020de3c3b..57d921b3b6a 100644 --- a/actions/admin/site/icons.php +++ b/actions/admin/site/icons.php @@ -48,4 +48,4 @@ elgg_save_config('font_awesome_zip', $zip->getClientOriginalName()); } -return elgg_ok_response(elgg_echo('save:success')); +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/actions/admin/site/theme.php b/actions/admin/site/theme.php new file mode 100644 index 00000000000..ac782805d88 --- /dev/null +++ b/actions/admin/site/theme.php @@ -0,0 +1,34 @@ +cssCompiler->getCssVars([], false); +foreach ($vars as $name => $value) { + if (empty($value)) { + unset($vars[$name]); + continue; + } + + if (!array_key_exists($name, $available_config)) { + unset($vars[$name]); + continue; + } + + if (strtolower($value) === strtolower((string) $available_config[$name])) { + unset($vars[$name]); + continue; + } +} + +if (empty($vars)) { + elgg_remove_config('custom_theme_vars'); +} else { + elgg_save_config('custom_theme_vars', $vars); +} + +elgg_invalidate_caches(); + +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/engine/actions.php b/engine/actions.php index ee15d5bea28..f7b17e9bd75 100644 --- a/engine/actions.php +++ b/engine/actions.php @@ -16,6 +16,7 @@ 'admin/site/icons' => ['access' => 'admin'], 'admin/site/set_maintenance_mode' => ['access' => 'admin'], 'admin/site/set_robots' => ['access' => 'admin'], + 'admin/site/theme' => ['access' => 'admin'], 'admin/site/unlock_upgrade' => ['access' => 'admin'], 'admin/site/settings' => ['access' => 'admin'], 'admin/upgrade' => ['access' => 'admin'], diff --git a/engine/classes/Elgg/Assets/CssCompiler.php b/engine/classes/Elgg/Assets/CssCompiler.php index 74d90aa3419..ac1feab050e 100644 --- a/engine/classes/Elgg/Assets/CssCompiler.php +++ b/engine/classes/Elgg/Assets/CssCompiler.php @@ -15,15 +15,9 @@ */ class CssCompiler { - /** - * @var Config - */ - protected $config; + protected Config $config; - /** - * @var EventsService - */ - protected $events; + protected EventsService $events; /** * Constructor @@ -44,7 +38,7 @@ public function __construct(Config $config, EventsService $events) { * * @return string */ - public function compile($css, array $options = []) { + public function compile($css, array $options = []): string { $defaults = [ 'minify' => false, // minify handled by \Elgg\Views\MinifyHandler::class 'formatter' => 'single-line', // shows lowest byte size @@ -56,31 +50,50 @@ public function compile($css, array $options = []) { $config = (array) $this->config->css_compiler_options; $options = array_merge($defaults, $config, $options); - - $default_vars = array_merge($this->getCoreVars(), $this->getPluginVars()); - $custom_vars = (array) elgg_extract('vars', $options, []); - $vars = array_merge($default_vars, $custom_vars); - - $options['vars'] = $this->events->triggerResults('vars:compiler', 'css', $options, $vars); + $options['vars'] = $this->getCssVars($options); Crush::$process = new CssCrushProcess($options, ['type' => 'filter', 'data' => $css]); return Crush::$process->compile()->__toString(); } + + /** + * Fetches a combined set of CSS variables and their value + * + * @param array $compiler_options compiler arguments with potential custom variables + * @param bool $load_config_vars (internal) determines if config values are being loaded + * + * @return array + */ + public function getCssVars(array $compiler_options = [], bool $load_config_vars = true): array { + $default_vars = array_merge($this->getCoreVars(), $this->getPluginVars()); + $custom_vars = (array) elgg_extract('vars', $compiler_options, []); + $vars = array_merge($default_vars, $custom_vars); + + $results = (array) $this->events->triggerResults('vars:compiler', 'css', $compiler_options, $vars); + + if (!$load_config_vars) { + return $results; + } + + return array_merge($results, (array) elgg_get_config('custom_theme_vars', [])); + } /** * Default Elgg theme variables + * * @return array */ - protected function getCoreVars() { + protected function getCoreVars(): array { $file = Paths::elgg() . 'engine/theme.php'; return Includer::includeFile($file); } /** * Plugin theme variables + * * @return array */ - protected function getPluginVars() { + protected function getPluginVars(): array { $return = []; $plugins = elgg_get_plugins('active'); diff --git a/engine/classes/Elgg/Menus/AdminHeader.php b/engine/classes/Elgg/Menus/AdminHeader.php index a54fed3942e..cb70c91ddbf 100644 --- a/engine/classes/Elgg/Menus/AdminHeader.php +++ b/engine/classes/Elgg/Menus/AdminHeader.php @@ -253,6 +253,14 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'parent_name' => 'configure', ]); + $return[] = \ElggMenuItem::factory([ + 'name' => 'settings:theme', + 'text' => elgg_echo('admin:theme'), + 'href' => 'admin/theme', + 'priority' => 25, + 'parent_name' => 'configure', + ]); + $return[] = \ElggMenuItem::factory([ 'name' => 'security', 'text' => elgg_echo('admin:security'), diff --git a/engine/theme.php b/engine/theme.php index 4cb1f89a4e4..26aecfbb403 100644 --- a/engine/theme.php +++ b/engine/theme.php @@ -6,7 +6,7 @@ return [ // layout and shell - 'body-background-color' => '#FFF', + 'body-background-color' => '#FFFFFF', 'walled-garden-background-image' => 'graphics/walled_garden.jpg', // Typography diff --git a/languages/en.php b/languages/en.php index 8e37be05c10..0f635d273a1 100644 --- a/languages/en.php +++ b/languages/en.php @@ -591,6 +591,11 @@ 'admin:site_icons:font_awesome:zip:help' => "Here you can upload a Font Awesome download from https://fontawesome.com/download. This webfont will be served locally.", 'admin:site_icons:font_awesome:zip:error' => "Uploaded ZIP can not be extracted", 'admin:site_icons:font_awesome:remove_zip' => "Remove uploaded font", + 'admin:theme' => "Theme", + 'admin:theme:info' => "Various theme variables can be configured on this form. This configuration will override the existing configuration.", + 'admin:theme:warning' => "Be advised that these changes could potentially break your styling.", + 'admin:theme:css_variable:name' => "CSS variable", + 'admin:theme:css_variable:value' => "Value", 'admin:site_settings' => "Site Settings", 'admin:site:description' => "This admin panel allows you to control global settings for your site. Choose an option below to get started.", 'admin:site:opt:linktext' => "Configure site...", diff --git a/views/default/admin/theme.php b/views/default/admin/theme.php new file mode 100644 index 00000000000..1bbf1805c32 --- /dev/null +++ b/views/default/admin/theme.php @@ -0,0 +1,3 @@ + elgg_echo('admin:theme:info')]); + +echo elgg_view_message('warning', elgg_echo('admin:theme:warning')); + +$css_vars = _elgg_services()->cssCompiler->getCssVars(); +$original_vars = _elgg_services()->cssCompiler->getCssVars([], false); + +$config_values = (array) elgg_get_config('custom_theme_vars', []); + +$headings = elgg_format_element('th', [], elgg_echo('admin:theme:css_variable:name')); +$headings .= elgg_format_element('th', [], elgg_echo('admin:theme:css_variable:value')); +$headings .= elgg_format_element('th', [], ' '); +$thead = elgg_format_element('tr', [], $headings); + +$tbody = ''; +foreach ($css_vars as $name => $value) { + $original_value = (string) elgg_extract($name, $original_vars); + $input_type = str_starts_with($original_value, '#') && strlen($original_value) === 7 ? 'color' : 'text'; + + $reset = ' '; + if (array_key_exists($name, $config_values)) { + $reset = elgg_view_field([ + '#type' => 'button', + '#class' => 'man', + 'text' => elgg_echo('reset'), + 'class' => 'elgg-button-action', + 'data-original-theme-var' => $original_vars[$name], + ]); + } + + $row = elgg_format_element('th', [], $name); + $row .= elgg_format_element('td', [], elgg_view_field([ + '#type' => $input_type, + '#class' => 'man', + 'name' => "vars[{$name}]", + 'value' => $value, + ])); + $row .= elgg_format_element('td', ['style' => 'width: 1%;'], $reset); + + $tbody .= elgg_format_element('tr', [], $row); +} + +$table = elgg_format_element('thead', [], $thead); +$table .= elgg_format_element('tbody', [], $tbody); + +echo elgg_format_element('table', ['class' => 'elgg-table-alt'], $table); + +$footer = elgg_view_field([ + '#type' => 'submit', + 'text' => elgg_echo('save'), +]); +elgg_set_form_footer($footer); From ad7ccdc34e8b382aa55ffa5654e2e46a43db9388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 26 Sep 2023 14:20:56 +0200 Subject: [PATCH 073/240] chore(composer): update composer/semver version --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index d03ccd0c1fc..b3a058a1846 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "ext-json": "*", "ext-xml": "*", "ckeditor/ckeditor": "~4.20.0", - "composer/semver": "~3.3.0", + "composer/semver": "~3.4.0", "css-crush/css-crush": "~4.1.0", "doctrine/dbal": "~3.4.4", "eloquent/composer-config-reader": "~3.0.0", diff --git a/composer.lock b/composer.lock index d3ed657f33f..fcad8dcfb3c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "af9353b501835f6af7ac449138aad273", + "content-hash": "d23b5378a159382534da12503d5cd4c4", "packages": [ { "name": "cakephp/core", @@ -289,16 +289,16 @@ }, { "name": "composer/semver", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", "shasum": "" }, "require": { @@ -348,9 +348,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/3.4.0" }, "funding": [ { @@ -366,7 +366,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2023-08-31T09:50:34+00:00" }, { "name": "css-crush/css-crush", From c08defac798761e0d568fc1a26255c9f5579367e Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 5 Oct 2023 10:34:24 +0200 Subject: [PATCH 074/240] chore(composer): lock htmlawed version --- composer.json | 2 +- composer.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b3a058a1846..be868658e65 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "symfony/mime": "~5.3", "symfony/routing": "~5.3", "symfony/var-dumper": "~5.3", - "vanilla/htmlawed": "~2.2.0" + "vanilla/htmlawed": "2.2.5" }, "config": { "process-timeout": 0, diff --git a/composer.lock b/composer.lock index fcad8dcfb3c..742291dfe85 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d23b5378a159382534da12503d5cd4c4", + "content-hash": "480ee308beaf57a3c8453aa2a9d1da2d", "packages": [ { "name": "cakephp/core", @@ -8708,5 +8708,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } From 8737dabb7f17c4e910329ccef55a5b08655e66a9 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Tue, 3 Oct 2023 11:37:04 +0200 Subject: [PATCH 075/240] chore(docs): updated readthedocs.yml with new options --- .readthedocs.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index abfabe60deb..646914ed6e3 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,6 +5,11 @@ # Required version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.7" + # Build documentation in the docs/ directory with Sphinx sphinx: builder: html @@ -20,6 +25,5 @@ formats: all # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 install: - requirements: docs/pip-requirements.txt \ No newline at end of file From 1b057186899ceb119b461613f65ac4b1f82e9b3b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 5 Oct 2023 09:35:22 +0200 Subject: [PATCH 076/240] fix(forms): prevent double submit on comment forms --- views/default/elgg/comments.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/views/default/elgg/comments.js b/views/default/elgg/comments.js index b786a16d727..7db7e6666e6 100644 --- a/views/default/elgg/comments.js +++ b/views/default/elgg/comments.js @@ -15,6 +15,8 @@ define(['jquery', 'elgg'], function ($, elgg) { $(document).on('submit', '.elgg-form-comment-save', function (event) { var $form = $(this); + + $form.find('.elgg-button-submit').prop('disabled', true); require(['elgg/Ajax'], function(Ajax) { var ajax = new Ajax(); @@ -39,6 +41,7 @@ define(['jquery', 'elgg'], function ($, elgg) { } if (!$container.length) { + $form.find('.elgg-button-submit').prop('disabled', true); return; } @@ -75,8 +78,14 @@ define(['jquery', 'elgg'], function ($, elgg) { $comment[0].scrollIntoView({behavior: 'smooth'}); fix_pagination($container); + }, + error: function() { + $form.find('.elgg-button-submit').prop('disabled', false); } }); + }, + error: function () { + $form.find('.elgg-button-submit').prop('disabled', false); } }); }); @@ -167,7 +176,8 @@ define(['jquery', 'elgg'], function ($, elgg) { submitForm: function () { var $form = this.getForm(); - + $form.find('.elgg-button-submit').prop('disabled', true); + require(['elgg/Ajax'], function(Ajax) { var ajax = new Ajax(); @@ -178,6 +188,9 @@ define(['jquery', 'elgg'], function ($, elgg) { // Update list item content $form.closest('.elgg-item-object-comment').html(result.output); } + }, + error: function() { + $form.find('.elgg-button-submit').prop('disabled', false); } }); }); From b34d9e68b5fe12d052f62326804e46d2a722ef23 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 5 Oct 2023 12:36:35 +0200 Subject: [PATCH 077/240] chore(docs): correctly set the default readthedocs theme --- docs/conf.py | 3 ++- docs/requirements.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 532cb9be836..cd16017f292 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ + 'sphinx_rtd_theme', 'sphinxcontrib.phpdomain' ] @@ -109,7 +110,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/requirements.txt b/docs/requirements.txt index 43228802693..a473cf27e23 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ docutils<0.18 sphinxcontrib.phpdomain sphinx-intl +sphinx_rtd_theme From 28b3bffa5b5c0b88801e9309580636fc194f10a8 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Thu, 5 Oct 2023 13:10:00 +0200 Subject: [PATCH 078/240] chore(docs): added the sphinx_rtd_theme to pip requirements --- docs/pip-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pip-requirements.txt b/docs/pip-requirements.txt index 195d12c3ce8..8efc1783f34 100644 --- a/docs/pip-requirements.txt +++ b/docs/pip-requirements.txt @@ -1,2 +1,3 @@ docutils<0.18 sphinxcontrib.phpdomain +sphinx_rtd_theme From e04e396b428b850b173fbcc42f3ac4efeb4d08d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 10 Oct 2023 12:15:01 +0200 Subject: [PATCH 079/240] fix(icons): retry icon resize after failure --- engine/classes/Elgg/EntityIconService.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index 28c00dfcfba..cb493ac87df 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -401,6 +401,12 @@ protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'i if (!_elgg_services()->imageService->resize($source, $destination, $resize_params)) { $this->getLogger()->error("Failed to create {$size} icon from {$file->getFilenameOnFilestore()} with coords [{$x1}, {$y1}],[{$x2}, {$y2}]"); + + if ($size !== 'master') { + // remove 0 byte icon in order to retry the resize on the next request + $icon->delete(); + } + return false; } } From 339b34884a383cfb250f97087d584ebe38ad7df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 10 Oct 2023 13:32:10 +0200 Subject: [PATCH 080/240] chore(release): v5.0.7 --- CHANGELOG.md | 14 +++++++++++ composer.json | 2 +- composer.lock | 69 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cec87873c34..f2efd94b1cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + +### 5.0.7 (2023-10-10) + +#### Contributors + +* Jeroen Dalsem (5) +* Jerôme Bakker (2) + +#### Bug Fixes + +* **forms:** prevent double submit on comment forms ([1b057186](https://github.com/Elgg/Elgg/commit/1b057186899ceb119b461613f65ac4b1f82e9b3b)) +* **icons:** retry icon resize after failure ([e04e396b](https://github.com/Elgg/Elgg/commit/e04e396b428b850b173fbcc42f3ac4efeb4d08d1)) + + ### 5.0.6 (2023-09-07) diff --git a/composer.json b/composer.json index be868658e65..e6333fda370 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "elgg/elgg", - "version": "5.0.6", + "version": "5.0.7", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 742291dfe85..bf8c13b7499 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "480ee308beaf57a3c8453aa2a9d1da2d", + "content-hash": "fcde5925a9172f77531e4568be028187", "packages": [ { "name": "cakephp/core", @@ -3699,7 +3699,7 @@ "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", "brotkrueml/typo3-matomo-integration": "<1.3.2", "buddypress/buddypress": "<7.2.1", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "bugsnag/bugsnag-laravel": "<2.0.2", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", @@ -3709,6 +3709,7 @@ "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", + "cecil/cecil": "<7.47.1", "centreon/centreon": "<22.10.0.0-beta1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1", @@ -3719,8 +3720,8 @@ "codeigniter4/framework": "<4.3.5", "codeigniter4/shield": "<1.0.0.0-beta4", "codiad/codiad": "<=2.8.4", - "composer/composer": "<1.10.26|>=2,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<9.2", + "composer/composer": "<1.10.27|>=2,<2.2.22|>=2.3,<2.6.4", + "concrete5/concrete5": "<=9.2.1", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", @@ -3735,6 +3736,7 @@ "czproject/git-php": "<4.0.3", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", + "datatables/datatables": "<1.10.10", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", "dcat/laravel-admin": "<=2.1.3.0-beta", @@ -3751,9 +3753,9 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<17.0.1", + "dolibarr/dolibarr": "<18", "dompdf/dompdf": "<2.0.2|==2.0.2", - "drupal/core": ">=7,<7.96|>=8,<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", + "drupal/core": "<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", "drupal/drupal": ">=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "dweeves/magmi": "<=0.7.24", "ecodev/newsletter": "<=4", @@ -3780,7 +3782,7 @@ "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev", "ezsystems/ezplatform-user": ">=1,<1.0.1", "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.30", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.06,<=2019.03.5.1", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<4.1.1", @@ -3811,7 +3813,7 @@ "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", - "froala/wysiwyg-editor": "<3.2.7", + "froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.1", "froxlor/froxlor": "<2.1", "fuel/core": "<1.8.1", "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", @@ -3823,7 +3825,7 @@ "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", - "gleez/cms": "<=1.2", + "gleez/cms": "<=1.2|==2", "globalpayments/php-sdk": "<2", "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", @@ -3831,6 +3833,7 @@ "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", "grumpydictator/firefly-iii": "<6", + "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", @@ -3856,11 +3859,11 @@ "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", "impresscms/impresscms": "<=1.4.5", - "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.1", + "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.2", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<=4.2.1", + "intelliants/subrion": "<4.2.2", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", @@ -3868,12 +3871,13 @@ "james-heinrich/phpthumb": "<1.7.12", "jasig/phpcas": "<1.3.3", "jcbrand/converse.js": "<3.3.3", + "joomla/application": "<1.0.13", "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", "joomla/framework": ">=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", - "joomla/joomla-cms": "<3.9.12", + "joomla/joomla-cms": ">=2.5,<3.9.12", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", @@ -3885,7 +3889,7 @@ "kimai/kimai": "<1.1", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<1.4.2", + "knplabs/knp-snappy": "<=1.4.2", "kohana/core": "<3.3.3", "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", @@ -3945,6 +3949,7 @@ "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", + "neos/neos-ui": "<=8.3.3", "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", @@ -3964,9 +3969,9 @@ "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "open-web-analytics/open-web-analytics": "<1.7.4", - "opencart/opencart": "<=3.0.3.7", + "opencart/opencart": "<=3.0.3.7|>=4,<4.0.2.3-dev", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", + "openmage/magento-lts": "<=19.5|>=20,<=20.1", "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", "orchid/platform": ">=9,<9.4.4|>=14.0.0.0-alpha4,<14.5", "oro/commerce": ">=4.1,<5.0.6", @@ -4003,20 +4008,21 @@ "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<1.0.3", + "pimcore/admin-ui-classic-bundle": "<1.1.2", "pimcore/customer-management-framework-bundle": "<3.4.2", "pimcore/data-hub": "<1.2.4", + "pimcore/demo": "<10.3", "pimcore/perspective-editor": "<1.5.1", "pimcore/pimcore": "<10.6.8", "pixelfed/pixelfed": "<=0.11.4", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1", + "pocketmine/pocketmine-mp": "<=4.23|>=5,<5.3.1", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<=8.1", + "prestashop/prestashop": "<8.1.2", "prestashop/productcomments": "<5.0.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", @@ -4026,11 +4032,12 @@ "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pterodactyl/panel": "<1.7", - "ptheofan/yii2-statemachine": ">=2", + "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", "ptrofimov/beanstalk_console": "<1.7.14", "pusher/pusher-php-server": "<2.2.1", "pwweb/laravel-core": "<=0.3.6.0-beta", "pyrocms/pyrocms": "<=3.9.1", + "rainlab/blog-plugin": "<1.4.1", "rainlab/debugbar-plugin": "<3.1", "rainlab/user-plugin": "<=1.4.5", "rankmath/seo-by-rank-math": "<=1.0.95", @@ -4083,12 +4090,12 @@ "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", - "sjbr/sr-freecap": "<=2.5.2", + "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", "slub/slub-events": "<3.0.3", "smarty/smarty": "<3.1.48|>=4,<4.3.1", - "snipe/snipe-it": "<=6.0.14", + "snipe/snipe-it": "<=6.2.1", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", @@ -4101,7 +4108,6 @@ "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<2.1.62", "subhh/libconnect": "<7.0.8|>=8,<8.1", - "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", "sulu/sulu": "<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8|==2.4.0.0-RC1|>=2.5,<2.5.10", "sumocoders/framework-user-bundle": "<1.4", @@ -4142,6 +4148,7 @@ "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", "symfony/symfony": "<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", "symfony/translation": ">=2,<2.0.17", + "symfony/ux-autocomplete": "<2.11.2", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", @@ -4166,11 +4173,11 @@ "topthink/think": "<=6.1.1", "topthink/thinkphp": "<=3.2.3", "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", - "tribalsystems/zenario": "<=9.3.57595", + "tribalsystems/zenario": "<=9.4.59197", "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", @@ -4194,7 +4201,7 @@ "vrana/adminer": "<4.8.1", "waldhacker/hcaptcha": "<2.1.2", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<=2.6.2", + "wallabag/wallabag": "<2.6.7", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", @@ -4250,7 +4257,15 @@ "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendopenid": "<2.0.2", + "zendframework/zendrest": "<2.0.2", + "zendframework/zendservice-amazon": "<2.0.3", + "zendframework/zendservice-api": "<1", + "zendframework/zendservice-audioscrobbler": "<2.0.2", + "zendframework/zendservice-nirvanix": "<2.0.2", + "zendframework/zendservice-slideshare": "<2.0.2", + "zendframework/zendservice-technorati": "<2.0.2", + "zendframework/zendservice-windowsazure": "<2.0.2", "zendframework/zendxml": "<1.0.1", "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", @@ -8708,5 +8723,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 831c15205d7a5621bb5c23cc97e5d8d37097baeb Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 11 Oct 2023 11:16:51 +0200 Subject: [PATCH 081/240] chore(composer): updated various dependencies --- composer.json | 8 +- composer.lock | 560 +++++++++++++++++++++++++------------------------- 2 files changed, 288 insertions(+), 280 deletions(-) diff --git a/composer.json b/composer.json index ef2910f2647..4d32f40398c 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ "css-crush/css-crush": "~4.1.0", "doctrine/dbal": "~3.4.4", "eloquent/composer-config-reader": "~3.0.0", - "fakerphp/faker": "~1.20.0", + "fakerphp/faker": "~1.23.0", "fortawesome/font-awesome": "~5.14", - "guzzlehttp/guzzle": "~7.5.0", + "guzzlehttp/guzzle": "~7.8.0", "hackzilla/password-generator": "~1.6.0", "imagine/imagine": "~1.3.0", "laminas/laminas-mail": "~2.4", @@ -30,9 +30,9 @@ "matthiasmullie/minify": "~1.3.0", "michelf/php-markdown": "~2.0.0", "misd/linkify": "~1.1.2", - "monolog/monolog": "~2.8.0", + "monolog/monolog": "~2.9.1", "npm-asset/cropperjs": "~1.5.9", - "npm-asset/jquery": "~3.6.0", + "npm-asset/jquery": "~3.7.1", "npm-asset/jquery-cropper": "~1.0.0", "npm-asset/jquery-colorbox": "^1.6.4", "npm-asset/jquery-ui": "~1.13.1", diff --git a/composer.lock b/composer.lock index e34b14523d8..e0ebea1d6e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "500465d46e17639d0779629f6a37cc48", + "content-hash": "5aadba05c1914f91462b7d930c0821f2", "packages": [ { "name": "cakephp/core", - "version": "4.4.14", + "version": "4.4.17", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63" + "reference": "e3eb8a531ca023292608f585d5c37c1a2d478a53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", - "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", + "url": "https://api.github.com/repos/cakephp/core/zipball/e3eb8a531ca023292608f585d5c37c1a2d478a53", + "reference": "e3eb8a531ca023292608f585d5c37c1a2d478a53", "shasum": "" }, "require": { @@ -64,20 +64,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2023-05-16T13:58:50+00:00" + "time": "2023-08-17T11:42:28+00:00" }, { "name": "cakephp/database", - "version": "4.4.14", + "version": "4.4.17", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e" + "reference": "b1456297c9aaefca463a17d571426509fb2999d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/752e3dfa61be055bf9d360880f00ab4ccfea6d1e", - "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e", + "url": "https://api.github.com/repos/cakephp/database/zipball/b1456297c9aaefca463a17d571426509fb2999d0", + "reference": "b1456297c9aaefca463a17d571426509fb2999d0", "shasum": "" }, "require": { @@ -120,11 +120,11 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2023-04-28T21:24:39+00:00" + "time": "2023-08-04T04:23:09+00:00" }, { "name": "cakephp/datasource", - "version": "4.4.14", + "version": "4.4.17", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", @@ -182,7 +182,7 @@ }, { "name": "cakephp/utility", - "version": "4.4.14", + "version": "4.4.17", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", @@ -634,16 +634,16 @@ }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { @@ -675,9 +675,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2023-09-27T20:04:15+00:00" }, { "name": "doctrine/event-manager", @@ -773,16 +773,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.2", + "version": "v3.3.3", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "shasum": "" }, "require": { @@ -822,7 +822,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" }, "funding": [ { @@ -830,7 +830,7 @@ "type": "github" } ], - "time": "2022-09-10T18:51:20+00:00" + "time": "2023-08-10T19:36:49+00:00" }, { "name": "eloquent/composer-config-reader", @@ -950,20 +950,20 @@ }, { "name": "fakerphp/faker", - "version": "v1.20.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b" + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/37f751c67a5372d4e26353bd9384bc03744ec77b", - "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", + "php": "^7.4 || ^8.0", "psr/container": "^1.0 || ^2.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" }, @@ -974,7 +974,8 @@ "bamarni/composer-bin-plugin": "^1.4.1", "doctrine/persistence": "^1.3 || ^2.0", "ext-intl": "*", - "symfony/phpunit-bridge": "^4.4 || ^5.2" + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" }, "suggest": { "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", @@ -986,7 +987,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.20-dev" + "dev-main": "v1.21-dev" } }, "autoload": { @@ -1011,9 +1012,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.20.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" }, - "time": "2022-07-20T13:12:54+00:00" + "time": "2023-06-12T08:44:38+00:00" }, { "name": "fortawesome/font-awesome", @@ -1086,22 +1087,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.5.3", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "584d1f06b5caa07b0587f5054d551ed65460ce5d" + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/584d1f06b5caa07b0587f5054d551ed65460ce5d", - "reference": "584d1f06b5caa07b0587f5054d551ed65460ce5d", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -1112,7 +1113,8 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.1", "ext-curl": "*", - "php-http/client-integration-tests": "^3.0", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.29 || ^9.5.23", "psr/log": "^1.1 || ^2.0 || ^3.0" }, @@ -1191,7 +1193,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.5.3" + "source": "https://github.com/guzzle/guzzle/tree/7.8.0" }, "funding": [ { @@ -1207,33 +1209,37 @@ "type": "tidelift" } ], - "time": "2023-05-15T20:42:18+00:00" + "time": "2023-08-27T10:20:53+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.5.3", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" }, "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\Promise\\": "src/" } @@ -1270,7 +1276,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.3" + "source": "https://github.com/guzzle/promises/tree/2.0.1" }, "funding": [ { @@ -1286,20 +1292,20 @@ "type": "tidelift" } ], - "time": "2023-05-21T12:31:43+00:00" + "time": "2023-08-03T15:11:55+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.5.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", "shasum": "" }, "require": { @@ -1386,7 +1392,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "source": "https://github.com/guzzle/psr7/tree/2.6.1" }, "funding": [ { @@ -1402,7 +1408,7 @@ "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2023-08-27T10:13:57+00:00" }, { "name": "hackzilla/password-generator", @@ -1512,16 +1518,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.12", + "version": "v5.2.13", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", "shasum": "" }, "require": { @@ -1576,9 +1582,9 @@ ], "support": { "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" }, - "time": "2022-04-13T08:02:27+00:00" + "time": "2023-09-26T02:20:38+00:00" }, { "name": "laminas/laminas-loader", @@ -2010,16 +2016,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902", + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902", "shasum": "" }, "require": { @@ -2066,7 +2072,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-01-30T18:31:20+00:00" + "time": "2023-07-14T13:56:28+00:00" }, { "name": "league/flysystem", @@ -2205,26 +2211,26 @@ }, { "name": "league/mime-type-detection", - "version": "1.11.0", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/a6dfb1194a2946fcdc1f38219445234f65b35c96", + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96", "shasum": "" }, "require": { "ext-fileinfo": "*", - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", "phpstan/phpstan": "^0.12.68", - "phpunit/phpunit": "^8.5.8 || ^9.3" + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" }, "type": "library", "autoload": { @@ -2245,7 +2251,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.13.0" }, "funding": [ { @@ -2257,7 +2263,7 @@ "type": "tidelift" } ], - "time": "2022-04-17T13:12:02+00:00" + "time": "2023-08-05T12:09:49+00:00" }, { "name": "matthiasmullie/minify", @@ -2490,16 +2496,16 @@ }, { "name": "monolog/monolog", - "version": "2.8.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { @@ -2514,7 +2520,7 @@ "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", - "graylog2/gelf-php": "^1.4.2", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", "guzzlehttp/guzzle": "^7.4", "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", @@ -2576,7 +2582,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.8.0" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -2588,7 +2594,7 @@ "type": "tidelift" } ], - "time": "2022-07-24T11:55:47+00:00" + "time": "2023-02-06T13:44:46+00:00" }, { "name": "npm-asset/cropperjs", @@ -2604,10 +2610,10 @@ }, { "name": "npm-asset/jquery", - "version": "3.6.4", + "version": "3.7.1", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz" + "url": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz" }, "type": "npm-asset", "license": [ @@ -2867,16 +2873,16 @@ }, { "name": "php-di/invoker", - "version": "2.3.3", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786" + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", "shasum": "" }, "require": { @@ -2910,7 +2916,7 @@ ], "support": { "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3" + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" }, "funding": [ { @@ -2918,7 +2924,7 @@ "type": "github" } ], - "time": "2021-12-13T09:22:56+00:00" + "time": "2023-09-08T09:24:21+00:00" }, { "name": "php-di/php-di", @@ -3264,16 +3270,16 @@ }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -3310,9 +3316,9 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", @@ -3645,12 +3651,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "601b276d21df95e49f1802c7432b788cfaac15a8" + "reference": "138c8164ca26fdf365c2d3091040d78b0723735f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/601b276d21df95e49f1802c7432b788cfaac15a8", - "reference": "601b276d21df95e49f1802c7432b788cfaac15a8", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/138c8164ca26fdf365c2d3091040d78b0723735f", + "reference": "138c8164ca26fdf365c2d3091040d78b0723735f", "shasum": "" }, "conflict": { @@ -3982,7 +3988,7 @@ "openmage/magento-lts": "<=19.5|>=20,<=20.1", "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", "orchid/platform": ">=9,<9.4.4|>=14.0.0.0-alpha4,<14.5", - "oro/commerce": ">=4.1,<5.0.6", + "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", "oxid-esales/oxideshop-ce": "<4.5", @@ -4317,7 +4323,7 @@ "type": "tidelift" } ], - "time": "2023-06-14T05:04:21+00:00" + "time": "2023-10-10T22:04:32+00:00" }, { "name": "robmorgan/phinx", @@ -4460,16 +4466,16 @@ }, { "name": "symfony/config", - "version": "v5.4.21", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" + "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", + "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", "shasum": "" }, "require": { @@ -4519,7 +4525,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.21" + "source": "https://github.com/symfony/config/tree/v5.4.26" }, "funding": [ { @@ -4535,20 +4541,20 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2023-07-19T20:21:11+00:00" }, { "name": "symfony/console", - "version": "v5.4.24", + "version": "v5.4.28", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8" + "reference": "f4f71842f24c2023b91237c72a365306f3c58827" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", - "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", + "url": "https://api.github.com/repos/symfony/console/zipball/f4f71842f24c2023b91237c72a365306f3c58827", + "reference": "f4f71842f24c2023b91237c72a365306f3c58827", "shasum": "" }, "require": { @@ -4618,7 +4624,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.24" + "source": "https://github.com/symfony/console/tree/v5.4.28" }, "funding": [ { @@ -4634,20 +4640,20 @@ "type": "tidelift" } ], - "time": "2023-05-26T05:13:16+00:00" + "time": "2023-08-07T06:12:30+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.21", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d" + "reference": "0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/95f3c7468db1da8cc360b24fa2a26e7cefcb355d", - "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a", + "reference": "0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a", "shasum": "" }, "require": { @@ -4684,7 +4690,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.21" + "source": "https://github.com/symfony/css-selector/tree/v5.4.26" }, "funding": [ { @@ -4700,7 +4706,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2023-07-07T06:10:25+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4771,16 +4777,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.23", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5" + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", "shasum": "" }, "require": { @@ -4815,7 +4821,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.23" + "source": "https://github.com/symfony/filesystem/tree/v5.4.25" }, "funding": [ { @@ -4831,20 +4837,20 @@ "type": "tidelift" } ], - "time": "2023-03-02T11:38:35+00:00" + "time": "2023-05-31T13:04:02+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.24", + "version": "v5.4.28", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5" + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3c59f97f6249ce552a44f01b93bfcbd786a954f5", - "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/365992c83a836dfe635f1e903ccca43ee03d3dd2", + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2", "shasum": "" }, "require": { @@ -4891,7 +4897,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.24" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.28" }, "funding": [ { @@ -4907,20 +4913,20 @@ "type": "tidelift" } ], - "time": "2023-05-19T07:21:23+00:00" + "time": "2023-08-21T07:23:18+00:00" }, { "name": "symfony/mime", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" + "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "url": "https://api.github.com/repos/symfony/mime/zipball/2ea06dfeee20000a319d8407cea1d47533d5a9d2", + "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2", "shasum": "" }, "require": { @@ -4935,7 +4941,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<4.4", - "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + "symfony/serializer": "<5.4.26|>=6,<6.2.13|>=6.3,<6.3.2" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", @@ -4943,7 +4949,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/property-access": "^4.4|^5.1|^6.0", "symfony/property-info": "^4.4|^5.1|^6.0", - "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + "symfony/serializer": "^5.4.26|~6.2.13|^6.3.2" }, "type": "library", "autoload": { @@ -4975,7 +4981,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.23" + "source": "https://github.com/symfony/mime/tree/v5.4.26" }, "funding": [ { @@ -4991,20 +4997,20 @@ "type": "tidelift" } ], - "time": "2023-04-19T09:49:13+00:00" + "time": "2023-07-27T06:29:31+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -5019,7 +5025,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5057,7 +5063,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -5073,20 +5079,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" + "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { @@ -5098,7 +5104,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5138,7 +5144,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" }, "funding": [ { @@ -5154,20 +5160,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", "shasum": "" }, "require": { @@ -5181,7 +5187,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5225,7 +5231,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" }, "funding": [ { @@ -5241,20 +5247,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:30:37+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { @@ -5266,7 +5272,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5309,7 +5315,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" }, "funding": [ { @@ -5325,20 +5331,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -5353,7 +5359,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5392,7 +5398,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -5408,20 +5414,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", "shasum": "" }, "require": { @@ -5430,7 +5436,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5468,7 +5474,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" }, "funding": [ { @@ -5484,20 +5490,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { @@ -5506,7 +5512,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5547,7 +5553,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" }, "funding": [ { @@ -5563,20 +5569,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -5585,7 +5591,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5630,7 +5636,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { @@ -5646,20 +5652,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", "shasum": "" }, "require": { @@ -5668,7 +5674,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5709,7 +5715,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" }, "funding": [ { @@ -5725,20 +5731,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/routing", - "version": "v5.4.22", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d" + "reference": "853fc7df96befc468692de0a48831b38f04d2cb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d", + "url": "https://api.github.com/repos/symfony/routing/zipball/853fc7df96befc468692de0a48831b38f04d2cb2", + "reference": "853fc7df96befc468692de0a48831b38f04d2cb2", "shasum": "" }, "require": { @@ -5799,7 +5805,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.22" + "source": "https://github.com/symfony/routing/tree/v5.4.26" }, "funding": [ { @@ -5815,7 +5821,7 @@ "type": "tidelift" } ], - "time": "2023-03-14T14:59:20+00:00" + "time": "2023-07-24T13:28:37+00:00" }, { "name": "symfony/service-contracts", @@ -5902,16 +5908,16 @@ }, { "name": "symfony/string", - "version": "v5.4.22", + "version": "v5.4.29", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" + "reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "url": "https://api.github.com/repos/symfony/string/zipball/e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", + "reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", "shasum": "" }, "require": { @@ -5968,7 +5974,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.22" + "source": "https://github.com/symfony/string/tree/v5.4.29" }, "funding": [ { @@ -5984,20 +5990,20 @@ "type": "tidelift" } ], - "time": "2023-03-14T06:11:53+00:00" + "time": "2023-09-13T11:47:41+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.24", + "version": "v5.4.29", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3" + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/8e12706bf9c68a2da633f23bfdc15b4dce5970b3", - "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65", "shasum": "" }, "require": { @@ -6011,6 +6017,7 @@ "require-dev": { "ext-iconv": "*", "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", "symfony/process": "^4.4|^5.0|^6.0", "symfony/uid": "^5.1|^6.0", "twig/twig": "^2.13|^3.0.4" @@ -6056,7 +6063,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.24" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.29" }, "funding": [ { @@ -6072,7 +6079,7 @@ "type": "tidelift" } ], - "time": "2023-05-25T13:05:00+00:00" + "time": "2023-09-12T10:09:58+00:00" }, { "name": "vanilla/htmlawed", @@ -6502,28 +6509,28 @@ }, { "name": "jms/serializer", - "version": "3.25.0", + "version": "3.28.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "d1384d37926a32b38731c1d9fed6dc71ad630d8b" + "reference": "5a5a03a71a28a480189c5a0ca95893c19f1d120c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/d1384d37926a32b38731c1d9fed6dc71ad630d8b", - "reference": "d1384d37926a32b38731c1d9fed6dc71ad630d8b", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/5a5a03a71a28a480189c5a0ca95893c19f1d120c", + "reference": "5a5a03a71a28a480189c5a0ca95893c19f1d120c", "shasum": "" }, "require": { "doctrine/annotations": "^1.13 || ^2.0", "doctrine/instantiator": "^1.0.3 || ^2.0", - "doctrine/lexer": "^2", + "doctrine/lexer": "^2.0 || ^3.0", "jms/metadata": "^2.6", "php": "^7.2||^8.0", "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" }, "require-dev": { - "doctrine/coding-standard": "^8.1", + "doctrine/coding-standard": "^12.0", "doctrine/orm": "~2.1", "doctrine/persistence": "^1.3.3|^2.0|^3.0", "doctrine/phpcr-odm": "^1.3|^2.0", @@ -6586,7 +6593,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.25.0" + "source": "https://github.com/schmittjoh/serializer/tree/3.28.0" }, "funding": [ { @@ -6594,7 +6601,7 @@ "type": "github" } ], - "time": "2023-06-09T15:44:27+00:00" + "time": "2023-08-03T14:43:08+00:00" }, { "name": "myclabs/deep-copy", @@ -6657,16 +6664,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v4.17.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", "shasum": "" }, "require": { @@ -6707,9 +6714,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2023-08-13T19:53:39+00:00" }, { "name": "phar-io/manifest", @@ -6934,16 +6941,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" + "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", + "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", "shasum": "" }, "require": { @@ -6986,9 +6993,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3" }, - "time": "2023-05-30T18:13:47+00:00" + "time": "2023-08-12T11:01:26+00:00" }, { "name": "phpoption/phpoption", @@ -7067,16 +7074,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.22.0", + "version": "1.24.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c" + "reference": "bcad8d995980440892759db0c32acae7c8e79442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", - "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", + "reference": "bcad8d995980440892759db0c32acae7c8e79442", "shasum": "" }, "require": { @@ -7108,22 +7115,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.22.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2" }, - "time": "2023-06-01T12:35:21+00:00" + "time": "2023-09-26T12:28:12+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { @@ -7179,7 +7186,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -7187,7 +7195,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", @@ -7432,16 +7440,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.9", + "version": "9.6.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a9aceaf20a682aeacf28d582654a1670d8826778" + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9aceaf20a682aeacf28d582654a1670d8826778", - "reference": "a9aceaf20a682aeacf28d582654a1670d8826778", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", "shasum": "" }, "require": { @@ -7456,7 +7464,7 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-code-coverage": "^9.2.28", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -7515,7 +7523,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" }, "funding": [ { @@ -7531,7 +7539,7 @@ "type": "tidelift" } ], - "time": "2023-06-11T06:13:56+00:00" + "time": "2023-09-19T05:39:22+00:00" }, { "name": "scrutinizer/ocular", @@ -8084,16 +8092,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -8136,7 +8144,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -8144,7 +8152,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", @@ -8601,16 +8609,16 @@ }, { "name": "symfony/process", - "version": "v5.4.24", + "version": "v5.4.28", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64" + "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/e3c46cc5689c8782944274bb30702106ecbe3b64", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64", + "url": "https://api.github.com/repos/symfony/process/zipball/45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", + "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", "shasum": "" }, "require": { @@ -8643,7 +8651,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.24" + "source": "https://github.com/symfony/process/tree/v5.4.28" }, "funding": [ { @@ -8659,7 +8667,7 @@ "type": "tidelift" } ], - "time": "2023-05-17T11:26:05+00:00" + "time": "2023-08-07T10:36:04+00:00" }, { "name": "theseer/tokenizer", @@ -8731,5 +8739,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } From b17877975ee5550d7c29b236e2252dacda59d22e Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 11 Oct 2023 10:48:57 +0200 Subject: [PATCH 082/240] fix(views): prevent duplicate ids on widget layouts fixes #14428 --- .../views/default/theme_sandbox/modules/widgets.php | 2 +- views/default/elgg/widgets.js | 6 +----- views/default/page/layouts/widgets.php | 4 ++-- views/default/resources/widgets/add_panel.js | 4 ++-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php b/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php index b2ebcfee57d..1d9152c41fc 100644 --- a/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php +++ b/mod/theme_sandbox/views/default/theme_sandbox/modules/widgets.php @@ -49,7 +49,7 @@ function css_permissions_override() { for ($column_index = 1; $column_index <= $num_columns; $column_index++) { $column_widgets = $widgets[$column_index]; - echo "
    "; + echo "
    "; if (is_array($column_widgets) && count($column_widgets) > 0) { foreach ($column_widgets as $widget) { echo elgg_view_entity($widget); diff --git a/views/default/elgg/widgets.js b/views/default/elgg/widgets.js index b0771cd220e..5bc594fb8f8 100644 --- a/views/default/elgg/widgets.js +++ b/views/default/elgg/widgets.js @@ -13,15 +13,11 @@ define(['jquery', 'elgg/Ajax', 'elgg/lightbox', 'jquery-ui/widgets/sortable'], f var guidString = ui.item.attr('id'); guidString = guidString.substring(guidString.indexOf('elgg-widget-') + "elgg-widget-".length); - // elgg-widget-col- - var col = ui.item.parent().attr('id'); - col = col.substring(col.indexOf('elgg-widget-col-') + "elgg-widget-col-".length); - var ajax = new Ajax(false); ajax.action('widgets/move', { data: { widget_guid: guidString, - column: col, + column: ui.item.parent().data('widgetColumn'), position: ui.item.index() } }); diff --git a/views/default/page/layouts/widgets.php b/views/default/page/layouts/widgets.php index 960f4226a2c..da7fe428836 100644 --- a/views/default/page/layouts/widgets.php +++ b/views/default/page/layouts/widgets.php @@ -98,11 +98,11 @@ } $grid .= elgg_format_element('div', [ - 'id' => "elgg-widget-col-{$column_index}", 'class' => [ 'elgg-widgets', + "elgg-widget-col-{$column_index}", ], - + 'data-widget-column' => $column_index, ], $widgets_content); } diff --git a/views/default/resources/widgets/add_panel.js b/views/default/resources/widgets/add_panel.js index 1a650bc73c6..e9efc569a11 100644 --- a/views/default/resources/widgets/add_panel.js +++ b/views/default/resources/widgets/add_panel.js @@ -31,9 +31,9 @@ define(['jquery', 'elgg', 'elgg/Ajax'], function($, elgg, Ajax) { if (context && page_owner_guid) { // target the correct widget layout - selector = '.elgg-layout-widgets-' + context + '[data-page-owner-guid="' + page_owner_guid + '"] #elgg-widget-col-' + new_widget_column; + selector = '.elgg-layout-widgets-' + context + '[data-page-owner-guid="' + page_owner_guid + '"] .elgg-widget-col-' + new_widget_column; } else { - selector = '#elgg-widget-col-' + new_widget_column; + selector = '.elgg-widget-col-' + new_widget_column; } if (new_widget_position === 'top') { From 00a874f5b956bf4fb2a86608b3dd177ac5c633cb Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 11 Oct 2023 11:47:06 +0200 Subject: [PATCH 083/240] chore(composer): updated doctrine/dbal dependency --- composer.json | 2 +- composer.lock | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index 4d32f40398c..d197da5e91a 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "ckeditor/ckeditor": "~4.20.0", "composer/semver": "~3.4.0", "css-crush/css-crush": "~4.1.0", - "doctrine/dbal": "~3.4.4", + "doctrine/dbal": "~3.7.1", "eloquent/composer-config-reader": "~3.0.0", "fakerphp/faker": "~1.23.0", "fortawesome/font-awesome": "~5.14", diff --git a/composer.lock b/composer.lock index e0ebea1d6e9..15f60cded87 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5aadba05c1914f91462b7d930c0821f2", + "content-hash": "a4b82ac69a7d7c0676fd83075efb3c52", "packages": [ { "name": "cakephp/core", @@ -523,38 +523,40 @@ }, { "name": "doctrine/dbal", - "version": "3.4.6", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "3ce132f7c0b83d33b26ab6ed308e9e9260699bc4" + "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/3ce132f7c0b83d33b26ab6ed308e9e9260699bc4", - "reference": "3ce132f7c0b83d33b26ab6ed308e9e9260699bc4", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5b7bd66c9ff58c04c5474ab85edce442f8081cb2", + "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2", "shasum": "" }, "require": { "composer-runtime-api": "^2", "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1.0", + "doctrine/event-manager": "^1|^2", "php": "^7.4 || ^8.0", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { - "doctrine/coding-standard": "10.0.0", - "jetbrains/phpstorm-stubs": "2022.2", - "phpstan/phpstan": "1.8.10", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "9.5.25", - "psalm/plugin-phpunit": "0.17.0", - "squizlabs/php_codesniffer": "3.7.1", + "doctrine/coding-standard": "12.0.0", + "fig/log-test": "^1", + "jetbrains/phpstorm-stubs": "2023.1", + "phpstan/phpstan": "1.10.35", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "9.6.13", + "psalm/plugin-phpunit": "0.18.4", + "slevomat/coding-standard": "8.13.1", + "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^5.4|^6.0", "symfony/console": "^4.4|^5.4|^6.0", - "vimeo/psalm": "4.29.0" + "vimeo/psalm": "4.30.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -614,7 +616,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.4.6" + "source": "https://github.com/doctrine/dbal/tree/3.7.1" }, "funding": [ { @@ -630,7 +632,7 @@ "type": "tidelift" } ], - "time": "2022-10-21T14:38:43+00:00" + "time": "2023-10-06T05:06:20+00:00" }, { "name": "doctrine/deprecations", From cfd488361b7e2eb1783afcf7dd16f00127897c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 11 Oct 2023 12:04:37 +0200 Subject: [PATCH 084/240] fix(cache): report HTTP 410 Gone on stale cache urls Instead of 200 Ok fixes #14086 --- engine/classes/Elgg/Application/CacheHandler.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/classes/Elgg/Application/CacheHandler.php b/engine/classes/Elgg/Application/CacheHandler.php index e2c412cbb93..359247e4273 100644 --- a/engine/classes/Elgg/Application/CacheHandler.php +++ b/engine/classes/Elgg/Application/CacheHandler.php @@ -189,6 +189,9 @@ public function handleRequest(Request $request, Application $app) { $this->simplecache->cacheAsset($viewtype, $view, $content); } else { // if wrong timestamp, don't send HTTP cache + // also report that the resource has gone away + $response->setStatusCode(ELGG_HTTP_GONE); + $content = $this->getProcessedView($view, $viewtype); } From adc89d40e199dffc0d5eae73fa91148ca24a6377 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 11 Oct 2023 12:05:32 +0200 Subject: [PATCH 085/240] chore(composer): removed unused ckeditor dependency --- composer.json | 1 - composer.lock | 50 +------------------------------------------------- 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/composer.json b/composer.json index d197da5e91a..6db0cdcb7c2 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,6 @@ "ext-gd": "*", "ext-json": "*", "ext-xml": "*", - "ckeditor/ckeditor": "~4.20.0", "composer/semver": "~3.4.0", "css-crush/css-crush": "~4.1.0", "doctrine/dbal": "~3.7.1", diff --git a/composer.lock b/composer.lock index 15f60cded87..5aafc0a67f4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a4b82ac69a7d7c0676fd83075efb3c52", + "content-hash": "0ca2d707d8a1e6fde7a280f223fbff3f", "packages": [ { "name": "cakephp/core", @@ -239,54 +239,6 @@ }, "time": "2023-02-24T22:07:16+00:00" }, - { - "name": "ckeditor/ckeditor", - "version": "4.20.2", - "source": { - "type": "git", - "url": "https://github.com/ckeditor/ckeditor4-releases.git", - "reference": "8cc8f1b065f93d90c305c2609fec4e4215dd20ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ckeditor/ckeditor4-releases/zipball/8cc8f1b065f93d90c305c2609fec4e4215dd20ba", - "reference": "8cc8f1b065f93d90c305c2609fec4e4215dd20ba", - "shasum": "" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+", - "LGPL-2.1+", - "MPL-1.1+" - ], - "authors": [ - { - "name": "CKSource", - "homepage": "https://cksource.com" - } - ], - "description": "JavaScript WYSIWYG web text editor.", - "homepage": "https://ckeditor.com/ckeditor-4/", - "keywords": [ - "CKEditor", - "ckeditor4", - "editor", - "fckeditor", - "html", - "javascript", - "richtext", - "text", - "wysiwyg" - ], - "support": { - "forum": "https://stackoverflow.com/tags/ckeditor", - "issues": "https://github.com/ckeditor/ckeditor4/issues", - "source": "https://github.com/ckeditor/ckeditor4", - "wiki": "https://ckeditor.com/docs/ckeditor4/latest/" - }, - "time": "2023-02-15T12:55:37+00:00" - }, { "name": "composer/semver", "version": "3.4.0", From 2efe2935a1b2b6643878dd224807e365f4bc6cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 18 Oct 2023 11:20:44 +0200 Subject: [PATCH 086/240] chore(i18n): update translations --- docs/locale/fr/LC_MESSAGES/admin.mo | Bin 119976 -> 119976 bytes docs/locale/fr/LC_MESSAGES/admin.po | 2 +- docs/locale/fr/LC_MESSAGES/appendix.mo | Bin 496549 -> 496443 bytes docs/locale/fr/LC_MESSAGES/appendix.po | 30 +- docs/locale/fr/LC_MESSAGES/contribute.mo | Bin 112955 -> 112955 bytes docs/locale/fr/LC_MESSAGES/contribute.po | 2 +- docs/locale/fr/LC_MESSAGES/design.mo | Bin 80906 -> 80906 bytes docs/locale/fr/LC_MESSAGES/design.po | 2 +- docs/locale/fr/LC_MESSAGES/guides.mo | Bin 426205 -> 426205 bytes docs/locale/fr/LC_MESSAGES/guides.po | 2 +- docs/locale/fr/LC_MESSAGES/index.mo | Bin 8212 -> 8212 bytes docs/locale/fr/LC_MESSAGES/index.po | 2 +- docs/locale/fr/LC_MESSAGES/intro.mo | Bin 66554 -> 66554 bytes docs/locale/fr/LC_MESSAGES/intro.po | 2 +- docs/locale/fr/LC_MESSAGES/plugins.mo | Bin 31892 -> 31892 bytes docs/locale/fr/LC_MESSAGES/plugins.po | 2 +- docs/locale/fr/LC_MESSAGES/tutorials.mo | Bin 31619 -> 31619 bytes docs/locale/fr/LC_MESSAGES/tutorials.po | 2 +- docs/locale/pot/admin.pot | 60 +- docs/locale/pot/appendix.pot | 53 +- docs/locale/pot/contribute.pot | 103 +- docs/locale/pot/design.pot | 2 +- docs/locale/pot/guides.pot | 1493 +++++++++++----------- docs/locale/pot/index.pot | 2 +- docs/locale/pot/intro.pot | 8 +- docs/locale/pot/plugins.pot | 6 +- docs/locale/pot/tutorials.pot | 2 +- languages/cmn.php | 11 +- languages/de.php | 12 +- languages/es.php | 11 +- languages/fr.php | 19 +- languages/it.php | 12 +- languages/nl.php | 75 +- languages/zh_hans.php | 11 +- mod/blog/languages/nl.php | 1 + mod/developers/languages/de.php | 30 - mod/developers/languages/es.php | 25 - mod/developers/languages/fr.php | 30 - mod/developers/languages/nl.php | 33 +- mod/developers/languages/ru.php | 114 ++ mod/externalpages/languages/cs.php | 1 + mod/externalpages/languages/de.php | 1 + mod/externalpages/languages/el.php | 1 + mod/externalpages/languages/es.php | 1 + mod/externalpages/languages/fi.php | 1 + mod/externalpages/languages/fr.php | 1 + mod/externalpages/languages/gd.php | 1 + mod/externalpages/languages/gl.php | 1 + mod/externalpages/languages/it.php | 1 + mod/externalpages/languages/ja.php | 1 + mod/externalpages/languages/ko.php | 1 + mod/externalpages/languages/nl.php | 2 + mod/externalpages/languages/pl.php | 1 + mod/externalpages/languages/ro_ro.php | 1 + mod/externalpages/languages/ru.php | 1 + mod/externalpages/languages/sr.php | 1 + mod/externalpages/languages/sv.php | 1 + mod/friends_collections/languages/nl.php | 1 + mod/groups/languages/cs.php | 2 + mod/groups/languages/da.php | 2 + mod/groups/languages/de.php | 2 + mod/groups/languages/el.php | 2 + mod/groups/languages/es.php | 2 + mod/groups/languages/fi.php | 2 + mod/groups/languages/fr.php | 2 + mod/groups/languages/gl.php | 2 + mod/groups/languages/it.php | 2 + mod/groups/languages/ja.php | 2 + mod/groups/languages/nl.php | 4 + mod/groups/languages/pl.php | 2 + mod/groups/languages/ro_ro.php | 2 + mod/groups/languages/ru.php | 2 + mod/groups/languages/sr.php | 2 + mod/groups/languages/sv.php | 2 + mod/members/languages/nl.php | 1 + mod/pages/languages/nl.php | 1 + mod/profile/languages/nl.php | 1 + mod/search/languages/nl.php | 2 + 78 files changed, 1248 insertions(+), 969 deletions(-) create mode 100644 mod/developers/languages/ru.php diff --git a/docs/locale/fr/LC_MESSAGES/admin.mo b/docs/locale/fr/LC_MESSAGES/admin.mo index e6530546e6b72c268b9a1bf42ef9b5d4a00d0b0b..9cc04651dc32bfc008c31651ca32e0f4d934112d 100644 GIT binary patch delta 25 hcmZ3nl6}QW_6_X!xy*D8Efoxntqct}3*Mjp6##dB32guX delta 25 hcmZ3nl6}QW_6_X!xlDD94HXPctxU`|3*Mjp6##c`32*=a diff --git a/docs/locale/fr/LC_MESSAGES/admin.po b/docs/locale/fr/LC_MESSAGES/admin.po index cf808a61b23..5ae437e286e 100644 --- a/docs/locale/fr/LC_MESSAGES/admin.po +++ b/docs/locale/fr/LC_MESSAGES/admin.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/appendix.mo b/docs/locale/fr/LC_MESSAGES/appendix.mo index 1e44f831efbee8176b194ea4ccd195ef6584f068..a02d42d961edc63c369319a73136ffd0ed1e406e 100644 GIT binary patch delta 40181 zcmYJ+b(qxF+s5(C?949iu8X_7FYfME7Afvfq{!e7#R~aWD_5o4^FzAO)kJ|g4*zY9={RX{Z*4{Y|6i*Gj#GoM zH8#Q3mhSD0M~L}y?u`J3-SB?Bq$y{ zz{BFGgVcX}HXa^yoH1CBqp|qFA6St1+F{2Tfr+Vx7&sea;Udq~oti< zpYcmv!QB^QtRs%28efabiGM+t%|=vUFR+?Mc*m99xlh&*!r~NB*ZSL0)>XK5nvRHkDsu{ z8GG{TXDulkUMIF9ZL~+z?irM zmBedNHG2j1pwBS{2CmTlIx#I9%Ia*W8yCb17=^`fG#0@<*Z`klZLD6D+Zg9^#{vLA?C%$G+ zRt{AYjZj(M7E53c)aO=VFWilKu$?<}h)VSVDGsANj$U(CpMC>BO?u?4-`YiHBs3bjrnkp7q3S3mV-DK zPhxp&_rYp#1@m6NdpgfC7j6E;@wp3;)PA4aZD%3R>fFKgcs2tf?SX7OUWRBNdFf~@l z=cH$24m*b8HmraJWBc3%#aF1TKZ;7Sr&yS(eS?w2x#QY}YNKx47^~vA`xI5~>a&9GrHpL2%e9g6!LA93LlmP$>-F?x2VrmtL$^Qmov7C&soX-gH`Q8I#%X#_hVU{Ueo8U@6TXC;_S72?h2?S>IPF$L-z67*5>~p>ENWT<8!}1l&R};R&%@& zmSz7(RI-+)-7;gF`XQf_pN%o>(1C4u1TUeI=KBVgR9PEZ@?6Jq>~GwNZpa1aAP?=l zY-~+bqN&gQV(|wm`^z=6ZaBts24>fFF%}*Rv7xd2JSM}tsImT&XN=|+C-O{#PdJ_x zmEFl&_}poF3hHwUym%$*3AduM{x8gcwOjh!6;Utb7EWjs8`$1O%&{6vtt_ki?||wjcL33 zoB%a64^QHvZa$|d`@8h85pfBoBtC#C@Go@N|IgXT&5js7t?G*)WpXN_M!I#qe2%*5 zx!ykKGe-CEx$gm@`&z-aVIuY)MfHZium?WE!`QN)4dvhiR}2cEE9{T=@@6<4aUB78q!=UMW;}9*I$S5U-$b z5dB}>@83a|d8_oX#M%w zB+L5vlkJ9CQ3Wl9TCg1S_J2ZMC-D?3aC%gnA9bVB7$2)+a%^sK$mzp|o@68{E9at; zXbtLvcf9>CFoHOIsx?tOTuYn-BPsCj$f)hSnr1_B)#>IF^M#O}nY=h+iZz%PjBqpJ2T{*4jynVj$j7QwXN z*__c3)kL#!BvxKP4Re3z7#nx-Hs!*i3;M0kfm3z9g!~8(>HyS|>KtJ%*z`IK^`zsyD1hjqS%!O>`TR;#<^( z<1Mj~EfSUGB~jO{gSyd|sDgftI)5GNKKqtX|2p9`J5+!hs3GzxYT*!TsZB1MQ3KKo zEQTqT*^|`6M#P=57Vbk`IM#A2NGjCz^P;X>5tT!&J-=KYva0UEj!qmHiYmx0RGU6W zjcmRZ_C&EzH^|^w05!&!#}YUQm*S5&85^y%f?dNV#Cd-3IXQ6*PQ^_jHW=2OGOO%{ z8&{kAP~GPgs>GMP{nzjs@e?eLXV+Mb#9V8WR(V{^{$W@J)2_27>wrCp2VxxVcL#qW z4!u}!)90!U_N3W1+R7zAYK;F1RrND*5$-_MRO3ySbo)>Ry@KQLKC0<@Z?-2)w#DZh zAYOravBQs+1GDh8=Kqy!oaey8pX>`pFZ$kOO1K~Uv%ki6n?4U1-byQQ<-)YI)1`7}mL)E}0OsDyO?=G^F9hXrTh_lDKQEJcZs0Bk2T#8Ys zS@8xc7v5tS#@=g579Uk3IXsJ?#)0yvIbtAc>Gl9?lYdV1KI_*T_gfWRM9tgb2Yl}9 z_YNrS<2EUjWo}i{48z3i{{_zyU;5Q@Va-XO`#Sz8c4dF{Q&y#0u?OehL4B^#Z#Fk{ zK4ZD^0}kW-cxQbMY2i%4mc(Vw)Blx)^UvGY>e?4<5*qb87v{tds0ByfKkX}2Gn~!- z$csK_A^W#ovh{s~zpQEAV`KI&`rGGx#1~i&pIx>B6!^#7gzA2Iu2BCvVb2w-n)j#$ zLgA}6j}O9$#0mek?}7_Z*`4?r-I9Xr!iL0$u3Hi(y&IsbBZ>(xB;n&0+-`dyr>ln>>W8c}pbLW5VI1qBa zdv6z5k6-eE+aK&rMa_>^)xEG8`;&g6zjA?|*qeCjXX}Qa@E~z=$M4qUCEP-s+UIvi z%F{TIc%$F%{;(=*nBV=DybLpF{$COByZ!NK(C@ypEgkN6Yvdfx;)8i3{7z$Td>C^P zr-68POODAREX`|sgK z?(a-Y=y$&s7f?!^3q*DPu5zog)I4_me%p(jnWyf!+{q9O8YZ@!*Sd3=>b5wFQOzU@t=sUQC zcvm{VJMgqf?|0XN`%z6&G1Bi2#amI+bTEV8T~n697Q{R78%&hZ@4h8lmeC(_2b2fw z7|nqmnf&fT;~8qGjGx)>E*M6krs3JBp?DE8s5z@q153}W*7grk{XZYyXlvkDRPQ;9 z>ek7#`<+N^i92v;_K@GH?x(-!ur?f?%aUbiZodQY7h z?w8O`sQy3O^MvOo%*p;j#mI8}0ux|&FCK>B)YxQHQ_U>yci(_4!0E)-Fa!1};dkGP z%|fQ*kkh)PJ=r(djuRfCZd9+76>JEq%2%NZmbSFteZknkvk#VL|8&&x(>MhEWvq&a zV?N?js3qD5)U;i+tZIh-SA~s)?C6L(aS&?#zS`S=6Ey(6!ZKK=98Zc)n@dF+#&jG4(Uj@JW66#4sE6~77e&+$l ze?(>PqRM{vjc4O3e)r93f~tOgqRA^7{LJwa)vR}%Aj8%Ds@Cwkzp$_jw-fiQN&nXf zm8F*7{T`pVw%_@acn}`Ix^?{SN+*6@OTz4^Co6*WusWv2?=TPUMAgI{jE!;X`Q4Y! zDLhMKRrW_?16*B?{;yT+dv@H$!u1)^c!E?7tnG(3BsYjxV-pN-?05EZUh5`)_oa2J zrgnpUxR3qUaXBt-W=&eLIZ4Rp8lzj#7H-lxJFzI|J!lc~yKA!yE&a|5b~MFVShJPi zeS`5Y>Vx+&8%DJDyFV?@hYN@cV+TBo`LW0se)pwRM{Gp=49j4ZHkRaLPzAh!%CT{w zXuq?H5*|V=p}MrQ0qA0Tzx&#)ZU?^;kNrPme?0%C4YgG}(bimGCkF5`uEJ|L11EI0 zUX!Ye4aL(@i`L_q9q*6D-rL+ zg7^_@WB%@z?ZZ(c;X%~G<^pEG$R6$_6>=)Dp`>ets;WXgZ4B>&%8g^Fs&#rjzQt0w8?)&Cui03SX}+>2 zIf0tR!Uy=>#bqm06>rAe_zJZu&N$GzTP;-F7gORw9E{sh1<60iZd?b|_I)rj&cIM1 zo#-8Sfa!>14K{OlRzuAZolrNJg}>tltcjz(wwn44m1Os^4*G{!0qUc!+Y6iGG+c^z zhS2|2wG)O~e?E^ISiTzOcbC~mQ6KC++-^J>b$lgO#@DE%D@`|64)j9R=z7!ulY4|E za|o3y3sLKVhp1#MG?Ek5#v?}h-Jkg^z)ZxCFcK4vvYaT0%Gye(8t8~waRh#et5C@n zceITY<*+?*CsaJ5V|E(TgjLw}r?A)ba081rOa~Lr+p;f?cQ&_9p%o)oo%-v=5X= zW&e0o$q#tGM>RpQNtXRxQ8ly}ljAPWbC{I)K7N6pk){nfUre^{GYplCTT#h&4~t-u zDP|39PCNotkiSt+oM@_<2bFx)umrY6O-c(eHJ-qhcpH_3<)>*NBU|RPp$pzXC0nX* z>ek&ceZ77T~xdf`{GqBiS_6B-B&hKPy^6Q zRPRVWm)_EXjjn7o!y_1l>Atm^XoD4rhogq(!`KR)d3J%;sNZ^iR|=I=El|lh>pS|tM!HMvP}}5PU{yH@Rb}UK3RYZbU$xGnYM|~STPrR?^?T=g zYtu5=hj0$|!idE-5)Q$;&I?8fs^N%0bOAm=Kx zKdONHQEirZwOz0yswTFhnk2Bs29~y%iFhd{#v|Ai|3aN#V6ER7>!;sgS>jM|gPm9j zbFiZsYSI{mYMLde{`?v>geKT%-6|T@&8DH+^f<;w-zGahF6JlBhNZ9>>Uy(LBj5w% zdLbw0X3OTUJrAN@!-a3Lk|#ygKo3+~A4aw1XH-%S{LyM^8)|X+8P$YUf3n$fHV!8~ zgxVjq)n?VHSV#T;IvaYD{M+oCN>@}izef$hUAFt(pMr12HpC5gSXKUni->(YtqB*S zvj2amCW+ofRpUM!h81`FojrI6yWp@r1E zgVev+x7;zPC%KGDrshYiAgfRVSkj}`E861M#7D3jMjf*PtjBi5agJM!^*T=fSDXCG zj!u~Tgtc`DTND3|^|0WtmVBcz8Sw>FKYxJH*y^NpuYK5rIQ}VXs`#s#}>dsJ`Q5Mo1F`_bD``FA@o2b;71HtI&@{;&d0!iL0;QBP9gPrKm~ z)CGeV?YzdQn%L#V2`<@p#Qvy(DAr##o`hPlp(oyidcugmtxB7q`s)r<0pnh_Cuxkj z@K)3l#{S2uavRSH&lSso?@n~k=!2^2%c%ZZ;hNp} z5bDWdUbp0Ij=JDB)P-W+u%WjLD%&@plJN~{#H@JJ9&j#>CVq@c&c3&_Aff*~Vj~?p z!fxA>WklUzu;*#~f;ht+Yr_#3O?(+ufYNtuHd}~VCtOF3n91(h{`{!%)kFvAJUv zDwmGncbMd>VRc&66ymd zuoK?KDp>oCP200kx$rCMMmgVF(pE=3z9GuPNz~^CVOpGl%KlBLO6GK*trv7e6?h%?#^*>AhFC_0 zxzpqtY|nvwzA$Gb&cdFU)F0*+a182#e_%6A8y4oS3kINu)|03kWDVGPJy12Z4V9c> zK|8N5<|AHnmJCMx4qQq}dH_jU;%pD(Upxd1>G5cSjX4{CkVeSCd2t#VaZEWbmZ&8y&&3IvM z+b%+_)34ze%o5*fXf5hVZ=l-Jmmti2vCtRC63;|EX^MpQ`J$-qIt2CPhfw!@lQ1mg zjz}dF*@b(c+IA%>89$+Jlp=AM`%R`8>Ph>enqm#=Mu)LAUPI+T*(BDaW3dqNS=@(# zq;{Rd*pm2T(omTD3y95=g}J|Oa~`$WY?<7WXEUnGKB3yYW{NQPJzz)F_%IFiWLr@K z(Em^cubKV&j53X5m!b;tAC|=m>8)l*qLO?UR>VMLm^-V6s zsu`?6^H5cN8CBw!s3eP@G0a_{HKd=R^$!aAJWU~S{LY?;m7Qp{d-7al*>-QzG6!ADL zjfYV+^BIe&|Ch~S7Z`wLIIstmrSC8!=F4f>-2jzbeNk1o3)N&FQB@n2%Z^V*)xddF zE~UvG=6>VpgN=!|U{Z|8L$_D|Ps@f%-T-ysF{tc3jzckXUQ3>(sH(h+s>-N*cB59P zC;S16;SJP{Q{@kHUs&`)CFOYRfJ;$L6<&b;-<*x6Y;?yh*o)*!SI`EQX@xAyU!vMR zRbflUBB(YWj;i`|_=wLXD`Ih=m>sWuC$_}mZ?&1zC zRwB$@$vnX?iNj0UNY)(_5Klur(PC7S>_Sb;PARLo&Zutp3uePOrL7wmMm6b3RKZu2 zrvGaIx$m72QN~VagcI365H$e#%G&-&R25f5<;W0k{}voU{5z^3jmw3(uj%%oa->02 zn7bmHgBrkYVHZptDsPj+SRBue16UHPRq* zJ(rH(@n2Mu zWT5h%!=1gH51X$+B`RwBW{Q4Udu2FA7Bd1)yS&85*8$mMm6CqFMf!coYFV8CLYk3 z{;#T?#*P8_5H+y0ZxZJI7=1gcd!9rk-F-}h>6_X#S{l_PKVp5ngBoy(H?tZViK@xV zs4pamnuob>PTFE(;xoox8Q2-z&sM5_U{Nb+g5&e!c-UM!&_WSp5q-?;@(I zAEIs;Y-2-oB&v5*LFL9WFaCfdh?_-QQ~ibNeyQ4qxxbDVie^Jk{tfED9n_GTyIq(Q zjr~wH@H;9wA7WF?+ulaTaj2?Yi5kLRqH3U02W!f?*qQh~s;L`%Y29!$@&F;{C>yak za2=Jsk5EnQ2=OHBf#E%^yY)v^?N-zi26|al7D2arp~m)ysH`s0 z+q!LSRMYiEO=6Q!HMIuaWX4c8c3faXPf)IptpmnkB=HN>WRaw=&3?^L-D?PHTK)x< z)j9jw$Tt-8@I5l6XOX`hQY3wt6T2>UrHe@hvvwc!IC2Dm$Q_ zus^EmCtxdFggNnlSO&8Uu%>8_Er`EE4Op*G-Mh>{d$5)RL)Og}v!fsfo}!v0(;ypY zmSZ8}gBXP`J&O#s^9P`Y(luBKFJLcB@wN4W37C)gZ`6av8e&f#iH(R$gxJtfI}O$E zx1rkF8EW78>Y;|FrXN#1mzl5#6{z>K5p#^X^1*^K=5rgI7760aW< z=Dz9JjhY3I;bcrWmL}o6MR-L0|LwRi_s?qVA8)f(_X#$(uR?XFv=eQpZGr(t$H z;l(2ydSmy4^-1+nr1mQ1l2uHp?X)AZ)}|Dj{4ki%&BCX!$uZ7h+1OZ z@qB|yo*2{ZiHoDMye%s0r=Z6C`>5oqJj0r(B`Rr8U`+gos=0`n-giROI5HC5`Ts{Y zG-m&fYWu9Stc2rGNx2A>l=rY77N2bc$a+*09l);m8k=C-IX3(4M0K~+b8TcTfvVvJ zr~zx!T>8I;+7Ikd73TWZZa5h05&wc3f|Jg(DlCBNW`j`s_n`))zfip><9u7~R>%It z-LN5ELp@;O@9f6oFpBuXcVxekCCLJN!eUsQc)aI9)Ee*|YQ8VJ(AvH?ssMAaJZ`~K z_yRRBm8{6y*)u2&ylF(%TY=55;c^@UThc2 z)~k!E(JrV0&O;5!TTw&q8Ps*|dHX}3*@$FEswH;gQkb5&HR?vgurki^_FqOl z;d|7RBv@)smKDnpx5Fr0hMGHWqRz{<%nDcrm5fc1f`y!!Y$&-lU>y8t2lzJ}wkXYl z>fhB-PdETIf=x$t+n=#B#$I9eM-8o4P;144D=k^;qQ--EsDk!E_uv0*@eVw}C=Pr= zyYM2+M7$eSkgHe*v#z!guLG*eH==6d7-|}hy~et6PRtr& zM`JdW)k9Gu)FD(idWUMudTT8SL#Xbv7d6D5MK#4$Y>zKcpKrR(vi=*?P<<11y=v=i z7F~=9h&N$K{qvx=<0@)l@B~#-{|1Ii#_9~HS#JDBn-jL6j=#i0n0S+YF{z3fhzFy3 z%>vZQ=Mt)>ZlMYsW3$~S?PmJF`elB0)WK1xvH2WEVX-Zi8-q|abQ}j^+#l`h^Em8J z{1mg{mp@t6PenD!MbzY#eyhdfP&xJ+s$iG5hO8>@dIw&ihGPFV8#=S2K2Q+V|I48Y zG8q5H{iv#(zulT)ohs^_5k%Tg7`#;jUXH6P)~jlGg0MbcG^(e zc9-4Y4~)g}I~X6Ip_;(A+mbF4)jPgGCEXy@jc1@n)_bVjDZ0nzfEu2miEL<+IF2ge zd5nR#u>d|sl{9j%9nX%sP$_f=9MlcFc>718YHTiQ{8)}^nmwo-y6G8rpW6#UPBAug zVml1SukkA!i7MC|)EMvEZ(k^C;2z>d7>&&jSX=JKBE&~g*ZY7fXp)0AH)O|T#C1^x z>4@(8|LJV#276I$7CdDAJ2mRW;;13G9p=HGFc)6;j>kQ015`28T+#tG8I4C}{YF$y zo%iCms1Y{J&y0ZT|E1Z;iA_=6XO!m(RQEiJ>NdAfH-3le|5<*q8x%s-TvHr@U!a=s zUo4CFP)VBYh}BeaY)g(+LihdO4@a%aoMTo+DX!h9c8V7P-kyG@44Imp%*(`M(=MjIvBw?N|DN9gcZnEOv8dj4Zi_6arcgk7;osSK)y24GE$f7NESme`57E2^!}qmub1 zszC3sEyn!Uru%NFTnkNMqXioqQ3FcMYjz+zDz1T%*ag)aCSg9@iW;(S;aV(oJ5ewf6w3n;@~|SVvpe0 z#7pjzy(CrY2Vw4Sw`cp$CYfvxDG)d4fCD)``>_p3ah`^`zqXSFH7);wqtX8?%>4^% zVB=7aqRrx$7jP5IG=@C=^0rK+kJ8@h1?jKmpu34g>1IQdhU`;X0&eD+?! zU_}8_SXysoT?P`F@{w2MI!?4 zkUJEW&CgLMri>AA|6#&j)R?|9X231rkN79?1yuK28!O;`5!r-sxNz*)0jCV6h!b!J zq9$?e^KDSM)*Wl(vABVd`%5HA;|1J*!7vgFb0B&Afcp)n7HXthgLQESR_4MH2?Fj= zTsvXF{Y~c~n4aUWFast{6mSQoVyFSDF&4#9I0tv(w^%oE$VzrMvEA?`X68WsBmsBU z8i1NazDKp;kEo$|H+G{SXS}#nvVc>JxE@a8_=MyEcf3fP!mghWwHPgpx?XeC5Zxoh zhMsr;s-LdIcDM)EVY-w7cOL&0l`9!i1>CREOHtEqp49flRZs=&j9P&7#vqQuFbXyS zixW>tLk;2)RPKagr?slefJ(x0r~zaeR>Z}a32&lmCL&$HorH3uo}?M-hTSn94#$=_ z70cp%tcBUr2izABUtv??d&uWQPE@2-bt7!dfuWcM&tnCAi&~hJ%3x1i2Q}$*LKSQ* zs=#YdRlFNjpo^#)y^s3*JB-9Q87+76p!@s(E!ohCgHcZ~5gXw=)CV8oWOOoF)=ohc z>~GZZw3!3$KdH)(1&Pn1vOFw{Rs9#JByN{A;C_4Vjn#>7VL`QN-fRJPz-WuXFosrq z#QxnmtvjvGWjU}dH#J3D#>o?K7aE20TFo`Za6fg4UHII%`~mmN=2O%(ox1={#^;)1 zYvR!b1MZ*SxQ?L;eDFY_fcuBR{6z!KPEP!Yg>ZXuvKb$g2snrN;8&#r?mxRNUfO!W zAE+mLfJ&yfs2Yh^#*Sye^29|^$u|f!j%>l?xW5ejUn`nF*^vSLWvw@4#v#PbQQhqi zRFyx#>zJn;BOS(%qUk7LPE=NxEFW-I;0RO_W~mTxXUUP+p7=B>M+#I7xL-o+R15{& zF9H+Up(mJwnnu^5Zk)JMz@6u_qjIAHs!Ho)9vtc&UyIp@e?dLjL)3YJ$^j<|^Pxu8 z-WUtN#SOSD#D=oIUKJa|f52hHN03x-Dps|&u8JCRyQ2Da`DzwdMfHMo)vf9)psKhr zsu#3F4K)4n1P(*hK-C)d;Gqs|RAfhQ)O)$DI2z;E3b=ozYF2GVI*#Y8L-MeHE~+3e z>sq#-tQT;9ruzv$uzyH>8^8uN2)JKpE@M9Smv3k_(+9sKo{03ikn@BMmH0C%nc_6E zs!oN9b9ff>tnAs)v#n<@&taaEJ?DF_^4#Y6vn&1Y92>2;(Z8s+FWs1dfhS#oHHZ&4 zu}LRx(}4R0qG2;DU{}xxp5L^#2wff|Hi+tVtcEJv>j{? zDT7nkKLrP1$}er?n~qBEK*xYHh#DT%k^ZkC^L-~9!}E5wf|SEA*xwc>;z88(TBA$A zxkWsxYruWY-l-c^?PsjVMeNVt(*~N~a2jz$uYmif*XCjdKL17UfYTF4^a;3sPv}Ws z`u_wju(4mj{X$V}fDN@T@h2`&b6~(-j(^6v#NP}GIQ+wRC+pyVyKGNAB;fqa{{LZb z+&?tnw8ebGtl%?H16k_f?B{deVo7|*eOF=O&`A0r1^8zaC1%IHF#-1vjt(3baAFcy z9v^W3?RMP>OqaxUCfW$sZc@Pg8xRqbt)MTlFE?5}h3=~xPBjXfY??{*jvB@ec9cxwg1m{w>og572U+ zjc`N1qsF+-a#U^VmzoDE@?c;s>}IfB7-s zyultn1)SyhpQlJ0=ZP6ga|LD^4xO@W!%{|x72(%-BqH(>+fU8wm!&KVmy zGh!4F8DLu)$3mm=<6p1-Xs7VEAo&fI7I2xFc$MO?1bS zwIseHZi5ljZ1cM|)VIAK;OB_+|8x(mimRe#yS`WfccO0a9^+!g|E$gHqq^M+YyC*hTYm#za){cFaP2;=SGI32K0f_rYe% zTv(I%$p`wss;bmSYx72^l0~DQIE1>xOA@ z5Juo!%!uFP2|VxqNz>$*3X zoAWay3A){`j^|L+eL`#5&)} z@4Vx&lLg(iWlq%GQVaFD_Q-Yl`!8&0h@9sg*onH)Mb8(g0VIC%pqmqwQ3Z;|3^)K) zfO)94UW5POG1OeKB1O>sx*acN(0#$t3^k;$!olkQC)v=XQ8`u6?bnMiCGn3~98X~` z45s$l8kI~HP{~&VHFvZ}jRW^l1$l#-rjw?z8%CneuY?*uT4Nja|GsRL$Md)clcWv0 zlg(LdN!&GE(EX{`QB?OVmpIMy&rn15^z1?R zd%;3fHw)$nx+|mXs0V9<9WZsyp!?c?M9yHy{oq!1e8Yi*_yFtW3c7DVO63l^FBEg+ z3A$e*i{`Z|?1*|79KxhHIbYCyN4zvY4?vuzK+yg5+s6fi?(d3>E<`Wky6Z6#@8g#k zt8ggjz8L6T*plvdoWOyns3#g+#GYgI=#-ZA@UthcOe&|Uv8EEjZc5Z8$!DfwK1^2&Z{uylo>`~7`8reNeMRMEOit;#|7 zcRJ>x{`!@#O3?k%*|ciV{R1N_urK?IRkaD=bl;+l#Bp4|(w9M}x%&Ufj*MjN$kNF!T(z?$-8Iy-9M&c11UP;J&lBJ6YB{mH zThLu0y~Jkhuio97Xc@jBeu7Q#W)I7Ol0Ad&qV*vvH_G**|7%%XqBnB@H@J$Mh-3F9 zYl-*ZRXo)%=)U1x_Z3Y;Tyucs$hd)wV4QyzTVeh|HYrWTZ;21$HO_A~IOzTvo)Sas zy2FPC-9N$l%`p1EvUuz8pu1krJR<0R;W&tMxWHEMq;ZQ3YpCwj2C~TJ3I_ zV%dIps@Z57Pssi|*b!4sx3(QI!ye!hs(XGnGw3eiV$BM=KWbTz>ZUJe2OU32oN-Rj z`Gq)3=v#(ZF7yB^W1{&?BAn3dJ1aoPg?57>i)_Sthx%Zf?`?sSd9fAvDduGVFH3^% z+VBbLRqnE-LHB1#Etk^-951{g=zj4Sj4Eho%1Wz}4|s?VjQGK()e5U^EboAN8+IDi zZ~t3k7wEh;=)TP!vd#vQCpeblUDi`G_yjj%lMS}832qF!ORm_Pg6=DwKX9Su|2CV0 z?q9$8fZh4Pnk|;y$$qr%Ru45&UB)%o_$QmkKjR|eI$Le-c!=4Fhi15bz zOR$s&>_M6w47zVh!w%Vq*Y+?4rUswlUOrdu7wdi>aJBmX>myde#Yb)7u?|)8BdB@% z3TjSxf>Z1l#P zs9w7)$6eo@m3Yz8Z`kuj(EciR%bP*> z7lj+$qQ7%OqTBY3XULtP`xA=8cZ2Rb+}`(S8jjz^CtUE&eY%t42Tb3@ul}>+^B)G? z_XcYo1>Ns_D<50(9>&C+cLsanP0XnN-{6UjOkbhecsC}+J6H%mplT-nQ>&5As0;jx zs`3)g=#~^@Ag;z;&x7u3_jWH?fDq3{{x~ZCgxgj?{omTUq3JsPm7o7;nHL=eZ?lxsH z+)Z2>`>GqgVM7<{>JN8Exb3L+7TAeaMdV>c|0yAp-- z|9@fQIXl#yN+b?ZQzjWHF@#yYqORg<4kFSAOewi+7~VxuHGPGD6Gq_GRv^6ZLAo(V{I zarUEf<2tG-N~R5W*M!li{e{wnJJC1=Ti_$qBDPw3as_9hM!g6za*pMD1UW8n}M;yy5A~818oKNK}*6Lj7^ej!1z+&b&-k zRnIU5C&bAd?k*~`pb9V+b>ZdsB_77Tm_3U<;cZlRippxo-{U^ww%P1+>9gC7%c6$# zX4n8vV?p)*$Q;%t4N*C;5L;uWoR-ZaQ3KBRsBRiJSGfC4r#Y&P*I_?AimKX@xx<}E z?10Mtv6unB#ay@xHTm4ej@+N0=Tjxv54D0>iJFdoLtUU;-f;IzWPMbxXot$?)mRiC zcxK3Fxzr4m3$w5(K13C)QvPuFWp_{1q?ND${a;B?lnp&eE7TJXMBV6TRPw|u814?q zjZkq{?26k^PZC+klBp_AB<_L5@eS%a`3qaF3_ulptLN*&^nZ1i;zh#U-+~#4N|N=c z0pzIXRn(mD8V6vUqSm&fQQc}8mcV~eRh+U|xVs>!>^TzqvVR{cY4aDi2ku!sWE&IN zq2ybET3GBu4M@HcHo_G~t(59vH#~@1H{>p97aWaB(nF{xyoM@R#!}XO+n^q34wl3X zsQcXuvC)_fUunBhQ&dy*Lw$3Zh70fk>cZp7*aeQGsy3`_xci$?)v+A$d{lP-g?fn#mv}2`ArgqPIMj>{6<{@1!B034E0?z$?ZdB#-=fBWo)yB~g~<%;O#A{nVylWa z(*2C8iA0sGmlQx1Y&5pTpHWGfrLucGyfmIkqd>3`W>{YF*t73KH zvDgC7U^M2eW)CtM)z;T>8aApP?u@{jsG8|e!|t;K%d7vVuW3)v7L{DbQ3FM}TH)@G z$+zNA;zG48-i%)p=c^O$zB^irU5Mk=wb^YDYWz5g!!dI`Yr5rFjQBQc4oO>|f~fz0 z!-m@G4GzLm4QxQ#ifXfusAQ|%(4KS!s+$HI*^|^qeSR0Jia+8P*ru^1>wZ+6vxzY#gINwv8g4~O3Xz3A8M@@znM1@qCPMZ~JmmK@QV{$G$C2iOrCpQAqT2~|}ozOWpqhq~Yl)I#GSMq`0CmP|8I zN%#QcVf|?9J<-^lcrTX3WNpLU*YNeREb(7$Lspe3+F4R{Ky|B)s3G|!j=`+$Et}V2 zGvbe^Zq%fMU1%+CC%%u$p(S71f+cy!aQBUBXH-p>>|{;45WgpW7-FLp8n8V59 zc&KMDJMk}U&yHHXZMNHtO0x8QtmNHLaPQC0U4JLtSYR%1V*mR1P{TlZ^& z>Ln+z4Mu)#Njn1T6JNk&m}Q7f*QK$YinN&xwPoU=R?<$W5%C~uI!-n$+t`UQYdj8X*&muv{37s<~fLU*!snq^4CR!`aYcj`AEU!1g;x#yzIQ~SdsUJ}N`G2SN{ zh$>KynRdPLs3yEJlQvR+FE`7ob}T9x&!L_${cL-}{y3KSH`H9vXpSvN&S5&@yQmrq zpKCX0!P2TLt*Epd@WHgt!su@S|Nm#FSh@FkiLasB`Z;Pg`;6)pCD&U)zrzH?&IU6f zstGe<87zgGYX+kV@F#|n>V%C}^5R&5xFPC;b5TvQ2{j9z#+2A#lT~SVRNL=C?T@$F z;_O(9cnGSdj${!JPRn?zZ7E}FbUo@JdvVH}sH#|g*4@G~n ztX_lTiJzmI>g%oH?)&{~sJ8F0&3efnSc5pnc3VgEM=e6nY!BJMkZp(EU@YpyGpHm? zwbQy)H;g9UhlMfSF6#viQ5OnfX}pMYFv)KF{;(ER16NQr`VN&NiT2p%^Mu$?6*ot< z{XomRV`J9LN*U7*-OyKx^}NIVtQpK~6vfua^h6Gx+}`j8iAJ8Vrd0b8^GJ*vr?|7_7;8|1>#yVk5Q3c)K|8K*Fl4Tg`MvqZ*K&4;pTkK4{Mtl;>;rf%d z5P68Bi0hvUcYhrJJ4O=^J#FL16;yXC_M5f&Y|KWy2{k@k#71hPk8G%I8l16`Z$wq` zaa1?Td)A(K2+kw^8I?q>&e{Hfs4@NkR>2tO!=0m87d7%FyI@KEB{n5DHlv2}7=Mr> z>UL3V=)^Iof#(7$tBd|=FBqm_AL1ie8H-)C*>M=^o6mXF(yR0(tHD{Q_&zG@qyDl2 zH%BFRe^iZ6|BL>w8~OgW4>m_V$tLWEZ&7X9;j-6_@CV{|7>P^%u{q!n<|fW`#hRub zYWm)WFEG|sE9fWG{?7k;-T7bozxsQ+YxbmFP~C0`*2jHV9^+rPk*hwICZ36^>NBV& zN_N9W&i1IG`3KC1*D*Z?Zd#3GMh#>`P!D<}#D)f%c(?3AZBR|I9-HHPRFyZrZB4TP zlM;VI^@b#OtSzgdhT;*}6EEO&tZ>(6#|zkkxa2*n$vN1JIJAWgJz=c-Rs*%LKk;Zx zj&Cs~CU{^~m=pD-bT)RxTd20I`CqtmfaKbX6NraCvMdiiwzkiO>Qz-x1(}W19KZk1 z#x6g}^Tc|=>t{BQGjKJAA5R<;Q0c9$x?TdV{tR8|I>8_#LIN3)V zpvK}l;{B+RuIndD#ucb4zl%!JBA+d{MtPpYP(ltwIuULa7sN>7I;f=Vg{r!Ps3*LE z%G$!d2)7M~VQk_{mIS}FgyzpBrOuPz}wEv)z>?KaYy1@u{a{32VBPGMl3E`m#_l3fr z?5Mzj)Dcz_U!X4dH5SKBsBU);)g+&A09J|-;l4`UgCmKrd2zd#5pJ&rf?+me#gN-z?BiuHsf*O)%p~iuWSPrwsiEw`s(h=1i2crr$3(MmvRFlPv zYgOC^n-ecU75Eh@`AWsJn(2$WPv|roiP%UO-)l3}4U3{~Gyrvcy619Kfw!Y_;~Hi{ ze*(*$teBO!DrUx>s5YO4mGBHU!6XUYg7NP^*+{{TEvSC}D;B^zs0BreL=o<6H2_-@ zZ$!0mti%!S`+$r%gLphP#gs`R++W4&gX*5+P($(x)X@Gf4#f{xT>XD=(g-J-9Y3Oy zBXP0__Z3WARLKvblI{bJ!1~D}+_z)rF%|J0RKa{H?1rsTHyna0=yp^M{)TPvI%=pc zpEAN3&;6a*Z0JI1QrQy}!}i4AV0?Um!!RthCDBOK`6oPYp}N^;RMo~!V{P97|0dp# zNpOBztLcrXnm&f^`~RD4sH$V8vnT0ezO3HK@Bixa3P)7Q{vi4hcs6XGshFCI_RrxgRLwpn4VdKo! z4R@ky;5XC&bRQGqD^yiSWQlP90YWO=OPmRR$7`4jw`GlRS6HXA(*L!iU^eR>)lpAA z!t*MYBrcuZMy!FTs@#I=9Y;|&zJ}`O&rvngJcm{BH1zxU)eO{hyCJ7_*YI3+ooXRA z^u(=E3yUon4-P-#oojRQR75` ze3pd$Fq$}Yfep1?;ry1>qf!0#TU6WaMa^QrqiX5}s)}P3h;YA(rA6h$bnJ)!U>2-b z(0b7T)GYc3stG@$X4~jO5qd!pa!#``oE^mrTbu4cjcn&pH;i4x3X;*YBx<~9fEtp! zq0SrWIS*CvP1qQZp=vU1QG38Vs3t6r9o7Gvu#uk~`%pvWW7J4hxLAaJT}G|h{=~Ex zS=`Pmi|WT?PzAn-BQQY;8)#;ra%Uq(;eF4XB_rII-rX>V`v3QA=!VBpRT#Haggd{F z#3$zr_AHBFdih6&57UTRy_+gl$nZcLLQ5;#aVE04gc>;t;G- z(XMwG^AgvoME_TE46DTK=VvK}8p)nliE!U^I906;xOwy z$yFN5U_;as&p`E>cc|Q`R@ahiChEpN;5T>^+hD(XHZop7HA$xWcHL?rHZ)|mLAB{7 zR8qxkU`^5r2NLf<4K(>0+6T*HKH_GW6DME-{K@kd)IjtH>WO1D`oF5}Hm1rtjN|wL z)H}hMf^IcPU<_?(;t`UCOR<3LY3&RV3=~2U1TifreBj&~#zPRLHp;>^2qtD$<`!xh zma%C|Q)xDf%@@>MYg4z9W$>c!?_BqrUYvdY|N9)y{eQTw>wn{eeJ&LhV{1^c;$Ehq z;98L9_!=<>AII}J8E3AvC5%Va@M3%jKg2}5iWNA9CAco%1~`bC*f6fZc?A|jyHNFG z6j>?PH+hv4`W-I^b&L++T8w?p(#=Kn4`2+271~)b6Eo?TqgJdBb$pLuEY~7F!xspOD7C%22es$Vpz1?0YO8uM0Z*c4`m1+6 zWvxvh+p`=suohGh52GsMU#RbiT1Wn?kx1iSOh@Hq0QG>d6LrjXqDpQ*>WeOV*RNv& z{qQooaT3PU&qm#-3>8cD-t|G$1b;`}_un$|Ka<9^^)|x*Y9%^wIS!*fm|SiHT#Whj z^H2jjf_Zorr{Js#yFM3_=;xpxD^U~d#B}@uwUsw2+|ViHTe87CgqwI{Mx_N`18OE+ zcsHIvZN)iMP))6}IuSr!FG1~fFRsK9{1`Jf+T;CojH91cZ37IrG!&J!sHGY}9jDGF zTk>4g9&bb)!>3XCehn40kuNyD9Q5Ndtiu94i8_>GHrw^5QQ6aus<7Rtt#Ci1QAT4B z6}@w}*pgP@dir0ZzA*VkD=xcHELknP)ph9U4I+3 zHC?F6`Ga@;3NEETf+|o+JDkwJklcdPmH*ZCwl^+nY4@RK+KYc&B= z#w)1c$!f5)DL|!ZA8MvIP<#Im-i1-S?a5~bYM{@e-p@yUPbDfHgS*Lp&Fo$8jiabM z9z+$I%czq12QI{^ubInm5&aredLG6}cm@yQ_o#u@G+OWmQ4{(ZZ(~XmGsom+mP&is z+iZDz6!nESQ6qI)EX`t319}uSkX4w5ZKz*hzCmqS^y`-2_oG%Q8+CZKVhY|w6{Pr9 zTcLnULl2*AsC+(!3dY~O{**SGX)3BTSE3G`{is6n73$}&q8?---|!9@OrT$c%JX{E z=k}t4_6({*x|e8Z>2Bj597pY8d%NZ9J2;L0HPlMo!ovjFIPRd|_m-_#@*Z2EM^L48 z1u8guP&fJrHNXp~EEz*$F4{MHuiYpMKjDqGV=eEOPB?bwgYfXEwD}8sY4iQO7B)n8 zH$``c@e1#c?v4n~iCpxc|KS9GYKGt6|K7QXBBwv{Qbfl8ex|8#D1z4nUK9HZhbBFF F`agiS(~STC delta 40283 zcmYJ+b+}a3+s5%db7sz=ySux)Idpe-r*!wwU6Rrb5+Vo^f=Gyfgn)pEG(SK}P>>LX z_j|8ruIu%m&wkeI*?aA^o)t6aa6GUv-G)u+LN^ly7JB@*H>T&M!Ao@%{r`V6mw8@I z!dci9uVQY@zufb>V=K&q-(zb069;146`t44?|I`eF7cyPp7#m9!A#g`wdbw(ypT7U zgY6XLUgLQIyoM2YE9||n55qnQ`#kK+ux~Jm_q`9t5o_%_QDI|;jUP5KHst7U zo|pgZ4b~pxU4DTj>fg^aFshDGf=bgr#xEn`r^t?rW&nvXa z^M(?i+H4P6VTw17VQD;zb1~+(p0|bb zmVQh7e@{V`?>z4a#yaeIJ@5>6!eSIo#HAREH>5vGKN9ES@yB8tjDa^X7CsF7SJ?kB z6Xh|uiCQ{0uE!eK1^)Au2b-gbwMqp@x0J84q|h#>8$4^#9gQg9mfE6Ip=we zuqR%|L-+v~{A5o)|GXvTax6*tRxE?}u_b1@U|lmBl_O8FAo?!42L zQB5`YXKSMQs5ibtwMe{6BrIk_omU2PU`rf=6L2{GgK=;WwXT8VP%Us8Q{jD#ukr6) zv56xACM8UPnP}>Kn2@*u?W-s5gdMTtRjbf(RNr3<$M-NX@!N2DoL{YCNihNC!bgu_3B!+T#xFf@;!a*FCQ+R!2SgWYm++ z$I`eRW8z~hgs(7^goEri>`BXD3gWt`6T6|ZxGmrc!Q#b#OLn zV!Dor@F~{9kC+i_-Li?O_bu9AC(fimeY+f0f!$%xqMGhO`1LoaE{T8J$}^&FPzd$@ zDwrGFpdM@*swGyUl6)(c#J#BZ{dqg&d3`wu+_5JcgjsX~>V)e!0-s|(?0MIoWC=1r zy!)t@*>%t6iz8TuIP3pBF9UW&CEo<>?B_kWfVj{@h9sT{anO!~HNUfRq3@Ap^?#U= zIQ3(eULXC6b%{?uVeDh7r=FJ=>ml9mjm8St;u#AMF2n1*ug)K~80C85c?F1HBfaKj z|BK2Ihk`FXZx03CUs-mi|J#ypJnG3l3&$H#*?kb>;dxY3-ol)i^0hT}CDeKKQC-qG z9FM}Z#B;F&ZpS#>-%IeuX1uic6)#jl-S{n@!N|9Eqn~jsaol&DgR@ateF+<2f`2UO zI$~zx0T_vkP&u>$E8})l1z);y`agZl~@g?hudaJ&$c6K}!%cr+aU zg&Hlf{^h2a6f591Op1SC9}N6w8D<_R-9Y zs&D~}iDhsZRz+3#F6ugOupIt}+?&ModAaHHl0Ki?h;;G$yih}4xWNIf;T4GRdD}2| zz~?p!SFsWC8~he)1$}Nu6f@H2MH3f5wOD^t3oS&QzZo@5|3eM$_)%thR9EB=$I($f z8~^pg1?|K33p+OK+_0;|?g)E0?D?>_!@daX#qhb+F9BBP#@+D-?!@vqCuYd!hTTsw zeXdDQv&cvB!Y`N}Z{aBXh!t^EY@gdue22>V1aW*W$x2}nnzjOFpnOPNyUt?NjaOkc z{2j|;fp|WzD)tF+pltpc)fMlM7`lIPQ(led~S=i0ecb0N@(#=Y)gC{ zyJ6`>K9@V|FfH*xR8Cw&<GO`$q_1%y@xjzSx1(v8#-4aGuA}@3GRb*!()zrtoIfU=&rN9S)AOWExvetzyl;5D zdnQZT%$a@OVB*d=h5LKgI2cGl$1FbYM=o#$HHEIp=JUp3qwMyimr)Z@p=7lGxo$(MSX7EPeN5JV=bPUCHOMPI*l$`@DKsv5LKK9&%6br>Z`01Ld)*Gye4?JF5HKN2Sy? zeBN~8^Qelos%d?G2`>=GsO57r+BIxWoU*ph?PLaELE;Ul8~lQrkP_9kKF@}vgVzm{ zQ9h-f&-)x#)(de#UZ_^zvUM^YmxUKLV*xyeneZd3OENW7(lCxuN!72Bn3u7!y*n*_OG^iREM9uZp!!``t zI&4>b&g=b9+1^<5$=Mt9G#*T8$cAxx3oLv=xgJM|88% zQyLTMjEx+8!VCLQO`oN^4U_z+C+dws9D${AERMs2sMV}o4|}qDn2oqA{))431a|A` z^8&QcT|A8sKk<3RDBsna8BsNS%t1~2Ux{EqPjG}KpPF2u{UvXJc=7I)SrXygM8i(cn$T2HG_R_x4RoN65qr0 z7#w2BlND1C*Tk&Y3Du|5Fb(d)&UhY`D@BJg{;?b?8AoCjoHUg2Uyg&*6hvdJVYWWk zLJhy1!!7w*q9&XHm>Ls~F!SOe;u?607Kt&^a^d1Ad%f#u8@}VQ5a(^c{CE{LU&I&_ zvZgIH#^+U{pgL;U%|u3sw+7Yp|8ky^G}c&qJu9k@OQCWk$vAt`jQ9(2E}Vz{@jh<= zF2v6;#sr_&71yA;Hb!Wo^-WRKg=(Ot-ljMX@8d-5HpyDzDNZF0OtwCrh1v_Q#7NwN zdVrm%_5BCjiLX$}xp9gO&$IX?aVYszn@qdZ~Rp2O(mxVW6 z#OwHGzLj5EXvy+F+)a71MLw?s=bv6|6H4CCY%A6U^@JC(E#AX;SaFHZyM_(06y{m# zbDx^KVR?=J6&$FKZs0hav&@<};c}n%kT^f)}k~K zd4(FbSyx$$RY5&y!>}DOl#qe}9H{9hqMCd;YOdai%Knq6H(m+*0M*p5QMr(CwRJ^) z)WlU0b=~HuiLEDUIi85R?q{g`e7TzOubO^Of!^>p>PAs(?1bc~3gkgus1$C%#;C>R zAJl4AcCB?qN7REX#m4v**2buHcHPFPigZR*VA#5lU3eA+N}^3+zeM%jUhIZHpemAY zy_J_i&1|($Pt+Jy@lV2zM9uLtup}PEHTW;iz?B=UV!1*aZF4ykbMeACoQ3bOAALS$ zlil#`=VsJq8&1hk70!gJXfC{sB~hzlsx8(cjZll$3|xgLuqt-jYF!rE&Osjvj$j;a zSYVsa+eKXV3tK+_L_KN$?Y46nftusLLpA+%T!FqXt)*6>k}hh8RWv(JCN7NXx^GYq z*nX$a`%dHk4-WECu>C8`fgAXm_&Hw02fOS8#(u^gbBh<_Yo9lW@&$YB14YceeDosD zff=w3s?Wz@eLRh7p)~t^?yH{MsIFXwX*K>gb5M|i6Q~w=hv|qTzhM{=XGLA0=>Z!? zUBV7P?H5A02B)J|#XJWs7ph{X=a|VRqHtBr@Z+|TN9?9vZOhIi7Aiwqt83f1u~tsTzHA&i4&Z$t<`)~ zi+;e~oL}Iqy>I0?TN}Rm$#UhzPmKT3oY?%l&m%9qE7*#7%0)}Udsu|>#Xs93bmkHl zCa!wfHXOsQ@DYmh*Wv=od;a3{mJ@%xYWw@;zgpK+xn>{L9^!wzUiLTJu9v>f_*Vr+ zUN_&NvUBJSJ0W<}TBZtWe=r8MjvvKo*y@&j7QBzj?l!j>mQ*C-j(rmn`>rK%I~>RB zh3?sgWH+j!zl1pWlY>G3vn^QH`?f>L`@m+nHmI%AYE)J~Ks9~ght?&5-);ES!pf9C z!sD3lk#*%O3{asdkA2=&%4a^Y(N*H9&znhkDE~8``=QgpKeQaOu0Q9~Di(R+^IGE& zY=J+chFRV}E$KSqXI$VB>WRm{w8d)rE1&l_=MDIqmZQA;Yo9lkc+DGY*-US3SG)t) zY5eDY=kwZg;!miFr@(ug2mXh;z-#P6dH(Q;^clm--0pz-f}RKf_@Qx_c8e?X5@l@1pIC|CW!RA?`$Wd zS|oLp-+ka1hD|sxP7J^M(z#!^-z4j z*GuEScLKlr>f{=(CN7lF?|vfsGwvoHpUCf4wc?5WZf{r*=W(H%_&KllPwIEO=Tyo3 z-hJX$*a0gf_q(Zm9k%2AL@E4kA{vm=@4mX3iJ=dic#ng|csG?bP4U!Lp%iKSZYR?Z zd-3{D*dEKIr2@DDHANRlXBCe~?{^c=dYnjkj0}F)C9_ad@dqr9^)mY1o^nb?f5`oi z$d}3Q&EbXCSPh?|CX^zX{q9F4doe9>=`4OXQ?@|u7tWv-r<;#UHSSpYfj4`tW3KB@5+w{O&uRa(Vsk zr{8t++3R~zQ}@^T{q9Tb+y$(OZ({skaT)ed1Xes6tp^?d4$)U>VA< zpke@H5vacIrx-= z)A$tk;J#WmL-nogcc0_i)bZSxk3CFHpTi){N6#% z-_+FazO?S#%x)0X-0yZqxp5t@KSFistQI68?_1R(6s~DYYjS@pzuUJL!J?e_3BJTN zI3E|b_PcK|a<;Me6-EuK1{lEMxD3Z&XH3=B?>^v!a60i0)J$8to#o8j5CcJX_IFilsRYCr8pUvnLQcdJlV+(euU zKgElvQPa7HO~s*W9HgKiQBTYI+^F@w7HZYlEtO)Vah8muQGNU)Ho*I+iK_T`%avBBoEU{l+S#az z?7(dJBX+?*u^={^VDrQ@>_og1_5P%xiMCv3M%wKI95{@6kO!!i@lCOusfLO}Gda*sUkfV$8D?1y(y z!>{2qyTA-APJ97X@tD)iDyS|PhgyDjqgv<@YF>$$;S71HIZy=(V_U3&%8AcW!{-Dl z89$(st_b?1}}}TT3j)fyBR|a;x43n|D47anOK*-%;6LYNL(o zC8!(UL-ldFO;$cA>>+GSd5q7k$=jeNvK^>g@HShQ)J4rJTQM^}!NeGUi?vKBGY5LZ zNMsK2PGLFXdSBRyvoR;}TGX6<2Guo>QR6v!yWO}Y<|W>O8fI5fU7F}i+w;{zo!<;K zvGqqrQ^;G(fi8FxRnsCn?1F<(+5COjSUcJA5Z6Zy({`v9*o*4xIA2*;)<7lY5!4L% z5tTbNc3BsGig}1{;uwwp*t_k8>DY)DenG8Lxxcn28G&<&ccZeo${w47ci~Fn57-V@ z?6sEs4_6S^+Gkz(2sNWt-fvy91t$?leZw}K`+KuEIDoMa_}veQPoR>e;6Zz$4XAOO z_FKRE$>&_uD2O^_4#O72k5Cn?^qqY;-HAFc)nWTSUzjr|O^(kzF>3+2JeiSO}&tfu6d)mf%5o}Mq z5jDD^&R9iTpt^VmYSj#!W&BU!An#eb@YkpcB|c|OKM*yZpP-Vi-cQzan^5EXPgJfn zKW{C!3H1d-oC`KTG(%PRdsNG2x@b>61vT7XhB(kTZ}_ua_zTn%y+LJdwM!Py3406G z*ZD8oji#Y0cnS4nC9c>FXQFQS7uS2!KN7Qv1-L}ruuVh@(q}l_)kENYT{Ui>VkKe0BinZwnFt`FVr$S3G3h?R0ZO^wQBVE^Re`7vc7teCGLONWcm$*I z36{n@AFZppBcmYX?chK){u}#Y8GdM{KKueF;Y-vEH{2KDeuQ!Z`w+MDN4N@}LyeB~ z5fN^)+6}c<97YYxq=5)`{eGzP_M%$qBi7RRuM@NrmtcNgc!e5fSt29clh()L#LI9z z{)~CCX;g%3fr+RlU5#q${iyd}LN&1$Bf{laI#i35MdeltbmM;r2Rd;Fs_)O?2n@uG za1%!el_R_HXZ!)R3@?pkH~JT~?amQ9!X?{C>_Yq-7Q+g0?8d`zGVua*!#Qq*7t%yg zmIE!f4X{0~MD^iE)P*a?i*RehLR9%f)C`s@euVp;zb~qVUZF-)o&*uDD{G-f&p}jI zUPnD>$AtF&u?ZtWuCI?%peK)=$Zk*p3lUF5U3f1x$LFYIte)6z)DcS&k3&7_K~z_~ zMBOM(k_b17a-ni;Dk^z@!orv;X(+;e<1wjSC{D5nx0qDJVVtlIr(&AqmQ)*1$@34Y z#j2;UK3|C0iFaUDyoy!u18VK4oYE@33^gBojY`I(p;UHa8yrl*I#d#+Oda7q^A$lg z`4Ei8{kR$bL4A-|pT?T<8CLi4={RkK8;&E>S&QsO&5%z}6)BoN!cAN=Q7s!f&4HRE zB142%3G1R}sClR<_%3Q+P(Gs#w@*Dlg!%^A29F<%L zQ7sse+ghj^>Pe@gUcZd$iZppFm%5_+{htFIG~tE!m=qi2wQ=7KRrBSj3!lSQm?)pM zR3B85Jwck%E12I}aysfp8&Om43)BPUDPTA5jLC`jV@Sj40tcP(395+@0PKPb-lSJLD! zVNX;GH7rhI224=W`m`YKB_4;#uw*H#NPWymyayBDRn!ALLN$3r=?M4vp(d*3zCv9; zUKty%P0KL;HIBznpgui~s_7r738Zk@@XUyMeI-uABdD3KRyiy0iE83msEO=&xcohi zB~Dk~DzXX}5JyE@jw}yxpe@lY)C`udLWJA(cEOUwKj9RNS0W-x~OHjEh=kg zqq2P?&cKhTzMWCS-uEzU;hNUOA&lnrqo`bqsAbnnkA*e<>v5oAHvx6x66}iCFbh_w z9pSzs>WYeQqUMW;I<~k(qn>yrs>?2-hF_ez5pD<66qR&iQG3RdsMn+Fh1dTE93-M( z1}b}3qMB+SR>TKb0dv;39Qgz_v8=^te1@7Q@-?tw+a7hJZ&25Lhic(C4K0V#q3+WH zLpos~2XZpz#3iWYIEI<=K4!p}jUwE)+qqCJ(E!!wL$Ewa2M)%`s4n>z z8(@LvHsOrN7R0Afqb+L-#=nMN>lP928;h-&m^fuio7wVWQ{w8V`Ct|5v)s3+ivERa zxmd02iPEBSU{PyRFdAi%mlx=0Q|b_GPx-f~7D(60lCu~#BOZpD8PB6y_Bm=~^Pi(negSyTQ)FSj3 zD%nc*if~_G_Cxi32xD`9Zw?1~vSs)+ZpYHtxwmEUY8**?343GxJ~rGAp_=vs7QniF zttCU~h8JpTFV@eJdIDl6?zeIf<6kxTngV$iQ{a76E_?`|m}IcM zAvfy0ir5HSqMC9$YSiol~ne-)A#+WoT5_`b5NXuT&V2rh#EF0QL9XLh??2a+p%G0B|rZ+05j-!TWvN?<{B~@PzG|}uq zz40U}Yj2_E@K|%hd%3U`P|4E}^~B>*=Wj)2{T0+qSNK!QtvRSJ+JH*h#PcHDFR@g^ zkeaRm2ih>qL`@{8F(dwq%GPxAt?&DxDtI21ln+r!S!h9o`}x6mOho(|)lxARM!2u_ zqOmFQR_uuWMK;>HEMok3pkM+88o&2ZP5%xx)mB|>O*j~J!(*r>jQ5#M!R=5J)JW7Y zI~p#JT4EDYX4EL^g?ga*I0(PSMwn|U*{&xXv(#>U9;1oVF0*85i+aLwSOPDEjkVm8 zsuF6wAB*byZ!k69!V35vHG0afu!(6n>cM8Cy8PP^2Rh*=)QlHsFavf* z-FOnF$4#gy_yktLTjBDoYwQWDpeoQ3^`p)cX&kCa`O$VHLb?saCym%R`cqp9GHg6nWH!blWel&T#i~B9-=B3_}nUz19iQAsD1x- zRExjGO5EQ|xY@Q$O;F=_5Grd|p|bi1)C3iKiw&bnsJ>i^n%PdFMo;8cn_^R;R>2(D z3Cp71zXp}{zhY<1yN&U$aXF8J`1lAD;5*cAH`W&x=Rl3?lBoScZS3OXx8qQ&+=cD7 zCcH{;40{ltM~(ARyKE8q64ms-pmHPQZd<&1><(GMc?y(dDZaLvWyQF} z1ySYYQB!ekjEMun<)cvJe;TSH$M71)*kdhs57jlVP~$zuUK<^$P%U2|#DSi83J$}i z7=?-VMR-9>je7Eon3*P@f&+=S?zbDH|0cry=5qm57nVkKK`m6$^+b)1&rwNt6m{d@ zunvX_9k3dXMXdn~!v2hU(nJTXf@v@Yaeh>vmOxdsXZZC2s3)C-y5SPk4R?jh&!AfJ zHfsKOhS|Bl7yQcRR#P4x1o<>!y!XcaEYhgp;1$Y1-VtZWoopoj4 zuzf~MfVy5)R7KljHjV!Q9B2w%f;n*q=EiGS9V3repVdQ+?=GnG#-pa_ZI~DTL%lEe zQG2}^YJwVvnQ%L5SYJRT{aehc@t@|H6;#CZ#9dJ{;AB)wtU(Q*GhzQg4bKGM+o;Kh zx^X2`()LB&U^J@b*5FwD9My$6k6Tw4!jQ&$e-1Pr$72VQY&Nzae({4fSbA-p+yc}Wk zge~wh<6kcn2^W+ITPAEYD$6T}- zZK4^7DxVjQcVhUZsl{LKYe10&!98p0F}+HW7v5U@OR>DF#~R{ zj~^@GDwqc8Yp*N@FiGry`+$-%b|B>b$>m@Q%5sD8aRP3JIvm$7a0-=dS5T`}!FU1p z#Y6}f551DV3I$yDh7twb zl)45rlYNK9@G0s>nG*-R#ke2iV1p!f!?u`(_yDq+dACs$Q;ehm*M(_NTd^$o2^A?B zjyEI=c*Tjo32`u;6aGpba1+Mp6n29psKsU@>Vn5mbN4T(C%%murb$x<+zgr(w-Qgq zrdT8ueTy@22F6YuaLe&x%t*Wgm1Cic9B5~94K=4f#RzKl7it1|oyPh+e_BhP!KlS& z1}X_RqvnsdSP5gM3%E6*4ytAPV{Tl8dXS^2`(43!8vnm@(29aLsKugD`hfckI1dL9 z-@<0tFoRuS3#zFPVH13SS+PvUfcs*iBWg#r0aM^URD~~KW_*sSaN9U$xZI?{zQ2!2h!)I zrHF@MCeB}(&sy#XMl$RlVWSUDVV;CH z<}4C$e=n?8v4FRa^STuec!e=TNs<{GmkM}CdEc$l0r#(5*OswSP`<1^SYy;g)Uhn% zUrjxX0u7THSOHg~lJ72RxTP)^aC^5LsAP)9jMxh`8fN22JchbX`SRA}jqwigVoZg@ zqv<*-xB#mVudfgackszYDaVcl|v80uP3QuU6C)ufp(=$Q787nXk3DtTCZU&^i>VGZ^PoCvi=*? z9G;+B!2RlFek2vVFEA7CL`}JuP{Vp_b&GeRM#0n?mW-io9H@!ELydwnsEOt#p2CNy ziD+j{d-8KwiTE1o>$-Hc0^S51UOV9ac-4P(Y>Hk`m)xP;t7kWETi=qmXoG*!>&bRt8fq0C>erk>WSfae%Li(zYP0r z*wbNubu#`Qh70}<8_~oroG@(quzACl#@5`h2CDBjVp^UwUekd4k}6L#TXcqEGG70- zxmEBIrYF9K8!)0pz`p<6%t3PsUSL72(bDGTk*KduC!l7$X00t3LZ}>=j`i_2mc@c? zZ078XZHW(}X3o@Yt$ZMA-Z+fv!o=+u|I0XN#z8N9iNmpdd-EE0C2rgy;C{{i0G1&x z)zOCEP*id)L3P0@tb*Gy557VrW5!Ma_pfCuMqAAfg;J(xCk0*$|eq5Lvp2R-*xPQR?p`jK71Kw0FkYZ54eZW{V z#HQM|Lj&#~uYZkmczcgwHX7a`{~+F*J3QdF?UP0ZykorHc~rpthE$Hw=z!OOf+eV$ zzemkvlg3ca8+}x;6m}XLaQ_}~}=D2i!lCpM@HB<>y#MHsB;K81<>$ zVAecdC!RUq7N@@!1l+e_WfofQe2))#f4M~g_s8wBEw;U7+|O85d4S`{1Q+riETze~ zP~2sf94nTyY!VM$VZ-S7N?R3UuO{m$kH5wir7mj&-dN&eI20?dx0X1#!74C)W59hM z5ZDxOf86RYuBJj$KDQY*$L4_dLhFAI4r=m3%Pj%-<gx#P!W+0xA zT3&Z!0lbUlF!4$2(uP=v_#kQ%8tas;uIWxOyfj5tp+Ga?3REtX{Lz|tBF-evc{VakJdVEKG z3ZrP+V-IbvKm91+e%vIJ)YLT5ANGX#o|~mH73I}Y!>iK^TPsrhX6>5F2|JH7t>m55B;xec%n}B-qxi}72zSI7nCeHAWeTFOiuidBxYK9ty$8aIm z!WREoOKm{)`5{!renjo>AE9m(_+aBaA?ibDR@8&lM74Cwume9Z{*^2J8gbH#&js@H$q&GHHWuhcgDX z*px~~pW-DPh6U0G-SFIu8t)JB9DP0~gXK`$OhGTCWa`a<`fwDgrgKqU@)@S&4O=jp z`1{P3oWU$X_W_~`UZ8v$DmPkX4Z4|h56&UJiMe=xpKL+z2=S8aLH7-7s~kZ$eE-S8 z-#_Wj3z0d4ZkY8&ZH?yP0X&7BaZ;|J`+2}))VNQV+is8x9}|Cr&u~MYp!)`7e%_$_ z47oa=wcvTwcfpS^DgK>5=)TI0T`B>H#m&uU2zPR zG#61Va1WL3t4i5<-=Vtb0%pZuQ4`n4@au6(GvN@Y!=v z^pXQ*fBteox9Y_yA9VZw$mpPVm-2lWi#IN-VA;R1V$gkl&rpe`W#U?aS`+qE3A*3) z@TvygHvJQoo*;t$k)@o=Ko6wl-=Q@9& zzIy$(30-4c4SdZGlH0^7-u^HDBuj|JezzwSR54t}hJ9q#| zOPqBe6~JPHg6V5Noy-8U#phcW)OyM05!V$3x>=-uWGN3k-l z8)+B*eN@o>Y1Vh6EsN7JY?pEV?6E<&Bg!={=)R`Eg-YhZ&q@Te$kN@J&SZOBX zne&s+vTV;Y+dPDYD6c;!=yk;jbFFJ1e`*iVJv7h8XJCHN?coNYe$eb!W~6-E=Rr4> zpF@2cR(!J!+a_D={TFc{=iT3G^GJ(rZWRo9KXcHP7g~G~bbs~kFb26m-|a!StgDYWlUN zddA-a4pb0-k0r?})Lgz7wOc)g#c1LSIEy&Oej6o=us88DY>%zJv3N->L58Q-$&_!o$s!n#!7M}*^82^=c zVHO4QLfE7~S)aDRl$6g$?d85eJ?Tjt$CKU0_{1GA*i<|Kw-8^(+&K1P(7T7*P}iUP zvn}(Na58a^ON{?$4qjZc^}gWcp!+*teXt|t{wuaC?t&Wsb5Jwn9@O}c`->%GV;n^6 zyJ|b6A*dVfLG2U%K}~eYeq|!V8dw(lggB_p!8X)h?;Vc7MAw4uXSTCY>;0Xuk5C(n zKe0Gw|IM1Z9d;ldg8{say6%0+Irg-nZ|c` za>}>kQ!a4zZqWUG(Bt=l?q5tE`XA$+*GJvAPdxV@1lHige?; z2WkczhZS%>*1^kI0y8I$bi=MSYB;S!4aX~31@k6}bU#lVh}vpR#*Fw2Y94uqX?U>2 zN$vUtl7%AOCzk=qBHegA8#Z=wJD~zG|P&3>I)M}M7wKZjT)E5*RP)+s+mcqhmBHg!H zeNY$P6ZR4+cm6_+mK6it#pk}59nL{j;5lmXiJLXj>wA~S07sfS&02o}T}m;>YIi*(Cz3Do;H zV*)&Y8Wm@-0w&5I={{XI4m$(g@Bbg=Ku!A}Hp8X`tdFpyJ{(!la$q&;Nq#`h zXm`*Jze1Kf12HM(hr;nC>`9!yusz6hR5I=?%=n+i!7mhO_;e^@7g~x+mfNVBrz>i< zM~#-XSOo8&awJ(Xn?DMKt&XZddmMs8P+j{BH5JDx9_cF zhNn@At9Jg4(JLM?J_a)cH>^ZUn1h z3%gk9DWsbUZsAP&3jO*U8?@pGSg5Mzl^$J z@d4J7wQkP8|+3cM(GFJlMF*mJa19szWNZ`6Yj$<#F0ZI z-EU0vLVX{A-iO?4p}xArftJyH zV{M8Yf!e*^LuF}^agpw`+%i;C|BkwFv+?%&UeuGPn_yW!6ZOQ;P}i+F(H>|KDrtWY z$Au=*!g|t)9H_6aU~Mck*=iUJPvYm z@ITb}PO#h-laY9h_&f=%|2-T+}x7a52 z1hyxR*lIWGj2cA~uoFJOgjjQ%^>u4hMS7reYCWo=fiD>U`k>I01341ahcmG(Za_^W z_fQpx-fmeu6H^hd#ftbX>V4jq)+H%Xt6*_davnsr=oM7oXWe1t!*($KRWOeN_1S&Y zlNZ`)Pg)nFiKk-~JdOD<;aApD(WvEgBG$xXsBs=|myL#|sQFN2*+?ECG5 z%2d=S_!f1YM_2|cguaP%Ke-r#g(ygJz*?Xhs!2PcntBxK0*g^ue+)Hh?x0%CJ7~$3 z2Gt@ZQRfXq_5C88j~B2ccKOzFB(#bHpO0-aDj9bjvKtlt&a%86YS}%2gE9AEyTBUM zjeo=C_y#lLf+IFh?7{ZLKcbpC_fd;KMRmzv*hcGrmt)pv$51E6{yx(EmP&tA6XiN? zPudNYRFg5i&if(K{g5d)>Pb(d-v05->$pe*&B zvKysFHBl)nje}5Ku>*CZQ>c03A?ilWf3$gGJC-2+7jI+H)Aqq6*%{l2G{y0hAHYpm z?kp{$CV#*|3#@j|hT9rcpMSvYnDQr^A1YvD;%?Xq527lb;=Db1A=D`P4E4nK@iWYO z!LIiMs{9UWG~~QUmsjOr00%$de$+S}`?F>BPuPsyNOj5P@&T7^*lj_b_Xld?DSO4T zdNmd!ev6tZ^Z#PQb`7fH53vW9xoRI!HeO}?s|o)L7c~0SntBVW1&*PT>?W$o|3M9( zPp(2kk zByrZwsEOu2>Phqe&nB8-sJ=dh>WXCdEr+^b72@wuT@!p@Q+9VO zOgsjQ<5#GeH}sf;J{**NXd8@e*j4fGHuJ4VHRVTaj;SBn6AnVPz#h~GiD#G`J3h9g z9D!=V1*q-&2h?@zKC!O+8o$&3VldlN+b%zNW?A0%59|AdsO5JDw$uesPu${pq_^MC zb{sVd+W%!!@ zsyF~O%qCzrT!FnX_{KJo15h{k4K-YIytQ1YkC}+qqPp-nYW|4-&R)-pnKb@G98A}V zs5w3FKlaAjs3z`R(Ih`&g8?=6}}3V^I^-bKHtK zJ}~|@(_P{~*%g$%+0Kdfe=nF=<7EKroMY*i4N`Y$F7H8sqWOeeYMn<`$S|9c=tW0@yRFrG6 zNvM`MiRz;Np_({lj3~F?Z;0xW?l=UuV;0OBGs^vBrDli&6`Vm$9DkyQN#R&gp62SM zSRU`9_I8LJic9cB)Tp`Rd6-xMz_PS{}VQD0;_NaRBqJ7%-9PvX#Jnd zK{g6@qFUlAszU#vn!04dC^r+1K{e%NOo6ErS<@H6g2eSvT{a#y!`;SKm?E)t@gVF> zJQF{~KhgdD?+Hnw-0x!jh8mwQuoT8i8s+Bp8aRr$E2;_aVS7xI%yMHiwk1A|s(7yC zmULZlEb#$MjAc?pxkar$s$!pDT8;k`9O#DkQB!D!l-9&0upMzN)Lgw4r{D)ng_Be1 z3HV@yo$wthyW6CWvfm#<<J0P(Ew&2dJ%9uKaf6WvC>)f$gzu0qeV! zsH}d58n(WI)^*uXT~!X%Qf*Kb8H59H3f97ZaG=J2)k2n3-=K!kZPYSazOeOSH|$0H zBlg7NMWWo->T6M1ow2A5%QC1N4o2nB%&_ZG^Tk0_E?h>P_r%Hg^B1!>q{Jq?P!QFW zQ&3O17}fM!QGIq83t;x*HX$`fO;jtfHQqz5_t7P6KADc1xIV{*_y=kpsZf&nLF0b} z2Wjvg^2leVj15AYdwBR-94k-`-j|7z0V6|LYlDl4;9igMrS?m%5IPvt20xqlz3A`h{) zpRH6Co5@;Ni*mm~(G%5$LvatD#Z`=^iPfXrFSll?8RgxgJY6kYv_8~g{I8&(Tx}ap z*Rect$~xAREl^LqG#nqpJj8*zHp3OfOvHmQ9xg^D*G4Rh-=d!QJ!;15RL^qbD^za% z8{$CYI6?g=_e*GXupRLY)XZ46fpy6&)P=u7m7hZOY08F{R0C06^27htZSOHv)^Qxi z4pNm?(wGq-1~sc|j1w1dF(c1e~RElZbTbBC|SME*S=Ftf(=& z=w{GbC1Gy0<>qQ&tu1XaTbK3z@IC+b$FtY(_dCydp5NvB`#ul4g9mVFt|gjY)c5)^ z7B65F-oks(y(G^HF{nhe7B%8p)QP82K{kfUbZPk(T(4mp^&#AVDO;SgzjSh=X0Q`8 za2%8H?ydIx&%g@mWmv5J|0M{zzCBE1?kdJBH-*Hw2{0Y->*)9v7Qq*?zpgM2~ z)q(4%?GsUAiKz;;bcaw6ml4!?zxTu9x6F*u6q;LoU(98hM7XDRABsi^iGbYUgxe%)p4|NAKn(x9CE6)Kpf zQ0=khHo_-S9oUWO*oYe8C~77gd+ZO5Ow@Tjs1BaNt@tsj1ECd`AL4N?^^OYmzdkrY zLl_QW98RJx5U|%?CS9m)SAcp5o%K5ZX-mB=sNnk*HITr4_6!L_bubj@f5B@_jL*d6vCgiT-}WN;C-Brw^1*PbE|DB?!z+bv8bRuf%!Or<@n%pcD)`{ zf|*7I<)5e-3aqjANMu{P9jO%5(`@wk5FDsXHLuP__z3FrHe8KoFa@unf+)1!QtN6A zq~3u_V6UKJ;XLa5-=OlqEmQ(}^njE9Sz-UZOF>hzu)z{fF=kPJ4;#^OP$%-Q<5-VV z7=b$)?Z$1WrMiN9aM|-#KZ**ntEi6sh?>dYyzT#Dl=gpMlcmmN)EClmEoNgjcH>|8 zJ!&eiHrvwNK-K?2jWnpmqWu9>EHvY*coLl$OR)Q63cikO(A~w9e@CI0hVmC|Z5)T3 zvp+-%#vs}kV*;+g$FUf-mVM~L&rsWJ8mlnB3`s$d;(RkM~(C} zDm71{9y)&AcAw>_?`Pl&bk|bQlzGsFmv8}2p-%i86}8bXSps?(HFZ1j7?z`!@HTEh zpB{^$ji{(E!hT|`9Gj?z9J3kgL1t*Z;~feLl8;c)Iq$gLXaTB+t57c@WvHNg8Fixp z9Kf03!c!%40`vFR?yYns#jK2q8vfu-f8WrAm;~3Ryj(|O%u0?pj(CoQ!(*QIF^><2 z@5q?PuO;HHr09e=S6otRV)Dr5aldWO;Hbi)FZ@DUW*#$@XzV=)5zgKL(IpN1K Ohr@s5=0rf&C;tJA1k#xR diff --git a/docs/locale/fr/LC_MESSAGES/appendix.po b/docs/locale/fr/LC_MESSAGES/appendix.po index 3cba9e1775b..6300b8e7e07 100644 --- a/docs/locale/fr/LC_MESSAGES/appendix.po +++ b/docs/locale/fr/LC_MESSAGES/appendix.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -2657,16 +2657,16 @@ msgid "January 2020" msgstr "Janvier 2020" #: ../../appendix/support.rst:69 -msgid "3.3 LTS" -msgstr "3.3 LTS" +msgid "3.3" +msgstr "" #: ../../appendix/support.rst:69 msgid "September 2022" msgstr "Septembre 2022" -#: ../../appendix/support.rst:69 -msgid "**Until 5.0**" -msgstr "**Jusqu'à la 5.0**" +#: ../../appendix/support.rst:69 ../../appendix/support.rst:79 +msgid "June 2023" +msgstr "" #: ../../appendix/support.rst:71 msgid "4.0" @@ -2693,14 +2693,26 @@ msgid "July 2022" msgstr "Juillet 2022" #: ../../appendix/support.rst:77 -msgid "4.3" -msgstr "4.3" +msgid "4.3 LTS" +msgstr "" + +#: ../../appendix/support.rst:77 +msgid "June 2024" +msgstr "" + +#: ../../appendix/support.rst:77 +msgid "**Until 6.0**" +msgstr "" #: ../../appendix/support.rst:79 msgid "5.0" msgstr "5.0" -#: ../../appendix/support.rst:79 +#: ../../appendix/support.rst:81 +msgid "6.0" +msgstr "" + +#: ../../appendix/support.rst:81 msgid "TBD" msgstr "A FAIRE" diff --git a/docs/locale/fr/LC_MESSAGES/contribute.mo b/docs/locale/fr/LC_MESSAGES/contribute.mo index 43dbd5295fdc70918c1530a165cd46a401cc56f8..35d992335d35d8f696f61a5017406492f6afd335 100644 GIT binary patch delta 25 hcmdn}iEZ~MwhgDRa+&EGS}GVCTNxT|zIrw7F#wlA3se9A delta 25 hcmdn}iEZ~MwhgDRa+&HH8!8x@TA7$_zIrw7F#wk_3s(RD diff --git a/docs/locale/fr/LC_MESSAGES/contribute.po b/docs/locale/fr/LC_MESSAGES/contribute.po index 5f0a00a69ce..f100793ca27 100644 --- a/docs/locale/fr/LC_MESSAGES/contribute.po +++ b/docs/locale/fr/LC_MESSAGES/contribute.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/design.mo b/docs/locale/fr/LC_MESSAGES/design.mo index 21373da973bcbea47375c30dedd63849404545bb..609c0d9042119ea501ce5d555f064920b2e736cd 100644 GIT binary patch delta 25 hcmeDB!P51EWy9PVTxPn4mI{W(R)&U~m(NIE3;>1v3E=<$ delta 25 hcmeDB!P51EWy9PVT&B9lh6;wJRwibfm(NIE3;>1f3FH6( diff --git a/docs/locale/fr/LC_MESSAGES/design.po b/docs/locale/fr/LC_MESSAGES/design.po index c74ee8f9cd7..eaef8378d15 100644 --- a/docs/locale/fr/LC_MESSAGES/design.po +++ b/docs/locale/fr/LC_MESSAGES/design.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Jerôme Bakker, 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/guides.mo b/docs/locale/fr/LC_MESSAGES/guides.mo index a5368afe3c3b68eba8e6c1bf0252132f2cd8b570..c84780ad00e2167877d62d1c959a370966a7c30a 100644 GIT binary patch delta 44 wcmccHD0R0{s-cCkg=q`3nl_i2uA!xZp|O>rVY`7gGZ3=?G3#~%ZMLr;pPbbJpuqy@dlFs delta 23 ecmbQ@FvVemA3v9=uCbwlp{bRL+2#oTJpuqy;Rcof diff --git a/docs/locale/fr/LC_MESSAGES/index.po b/docs/locale/fr/LC_MESSAGES/index.po index 4f296400cce..f94f900189d 100644 --- a/docs/locale/fr/LC_MESSAGES/index.po +++ b/docs/locale/fr/LC_MESSAGES/index.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/intro.mo b/docs/locale/fr/LC_MESSAGES/intro.mo index 72d213d9ed23b583219bf7f8346580257fa3bd80..06cf6f78b1cb90b41bd73b392116f5553cb42783 100644 GIT binary patch delta 25 gcmey>&ho3BWdma^mzl1irGlZcm7(Eg?%MZl0C*+{-~a#s delta 25 gcmey>&ho3BWdma^m#MC?p@N~Qm5JGA?%MZl0C*M%;{X5v diff --git a/docs/locale/fr/LC_MESSAGES/intro.po b/docs/locale/fr/LC_MESSAGES/intro.po index 85fcc9c5d6d..599948ffc3a 100644 --- a/docs/locale/fr/LC_MESSAGES/intro.po +++ b/docs/locale/fr/LC_MESSAGES/intro.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/plugins.mo b/docs/locale/fr/LC_MESSAGES/plugins.mo index 277aad6e08fd5f452a4a61ec73dc49d70db0d929..7c61a96903edcc7f2db2bc74ea15ddb02eaaa5f5 100644 GIT binary patch delta 25 hcmbR8lX1#V#tqM{xXg47Efoxntqct}f3#Zc2mpql38w%6 delta 25 hcmbR8lX1#V#tqM{xJ-484HXPctxU`|f3#Zc2mpqV390}9 diff --git a/docs/locale/fr/LC_MESSAGES/plugins.po b/docs/locale/fr/LC_MESSAGES/plugins.po index c23d1863bda..d0fcc3c05fc 100644 --- a/docs/locale/fr/LC_MESSAGES/plugins.po +++ b/docs/locale/fr/LC_MESSAGES/plugins.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/fr/LC_MESSAGES/tutorials.mo b/docs/locale/fr/LC_MESSAGES/tutorials.mo index 5eca73cfebf87afb9033343810b1d18c2a353fdd..1a0cbe9435b85dc47ccd0a4fcb22b19021c07db4 100644 GIT binary patch delta 25 hcmZqv&e;5&al>kBE;C(2O9ew?D?`K0TdmL80|0(!2{Zrz delta 25 hcmZqv&e;5&al>kBE>m4&Lj^-qD-*NLTdmL80|0(k2{!-$ diff --git a/docs/locale/fr/LC_MESSAGES/tutorials.po b/docs/locale/fr/LC_MESSAGES/tutorials.po index 7d794dd57d5..323a6cd1e95 100644 --- a/docs/locale/fr/LC_MESSAGES/tutorials.po +++ b/docs/locale/fr/LC_MESSAGES/tutorials.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-06-19 13:11+0200\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Jerôme Bakker, 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" diff --git a/docs/locale/pot/admin.pot b/docs/locale/pot/admin.pot index 8f7e8abb1c7..bbf244a08ed 100644 --- a/docs/locale/pot/admin.pot +++ b/docs/locale/pot/admin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1403,119 +1403,119 @@ msgstr "" msgid "Uncomment and populate the following sections in ``settings.php``" msgstr "" -#: ../../admin/performance.rst:195 +#: ../../admin/performance.rst:201 msgid "Optionaly if you run multiple Elgg installations but use ony one Memcache server, you may want to add a namespace prefix. In order to do this, uncomment the following line" msgstr "" -#: ../../admin/performance.rst:203 +#: ../../admin/performance.rst:209 msgid "Squid" msgstr "" -#: ../../admin/performance.rst:205 +#: ../../admin/performance.rst:211 msgid "We have had good results by using `Squid`_ to cache images for us." msgstr "" -#: ../../admin/performance.rst:211 +#: ../../admin/performance.rst:217 msgid "Bytecode caching" msgstr "" -#: ../../admin/performance.rst:213 +#: ../../admin/performance.rst:219 msgid "There are numerous PHP code caches available on the market. These speed up your site by caching the compiled byte code from your script meaning that your server doesn't have to compile the PHP code each time it is executed." msgstr "" -#: ../../admin/performance.rst:219 +#: ../../admin/performance.rst:225 msgid "Direct file serving" msgstr "" -#: ../../admin/performance.rst:221 +#: ../../admin/performance.rst:227 msgid "If your server can be configured to support the X-Sendfile or X-Accel headers, you can configure it to be used in ``settings.php``. This allows your web server to directly stream files to the client instead of using PHP's ``readfile()``." msgstr "" -#: ../../admin/performance.rst:226 +#: ../../admin/performance.rst:232 msgid "Composer Autoloader Optimization" msgstr "" -#: ../../admin/performance.rst:228 +#: ../../admin/performance.rst:234 msgid "The Composer autoloader is responsible for loading classes provided by dependencies of Elgg. The way the autoloader works is it searches for a classname in the installed dependencies. While this is mostly a fast process it can be optimized." msgstr "" -#: ../../admin/performance.rst:231 +#: ../../admin/performance.rst:237 msgid "You can optimize the autoloader 2 different ways. The first is in the commandline, the other is in the ``composer.json`` of your project." msgstr "" -#: ../../admin/performance.rst:233 +#: ../../admin/performance.rst:239 msgid "If you want to optimize the autoloader using the commandline use the ``-o`` flag. The disadvantage is you have to add the ``-o`` flag every time you run Composer." msgstr "" -#: ../../admin/performance.rst:244 +#: ../../admin/performance.rst:250 msgid "The second option is to add the optimization to your ``composer.json`` file, that way you never forget it." msgstr "" -#: ../../admin/performance.rst:257 +#: ../../admin/performance.rst:263 msgid "Check out the `Autoloader Optimization`__ page for more information about how to optimize the Composer autoloader." msgstr "" -#: ../../admin/performance.rst:263 +#: ../../admin/performance.rst:269 msgid "As of Elgg 3.0 all the `downloads`__ of Elgg from the website have the optimized autoloader." msgstr "" -#: ../../admin/performance.rst:268 +#: ../../admin/performance.rst:274 msgid "Hosting" msgstr "" -#: ../../admin/performance.rst:270 +#: ../../admin/performance.rst:276 msgid "Don't expect to run a site catering for millions of users on a cheap shared host. You will need to have your own host hardware and access over the configuration, as well as lots of bandwidth and memory available." msgstr "" -#: ../../admin/performance.rst:275 +#: ../../admin/performance.rst:281 msgid "Memory, CPU and bandwidth" msgstr "" -#: ../../admin/performance.rst:277 +#: ../../admin/performance.rst:283 msgid "Due to the nature of caching, all caching solutions will require memory. It is a fairly cheap return to throw memory and CPU at the problem." msgstr "" -#: ../../admin/performance.rst:280 +#: ../../admin/performance.rst:286 msgid "On advanced hardware it is likely that bandwidth is going to be your bottleneck before the server itself. Ensure that your host can support the load you are suggesting." msgstr "" -#: ../../admin/performance.rst:284 +#: ../../admin/performance.rst:290 msgid "Configuration" msgstr "" -#: ../../admin/performance.rst:286 +#: ../../admin/performance.rst:292 msgid "Lastly, take a look at your configuration as there are a few gotchas that can catch people." msgstr "" -#: ../../admin/performance.rst:288 +#: ../../admin/performance.rst:294 msgid "For example, out of the box, Apache can handle quite a high load. However, most distros of Linux come with mysql configured for small sites. This can result in Apache processes getting stalled waiting to talk to one very overloaded MySQL process." msgstr "" -#: ../../admin/performance.rst:293 +#: ../../admin/performance.rst:299 msgid "Check for poorly-behaved plugins" msgstr "" -#: ../../admin/performance.rst:295 +#: ../../admin/performance.rst:301 msgid "Plugins can be programmed in a very naive way and this can cause your whole site to feel slow." msgstr "" -#: ../../admin/performance.rst:297 +#: ../../admin/performance.rst:303 msgid "Try disabling some plugins to see if that noticeably improves performance. Once you've found a likely offender, go to the original plugin author and report your findings." msgstr "" -#: ../../admin/performance.rst:301 +#: ../../admin/performance.rst:307 msgid "Use client-rendered HTML" msgstr "" -#: ../../admin/performance.rst:303 +#: ../../admin/performance.rst:309 msgid "We've found that at a certain point, much of the time spent on the server is simply building the HTML of the page with Elgg's views system." msgstr "" -#: ../../admin/performance.rst:306 +#: ../../admin/performance.rst:312 msgid "It's very difficult to cache the output of templates since they can generally take arbitrary inputs. Instead of trying to cache the HTML output of certain pages or views, the suggestion is to switch to an HTML-based templating system so that the user's browser can cache the templates themselves. Then have the user's computer do the work of generating the output by applying JSON data to those templates." msgstr "" -#: ../../admin/performance.rst:311 +#: ../../admin/performance.rst:317 msgid "This can be very effective, but has the downside of being significant extra development cost. The Elgg team is looking to integrate this strategy into Elgg directly, since it is so effective especially on pages with repeated or hidden content." msgstr "" diff --git a/docs/locale/pot/appendix.pot b/docs/locale/pot/appendix.pot index 5ba2d8060b1..dfa6c77b7d0 100644 --- a/docs/locale/pot/appendix.pot +++ b/docs/locale/pot/appendix.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,6 +44,7 @@ msgstr "" #: ../../appendix/upgrade-notes/4.1-to-4.2.rst:6 #: ../../appendix/upgrade-notes/4.2-to-4.3.rst:6 #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:6 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:6 msgid "Contents" msgstr "" @@ -1364,26 +1365,34 @@ msgid "``upgrade``" msgstr "" #: ../../appendix/releases.rst:116 -msgid "Views" +msgid "Test suite" msgstr "" #: ../../appendix/releases.rst:118 +msgid "The Elgg PHPUnit test suite files are not considered part of the public API and can be changed / removed at any time." +msgstr "" + +#: ../../appendix/releases.rst:121 +msgid "Views" +msgstr "" + +#: ../../appendix/releases.rst:123 msgid "View names are API." msgstr "" -#: ../../appendix/releases.rst:119 +#: ../../appendix/releases.rst:124 msgid "View arguments ($vars array) are API." msgstr "" -#: ../../appendix/releases.rst:120 +#: ../../appendix/releases.rst:125 msgid "Removing views or renaming views follows API deprecation policies." msgstr "" -#: ../../appendix/releases.rst:121 +#: ../../appendix/releases.rst:126 msgid "Adding new views requires a minor version change." msgstr "" -#: ../../appendix/releases.rst:122 +#: ../../appendix/releases.rst:127 msgid "View output is not API and can be changed between patch releases." msgstr "" @@ -3440,6 +3449,7 @@ msgstr "" #: ../../appendix/upgrade-notes/2.1-to-2.2.rst:19 #: ../../appendix/upgrade-notes/2.2-to-2.3.rst:38 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:15 msgid "Deprecated Views" msgstr "" @@ -6807,6 +6817,7 @@ msgid "The legacy style hook and event callback arguments are deprecated. You sh msgstr "" #: ../../appendix/upgrade-notes/3.0-to-3.1.rst:76 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:22 msgid "Deprecated Routes" msgstr "" @@ -11345,7 +11356,7 @@ msgid "``elgg_register_plugin_hook_handler`` use ``elgg_register_event_handler`` msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:443 -msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_result``" +msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_results``" msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:444 @@ -11465,3 +11476,31 @@ msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:495 msgid "The ``REFERRER`` constant has been changed to a string with the value ``__elgg_referrer``" msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:2 +msgid "From 5.0 to 5.1" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:9 +msgid "Changes in the DOM structure" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:11 +msgid "In order to improve accessibility the HTML DOM structure has been changed slightly. Some sections of the page have been changed from a ``div`` to ``header``, ``main`` or ``footer``. The classes or place in the DOM has not been changed." +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:17 +msgid "``page/elements/
    /after`` is deprecated: Extend the correct ``page/elements/
    ``" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:18 +msgid "``page/elements/
    /before`` is deprecated: Prepend the correct ``page/elements/
    ``" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:19 +msgid "``resources/comments/edit`` is deprecated: This resource is no longer in use" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:24 +msgid "``edit:object:comment`` is deprecated: Editing comments uses an inline form" +msgstr "" diff --git a/docs/locale/pot/contribute.pot b/docs/locale/pot/contribute.pot index b2c9af50e1a..f708042d2e2 100644 --- a/docs/locale/pot/contribute.pot +++ b/docs/locale/pot/contribute.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1180,12 +1180,11 @@ msgid "Make a PR with translation updates" msgstr "" #: ../../contribute/core/releases.rst:75 -#: ../../contribute/core/releases.rst:113 msgid "Install the prerequisites:" msgstr "" #: ../../contribute/core/releases.rst:85 -#: ../../contribute/core/releases.rst:121 +#: ../../contribute/core/releases.rst:115 msgid "On Windows you need to run these command in a console with admin privileges" msgstr "" @@ -1217,196 +1216,196 @@ msgstr "" msgid "Visit ``https://github.com/Elgg/Elgg/compare/...`` and submit the PR if there is anything that needs to be merged up." msgstr "" -#: ../../contribute/core/releases.rst:123 +#: ../../contribute/core/releases.rst:117 msgid "Run the ``release.php`` script. For example, to release 1.12.5:" msgstr "" -#: ../../contribute/core/releases.rst:130 +#: ../../contribute/core/releases.rst:124 msgid "This creates a ``release-1.12.5`` branch in your local repo." msgstr "" -#: ../../contribute/core/releases.rst:132 +#: ../../contribute/core/releases.rst:126 msgid "Next, submit a pull request via GitHub for automated testing and approval by another developer:" msgstr "" -#: ../../contribute/core/releases.rst:139 +#: ../../contribute/core/releases.rst:133 msgid "Tag the release" msgstr "" -#: ../../contribute/core/releases.rst:141 +#: ../../contribute/core/releases.rst:135 msgid "Once approved and merged, create a release on GitHub:" msgstr "" -#: ../../contribute/core/releases.rst:143 +#: ../../contribute/core/releases.rst:137 msgid "Goto releases" msgstr "" -#: ../../contribute/core/releases.rst:144 +#: ../../contribute/core/releases.rst:138 msgid "Click 'Draft a new release'" msgstr "" -#: ../../contribute/core/releases.rst:145 +#: ../../contribute/core/releases.rst:139 msgid "Enter the version" msgstr "" -#: ../../contribute/core/releases.rst:146 +#: ../../contribute/core/releases.rst:140 msgid "Select the correct branch (eg 1.12 for a 1.12.x release, 2.3 for a 2.3.x release, etc)" msgstr "" -#: ../../contribute/core/releases.rst:147 +#: ../../contribute/core/releases.rst:141 msgid "Set the release title as 'Elgg {version}'" msgstr "" -#: ../../contribute/core/releases.rst:148 +#: ../../contribute/core/releases.rst:142 msgid "Paste the CHANGELOG.md part related to this release in the description" msgstr "" -#: ../../contribute/core/releases.rst:152 +#: ../../contribute/core/releases.rst:146 msgid "GitHub is setup to listen to the creation of a new release to automaticly make the ZIP release of Elgg. After the release was created wait a few minutes and the ZIP should be added to the release." msgstr "" -#: ../../contribute/core/releases.rst:155 +#: ../../contribute/core/releases.rst:149 msgid "Some final administration" msgstr "" -#: ../../contribute/core/releases.rst:157 +#: ../../contribute/core/releases.rst:151 msgid "Mark GitHub release milestones as completed" msgstr "" -#: ../../contribute/core/releases.rst:158 +#: ../../contribute/core/releases.rst:152 msgid "Move unresolved tickets in released milestones to later milestones" msgstr "" -#: ../../contribute/core/releases.rst:161 +#: ../../contribute/core/releases.rst:155 msgid "Additional actions for the first new minor / major" msgstr "" -#: ../../contribute/core/releases.rst:163 +#: ../../contribute/core/releases.rst:157 msgid "Make a new branch on GitHub (for example 3.3)" msgstr "" -#: ../../contribute/core/releases.rst:164 +#: ../../contribute/core/releases.rst:158 msgid "Set the new branch as the default branch (optional, but suggested for stable releases)" msgstr "" -#: ../../contribute/core/releases.rst:165 +#: ../../contribute/core/releases.rst:159 msgid "Configure `Read The Docs`_ to build the new branch (not the new tag)" msgstr "" -#: ../../contribute/core/releases.rst:166 +#: ../../contribute/core/releases.rst:160 msgid "Configure `Scrutinizer`_ to build the new branch" msgstr "" -#: ../../contribute/core/releases.rst:167 +#: ../../contribute/core/releases.rst:161 msgid "Check the Elgg starter project for potential requirement / config changes in the ``composer.json``" msgstr "" -#: ../../contribute/core/releases.rst:168 +#: ../../contribute/core/releases.rst:162 msgid "Add the new minor / major version to the ``Elgg/community_plugins`` repository so developers can upload plugins for the new release" msgstr "" -#: ../../contribute/core/releases.rst:169 +#: ../../contribute/core/releases.rst:163 msgid "Update the build configuration for the `Elgg reference`_ (on the Elgg.org webserver)" msgstr "" -#: ../../contribute/core/releases.rst:179 +#: ../../contribute/core/releases.rst:173 msgid "Additional action for the first new major" msgstr "" -#: ../../contribute/core/releases.rst:181 +#: ../../contribute/core/releases.rst:175 msgid "On GitHub add a branch protection rule (for example ``4.*``)" msgstr "" -#: ../../contribute/core/releases.rst:182 +#: ../../contribute/core/releases.rst:176 msgid "Configure Scrutinizer to track the new major branches (for example ``4.*``)" msgstr "" -#: ../../contribute/core/releases.rst:185 +#: ../../contribute/core/releases.rst:179 msgid "Update the website" msgstr "" -#: ../../contribute/core/releases.rst:188 +#: ../../contribute/core/releases.rst:182 msgid "Update elgg.org download page" msgstr "" -#: ../../contribute/core/releases.rst:190 +#: ../../contribute/core/releases.rst:184 msgid "Clone https://github.com/Elgg/community" msgstr "" -#: ../../contribute/core/releases.rst:191 +#: ../../contribute/core/releases.rst:185 msgid "Add the new version to ``classes/Elgg/Releases.php``" msgstr "" -#: ../../contribute/core/releases.rst:192 -#: ../../contribute/core/releases.rst:212 +#: ../../contribute/core/releases.rst:186 +#: ../../contribute/core/releases.rst:206 msgid "Commit and push the changes" msgstr "" -#: ../../contribute/core/releases.rst:193 +#: ../../contribute/core/releases.rst:187 msgid "Download the ZIP release from GitHub" msgstr "" -#: ../../contribute/core/releases.rst:194 +#: ../../contribute/core/releases.rst:188 msgid "Upload the ZIP to the elgg.org webserver" msgstr "" -#: ../../contribute/core/releases.rst:202 +#: ../../contribute/core/releases.rst:196 msgid "Update elgg.org" msgstr "" -#: ../../contribute/core/releases.rst:204 +#: ../../contribute/core/releases.rst:198 msgid "Clone https://github.com/Elgg/www.elgg.org" msgstr "" -#: ../../contribute/core/releases.rst:205 +#: ../../contribute/core/releases.rst:199 msgid "(optional) Change the required Elgg version in ``composer.json``" msgstr "" -#: ../../contribute/core/releases.rst:206 +#: ../../contribute/core/releases.rst:200 msgid "Update vendors" msgstr "" -#: ../../contribute/core/releases.rst:213 +#: ../../contribute/core/releases.rst:207 msgid "Pull to live site" msgstr "" -#: ../../contribute/core/releases.rst:222 +#: ../../contribute/core/releases.rst:216 msgid "Go to community admin panel" msgstr "" -#: ../../contribute/core/releases.rst:223 +#: ../../contribute/core/releases.rst:217 msgid "Flush APC cache" msgstr "" -#: ../../contribute/core/releases.rst:224 +#: ../../contribute/core/releases.rst:218 msgid "Run upgrade" msgstr "" -#: ../../contribute/core/releases.rst:227 +#: ../../contribute/core/releases.rst:221 msgid "Make the announcement" msgstr "" -#: ../../contribute/core/releases.rst:229 +#: ../../contribute/core/releases.rst:223 msgid "This should be the very last thing you do." msgstr "" -#: ../../contribute/core/releases.rst:231 +#: ../../contribute/core/releases.rst:225 msgid "Open ``https://github.com/Elgg/Elgg/blob//CHANGELOG.md`` and copy the contents for that version" msgstr "" -#: ../../contribute/core/releases.rst:232 +#: ../../contribute/core/releases.rst:226 msgid "Sign in at https://elgg.org/blog and compose a new blog with a summary" msgstr "" -#: ../../contribute/core/releases.rst:233 +#: ../../contribute/core/releases.rst:227 msgid "Copy in the CHANGELOG contents, clear formatting, and manually remove the SVG anchors" msgstr "" -#: ../../contribute/core/releases.rst:234 +#: ../../contribute/core/releases.rst:228 msgid "Add tags ``release`` and ``elgg2.x`` where x is whatever branch is being released" msgstr "" -#: ../../contribute/core/releases.rst:235 +#: ../../contribute/core/releases.rst:229 msgid "Tweet from the elgg `Twitter account`_" msgstr "" diff --git a/docs/locale/pot/design.pot b/docs/locale/pot/design.pot index cd712ec8dc7..37f62427886 100644 --- a/docs/locale/pot/design.pot +++ b/docs/locale/pot/design.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/docs/locale/pot/guides.pot b/docs/locale/pot/guides.pot index 08770df09fb..c8d3b07f14d 100644 --- a/docs/locale/pot/guides.pot +++ b/docs/locale/pot/guides.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -565,281 +565,289 @@ msgid "``input/userpicker`` - renders an Elgg user autocomplete" msgstr "" #: ../../guides/actions.rst:381 +msgid "``input/grouppicker`` - renders an Elgg group autocomplete" +msgstr "" + +#: ../../guides/actions.rst:382 +msgid "``input/objectpicker`` - renders an Elgg object autocomplete" +msgstr "" + +#: ../../guides/actions.rst:383 msgid "``input/location`` renders an Elgg location input" msgstr "" -#: ../../guides/actions.rst:384 +#: ../../guides/actions.rst:386 msgid "Files and images" msgstr "" -#: ../../guides/actions.rst:386 +#: ../../guides/actions.rst:388 msgid "Use the ``input/file`` view in your form’s content view." msgstr "" -#: ../../guides/actions.rst:393 +#: ../../guides/actions.rst:395 msgid "If you wish to upload an icon for entity you can use the helper view ``entity/edit/icon``. This view shows a file input for uploading a new icon for the entity, an thumbnail of the current icon and the option to remove the current icon." msgstr "" -#: ../../guides/actions.rst:397 +#: ../../guides/actions.rst:399 msgid "The view supports some variables to control the output" msgstr "" -#: ../../guides/actions.rst:399 +#: ../../guides/actions.rst:401 msgid "``entity`` - the entity to add/remove the icon for. If provided based on this entity the thumbnail and remove option wil be shown" msgstr "" -#: ../../guides/actions.rst:400 +#: ../../guides/actions.rst:402 msgid "``entity_type`` - the entity type for which the icon will be uploaded. Plugins could find this useful, maybe to validate icon sizes" msgstr "" -#: ../../guides/actions.rst:401 +#: ../../guides/actions.rst:403 msgid "``entity_subtype`` - the entity subtype for which the icon will be uploaded. Plugins could find this useful, maybe to validate icon sizes" msgstr "" -#: ../../guides/actions.rst:402 +#: ../../guides/actions.rst:404 msgid "``icon_type`` - the type of the icon (default: icon)" msgstr "" -#: ../../guides/actions.rst:403 +#: ../../guides/actions.rst:405 msgid "``name`` - name of the input/file (default: icon)" msgstr "" -#: ../../guides/actions.rst:404 +#: ../../guides/actions.rst:406 msgid "``remove_name`` - name of the remove icon toggle (default: $vars['name'] . '_remove')" msgstr "" -#: ../../guides/actions.rst:405 +#: ../../guides/actions.rst:407 msgid "``required`` - is icon upload required (default: false)" msgstr "" -#: ../../guides/actions.rst:406 +#: ../../guides/actions.rst:408 msgid "``cropper_enabled`` - is icon cropping allowed (default: true)" msgstr "" -#: ../../guides/actions.rst:407 +#: ../../guides/actions.rst:409 msgid "``show_remove`` - show the remove icon option (default: true)" msgstr "" -#: ../../guides/actions.rst:408 +#: ../../guides/actions.rst:410 msgid "``show_thumb`` - show the thumb of the entity if available (default: true)" msgstr "" -#: ../../guides/actions.rst:409 +#: ../../guides/actions.rst:411 msgid "``thumb_size`` - the icon size to use as the thumb (default: medium)" msgstr "" -#: ../../guides/actions.rst:411 +#: ../../guides/actions.rst:413 msgid "If using the helper view you can use the following code in you action to save the icon to the entity or remove the current icon." msgstr "" -#: ../../guides/actions.rst:421 +#: ../../guides/actions.rst:423 msgid "Set the enctype of the form to ``multipart/form-data``:" msgstr "" -#: ../../guides/actions.rst:431 +#: ../../guides/actions.rst:433 msgid "The ``enctype`` of all forms that use the method ``POST`` defaults to ``multipart/form-data``." msgstr "" -#: ../../guides/actions.rst:433 +#: ../../guides/actions.rst:435 msgid "In your action file, use ``elgg_get_uploaded_file('your-input-name')`` to access the uploaded file:" msgstr "" -#: ../../guides/actions.rst:440 +#: ../../guides/actions.rst:442 msgid "Sticky forms" msgstr "" -#: ../../guides/actions.rst:442 +#: ../../guides/actions.rst:444 msgid "Sticky forms are forms that retain user input if saving fails. They are \"sticky\" because the user's data \"sticks\" in the form after submitting, though it was never saved to the database. This greatly improves the user experience by minimizing data loss. Elgg includes helper functions so you can make any form sticky." msgstr "" -#: ../../guides/actions.rst:447 +#: ../../guides/actions.rst:449 #: ../../guides/helpers.rst:2 msgid "Helper functions" msgstr "" -#: ../../guides/actions.rst:449 +#: ../../guides/actions.rst:451 msgid "Sticky forms are implemented in Elgg by the following functions:" msgstr "" -#: ../../guides/actions.rst:451 +#: ../../guides/actions.rst:453 msgid "``elgg_make_sticky_form($name)`` - Tells the engine to make all input on a form sticky." msgstr "" -#: ../../guides/actions.rst:452 +#: ../../guides/actions.rst:454 msgid "``elgg_clear_sticky_form($name)`` - Tells the engine to discard all sticky input on a form." msgstr "" -#: ../../guides/actions.rst:453 +#: ../../guides/actions.rst:455 msgid "``elgg_is_sticky_form($name)`` - Checks if ``$name`` is a valid sticky form." msgstr "" -#: ../../guides/actions.rst:454 +#: ../../guides/actions.rst:456 msgid "``elgg_get_sticky_values($name)`` - Returns all sticky values saved for ``$name`` by ``elgg_make_sticky_form($name)``." msgstr "" -#: ../../guides/actions.rst:457 +#: ../../guides/actions.rst:459 #: ../../guides/ajax.rst:11 #: ../../guides/i18n.rst:15 #: ../../guides/plugins/dependencies.rst:11 msgid "Overview" msgstr "" -#: ../../guides/actions.rst:459 +#: ../../guides/actions.rst:461 msgid "The basic flow of using sticky forms is:" msgstr "" -#: ../../guides/actions.rst:461 +#: ../../guides/actions.rst:463 msgid "Call ``elgg_make_sticky_form($name)`` at the top of actions for forms you want to be sticky." msgstr "" -#: ../../guides/actions.rst:462 +#: ../../guides/actions.rst:464 msgid "Use ``elgg_is_sticky_form($name)`` and ``elgg_get_sticky_values($name)`` to get sticky values when rendering a form view." msgstr "" -#: ../../guides/actions.rst:463 +#: ../../guides/actions.rst:465 msgid "Call ``elgg_clear_sticky_form($name)`` after the action has completed successfully or after data has been loaded by ``elgg_get_sticky_values($name)``." msgstr "" -#: ../../guides/actions.rst:467 +#: ../../guides/actions.rst:469 msgid "As of Elgg 5.0 forms rendered with ``elgg_view_form()`` can set the ``$form_vars['sticky_enabled'] = true`` flag to automatically get sticky form support. The submitted values to the action will automatically be filled in the ``$body_vars`` when an error occured in the action." msgstr "" -#: ../../guides/actions.rst:470 +#: ../../guides/actions.rst:472 msgid "``elgg_view_form()`` supports the following ``$form_vars`` to help with sticky form support:" msgstr "" -#: ../../guides/actions.rst:472 +#: ../../guides/actions.rst:474 msgid "``sticky_enabled``: a ``bool`` to enable automatic sticky form support" msgstr "" -#: ../../guides/actions.rst:473 +#: ../../guides/actions.rst:475 msgid "``sticky_form_name``: an optional ``string`` to set where the sticky form values are saved. This defaults to the ``$action_name`` and should only be changed if the ``$action_name`` is different from the actual action" msgstr "" -#: ../../guides/actions.rst:474 +#: ../../guides/actions.rst:476 msgid "``sticky_ignored_fields: an ``array`` with the names fo the form fields that should be saved. For example password fields" msgstr "" -#: ../../guides/actions.rst:477 +#: ../../guides/actions.rst:479 msgid "Example: User registration" msgstr "" -#: ../../guides/actions.rst:479 +#: ../../guides/actions.rst:481 msgid "Simple sticky forms require little logic to determine the input values for the form. This logic is placed at the top of the form body view itself." msgstr "" -#: ../../guides/actions.rst:482 +#: ../../guides/actions.rst:484 msgid "The registration form view first sets default values for inputs, then checks if there are sticky values. If so, it loads the sticky values before clearing the sticky form:" msgstr "" -#: ../../guides/actions.rst:498 +#: ../../guides/actions.rst:500 msgid "The registration action sets creates the sticky form and clears it once the action is completed:" msgstr "" -#: ../../guides/actions.rst:516 +#: ../../guides/actions.rst:518 msgid "The function ``elgg_make_sticky_form()`` supports an optional second argument ``$ignored_field_names``. This needs to be an ``array`` of the field names you don't wish to be made sticky. This is usefull for fields which contain sensitive data, like passwords." msgstr "" -#: ../../guides/actions.rst:520 +#: ../../guides/actions.rst:522 msgid "Example: Bookmarks" msgstr "" -#: ../../guides/actions.rst:522 +#: ../../guides/actions.rst:524 msgid "The bundled plugin Bookmarks' save form and action is an example of a complex sticky form." msgstr "" -#: ../../guides/actions.rst:524 +#: ../../guides/actions.rst:526 msgid "The form view for the save bookmark action uses ``elgg_extract()`` to pull values from the ``$vars`` array:" msgstr "" -#: ../../guides/actions.rst:538 +#: ../../guides/actions.rst:540 msgid "The page handler scripts enables sticky form support by passing the correct values to ``elgg_view_form()``:" msgstr "" -#: ../../guides/actions.rst:545 +#: ../../guides/actions.rst:547 msgid "Similarly, ``mod/bookmarks/pages/edit.php`` uses the same sticky support, but passes the entity that is being edited:" msgstr "" -#: ../../guides/actions.rst:556 +#: ../../guides/actions.rst:558 msgid "The plugin has an event listener on the ``'form:prepare:fields', 'bookmarks/save'`` event and the handler does 2 things:" msgstr "" -#: ../../guides/actions.rst:558 +#: ../../guides/actions.rst:560 msgid "Defines the input names and default values for form inputs." msgstr "" -#: ../../guides/actions.rst:559 +#: ../../guides/actions.rst:561 msgid "Extracts the values from a bookmark object if it's passed." msgstr "" -#: ../../guides/actions.rst:606 +#: ../../guides/actions.rst:608 msgid "The save action doesn't need to do anything with sticky form support as this is all handled by the system." msgstr "" -#: ../../guides/actions.rst:609 +#: ../../guides/actions.rst:611 #: ../../guides/ajax.rst:2 -#: ../../guides/events-list.rst:862 +#: ../../guides/events-list.rst:868 msgid "Ajax" msgstr "" -#: ../../guides/actions.rst:611 +#: ../../guides/actions.rst:613 msgid "See the :doc:`Ajax guide` for instructions on calling actions from JavaScript." msgstr "" -#: ../../guides/actions.rst:614 +#: ../../guides/actions.rst:616 #: ../../guides/web-services.rst:27 msgid "Security" msgstr "" -#: ../../guides/actions.rst:616 +#: ../../guides/actions.rst:618 msgid "For enhanced security, all actions require an CSRF token. Calls to action URLs that do not include security tokens will be ignored and a warning will be generated." msgstr "" -#: ../../guides/actions.rst:619 +#: ../../guides/actions.rst:621 msgid "A few views and functions automatically generate security tokens:" msgstr "" -#: ../../guides/actions.rst:628 +#: ../../guides/actions.rst:630 msgid "In rare cases, you may need to generate tokens manually:" msgstr "" -#: ../../guides/actions.rst:635 +#: ../../guides/actions.rst:637 msgid "You can also access the tokens from javascript:" msgstr "" -#: ../../guides/actions.rst:642 +#: ../../guides/actions.rst:644 msgid "These are refreshed periodically so should always be up-to-date." msgstr "" -#: ../../guides/actions.rst:645 +#: ../../guides/actions.rst:647 msgid "Security Tokens" msgstr "" -#: ../../guides/actions.rst:647 +#: ../../guides/actions.rst:649 msgid "On occasion we need to pass data through an untrusted party or generate an \"unguessable token\" based on some data. The industry-standard `HMAC `_ algorithm is the right tool for this. It allows us to verify that received data were generated by our site, and were not tampered with. Note that even strong hash functions like SHA-2 should *not* be used without HMAC for these tasks." msgstr "" -#: ../../guides/actions.rst:652 +#: ../../guides/actions.rst:654 msgid "Elgg provides ``elgg_build_hmac()`` to generate and validate HMAC message authentication codes that are unguessable without the site's private key." msgstr "" -#: ../../guides/actions.rst:676 +#: ../../guides/actions.rst:678 msgid "Note: If you use a non-string as HMAC data, you must use types consistently. Consider the following:" msgstr "" -#: ../../guides/actions.rst:689 +#: ../../guides/actions.rst:691 msgid "Signed URLs" msgstr "" -#: ../../guides/actions.rst:691 +#: ../../guides/actions.rst:693 msgid "Signed URLs offer a limited level of security for situations where action tokens are not suitable, for example when sending a confirmation link via email. URL signatures verify that the URL has been generated by your Elgg installation (using site secret) and that the URL query elements were not tampered with." msgstr "" -#: ../../guides/actions.rst:695 +#: ../../guides/actions.rst:697 msgid "URLs a signed with an unguessable SHA-256 HMAC key. See `Security Tokens`_ for more details." msgstr "" -#: ../../guides/actions.rst:709 +#: ../../guides/actions.rst:711 msgid "Signed URLs do not offer CSRF protection and should not be used instead of action tokens." msgstr "" @@ -2097,7 +2105,7 @@ msgstr "" msgid "Allows plugins to register their own commands executable via ``elgg-cli`` binary. Handlers must return an array of command class names. Commands must extend ``\\Elgg\\Cli\\Command`` to be executable." msgstr "" -#: ../../guides/events-list.rst:42 +#: ../../guides/events-list.rst:48 msgid "**cron, ** |results|" msgstr "" @@ -2105,1971 +2113,1984 @@ msgstr "" msgid "Triggered by cron for each period." msgstr "" -#: ../../guides/events-list.rst:45 +#: ../../guides/events-list.rst:44 +#: ../../guides/events-list.rst:110 +#: ../../guides/events-list.rst:135 +#: ../../guides/events-list.rst:256 +#: ../../guides/events-list.rst:297 +#: ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:473 +#: ../../guides/events-list.rst:480 +#: ../../guides/events-list.rst:560 +#: ../../guides/events-list.rst:574 +#: ../../guides/events-list.rst:593 +msgid "The ``$params`` array will contain:" +msgstr "" + +#: ../../guides/events-list.rst:46 +msgid "``time`` - the timestamp of when the cron command was started" +msgstr "" + +#: ../../guides/events-list.rst:47 +msgid "``dt`` - the ``\\DateTime`` object of when the cron command was started" +msgstr "" + +#: ../../guides/events-list.rst:48 +msgid "``logger`` - instance of ``\\Elgg\\Logger\\Cron`` to log any information to the cron log" +msgstr "" + +#: ../../guides/events-list.rst:51 msgid "**cron:intervals, system** |results|" msgstr "" -#: ../../guides/events-list.rst:45 +#: ../../guides/events-list.rst:51 msgid "Allow the configuration of custom cron intervals" msgstr "" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "**deactivate, plugin**" msgstr "" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "Return false to prevent deactivation of the plugin." msgstr "" -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "**diagnostics:report, system** |results|" msgstr "" -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "Filter the output for the diagnostics report download." msgstr "" -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "**elgg.data, page** |results|" msgstr "" -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "Filters uncached, page-specific configuration data to pass to the client. :ref:`More info `" msgstr "" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "**elgg.data, site** |results|" msgstr "" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "Filters cached configuration data to pass to the client. :ref:`More info `" msgstr "" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "**format, friendly:title** |results|" msgstr "" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "Formats the \"friendly\" title for strings. This is used for generating URLs." msgstr "" -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "**format, friendly:time** |results|" msgstr "" -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "Formats the \"friendly\" time for the timestamp ``$params['time']``." msgstr "" -#: ../../guides/events-list.rst:67 +#: ../../guides/events-list.rst:73 msgid "**format, strip_tags** |results|" msgstr "" -#: ../../guides/events-list.rst:66 +#: ../../guides/events-list.rst:72 msgid "Filters a string to remove tags. The original string is passed as ``$params['original_string']`` and an optional set of allowed tags is passed as ``$params['allowed_tags']``." msgstr "" -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "**gc, system** |results|" msgstr "" -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "Allows plugins to run garbage collection for ``$params['period']``." msgstr "" -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "**generate, password** |results|" msgstr "" -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "Allows plugins to generate new random cleartext passwords." msgstr "" -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "**init:cookie, **" msgstr "" -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "Return false to override setting a cookie." msgstr "" -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "**init, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "Plugins tend to use this event for initialization (extending views, registering callbacks, etc.)" msgstr "" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "**languages, translations** |results|" msgstr "" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "Allows plugins to add/remove languages from the configurable languages in the system." msgstr "" -#: ../../guides/events-list.rst:86 +#: ../../guides/events-list.rst:92 msgid "**log, systemlog**" msgstr "" -#: ../../guides/events-list.rst:85 +#: ../../guides/events-list.rst:91 msgid "Called for all triggered events by ``system_log`` plugin. Used internally by ``Elgg\\SystemLog\\Logger::log()`` to populate the ``system_log`` table." msgstr "" -#: ../../guides/events-list.rst:91 +#: ../../guides/events-list.rst:97 msgid "**login_url, site** |results|" msgstr "" -#: ../../guides/events-list.rst:89 +#: ../../guides/events-list.rst:95 msgid "Filters site's login URL. ``$params`` array contains an array of query elements added to the login URL by the invoking script. The event must return an absolute URL of the login page." msgstr "" -#: ../../guides/events-list.rst:96 +#: ../../guides/events-list.rst:102 msgid "**output:before, page** |results|" msgstr "" -#: ../../guides/events-list.rst:94 +#: ../../guides/events-list.rst:100 msgid "In ``elgg_view_page()``, this filters ``$vars`` before it's passed to the page shell view (``page/``). To stop sending the X-Frame-Options header, unregister the handler ``Elgg\\Page\\SetXFrameOptionsHeaderHandler::class`` from this event." msgstr "" -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "**output, page** |results|" msgstr "" -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "In ``elgg_view_page()``, this filters the output return value." msgstr "" -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "**parameters, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:102 +#: ../../guides/events-list.rst:108 msgid "Triggered by ``elgg_view_menu()``. Used to change menu variables (like sort order) before rendering." msgstr "" -#: ../../guides/events-list.rst:104 -#: ../../guides/events-list.rst:129 -#: ../../guides/events-list.rst:250 -#: ../../guides/events-list.rst:291 -#: ../../guides/events-list.rst:324 -#: ../../guides/events-list.rst:467 -#: ../../guides/events-list.rst:474 -#: ../../guides/events-list.rst:554 -#: ../../guides/events-list.rst:568 -#: ../../guides/events-list.rst:587 -msgid "The ``$params`` array will contain:" -msgstr "" - -#: ../../guides/events-list.rst:106 +#: ../../guides/events-list.rst:112 msgid "``name`` - name of the menu" msgstr "" -#: ../../guides/events-list.rst:107 +#: ../../guides/events-list.rst:113 msgid "``sort_by`` - preferring sorting parameter" msgstr "" -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "other parameters passed to ``elgg_view_menu()``" msgstr "" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "**plugins_load, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "Triggered before the plugins are loaded. Rarely used. init, system is used instead. Can be used to load additional libraries." msgstr "" -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "**plugins_boot, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "Triggered just after the plugins are loaded. Rarely used. init, system is used instead." msgstr "" -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "**prepare, html** |results|" msgstr "" -#: ../../guides/events-list.rst:117 +#: ../../guides/events-list.rst:123 msgid "Triggered by ``elgg_format_html()`` and used to prepare untrusted HTML." msgstr "" -#: ../../guides/events-list.rst:119 +#: ../../guides/events-list.rst:125 msgid "The ``$return`` value is an array:" msgstr "" -#: ../../guides/events-list.rst:121 +#: ../../guides/events-list.rst:127 msgid "``html`` - HTML string being prepared" msgstr "" -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "``options`` - Preparation options" msgstr "" -#: ../../guides/events-list.rst:134 +#: ../../guides/events-list.rst:140 msgid "**prepare, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:125 +#: ../../guides/events-list.rst:131 msgid "Filters the array of menu sections before they're displayed. Each section is a string key mapping to an area of menu items. This is a good event to sort, add, remove, and modify menu items. Triggered by ``elgg_view_menu()`` and ``elgg()->menus->prepareMenu()``." msgstr "" -#: ../../guides/events-list.rst:131 +#: ../../guides/events-list.rst:137 msgid "``selected_item`` - ``ElggMenuItem`` selected in the menu, if any" msgstr "" -#: ../../guides/events-list.rst:133 +#: ../../guides/events-list.rst:139 msgid "The return value is an instance of ``\\Elgg\\Menu\\PreparedMenu``. The prepared menu is a collection of ``\\Elgg\\Menu\\MenuSection``, which in turn are collections of ``\\ElggMenuItem`` objects." msgstr "" -#: ../../guides/events-list.rst:142 +#: ../../guides/events-list.rst:148 msgid "**prepare, menu:::** |results|" msgstr "" -#: ../../guides/events-list.rst:137 +#: ../../guides/events-list.rst:143 msgid "More granular version of the menu event triggered before the **prepare, menu:** event." msgstr "" -#: ../../guides/events-list.rst:139 -#: ../../guides/events-list.rst:168 +#: ../../guides/events-list.rst:145 +#: ../../guides/events-list.rst:174 msgid "Only applied if menu params contain - params['entity'] with an ``\\ElggEntity`` (```` is ``\\ElggEntity::type`` and ```` is ``\\ElggEntity::subtype``) or - params['annotation'] with an ``\\ElggAnnotation`` (```` is ``\\ElggAnnotation::getType()`` and ```` is ``\\ElggAnnotation::getSubtype()``) or - params['relationship'] with an ``\\ElggRelationship`` (```` is ``\\ElggRelationship::getType()`` and ```` is ``\\ElggRelationship::getSubtype()``)" msgstr "" -#: ../../guides/events-list.rst:146 +#: ../../guides/events-list.rst:152 msgid "**ready, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:145 +#: ../../guides/events-list.rst:151 msgid "Triggered after the ``init, system`` event. All plugins are fully loaded and the engine is ready to serve pages." msgstr "" -#: ../../guides/events-list.rst:150 +#: ../../guides/events-list.rst:156 msgid "**regenerate_site_secret:before, system**" msgstr "" -#: ../../guides/events-list.rst:149 +#: ../../guides/events-list.rst:155 msgid "Return false to cancel regenerating the site secret. You should also provide a message to the user." msgstr "" -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "**regenerate_site_secret:after, system**" msgstr "" -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "Triggered after the site secret has been regenerated." msgstr "" -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "**register, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:156 +#: ../../guides/events-list.rst:162 msgid "Filters the initial list of menu items pulled from configuration, before the menu has been split into sections. Triggered by ``elgg_view_menu()`` and ``elgg()->menus->getMenu()``." msgstr "" -#: ../../guides/events-list.rst:159 +#: ../../guides/events-list.rst:165 msgid "The ``$params`` array will contain parameters returned by ``parameters, menu:`` event." msgstr "" -#: ../../guides/events-list.rst:161 +#: ../../guides/events-list.rst:167 msgid "The return value is an instance of ``\\Elgg\\Menu\\MenuItems`` containing ``\\ElggMenuItem`` objects." msgstr "" -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "Event handlers can add/remove items to the collection using the collection API, as well as array access operations." msgstr "" -#: ../../guides/events-list.rst:171 +#: ../../guides/events-list.rst:177 msgid "**register, menu:::** |results|" msgstr "" -#: ../../guides/events-list.rst:166 +#: ../../guides/events-list.rst:172 msgid "More granular version of the menu event triggered before the **register, menu:** event." msgstr "" -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "**register, menu:filter:** |results|" msgstr "" -#: ../../guides/events-list.rst:174 +#: ../../guides/events-list.rst:180 msgid "Allows plugins to modify layout filter tabs on layouts that specify ```` parameter. Parameters and return values are same as in ``register, menu:`` event." msgstr "" -#: ../../guides/events-list.rst:177 +#: ../../guides/events-list.rst:183 msgid "If ``filter_id`` is ``filter`` (the default) then the ``all``, ``mine`` and ``friends`` tabs will be generated base on some provided information or be tried for routes similar to the current route." msgstr "" -#: ../../guides/events-list.rst:180 +#: ../../guides/events-list.rst:186 msgid "params['all_link'] will be used for the ``all`` tab" msgstr "" -#: ../../guides/events-list.rst:181 +#: ../../guides/events-list.rst:187 msgid "params['mine_link'] will be used for the ``mine`` tab" msgstr "" -#: ../../guides/events-list.rst:182 +#: ../../guides/events-list.rst:188 msgid "params['friends_link'] will be used for the ``friend`` tab" msgstr "" -#: ../../guides/events-list.rst:184 +#: ../../guides/events-list.rst:190 msgid "If the above are not provided than a route will be tried based on ``params['entity_type']`` and ``params['entity_subtype']``. If not provided ``entity_type`` and ``entity_subtype`` will be based on route detection of the current route. For example if the current route is ``collection:object:blog:all`` ``entity_type`` will be ``object`` and ``entity_subtype`` will be ``blog``. - The ``all`` tab will be based on the route ``collection:::all`` - The ``mine`` tab will be based on the route ``collection:::owner`` - The ``friend`` tab will be based on the route ``collection:::friends``" msgstr "" -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "If the routes aren't registered the tabs will not appear." msgstr "" -#: ../../guides/events-list.rst:196 +#: ../../guides/events-list.rst:202 msgid "**registration_url, site** |results|" msgstr "" -#: ../../guides/events-list.rst:194 +#: ../../guides/events-list.rst:200 msgid "Filters site's registration URL. Can be used by plugins to attach invitation codes, referrer codes etc. to the registration URL. ``$params`` array contains an array of query elements added to the registration URL by the invoking script. The event must return an absolute URL to the registration page." msgstr "" -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "**reload:after, translations**" msgstr "" -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "Triggered after the translations are (re)loaded." msgstr "" -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "**sanitize, input** |results|" msgstr "" -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "Filter GET and POST input. This is used by ``get_input()`` to sanitize user input." msgstr "" -#: ../../guides/events-list.rst:206 +#: ../../guides/events-list.rst:212 msgid "**seeds, database** |results|" msgstr "" -#: ../../guides/events-list.rst:205 +#: ../../guides/events-list.rst:211 msgid "Allows plugins to register their own database seeds. Seeds populate the database with fake entities for testing purposes. Seeds must extend ``\\Elgg\\Database\\Seeds\\Seed`` class to be executable via ``elgg-cli database:seed``." msgstr "" -#: ../../guides/events-list.rst:210 +#: ../../guides/events-list.rst:216 msgid "**send:before, http_response**" msgstr "" -#: ../../guides/events-list.rst:209 +#: ../../guides/events-list.rst:215 msgid "Triggered before an HTTP response is sent. Handlers will receive an instance of `\\Symfony\\Component\\HttpFoundation\\Response` that is to be sent to the requester. Handlers can terminate the event and prevent the response from being sent by returning `false`." msgstr "" -#: ../../guides/events-list.rst:214 +#: ../../guides/events-list.rst:220 msgid "**send:after, http_response**" msgstr "" -#: ../../guides/events-list.rst:213 +#: ../../guides/events-list.rst:219 msgid "Triggered after an HTTP response is sent. Handlers will receive an instance of `\\Symfony\\Component\\HttpFoundation\\Response` that was sent to the requester." msgstr "" -#: ../../guides/events-list.rst:218 +#: ../../guides/events-list.rst:224 msgid "**shutdown, system**" msgstr "" -#: ../../guides/events-list.rst:217 +#: ../../guides/events-list.rst:223 msgid "Triggered after the page has been sent to the user. Expensive operations could be done here and not make the user wait." msgstr "" -#: ../../guides/events-list.rst:220 +#: ../../guides/events-list.rst:226 msgid "Depending upon your server configuration the PHP output might not be shown until after the process is completed. This means that any long-running processes will still delay the page load." msgstr "" -#: ../../guides/events-list.rst:224 +#: ../../guides/events-list.rst:230 msgid "This event is prefered above using ``register_shutdown_function`` as you may not have access to all the Elgg services (eg. database) in the shutdown function but you will in the event." msgstr "" -#: ../../guides/events-list.rst:227 +#: ../../guides/events-list.rst:233 msgid "The Elgg session is already closed before this event. Manipulating session is not possible." msgstr "" -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "**simplecache:generate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "Filters the view output for a ``/cache`` URL when simplecache is enabled." msgstr "" -#: ../../guides/events-list.rst:234 +#: ../../guides/events-list.rst:240 msgid "**upgrade, system**" msgstr "" -#: ../../guides/events-list.rst:233 +#: ../../guides/events-list.rst:239 msgid "Triggered after a system upgrade has finished. All upgrade scripts have run, but the caches are not cleared." msgstr "" -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "**upgrade:execute, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "Triggered when executing an ``ElggUpgrade``. The ``$object`` of the event is the ``ElggUpgrade``." msgstr "" -#: ../../guides/events-list.rst:240 +#: ../../guides/events-list.rst:246 msgid "User events" msgstr "" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "**ban, user**" msgstr "" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "Triggered before a user is banned. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:254 +#: ../../guides/events-list.rst:260 msgid "**change:email, user** |results|" msgstr "" -#: ../../guides/events-list.rst:246 +#: ../../guides/events-list.rst:252 msgid "Triggered before the user email is changed. Allows plugins to implement additional logic required to change email, e.g. additional email validation. The event handler must return false to prevent the email from being changed right away." msgstr "" -#: ../../guides/events-list.rst:252 -#: ../../guides/events-list.rst:326 +#: ../../guides/events-list.rst:258 +#: ../../guides/events-list.rst:332 msgid "``user`` - ``\\ElggUser``, whose settings are being saved" msgstr "" -#: ../../guides/events-list.rst:253 +#: ../../guides/events-list.rst:259 msgid "``email`` - Email address that passes sanity checks" msgstr "" -#: ../../guides/events-list.rst:254 -#: ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:333 msgid "``request`` - ``\\Elgg\\Request`` to the action controller" msgstr "" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "**invalidate:after, user**" msgstr "" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "Triggered when user's account validation has been revoked." msgstr "" -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "**login:after, user**" msgstr "" -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "Triggered after the user logs in." msgstr "" -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "**login:before, user**" msgstr "" -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "Triggered during login. Returning false prevents the user from logging" msgstr "" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "**login:forward, user** |results|" msgstr "" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "Filters the URL to which the user will be forwarded after login." msgstr "" -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "**login:first, user**" msgstr "" -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "Triggered after a successful login. Only if there is no previous login." msgstr "" -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "**logout:after, user**" msgstr "" -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "Triggered after the user logouts." msgstr "" -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "**logout:before, user**" msgstr "" -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "Triggered during logout. Returning false should prevent the user from logging out." msgstr "" -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "**make_admin, user**" msgstr "" -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "Triggered before a user is promoted to an admin. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "**profileiconupdate, user**" msgstr "" -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "User has changed profile icon" msgstr "" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "**profileupdate, user**" msgstr "" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "User has changed profile" msgstr "" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "**register, user** |results|" msgstr "" -#: ../../guides/events-list.rst:287 +#: ../../guides/events-list.rst:293 msgid "Triggered by the ``register`` action after the user registers. Return ``false`` to delete the user. Note the function ``register_user`` does *not* trigger this event. Event handlers can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be displayed to the user." msgstr "" -#: ../../guides/events-list.rst:293 +#: ../../guides/events-list.rst:299 msgid "``user`` - Newly registered user entity" msgstr "" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "All parameters sent with the request to the action (incl. ``password``, ``friend_guid``, ``invitecode`` etc)" msgstr "" -#: ../../guides/events-list.rst:298 +#: ../../guides/events-list.rst:304 msgid "**registeruser:validate:email, all** |results|" msgstr "" -#: ../../guides/events-list.rst:297 +#: ../../guides/events-list.rst:303 msgid "Return boolean for if the string in ``$params['email']`` is valid for an email address. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:302 +#: ../../guides/events-list.rst:308 msgid "**registeruser:validate:password, all** |results|" msgstr "" -#: ../../guides/events-list.rst:301 +#: ../../guides/events-list.rst:307 msgid "Return boolean for if the string in ``$params['password']`` is valid for a password. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:306 +#: ../../guides/events-list.rst:312 msgid "**registeruser:validate:username, all** |results|" msgstr "" -#: ../../guides/events-list.rst:305 +#: ../../guides/events-list.rst:311 msgid "Return boolean for if the string in ``$params['username']`` is valid for a username. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "**remove_admin, user**" msgstr "" -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "Triggered before a user is demoted from an admin. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "**unban, user**" msgstr "" -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "Triggered before a user is unbanned. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:317 +#: ../../guides/events-list.rst:323 msgid "**username:character_blacklist, user** |results|" msgstr "" -#: ../../guides/events-list.rst:315 +#: ../../guides/events-list.rst:321 msgid "Filters the string of blacklisted characters used to validate username during registration. The return value should be a string consisting of the disallowed characters. The default string can be found from ``$params['blacklist']``." msgstr "" -#: ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:333 msgid "**usersettings:save, user** |results|" msgstr "" -#: ../../guides/events-list.rst:320 +#: ../../guides/events-list.rst:326 msgid "Triggered in the aggregate action to save user settings. The event handler must return ``false`` to prevent sticky forms from being cleared (i.e. to indicate that some of the values were not saved). Do not return ``true`` from your event handler, as you will override other events' output, instead return ``null`` to indicate successful operation." msgstr "" -#: ../../guides/events-list.rst:332 +#: ../../guides/events-list.rst:338 msgid "**validate, user**" msgstr "" -#: ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:336 msgid "When a user registers, the user's account is disabled. This event is triggered to allow a plugin to determine how the user should be validated (for example, through an email with a validation link)." msgstr "" -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "**validate:after, user**" msgstr "" -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "Triggered when user's account has been validated." msgstr "" -#: ../../guides/events-list.rst:338 +#: ../../guides/events-list.rst:344 msgid "Relationship events" msgstr "" -#: ../../guides/events-list.rst:342 +#: ../../guides/events-list.rst:348 msgid "**create, relationship**" msgstr "" -#: ../../guides/events-list.rst:341 +#: ../../guides/events-list.rst:347 msgid "Triggered after a relationship has been created. Returning false deletes the relationship that was just created." msgstr "" -#: ../../guides/events-list.rst:346 +#: ../../guides/events-list.rst:352 msgid "**delete, relationship**" msgstr "" -#: ../../guides/events-list.rst:345 +#: ../../guides/events-list.rst:351 msgid "Triggered before a relationship is deleted. Return false to prevent it from being deleted." msgstr "" -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "**join, group**" msgstr "" -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "Triggered after the user ``$params['user']`` has joined the group ``$params['group']``." msgstr "" -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "**leave, group**" msgstr "" -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "Triggered before the user ``$params['user']`` has left the group ``$params['group']``." msgstr "" -#: ../../guides/events-list.rst:355 +#: ../../guides/events-list.rst:361 msgid "Entity events" msgstr "" -#: ../../guides/events-list.rst:359 +#: ../../guides/events-list.rst:365 msgid "**comments, ** |results|" msgstr "" -#: ../../guides/events-list.rst:358 +#: ../../guides/events-list.rst:364 msgid "Triggered in ``elgg_view_comments()``. If returning content, this overrides the ``page/elements/comments`` view." msgstr "" -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "**comments:count, ** |results|" msgstr "" -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "Return the number of comments on ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:366 +#: ../../guides/events-list.rst:372 msgid "**create, **" msgstr "" -#: ../../guides/events-list.rst:365 +#: ../../guides/events-list.rst:371 msgid "Triggered for user, group, object, and site entities after creation. Triggered just before the ``create:after`` event, mostly for BC reasons. The use of the ``create:after`` event is preferred." msgstr "" -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "**create:after, **" msgstr "" -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "Triggered for user, group, object, and site entities after creation." msgstr "" -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "**create:before, **" msgstr "" -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "Triggered for user, group, object, and site entities before creation. Return false to prevent creating the entity." msgstr "" -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "**delete, **" msgstr "" -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "Triggered before entity deletion." msgstr "" -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "**delete:after, **" msgstr "" -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "Triggered after entity deletion." msgstr "" -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "**delete:before, **" msgstr "" -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "Triggered before entity deletion. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "**disable, **" msgstr "" -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "Triggered before the entity is disabled. Return false to prevent disabling." msgstr "" -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "**disable:after, **" msgstr "" -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "Triggered after the entity is disabled." msgstr "" -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "**enable, **" msgstr "" -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "Return false to prevent enabling." msgstr "" -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "**enable:after, **" msgstr "" -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "Triggered after the entity is enabled." msgstr "" -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "**likes:count, ** |results|" msgstr "" -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "Return the number of likes for ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:401 +#: ../../guides/events-list.rst:407 msgid "**update, **" msgstr "" -#: ../../guides/events-list.rst:399 +#: ../../guides/events-list.rst:405 msgid "Triggered before an update for the user, group, object, and site entities. Return false to prevent update. The entity method ``getOriginalAttributes()`` can be used to identify which attributes have changed since the entity was last saved." msgstr "" -#: ../../guides/events-list.rst:406 +#: ../../guides/events-list.rst:412 msgid "**update:after, **" msgstr "" -#: ../../guides/events-list.rst:404 +#: ../../guides/events-list.rst:410 msgid "Triggered after an update for the user, group, object, and site entities. The entity method ``getOriginalAttributes()`` can be used to identify which attributes have changed since the entity was last saved." msgstr "" -#: ../../guides/events-list.rst:409 +#: ../../guides/events-list.rst:415 msgid "Metadata events" msgstr "" -#: ../../guides/events-list.rst:413 +#: ../../guides/events-list.rst:419 msgid "**create, metadata**" msgstr "" -#: ../../guides/events-list.rst:412 +#: ../../guides/events-list.rst:418 msgid "Called after the metadata has been created. Return false to delete the metadata that was just created." msgstr "" -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "**delete, metadata**" msgstr "" -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "Called before metadata is deleted. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "**update, metadata**" msgstr "" -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "Called after the metadata has been updated. Return false to *delete the metadata.*" msgstr "" -#: ../../guides/events-list.rst:422 +#: ../../guides/events-list.rst:428 msgid "Annotation events" msgstr "" -#: ../../guides/events-list.rst:426 +#: ../../guides/events-list.rst:432 msgid "**annotate, **" msgstr "" -#: ../../guides/events-list.rst:425 +#: ../../guides/events-list.rst:431 msgid "Called before the annotation has been created. Return false to prevent annotation of this entity." msgstr "" -#: ../../guides/events-list.rst:430 +#: ../../guides/events-list.rst:436 msgid "**create, annotation**" msgstr "" -#: ../../guides/events-list.rst:429 +#: ../../guides/events-list.rst:435 msgid "Called after the annotation has been created. Return false to delete the annotation." msgstr "" -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "**delete, annotation**" msgstr "" -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "Called before annotation is deleted. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "**disable, annotations**" msgstr "" -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "Called when disabling annotations. Return false to prevent disabling." msgstr "" -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "**enable, annotation**" msgstr "" -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "Called when enabling annotations. Return false to prevent enabling." msgstr "" -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "**update, annotation**" msgstr "" -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "Called after the annotation has been updated. Return false to *delete the annotation.*" msgstr "" -#: ../../guides/events-list.rst:445 +#: ../../guides/events-list.rst:451 msgid "River events" msgstr "" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "**create:after, river**" msgstr "" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "Called after a river item is created." msgstr "" -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "**create:before, river**" msgstr "" -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "Called before the river item is saved to the database. Return ``false`` to prevent the item from being created." msgstr "" -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "**delete:after, river**" msgstr "" -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "Triggered after a river item was deleted." msgstr "" -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "**delete:before, river**" msgstr "" -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "Triggered before a river item is deleted. Returning false cancels the deletion." msgstr "" -#: ../../guides/events-list.rst:462 +#: ../../guides/events-list.rst:468 msgid "Access events" msgstr "" -#: ../../guides/events-list.rst:469 +#: ../../guides/events-list.rst:475 msgid "**access_collection:url, access_collection** |results|" msgstr "" -#: ../../guides/events-list.rst:465 +#: ../../guides/events-list.rst:471 msgid "Can be used to filter the URL of the access collection." msgstr "" -#: ../../guides/events-list.rst:469 -#: ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:475 +#: ../../guides/events-list.rst:482 msgid "``access_collection`` - `ElggAccessCollection`" msgstr "" -#: ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:482 msgid "**access_collection:name, access_collection** |results|" msgstr "" -#: ../../guides/events-list.rst:472 +#: ../../guides/events-list.rst:478 msgid "Can be used to filter the display name (readable access level) of the access collection." msgstr "" -#: ../../guides/events-list.rst:483 +#: ../../guides/events-list.rst:489 msgid "**access:collections:read, user** |results|" msgstr "" -#: ../../guides/events-list.rst:479 +#: ../../guides/events-list.rst:485 msgid "Filters an array of access IDs that the user ``$params['user_id']`` can see." msgstr "" -#: ../../guides/events-list.rst:482 -#: ../../guides/events-list.rst:494 +#: ../../guides/events-list.rst:488 +#: ../../guides/events-list.rst:500 msgid "The handler needs to either not use parts of the API that use the access system (triggering the event again) or to ignore the second call. Otherwise, an infinite loop will be created." msgstr "" -#: ../../guides/events-list.rst:495 +#: ../../guides/events-list.rst:501 msgid "**access:collections:write, user** |results|" msgstr "" -#: ../../guides/events-list.rst:486 +#: ../../guides/events-list.rst:492 msgid "Filters an array of access IDs that the user ``$params['user_id']`` can write to. In ``elgg_get_write_access_array()``, this event filters the return value, so it can be used to alter the available options in the ``input/access`` view. For core plugins, the value \"input_params\" has the keys \"entity\" (ElggEntity|false), \"entity_type\" (string), \"entity_subtype\" (string), \"container_guid\" (int) are provided. An empty entity value generally means the form is to create a new object." msgstr "" -#: ../../guides/events-list.rst:499 +#: ../../guides/events-list.rst:505 msgid "**access:collections:write:subtypes, user** |results|" msgstr "" -#: ../../guides/events-list.rst:498 +#: ../../guides/events-list.rst:504 msgid "Returns an array of access collection subtypes to be used when retrieving access collections owned by a user as part of the ``elgg_get_write_access_array()`` function." msgstr "" -#: ../../guides/events-list.rst:503 +#: ../../guides/events-list.rst:509 msgid "**access:collections:add_user, collection** |results|" msgstr "" -#: ../../guides/events-list.rst:502 +#: ../../guides/events-list.rst:508 msgid "Triggered before adding user ``$params['user_id']`` to collection ``$params['collection_id']``. Return false to prevent adding." msgstr "" -#: ../../guides/events-list.rst:507 +#: ../../guides/events-list.rst:513 msgid "**access:collections:remove_user, collection** |results|" msgstr "" -#: ../../guides/events-list.rst:506 +#: ../../guides/events-list.rst:512 msgid "Triggered before removing user ``$params['user_id']`` to collection ``$params['collection_id']``. Return false to prevent removal." msgstr "" -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "**create, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "Triggered during the creation of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "**delete, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "Triggered during the deletion of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "**get_sql, access** |results|" msgstr "" -#: ../../guides/events-list.rst:516 +#: ../../guides/events-list.rst:522 msgid "Filters SQL clauses restricting/allowing access to entities and annotations." msgstr "" -#: ../../guides/events-list.rst:519 +#: ../../guides/events-list.rst:525 msgid "**The event is triggered regardless if the access is ignored**. The handlers may need to check if access is ignored and return early, if appended clauses should only apply to access controlled contexts." msgstr "" -#: ../../guides/events-list.rst:523 +#: ../../guides/events-list.rst:529 msgid "``$return`` value is a nested array of ``ands`` and ``ors``." msgstr "" -#: ../../guides/events-list.rst:525 +#: ../../guides/events-list.rst:531 msgid "``$params`` includes:" msgstr "" -#: ../../guides/events-list.rst:527 +#: ../../guides/events-list.rst:533 msgid "``table_alias`` - alias of the main table used in select clause" msgstr "" -#: ../../guides/events-list.rst:528 +#: ../../guides/events-list.rst:534 msgid "``ignore_access`` - whether ignored access is enabled" msgstr "" -#: ../../guides/events-list.rst:529 +#: ../../guides/events-list.rst:535 msgid "``use_enabled_clause`` - whether disabled entities are shown/hidden" msgstr "" -#: ../../guides/events-list.rst:530 +#: ../../guides/events-list.rst:536 msgid "``access_column`` - column in the main table containing the access collection ID value" msgstr "" -#: ../../guides/events-list.rst:531 +#: ../../guides/events-list.rst:537 msgid "``owner_guid_column`` - column in the main table referencing the GUID of the owner" msgstr "" -#: ../../guides/events-list.rst:532 +#: ../../guides/events-list.rst:538 msgid "``guid_column`` - column in the main table referencing the GUID of the entity" msgstr "" -#: ../../guides/events-list.rst:533 +#: ../../guides/events-list.rst:539 msgid "``enabled_column`` - column in the main table referencing the enabled status of the entity" msgstr "" -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "``query_builder`` - an instance of the ``QueryBuilder``" msgstr "" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "**update, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "Triggered during the update of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:542 +#: ../../guides/events-list.rst:548 msgid "Permission events" msgstr "" -#: ../../guides/events-list.rst:558 +#: ../../guides/events-list.rst:564 msgid "**container_logic_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:545 +#: ../../guides/events-list.rst:551 msgid "Triggered by ``ElggEntity:canWriteToContainer()`` before triggering ``permissions_check`` and ``container_permissions_check`` events. Unlike permissions events, logic check can be used to prevent certain entity types from being contained by other entity types, e.g. discussion replies should only be contained by discussions. This event can also be used to apply status logic, e.g. do disallow new replies for closed discussions." msgstr "" -#: ../../guides/events-list.rst:550 +#: ../../guides/events-list.rst:556 msgid "The handler should return ``false`` to prevent an entity from containing another entity. The default value passed to the event is ``null``, so the handler can check if another event has modified the value by checking if return value is set. Should this event return ``false``, ``container_permissions_check`` and ``permissions_check`` events will not be triggered." msgstr "" -#: ../../guides/events-list.rst:556 -#: ../../guides/events-list.rst:570 +#: ../../guides/events-list.rst:562 +#: ../../guides/events-list.rst:576 msgid "``container`` - An entity that will be used as a container" msgstr "" -#: ../../guides/events-list.rst:557 -#: ../../guides/events-list.rst:571 +#: ../../guides/events-list.rst:563 +#: ../../guides/events-list.rst:577 msgid "``user`` - User who will own the entity to be written to container" msgstr "" -#: ../../guides/events-list.rst:558 -#: ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:564 +#: ../../guides/events-list.rst:578 msgid "``subtype`` - Subtype of the entity to be written to container (entity type is assumed from event type)" msgstr "" -#: ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:578 msgid "**container_permissions_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:561 +#: ../../guides/events-list.rst:567 msgid "Return boolean for if the user ``$params['user']`` can use the entity ``$params['container']`` as a container for an entity of ```` and subtype ``$params['subtype']``." msgstr "" -#: ../../guides/events-list.rst:564 +#: ../../guides/events-list.rst:570 msgid "In the rare case where an entity is created with neither the ``container_guid`` nor the ``owner_guid`` matching the logged in user, this event is called *twice*, and in the first call ``$params['container']`` will be the *owner*, not the entity's real container." msgstr "" -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "**permissions_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "Return boolean for if the user ``$params['user']`` can edit the entity ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "**permissions_check:delete, ** |results|" msgstr "" -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "Return boolean for if the user ``$params['user']`` can delete the entity ``$params['entity']``. Defaults to ``$entity->canEdit()``." msgstr "" -#: ../../guides/events-list.rst:582 +#: ../../guides/events-list.rst:588 msgid "**permissions_check:delete, river** |results|" msgstr "" -#: ../../guides/events-list.rst:581 +#: ../../guides/events-list.rst:587 msgid "Return boolean for if the user ``$params['user']`` can delete the river item ``$params['item']``. Defaults to ``true`` for admins and ``false`` for other users." msgstr "" -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "**permissions_check:download, file** |results|" msgstr "" -#: ../../guides/events-list.rst:585 +#: ../../guides/events-list.rst:591 msgid "Return boolean for if the user ``$params['user']`` can download the file in ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:589 +#: ../../guides/events-list.rst:595 msgid "``entity`` - Instance of ``ElggFile``" msgstr "" -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "``user`` - User who will download the file" msgstr "" -#: ../../guides/events-list.rst:594 +#: ../../guides/events-list.rst:600 msgid "**permissions_check, widget_layout** |results|" msgstr "" -#: ../../guides/events-list.rst:593 +#: ../../guides/events-list.rst:599 msgid "Return boolean for if ``$params['user']`` can edit the widgets in the context passed as ``$params['context']`` and with a page owner of ``$params['page_owner']``." msgstr "" -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "**permissions_check:comment, ** |results|" msgstr "" -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "Return boolean for if the user ``$params['user']`` can comment on the entity ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "**permissions_check:annotate:, ** |results|" msgstr "" -#: ../../guides/events-list.rst:600 +#: ../../guides/events-list.rst:606 msgid "Return boolean for if the user ``$params['user']`` can create an annotation ```` on the entity ``$params['entity']``. If logged in, the default is true." msgstr "" -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "This is called before the more general ``permissions_check:annotate`` event, and its return value is that event's initial value." msgstr "" -#: ../../guides/events-list.rst:607 +#: ../../guides/events-list.rst:613 msgid "**permissions_check:annotate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:606 +#: ../../guides/events-list.rst:612 msgid "Return boolean for if the user ``$params['user']`` can create an annotation ``$params['annotation_name']`` on the entity ``$params['entity']``. if logged in, the default is true." msgstr "" -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "**api_key, use** |results|" msgstr "" -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "Triggered in the class ``\\Elgg\\WebServices\\PAM\\API\\APIKey``. Returning false prevents the key from being authenticated." msgstr "" -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "**gatekeeper, :** |results|" msgstr "" -#: ../../guides/events-list.rst:613 +#: ../../guides/events-list.rst:619 msgid "Filters the result of ``elgg_entity_gatekeeper()`` to prevent or allow access to an entity that user would otherwise have or not have access to. A handler can return ``false`` or an instance of ``\\Elgg\\Exceptions\\HttpException`` to prevent access to an entity. A handler can return ``true`` to override the result of the gatekeeper. **Important** that the entity received by this event is fetched with ignored access and including disabled entities, so you have to be careful to not bypass the access system." msgstr "" -#: ../../guides/events-list.rst:619 -#: ../../guides/events-list.rst:640 -#: ../../guides/events-list.rst:654 -#: ../../guides/events-list.rst:674 -#: ../../guides/events-list.rst:729 -#: ../../guides/events-list.rst:737 -#: ../../guides/events-list.rst:790 -#: ../../guides/events-list.rst:800 -#: ../../guides/events-list.rst:823 -#: ../../guides/events-list.rst:842 +#: ../../guides/events-list.rst:625 +#: ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:735 +#: ../../guides/events-list.rst:743 +#: ../../guides/events-list.rst:796 +#: ../../guides/events-list.rst:806 +#: ../../guides/events-list.rst:829 +#: ../../guides/events-list.rst:848 msgid "``$params`` array includes:" msgstr "" -#: ../../guides/events-list.rst:621 +#: ../../guides/events-list.rst:627 msgid "``entity`` - Entity that is being accessed" msgstr "" -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "``user`` - User accessing the entity (``null`` implies logged in user)" msgstr "" -#: ../../guides/events-list.rst:625 +#: ../../guides/events-list.rst:631 msgid "Notifications events" msgstr "" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "**dequeue, notifications**" msgstr "" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "Called when an ElggData object is removed from the notifications queue to be processed" msgstr "" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "**enqueue, notifications**" msgstr "" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "Called when an ElggData object is being added to the notifications queue" msgstr "" -#: ../../guides/events-list.rst:633 +#: ../../guides/events-list.rst:639 msgid "The following events are listed chronologically in the lifetime of the notification event. Note that not all events apply to instant notifications." msgstr "" -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "**enqueue, notification** |results|" msgstr "" -#: ../../guides/events-list.rst:637 +#: ../../guides/events-list.rst:643 msgid "Can be used to prevent a notification event from sending **subscription** notifications. Event handler must return ``false`` to prevent a subscription notification event from being enqueued." msgstr "" -#: ../../guides/events-list.rst:642 +#: ../../guides/events-list.rst:648 msgid "``object`` - object of the notification event" msgstr "" -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "``action`` - action that triggered the notification event. E.g. corresponds to ``publish`` when ``elgg_trigger_event('publish', 'object', $object)`` is called" msgstr "" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "**get, subscriptions** |results|" msgstr "" -#: ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:652 msgid "Filters subscribers of the notification event. Applies to **subscriptions** and **instant** notifications. In case of a subscription event, by default, the subscribers list consists of the users subscribed to the container entity of the event object. In case of an instant notification event, the subscribers list consists of the users passed as recipients to ``notify_user()``" msgstr "" -#: ../../guides/events-list.rst:651 +#: ../../guides/events-list.rst:657 msgid "**IMPORTANT** Always validate the notification event, object and/or action types before adding any new recipients to ensure that you do not accidentally dispatch notifications to unintended recipients. Consider a situation, where a mentions plugin sends out an instant notification to a mentioned user - any event acting on a subject or an object without validating an event or action type (e.g. including an owner of the original wire thread) might end up sending notifications to wrong users." msgstr "" -#: ../../guides/events-list.rst:656 -#: ../../guides/events-list.rst:676 -#: ../../guides/events-list.rst:687 -#: ../../guides/events-list.rst:704 -#: ../../guides/events-list.rst:739 +#: ../../guides/events-list.rst:662 +#: ../../guides/events-list.rst:682 +#: ../../guides/events-list.rst:693 +#: ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:745 msgid "``event`` - ``\\Elgg\\Notifications\\NotificationEvent`` instance that describes the notification event" msgstr "" -#: ../../guides/events-list.rst:657 -#: ../../guides/events-list.rst:694 -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:663 +#: ../../guides/events-list.rst:700 +#: ../../guides/events-list.rst:717 msgid "``origin`` - ``subscriptions_service`` or ``instant_notifications``" msgstr "" -#: ../../guides/events-list.rst:658 +#: ../../guides/events-list.rst:664 msgid "``methods_override`` - delivery method preference for instant notifications" msgstr "" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "Handlers must return an array in the form:" msgstr "" -#: ../../guides/events-list.rst:677 +#: ../../guides/events-list.rst:683 msgid "**send:before, notifications** |results|" msgstr "" -#: ../../guides/events-list.rst:671 +#: ../../guides/events-list.rst:677 msgid "Triggered before the notification event queue is processed. Can be used to terminate the notification event. Applies to **subscriptions** and **instant** notifications." msgstr "" -#: ../../guides/events-list.rst:677 -#: ../../guides/events-list.rst:740 +#: ../../guides/events-list.rst:683 +#: ../../guides/events-list.rst:746 msgid "``subscriptions`` - a list of subscriptions. See ``'get', 'subscriptions'`` event for details" msgstr "" -#: ../../guides/events-list.rst:694 +#: ../../guides/events-list.rst:700 msgid "**prepare, notification** |results|" msgstr "" -#: ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:686 msgid "A high level event that can be used to alter an instance of ``\\Elgg\\Notifications\\Notification`` before it is sent to the user. Applies to **subscriptions** and **instant** notifications. This event is triggered before a more granular ``'prepare', 'notification:::'`` and after ``'send:before', 'notifications``. Event handler should return an altered notification object." msgstr "" -#: ../../guides/events-list.rst:685 +#: ../../guides/events-list.rst:691 msgid "``$params`` may vary based on the notification type and may include:" msgstr "" -#: ../../guides/events-list.rst:688 -#: ../../guides/events-list.rst:705 +#: ../../guides/events-list.rst:694 +#: ../../guides/events-list.rst:711 msgid "``object`` - object of the notification ``event``. Can be ``null`` for instant notifications" msgstr "" -#: ../../guides/events-list.rst:689 -#: ../../guides/events-list.rst:706 +#: ../../guides/events-list.rst:695 +#: ../../guides/events-list.rst:712 msgid "``action`` - action that triggered the notification ``event``. May default to ``notify_user`` for instant notifications" msgstr "" -#: ../../guides/events-list.rst:690 -#: ../../guides/events-list.rst:707 +#: ../../guides/events-list.rst:696 +#: ../../guides/events-list.rst:713 msgid "``method`` - delivery method (e.g. ``email``, ``site``)" msgstr "" -#: ../../guides/events-list.rst:691 -#: ../../guides/events-list.rst:708 +#: ../../guides/events-list.rst:697 +#: ../../guides/events-list.rst:714 msgid "``sender`` - sender" msgstr "" -#: ../../guides/events-list.rst:692 -#: ../../guides/events-list.rst:709 +#: ../../guides/events-list.rst:698 +#: ../../guides/events-list.rst:715 msgid "``recipient`` - recipient" msgstr "" -#: ../../guides/events-list.rst:693 -#: ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:699 +#: ../../guides/events-list.rst:716 msgid "``language`` - language of the notification (recipient's language)" msgstr "" -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:717 msgid "**prepare, notification:::** |results|" msgstr "" -#: ../../guides/events-list.rst:697 +#: ../../guides/events-list.rst:703 msgid "A granular event that can be used to filter a notification ``\\Elgg\\Notifications\\Notification`` before it is sent to the user. Applies to **subscriptions** and **instant** notifications. In case of instant notifications that have not received an object, the event will be called as ``'prepare', 'notification:'``. In case of instant notifications that have not received an action name, it will default to ``notify_user``." msgstr "" -#: ../../guides/events-list.rst:702 +#: ../../guides/events-list.rst:708 msgid "``$params`` include:" msgstr "" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "**format, notification:** |results|" msgstr "" -#: ../../guides/events-list.rst:714 +#: ../../guides/events-list.rst:720 msgid "This event can be used to format a notification before it is passed to the ``'send', 'notification:'`` event. Applies to **subscriptions** and **instant** notifications. The event handler should return an instance of ``\\Elgg\\Notifications\\Notification``. The event does not receive any ``$params``. Some of the use cases include:" msgstr "" -#: ../../guides/events-list.rst:720 +#: ../../guides/events-list.rst:726 msgid "Strip tags from notification title and body for plaintext email notifications" msgstr "" -#: ../../guides/events-list.rst:721 +#: ../../guides/events-list.rst:727 msgid "Inline HTML styles for HTML email notifications" msgstr "" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "Wrap notification in a template, add signature etc." msgstr "" -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "**send, notification:** |results|" msgstr "" -#: ../../guides/events-list.rst:725 +#: ../../guides/events-list.rst:731 msgid "Delivers a notification. Applies to **subscriptions** and **instant** notifications. The handler must return ``true`` or ``false`` indicating the success of the delivery." msgstr "" -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "``notification`` - a notification object ``\\Elgg\\Notifications\\Notification``" msgstr "" -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "**send:after, notifications** |results|" msgstr "" -#: ../../guides/events-list.rst:734 +#: ../../guides/events-list.rst:740 msgid "Triggered after all notifications in the queue for the notifications event have been processed. Applies to **subscriptions** and **instant** notifications." msgstr "" -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "``deliveries`` - a matrix of delivery statuses by user for each delivery method" msgstr "" -#: ../../guides/events-list.rst:744 +#: ../../guides/events-list.rst:750 msgid "Emails" msgstr "" -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "**prepare, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:747 +#: ../../guides/events-list.rst:753 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to alter an instance of ``\\Elgg\\Email`` before it is passed to the email transport. This event can be used to alter the sender, recipient, subject, body, and/or headers of the email." msgstr "" -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "``$params`` are empty. The ``$return`` value is an instance of ``\\Elgg\\Email``." msgstr "" -#: ../../guides/events-list.rst:762 +#: ../../guides/events-list.rst:768 msgid "**transport, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:755 +#: ../../guides/events-list.rst:761 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to implement a custom email transport, e.g. delivering emails via a third-party proxy service such as SendGrid or Mailgun. The handler must return ``true`` to indicate that the email was transported." msgstr "" -#: ../../guides/events-list.rst:760 -#: ../../guides/events-list.rst:770 -#: ../../guides/events-list.rst:779 +#: ../../guides/events-list.rst:766 +#: ../../guides/events-list.rst:776 +#: ../../guides/events-list.rst:785 msgid "``$params`` contains:" msgstr "" -#: ../../guides/events-list.rst:762 -#: ../../guides/events-list.rst:772 -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:768 +#: ../../guides/events-list.rst:778 +#: ../../guides/events-list.rst:787 msgid "``email`` - An instance of ``\\Elgg\\Email``" msgstr "" -#: ../../guides/events-list.rst:772 +#: ../../guides/events-list.rst:778 msgid "**validate, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:765 +#: ../../guides/events-list.rst:771 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to suppress or whitelist outgoing emails, e.g. when the site is in a development mode. The handler must return ``false`` to supress the email delivery." msgstr "" -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:787 msgid "**zend:message, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:775 +#: ../../guides/events-list.rst:781 msgid "Triggered by the default email transport handler (Elgg uses ``laminas/laminas-mail``). Applies to all outgoing system and notification emails that were not transported using the **transport, system:email** event. This event allows you to alter an instance of ``\\Laminas\\Mail\\Message`` before it is passed to the Laminas email transport." msgstr "" -#: ../../guides/events-list.rst:784 +#: ../../guides/events-list.rst:790 msgid "File events" msgstr "" -#: ../../guides/events-list.rst:794 +#: ../../guides/events-list.rst:800 msgid "**download:url, file** |results|" msgstr "" -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "Allows plugins to filter the download URL of the file." msgstr "" -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "By default, the download URL is generated by the file service." msgstr "" -#: ../../guides/events-list.rst:792 -#: ../../guides/events-list.rst:802 +#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:808 msgid "``entity`` - instance of ``ElggFile``" msgstr "" -#: ../../guides/events-list.rst:793 -#: ../../guides/events-list.rst:803 +#: ../../guides/events-list.rst:799 +#: ../../guides/events-list.rst:809 msgid "``use_cookie`` - whether or not to use a cookie to secure download link" msgstr "" -#: ../../guides/events-list.rst:794 -#: ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:800 +#: ../../guides/events-list.rst:810 msgid "``expires`` - a string representation of when the download link should expire" msgstr "" -#: ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:810 msgid "**inline:url, file** |results|" msgstr "" -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "Allows plugins to filter the inline URL of the image file." msgstr "" -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "By default, the inline URL is generated by the file service." msgstr "" -#: ../../guides/events-list.rst:808 +#: ../../guides/events-list.rst:814 msgid "**mime_type, file** |results|" msgstr "" -#: ../../guides/events-list.rst:807 +#: ../../guides/events-list.rst:813 msgid "Return the mimetype for the filename ``$params['filename']`` with original filename ``$params['original_filename']`` and with the default detected mimetype of ``$params['default']``." msgstr "" -#: ../../guides/events-list.rst:814 +#: ../../guides/events-list.rst:820 msgid "**simple_type, file** |results|" msgstr "" -#: ../../guides/events-list.rst:811 +#: ../../guides/events-list.rst:817 msgid "The event provides ``$params['mime_type']`` (e.g. ``application/pdf`` or ``image/jpeg``) and determines an overall category like ``document`` or ``image``. The bundled file plugin and other-third party plugins usually store ``simpletype`` metadata on file entities and make use of it when serving icons and constructing ``ege*`` filters and menus." msgstr "" -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "**upload, file** |results|" msgstr "" -#: ../../guides/events-list.rst:817 +#: ../../guides/events-list.rst:823 msgid "Allows plugins to implement custom logic for moving an uploaded file into an instance of ``ElggFile``. The handler must return ``true`` to indicate that the uploaded file was moved. The handler must return ``false`` to indicate that the uploaded file could not be moved. Other returns will indicate that ``ElggFile::acceptUploadedFile`` should proceed with the default upload logic." msgstr "" -#: ../../guides/events-list.rst:825 +#: ../../guides/events-list.rst:831 msgid "``file`` - instance of ``ElggFile`` to write to" msgstr "" -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "``upload`` - instance of Symfony's ``UploadedFile``" msgstr "" -#: ../../guides/events-list.rst:831 +#: ../../guides/events-list.rst:837 msgid "**upload:after, file**" msgstr "" -#: ../../guides/events-list.rst:829 +#: ../../guides/events-list.rst:835 msgid "Called after an uploaded file has been written to filestore. Receives an instance of ``ElggFile`` the uploaded file was written to. The ``ElggFile`` may or may not be an entity with a GUID." msgstr "" -#: ../../guides/events-list.rst:834 +#: ../../guides/events-list.rst:840 msgid "Action events" msgstr "" -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "**action:validate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:837 +#: ../../guides/events-list.rst:843 msgid "Trigger before action script/controller is executed. This event should be used to validate/alter user input, before proceeding with the action. The event handler can throw an instance of ``\\Elgg\\Exceptions\\Http\\ValidationException`` or return ``false`` to terminate further execution." msgstr "" -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "``request`` - instance of ``\\Elgg\\Request``" msgstr "" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "**action_gatekeeper:permissions:check, all** |results|" msgstr "" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "Triggered after a CSRF token is validated. Return false to prevent validation." msgstr "" -#: ../../guides/events-list.rst:851 +#: ../../guides/events-list.rst:857 msgid "**forward, ** |results|" msgstr "" -#: ../../guides/events-list.rst:850 +#: ../../guides/events-list.rst:856 msgid "Filter the URL to forward a user to when ``forward($url, $reason)`` is called. In certain cases, the ``params`` array will contain an instance of ``\\Elgg\\Exceptions\\HttpException`` that triggered the error." msgstr "" -#: ../../guides/events-list.rst:857 +#: ../../guides/events-list.rst:863 msgid "**response, action:** |results|" msgstr "" -#: ../../guides/events-list.rst:854 +#: ../../guides/events-list.rst:860 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. This event can be used to modify response content, status code, forward URL, or set additional response headers. Note that the ```` value is parsed from the request URL, therefore you may not be able to filter the responses of `action()` calls if they are nested within the another action script file." msgstr "" -#: ../../guides/events-list.rst:876 +#: ../../guides/events-list.rst:882 msgid "**ajax_response, \\*** |results|" msgstr "" -#: ../../guides/events-list.rst:865 +#: ../../guides/events-list.rst:871 msgid "When the ``elgg/Ajax`` AMD module is used, this event gives access to the response object (``\\Elgg\\Services\\AjaxResponse``) so it can be altered/extended. The event type depends on the method call:" msgstr "" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "elgg/Ajax method" msgstr "" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "event type" msgstr "" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action()" msgstr "" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action:" msgstr "" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path()" msgstr "" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path:" msgstr "" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view()" msgstr "" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view:" msgstr "" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form()" msgstr "" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form:" msgstr "" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "**ajax_response, action:** |results|" msgstr "" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "Filters ``action/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:883 +#: ../../guides/events-list.rst:889 msgid "**ajax_response, path:** |results|" msgstr "" -#: ../../guides/events-list.rst:882 +#: ../../guides/events-list.rst:888 msgid "Filters ajax responses before they're sent back to the ``elgg/Ajax`` module. This event type will only be used if the path did not start with \"action/\" or \"ajax/\"." msgstr "" -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "**ajax_response, view:** |results|" msgstr "" -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "Filters ``ajax/view/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "**ajax_response, form:** |results|" msgstr "" -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "Filters ``ajax/form/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:892 +#: ../../guides/events-list.rst:898 #: ../../guides/routing.rst:2 msgid "Routing" msgstr "" -#: ../../guides/events-list.rst:899 +#: ../../guides/events-list.rst:905 msgid "**response, path:** |results|" msgstr "" -#: ../../guides/events-list.rst:895 +#: ../../guides/events-list.rst:901 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. This event type will only be used if the path did not start with \"action/\" or \"ajax/\". This event can be used to modify response content, status code, forward URL, or set additional response headers. Note that the ```` value is parsed from the request URL, therefore plugins using the ``route`` event should use the original ```` to filter the response, or switch to using the ``route:rewrite`` event." msgstr "" -#: ../../guides/events-list.rst:904 +#: ../../guides/events-list.rst:910 msgid "**route:config, ** |results|" msgstr "" -#: ../../guides/events-list.rst:902 +#: ../../guides/events-list.rst:908 msgid "Allows altering the route configuration before it is registered. This event can be used to alter the path, default values, requirements, as well as to set/remove middleware. Please note that the handler for this event should be registered outside of the ``init`` event handler, as core routes are registered during ``plugins_boot`` event." msgstr "" -#: ../../guides/events-list.rst:908 +#: ../../guides/events-list.rst:914 msgid "**route:rewrite, ** |results|" msgstr "" -#: ../../guides/events-list.rst:907 +#: ../../guides/events-list.rst:913 msgid "Allows altering the site-relative URL path for an incoming request. See :doc:`routing` for details. Please note that the handler for this event should be registered outside of the ``init`` event handler, as route rewrites take place after ``plugins_boot`` event has completed." msgstr "" -#: ../../guides/events-list.rst:913 +#: ../../guides/events-list.rst:919 #: ../../guides/plugins/plugin-skeleton.rst:141 #: ../../guides/views.rst:2 msgid "Views" msgstr "" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "**attributes, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "Allows changes to individual attributes." msgstr "" -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "**allowed_styles, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "Configure allowed styles for HTMLawed." msgstr "" -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "**config, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "Filter the HTMLawed ``$config`` array." msgstr "" -#: ../../guides/events-list.rst:926 +#: ../../guides/events-list.rst:932 msgid "**form:prepare:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:925 +#: ../../guides/events-list.rst:931 msgid "Prepare field values for use in the form. Eg. when editing a blog, fill this with the current values of the blog. Sticky form values will automatically be added to the field values (when available)." msgstr "" -#: ../../guides/events-list.rst:934 +#: ../../guides/events-list.rst:940 msgid "**head, page** |results|" msgstr "" -#: ../../guides/events-list.rst:929 +#: ../../guides/events-list.rst:935 msgid "In ``elgg_view_page()``, filters ``$vars['head']`` Return value contains an array with ``title``, ``metas`` and ``links`` keys, where ``metas`` is an array of elements to be formatted as ```` head tags, and ``links`` is an array of elements to be formatted as ```` head tags. Each meta and link element contains a set of key/value pairs that are formatted into html tag attributes, e.g." msgstr "" -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "**layout, page** |results|" msgstr "" -#: ../../guides/events-list.rst:963 +#: ../../guides/events-list.rst:969 msgid "In ``elgg_view_layout()``, filters the layout name. ``$params`` array includes:" msgstr "" -#: ../../guides/events-list.rst:966 +#: ../../guides/events-list.rst:972 msgid "``identifier`` - ID of the page being rendered" msgstr "" -#: ../../guides/events-list.rst:967 +#: ../../guides/events-list.rst:973 msgid "``segments`` - URL segments of the page being rendered" msgstr "" -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "other ``$vars`` received by ``elgg_view_layout()``" msgstr "" -#: ../../guides/events-list.rst:973 +#: ../../guides/events-list.rst:979 msgid "**response, form:** |results|" msgstr "" -#: ../../guides/events-list.rst:971 +#: ../../guides/events-list.rst:977 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. Applies to request to ``/ajax/form/``. This event can be used to modify response content, status code, forward URL, or set additional response headers." msgstr "" -#: ../../guides/events-list.rst:978 +#: ../../guides/events-list.rst:984 msgid "**response, view:** |results|" msgstr "" -#: ../../guides/events-list.rst:976 +#: ../../guides/events-list.rst:982 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. Applies to request to ``/ajax/view/``. This event can be used to modify response content, status code, forward URL, or set additional response headers." msgstr "" -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "**shell, page** |results|" msgstr "" -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "In ``elgg_view_page()``, filters the page shell name" msgstr "" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "**spec, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "Filter the HTMLawed ``$spec`` string (default empty)." msgstr "" -#: ../../guides/events-list.rst:990 +#: ../../guides/events-list.rst:996 msgid "**table_columns:call, ** |results|" msgstr "" -#: ../../guides/events-list.rst:987 +#: ../../guides/events-list.rst:993 msgid "When the method ``elgg()->table_columns->$name()`` is called, this event is called to allow plugins to override or provide an implementation. Handlers receive the method arguments via ``$params['arguments']`` and should return an instance of ``Elgg\\Views\\TableColumn`` if they wish to specify the column directly." msgstr "" -#: ../../guides/events-list.rst:994 +#: ../../guides/events-list.rst:1000 msgid "**vars:compiler, css** |results|" msgstr "" -#: ../../guides/events-list.rst:993 +#: ../../guides/events-list.rst:999 msgid "Allows plugins to alter CSS variables passed to CssCrush during compilation. See `CSS variables <_guides/theming#css-vars>`." msgstr "" -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "**view, ** |results|" msgstr "" -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "Filters the returned content of the view" msgstr "" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "**view_vars, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "Filters the ``$vars`` array passed to the view" msgstr "" -#: ../../guides/events-list.rst:1005 +#: ../../guides/events-list.rst:1011 #: ../../guides/search.rst:2 msgid "Search" msgstr "" -#: ../../guides/events-list.rst:1010 +#: ../../guides/events-list.rst:1016 msgid "**search:config, search_types** |results|" msgstr "" -#: ../../guides/events-list.rst:1008 +#: ../../guides/events-list.rst:1014 msgid "Implemented in the **search** plugin. Filters an array of custom search types. This allows plugins to add custom search types (e.g. tag or location search). Adding a custom search type will extend the search plugin user interface with appropriate links and lists." msgstr "" -#: ../../guides/events-list.rst:1015 +#: ../../guides/events-list.rst:1021 msgid "**search:config, type_subtype_pairs** |results|" msgstr "" -#: ../../guides/events-list.rst:1013 +#: ../../guides/events-list.rst:1019 msgid "Implemented in the **search** plugin. Filters entity type/subtype pairs before entity search is performed. Allows plugins to remove certain entity types/subtypes from search results, group multiple subtypes together, or to reorder search sections." msgstr "" -#: ../../guides/events-list.rst:1020 +#: ../../guides/events-list.rst:1026 msgid "**search:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1018 +#: ../../guides/events-list.rst:1024 msgid "Triggered by ``elgg_search()``. Filters search fields before search clauses are prepared. ``$return`` value contains an array of names for each entity property type, which should be matched against the search query. ``$params`` array contains an array of search params passed to and filtered by ``elgg_search()``." msgstr "" -#: ../../guides/events-list.rst:1031 +#: ../../guides/events-list.rst:1037 msgid "**search:fields, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1031 -#: ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1037 +#: ../../guides/events-list.rst:1040 msgid "See **search:fields, **" msgstr "" -#: ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1040 msgid "**search:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1039 +#: ../../guides/events-list.rst:1045 msgid "**search:format, entity** |results|" msgstr "" -#: ../../guides/events-list.rst:1037 +#: ../../guides/events-list.rst:1043 msgid "Implemented in the **search** plugin. Allows plugins to populate entity's volatile data before it's passed to search view. This is used for highlighting search hit, extracting relevant substrings in long text fields etc." msgstr "" -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "**search:options, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "Triggered by ``elgg_search()``. Prepares search clauses (options) to be passed to ``elgg_get_entities()``." msgstr "" -#: ../../guides/events-list.rst:1045 +#: ../../guides/events-list.rst:1051 msgid "**search:options, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1045 -#: ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1051 +#: ../../guides/events-list.rst:1054 msgid "See **search:options, **" msgstr "" -#: ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1054 msgid "**search:options, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1052 +#: ../../guides/events-list.rst:1058 msgid "**search:params, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1051 +#: ../../guides/events-list.rst:1057 msgid "Triggered by ``elgg_search()``. Filters search parameters (query, sorting, search fields etc) before search clauses are prepared for a given search type. Elgg core only provides support for ``entities`` search type." msgstr "" -#: ../../guides/events-list.rst:1056 +#: ../../guides/events-list.rst:1062 msgid "**search:results, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1055 +#: ../../guides/events-list.rst:1061 msgid "Triggered by ``elgg_search()``. Receives normalized options suitable for ``elgg_get_entities()`` call and must return an array of entities matching search options. This event is designed for use by plugins integrating third-party indexing services, such as Solr and Elasticsearch." msgstr "" -#: ../../guides/events-list.rst:1061 +#: ../../guides/events-list.rst:1067 msgid "Other" msgstr "" -#: ../../guides/events-list.rst:1065 +#: ../../guides/events-list.rst:1071 msgid "**config, comments_per_page** |results|" msgstr "" -#: ../../guides/events-list.rst:1064 +#: ../../guides/events-list.rst:1070 msgid "Filters the number of comments displayed per page. Default is 25. ``$params['entity']`` will hold the containing entity or null if not provided. Use ``elgg_comments_per_page()`` to get the value." msgstr "" -#: ../../guides/events-list.rst:1069 +#: ../../guides/events-list.rst:1075 msgid "**config, comments_latest_first** |results|" msgstr "" -#: ../../guides/events-list.rst:1068 +#: ../../guides/events-list.rst:1074 msgid "Filters the order of comments. Default is ``true`` for latest first. ``$params['entity']`` will hold the containing entity or null if not provided." msgstr "" -#: ../../guides/events-list.rst:1076 +#: ../../guides/events-list.rst:1082 msgid "**default, access** |results|" msgstr "" -#: ../../guides/events-list.rst:1072 +#: ../../guides/events-list.rst:1078 msgid "In ``elgg_get_default_access()``, this event filters the return value, so it can be used to alter the default value in the input/access view. For core plugins, the value \"input_params\" has the keys \"entity\" (ElggEntity|false), \"entity_type\" (string), \"entity_subtype\" (string), \"container_guid\" (int) are provided. An empty entity value generally means the form is to create a new object." msgstr "" -#: ../../guides/events-list.rst:1080 +#: ../../guides/events-list.rst:1086 msgid "**classes, icon** |results|" msgstr "" -#: ../../guides/events-list.rst:1079 +#: ../../guides/events-list.rst:1085 msgid "Can be used to filter CSS classes applied to icon glyphs. By default, Elgg uses FontAwesome. Plugins can use this event to switch to a different font family and remap icon classes." msgstr "" -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "**config, amd** |results|" msgstr "" -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "Filter the AMD config for the requirejs library." msgstr "" -#: ../../guides/events-list.rst:1087 +#: ../../guides/events-list.rst:1093 msgid "**entity:icon:sizes, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1086 +#: ../../guides/events-list.rst:1092 msgid "Triggered by ``elgg_get_icon_sizes()`` and sets entity type/subtype specific icon sizes. ``entity_subtype`` will be passed with the ``$params`` array to the callback." msgstr "" -#: ../../guides/events-list.rst:1104 +#: ../../guides/events-list.rst:1110 msgid "**entity::sizes, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1090 +#: ../../guides/events-list.rst:1096 msgid "Allows filtering sizes for custom icon types, see ``entity:icon:sizes, ``." msgstr "" -#: ../../guides/events-list.rst:1092 +#: ../../guides/events-list.rst:1098 msgid "The event must return an associative array where keys are the names of the icon sizes (e.g. \"large\"), and the values are arrays with the following keys:" msgstr "" -#: ../../guides/events-list.rst:1095 +#: ../../guides/events-list.rst:1101 msgid "``w`` - Width of the image in pixels" msgstr "" -#: ../../guides/events-list.rst:1096 +#: ../../guides/events-list.rst:1102 msgid "``h`` - Height of the image in pixels" msgstr "" -#: ../../guides/events-list.rst:1097 +#: ../../guides/events-list.rst:1103 msgid "``square`` - Should the aspect ratio be a square (true/false)" msgstr "" -#: ../../guides/events-list.rst:1098 +#: ../../guides/events-list.rst:1104 msgid "``upscale`` - Should the image be upscaled in case it is smaller than the given width and height (true/false)" msgstr "" -#: ../../guides/events-list.rst:1099 +#: ../../guides/events-list.rst:1105 msgid "``crop`` - Is cropping allowed on this image size (true/false, default: true)" msgstr "" -#: ../../guides/events-list.rst:1101 +#: ../../guides/events-list.rst:1107 msgid "If the configuration array for an image size is empty, the image will be saved as an exact copy of the source without resizing or cropping." msgstr "" -#: ../../guides/events-list.rst:1104 +#: ../../guides/events-list.rst:1110 #: ../../guides/i18n.rst:51 #: ../../guides/notifications.rst:24 #: ../../guides/notifications.rst:309 @@ -4078,303 +4099,303 @@ msgstr "" msgid "Example:" msgstr "" -#: ../../guides/events-list.rst:1136 +#: ../../guides/events-list.rst:1142 msgid "**entity:icon:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1124 +#: ../../guides/events-list.rst:1130 msgid "Triggered when entity icon URL is requested, see :ref:`entity icons `. Callback should return URL for the icon of size ``$params['size']`` for the entity ``$params['entity']``. Following parameters are available through the ``$params`` array:" msgstr "" -#: ../../guides/events-list.rst:1128 +#: ../../guides/events-list.rst:1134 msgid "entity" msgstr "" -#: ../../guides/events-list.rst:1129 +#: ../../guides/events-list.rst:1135 msgid "Entity for which icon url is requested." msgstr "" -#: ../../guides/events-list.rst:1130 +#: ../../guides/events-list.rst:1136 msgid "viewtype" msgstr "" -#: ../../guides/events-list.rst:1131 +#: ../../guides/events-list.rst:1137 msgid "The type of :ref:`view ` e.g. ``'default'`` or ``'json'``." msgstr "" -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "size" msgstr "" -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "Size requested, see :ref:`entity icons ` for possible values." msgstr "" -#: ../../guides/events-list.rst:1135 +#: ../../guides/events-list.rst:1141 msgid "Example on how one could default to a Gravatar icon for users that have not yet uploaded an avatar:" msgstr "" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "**entity::url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "Allows filtering URLs for custom icon types, see ``entity:icon:url, ``" msgstr "" -#: ../../guides/events-list.rst:1181 +#: ../../guides/events-list.rst:1187 msgid "**entity:icon:file, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1179 +#: ../../guides/events-list.rst:1185 msgid "Triggered by ``ElggEntity::getIcon()`` and allows plugins to provide an alternative ``ElggIcon`` object that points to a custom location of the icon on filestore. The handler must return an instance of ``ElggIcon`` or an exception will be thrown." msgstr "" -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "**entity::file, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "Allows filtering icon file object for custom icon types, see ``entity:icon:file, ``" msgstr "" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "**entity::prepare, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1187 +#: ../../guides/events-list.rst:1193 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to prepare an image from uploaded/linked file. This event can be used to e.g. rotate the image before it is resized/cropped, or it can be used to extract an image frame if the uploaded file is a video. The handler must return an instance of ``ElggFile`` with a `simpletype` that resolves to `image`. The ``$return`` value passed to the event is an instance of ``ElggFile`` that points to a temporary copy of the uploaded/linked file." msgstr "" -#: ../../guides/events-list.rst:1193 -#: ../../guides/events-list.rst:1289 -#: ../../guides/events-list.rst:1322 +#: ../../guides/events-list.rst:1199 +#: ../../guides/events-list.rst:1295 +#: ../../guides/events-list.rst:1328 msgid "The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1195 -#: ../../guides/events-list.rst:1203 -#: ../../guides/events-list.rst:1213 -#: ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1201 +#: ../../guides/events-list.rst:1209 +#: ../../guides/events-list.rst:1219 +#: ../../guides/events-list.rst:1227 msgid "``entity`` - entity that owns the icons" msgstr "" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "``file`` - original input file before it has been modified by other events" msgstr "" -#: ../../guides/events-list.rst:1205 +#: ../../guides/events-list.rst:1211 msgid "**entity::save, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1199 +#: ../../guides/events-list.rst:1205 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to apply custom image manipulation logic to resizing/cropping icons. The handler must return ``true`` to prevent the core APIs from resizing/cropping icons. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1204 +#: ../../guides/events-list.rst:1210 msgid "``file`` - ``ElggFile`` object that points to the image file to be used as source for icons" msgstr "" -#: ../../guides/events-list.rst:1205 -#: ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1211 +#: ../../guides/events-list.rst:1220 msgid "``x1``, ``y1``, ``x2``, ``y2`` - cropping coordinates" msgstr "" -#: ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1220 msgid "**entity::saved, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1208 +#: ../../guides/events-list.rst:1214 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods once icons have been created. This event can be used by plugins to create river items, update cropping coordinates for custom icon types etc. The handler can access the created icons using ``ElggEntity::getIcon()``. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1227 msgid "**entity::delete, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1217 +#: ../../guides/events-list.rst:1223 msgid "Triggered by ``ElggEntity::deleteIcon()`` method and can be used for clean up operations. This event is triggered before the icons are deleted. The handler can return ``false`` to prevent icons from being deleted. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1226 +#: ../../guides/events-list.rst:1232 msgid "**entity:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1224 +#: ../../guides/events-list.rst:1230 msgid "Return the URL for the entity ``$params['entity']``. Note: Generally it is better to override the ``getUrl()`` method of ElggEntity. This event should be used when it's not possible to subclass (like if you want to extend a bundled plugin without overriding many views)." msgstr "" -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "**extender:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "Return the URL for the annotation or metadata ``$params['extender']``." msgstr "" -#: ../../guides/events-list.rst:1233 +#: ../../guides/events-list.rst:1239 msgid "**fields, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1232 +#: ../../guides/events-list.rst:1238 msgid "Return an array of fields usable for ``elgg_view_field()``. The result should be returned as an array of fields. It is required to provide ``name`` and ``#type`` for each field." msgstr "" -#: ../../guides/events-list.rst:1248 +#: ../../guides/events-list.rst:1254 msgid "**get_list, default_widgets** |results|" msgstr "" -#: ../../guides/events-list.rst:1247 +#: ../../guides/events-list.rst:1253 msgid "Filters a list of default widgets to add for newly registered users. The list is an array of arrays in the format:" msgstr "" -#: ../../guides/events-list.rst:1266 +#: ../../guides/events-list.rst:1272 msgid "**handlers, widgets** |results|" msgstr "" -#: ../../guides/events-list.rst:1265 +#: ../../guides/events-list.rst:1271 msgid "Triggered when a list of available widgets is needed. Plugins can conditionally add or remove widgets from this list or modify attributes of existing widgets like ``context`` or ``multiple``." msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "**maintenance:allow, url** |results|" msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "Return boolean if the URL ``$params['current_url']`` and the path ``$params['current_path']``" msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "is allowed during maintenance mode." msgstr "" -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "**plugin_setting, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1273 +#: ../../guides/events-list.rst:1279 msgid "Can be used to change the value of the setting being saved" msgstr "" -#: ../../guides/events-list.rst:1275 +#: ../../guides/events-list.rst:1281 msgid "Params contains: - ``entity`` - The ``ElggEntity`` where the plugin setting is being saved - ``plugin_id`` - The ID of the plugin for which the setting is being saved - ``name`` - The name of the setting being saved - ``value`` - The original value of the setting being saved" msgstr "" -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "Return value should be a scalar in order to be able to save it to the database. An error will be logged if this is not the case." msgstr "" -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "**public_pages, walled_garden** |results|" msgstr "" -#: ../../guides/events-list.rst:1284 +#: ../../guides/events-list.rst:1290 msgid "Filters a list of URLs (paths) that can be seen by logged out users in a walled garden mode. Handlers must return an array of regex strings that will allow access if matched. Please note that system public routes are passed as the default value to the event, and plugins must take care to not accidentally override these values." msgstr "" -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "``url`` - URL of the page being tested for public accessibility" msgstr "" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "**relationship:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "Filter the URL for the relationship object ``$params['relationship']``." msgstr "" -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "**robots.txt, site** |results|" msgstr "" -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "Filter the robots.txt values for ``$params['site']``." msgstr "" -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "**setting, plugin** |results|" msgstr "" -#: ../../guides/events-list.rst:1300 +#: ../../guides/events-list.rst:1306 msgid "Filter plugin settings. ``$params`` contains:" msgstr "" -#: ../../guides/events-list.rst:1302 +#: ../../guides/events-list.rst:1308 msgid "``plugin`` - An ElggPlugin instance" msgstr "" -#: ../../guides/events-list.rst:1303 +#: ../../guides/events-list.rst:1309 msgid "``plugin_id`` - The plugin ID" msgstr "" -#: ../../guides/events-list.rst:1304 +#: ../../guides/events-list.rst:1310 msgid "``name`` - The name of the setting" msgstr "" -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "``value`` - The value to set" msgstr "" -#: ../../guides/events-list.rst:1309 +#: ../../guides/events-list.rst:1315 msgid "**to:object, **" msgstr "" -#: ../../guides/events-list.rst:1308 +#: ../../guides/events-list.rst:1314 msgid "Converts the entity ``$params['entity']`` to a StdClass object. This is used mostly for exporting entity properties for portable data formats like JSON and XML." msgstr "" -#: ../../guides/events-list.rst:1312 +#: ../../guides/events-list.rst:1318 #: ../../guides/helpers.rst:41 #: ../../guides/plugins.rst:2 msgid "Plugins" msgstr "" -#: ../../guides/events-list.rst:1315 +#: ../../guides/events-list.rst:1321 msgid "Groups" msgstr "" -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "**tool_options, group** |results|" msgstr "" -#: ../../guides/events-list.rst:1318 +#: ../../guides/events-list.rst:1324 msgid "Filters a collection of tools available within a specific group:" msgstr "" -#: ../../guides/events-list.rst:1320 +#: ../../guides/events-list.rst:1326 msgid "The ``$return`` is ``\\Elgg\\Collections\\Collection<\\Elgg\\Groups\\Tool>``, a collection of group tools." msgstr "" -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "``entity`` - ``\\ElggGroup``" msgstr "" -#: ../../guides/events-list.rst:1327 +#: ../../guides/events-list.rst:1333 msgid "Web Services" msgstr "" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "**register, api_methods``** |results|" msgstr "" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "Triggered when the ApiRegistrationService is constructed which allows to add/remove/edit webservice configurations" msgstr "" -#: ../../guides/events-list.rst:1334 +#: ../../guides/events-list.rst:1340 msgid "**rest, init** |results|" msgstr "" -#: ../../guides/events-list.rst:1333 +#: ../../guides/events-list.rst:1339 msgid "Triggered by the web services rest handler. Plugins can set up their own authentication handlers, then return ``true`` to prevent the default handlers from being registered." msgstr "" -#: ../../guides/events-list.rst:1338 +#: ../../guides/events-list.rst:1344 msgid "**rest:output, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1337 +#: ../../guides/events-list.rst:1343 msgid "Filter the result (and subsequently the output) of the API method" msgstr "" @@ -5091,7 +5112,7 @@ msgid "Customize Elgg's behavior with plugins." msgstr "" #: ../../guides/javascript.rst:2 -#: ../../guides/menus.rst:280 +#: ../../guides/menus.rst:299 msgid "JavaScript" msgstr "" @@ -5658,7 +5679,7 @@ msgid "You normally want to call them from your plugin's init function." msgstr "" #: ../../guides/menus.rst:25 -#: ../../guides/menus.rst:76 +#: ../../guides/menus.rst:95 msgid "Examples" msgstr "" @@ -5671,7 +5692,7 @@ msgid "You can also register ``page`` menu items to the admin backend menu. When msgstr "" #: ../../guides/menus.rst:47 -msgid "``administer`` for daily tasks, usermanagement and other actionable tasks" +msgid "``administer`` for daily tasks, user management and other actionable tasks" msgstr "" #: ../../guides/menus.rst:48 @@ -5686,111 +5707,131 @@ msgstr "" msgid "Advanced usage" msgstr "" -#: ../../guides/menus.rst:55 -msgid "You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class." +#: ../../guides/menus.rst:56 +msgid "Headers" +msgstr "" + +#: ../../guides/menus.rst:58 +msgid "For accessibility reasons each menu will get an ``aria-label`` which defaults to the menu name, but can be translated by making sure the language key ``menu::header`` is available." msgstr "" #: ../../guides/menus.rst:61 +msgid "It's also possible to show menu section headers by setting ``show_section_headers`` to ``true`` in ``elgg_view_menu()``" +msgstr "" + +#: ../../guides/menus.rst:69 +msgid "The headers have a magic language key available ``menu::header:
    `` in order to be able to translate the headers." +msgstr "" + +#: ../../guides/menus.rst:72 +msgid "Events" +msgstr "" + +#: ../../guides/menus.rst:74 +msgid "You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class." +msgstr "" + +#: ../../guides/menus.rst:80 msgid "There are three events that can be used to modify a menu:" msgstr "" -#: ../../guides/menus.rst:59 +#: ../../guides/menus.rst:78 msgid "``'parameters', 'menu:'`` to add or modify parameters use for the menu building (eg. sorting)" msgstr "" -#: ../../guides/menus.rst:60 +#: ../../guides/menus.rst:79 msgid "``'register', 'menu:'`` to add or modify items (especially in dynamic menus)" msgstr "" -#: ../../guides/menus.rst:61 +#: ../../guides/menus.rst:80 msgid "``'prepare', 'menu:'`` to modify the structure of the menu before it is displayed" msgstr "" -#: ../../guides/menus.rst:63 +#: ../../guides/menus.rst:82 msgid "When you register an event handler, replace the ```` part with the internal name of the menu." msgstr "" -#: ../../guides/menus.rst:66 +#: ../../guides/menus.rst:85 msgid "The third parameter passed into a menu handler contains all the menu items that have been registered so far by Elgg core and other enabled plugins. In the handler we can loop through the menu items and use the class methods to interact with the properties of the menu item." msgstr "" -#: ../../guides/menus.rst:71 +#: ../../guides/menus.rst:90 msgid "In some cases a more granular version of the ``register`` and ``prepare`` menu events exist with ``menu:::``, this applies when the menu gets provided an ``\\ElggEntity`` in ``$params['entity']`` or an ``\\ElggAnnotation`` in ``$params['annotation']`` or an ``\\ElggRelationship`` in ``$params['relationship']``." msgstr "" -#: ../../guides/menus.rst:78 +#: ../../guides/menus.rst:97 msgid "**Example 1:** Change the URL for menu item called \"albums\" in the ``owner_block`` menu:" msgstr "" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "**Example 2:** Modify the ``entity`` menu for the ``ElggBlog`` objects" msgstr "" -#: ../../guides/menus.rst:116 +#: ../../guides/menus.rst:135 msgid "Remove the thumb icon" msgstr "" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "Change the \"Edit\" text into a custom icon" msgstr "" -#: ../../guides/menus.rst:155 +#: ../../guides/menus.rst:174 msgid "Creating a new menu" msgstr "" -#: ../../guides/menus.rst:157 +#: ../../guides/menus.rst:176 msgid "Elgg provides multiple different menus by default. Sometimes you may however need some menu items that don't fit in any of the existing menus. If this is the case, you can create your very own menu with the ``elgg_view_menu()`` function. You must call the function from the view, where you want to menu to be displayed." msgstr "" -#: ../../guides/menus.rst:163 +#: ../../guides/menus.rst:182 msgid "**Example:** Display a menu called \"my_menu\" that displays it's menu items in alphapetical order:" msgstr "" -#: ../../guides/menus.rst:171 +#: ../../guides/menus.rst:190 msgid "You can now add new items to the menu like this:" msgstr "" -#: ../../guides/menus.rst:182 +#: ../../guides/menus.rst:201 msgid "Furthermore it is now possible to modify the menu using the events ``'register', 'menu:my_menu'`` and ``'prepare', 'menu:my_menu'``." msgstr "" -#: ../../guides/menus.rst:186 +#: ../../guides/menus.rst:205 msgid "Child Dropdown Menus" msgstr "" -#: ../../guides/menus.rst:188 +#: ../../guides/menus.rst:207 msgid "Child menus can be configured using ``child_menu`` factory option on the parent item." msgstr "" -#: ../../guides/menus.rst:190 +#: ../../guides/menus.rst:209 msgid "``child_menu`` options array accepts ``display`` parameter, which can be used to set the child menu to open as ``dropdown`` or be displayed via ``toggle``. All other key value pairs will be passed as attributes to the ``ul`` element." msgstr "" -#: ../../guides/menus.rst:231 +#: ../../guides/menus.rst:250 msgid "Theming" msgstr "" -#: ../../guides/menus.rst:233 +#: ../../guides/menus.rst:252 msgid "The menu name, section names, and item names are all embedded into the HTML as CSS classes (normalized to contain only hyphens, rather that underscores or colons). This increases the size of the markup slightly but provides themers with a high degree of control and flexibility when styling the site." msgstr "" -#: ../../guides/menus.rst:238 +#: ../../guides/menus.rst:257 msgid "**Example:** The following would be the output of the ``foo`` menu with sections ``alt`` and ``default`` containing items ``baz`` and ``bar`` respectively." msgstr "" -#: ../../guides/menus.rst:251 +#: ../../guides/menus.rst:270 msgid "Toggling Menu Items" msgstr "" -#: ../../guides/menus.rst:253 +#: ../../guides/menus.rst:272 msgid "There are situations where you wish to toggle menu items that are actions that are the opposite of each other and ajaxify them. E.g. like/unlike, friend/unfriend, ban/unban, etc. Elgg has built-in support for this kind of actions. When you register a menu item you can provide a name of the menu item (in the same menu) that should be toggled. An ajax call will be made using the href of the menu item." msgstr "" -#: ../../guides/menus.rst:276 +#: ../../guides/menus.rst:295 msgid "The menu items are optimistically toggled. This means the menu items are toggled before the actions finish. If the actions fail, the menu items will be toggled back." msgstr "" -#: ../../guides/menus.rst:282 +#: ../../guides/menus.rst:301 msgid "It is common that menu items rely on JavaScript. You can bind client-side events to menu items by placing your JavaScript into AMD module and defining the requirement during the registration." msgstr "" @@ -6292,7 +6333,7 @@ msgid "Plugins can then use PHP-DI API to autowire and call the service:" msgstr "" #: ../../guides/plugins.rst:277 -msgid "See `PHP-DI documentation `_ for a comprehensive list of definition and invokation possibilities." +msgid "See `PHP-DI documentation `_ for a comprehensive list of definition and invocation possibilities." msgstr "" #: ../../guides/plugins.rst:280 @@ -6344,18 +6385,38 @@ msgid "It's encouraged to create PHPUnit test for your plugin. All tests should msgstr "" #: ../../guides/plugins.rst:311 -msgid "An easy example of adding test is the ``ViewStackTest``, this will test that the views in your plugin are registered correctly and have no syntax errors. To add this test create a file ``ViewStackTest.php`` in the folder ``tests/phpunit/unit///`` with the content:" +msgid "Unit tests should extend the ``Elgg\\UnitTestCase`` class. Integration tests should extend the ``Elgg\\Plugins\\IntegrationTestCase``." +msgstr "" + +#: ../../guides/plugins.rst:313 +msgid "There are a set of global plugin integration tests that run on all active plugins. These tests are:" +msgstr "" + +#: ../../guides/plugins.rst:315 +msgid "``Elgg\\Plugins\\ActionRegistrationIntegrationTest`` will test all registered actions of the plugin without supplying data" +msgstr "" + +#: ../../guides/plugins.rst:316 +msgid "``Elgg\\Plugins\\ComposerIntegrationTest`` will test if the ``composer.json`` is considered valid" +msgstr "" + +#: ../../guides/plugins.rst:317 +msgid "``Elgg\\Plugins\\StaticConfigIntegrationTest`` will test the sections of the ``elgg-plugin.php`` and check for the correct format" +msgstr "" + +#: ../../guides/plugins.rst:318 +msgid "``Elgg\\Plugins\\TranslationsIntegrationTest`` will test all language files for the correct format and encoding" msgstr "" -#: ../../guides/plugins.rst:328 -msgid "If you wish to see a better example, look in any of the Elgg core plugins." +#: ../../guides/plugins.rst:319 +msgid "``Elgg\\Plugins\\ViewStackIntegrationTest`` will test all views of the plugin if there are any PHP parsing errors" msgstr "" -#: ../../guides/plugins.rst:332 +#: ../../guides/plugins.rst:323 msgid ":doc:`/contribute/tests`" msgstr "" -#: ../../guides/plugins.rst:335 +#: ../../guides/plugins.rst:326 #: ../../guides/views.rst:647 #: ../../guides/web-services.rst:398 msgid "Related" @@ -7295,7 +7356,7 @@ msgid "Autocomplete and livesearch endpoint" msgstr "" #: ../../guides/search.rst:186 -msgid "Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/userpicker`` views." +msgid "Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/entitypicker`` views." msgstr "" #: ../../guides/search.rst:194 diff --git a/docs/locale/pot/index.pot b/docs/locale/pot/index.pot index 43da384daf7..92ad6d92c97 100644 --- a/docs/locale/pot/index.pot +++ b/docs/locale/pot/index.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/docs/locale/pot/intro.pot b/docs/locale/pot/intro.pot index d35ce4a172a..3122f702aca 100644 --- a/docs/locale/pot/intro.pot +++ b/docs/locale/pot/intro.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -149,15 +149,15 @@ msgstr "" msgid "Available commands" msgstr "" -#: ../../intro/elgg-cli.rst:94 +#: ../../intro/elgg-cli.rst:108 msgid "Adding custom commands" msgstr "" -#: ../../intro/elgg-cli.rst:96 +#: ../../intro/elgg-cli.rst:110 msgid "Plugins can add their commands to the CLI application, by adding command class name via a configuration in ``elgg-plugin.php`` or via the ``'commands','cli'`` event. Command class must extend ``\\Elgg\\CLI\\Command``." msgstr "" -#: ../../intro/elgg-cli.rst:114 +#: ../../intro/elgg-cli.rst:128 msgid "Custom commands are based on `Symfony Console Commands`_. Please refer to their documentation for more details." msgstr "" diff --git a/docs/locale/pot/plugins.pot b/docs/locale/pot/plugins.pot index 3f9586de0ba..bf2e4347fc6 100644 --- a/docs/locale/pot/plugins.pot +++ b/docs/locale/pot/plugins.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -278,6 +278,10 @@ msgid "tagcloud" msgstr "" #: ../../plugins/index.rst:40 +msgid "theme_sandbox" +msgstr "" + +#: ../../plugins/index.rst:41 msgid "web_services" msgstr "" diff --git a/docs/locale/pot/tutorials.pot b/docs/locale/pot/tutorials.pot index 3006add9e3f..b3100dcb04f 100644 --- a/docs/locale/pot/tutorials.pot +++ b/docs/locale/pot/tutorials.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2023-10-18 11:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/languages/cmn.php b/languages/cmn.php index ab4f257383a..04cf9bd4ed0 100644 --- a/languages/cmn.php +++ b/languages/cmn.php @@ -1163,7 +1163,12 @@ /** * Miscellaneous */ - + 'field:required' => "需要的", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1321,5 +1326,7 @@ "zh_hans" => "简体中文", "zu" => "Zulu", - "field:required" => '需要的', +/** + * Upgrades + */ ); diff --git a/languages/de.php b/languages/de.php index e80ef310556..df91b7af4be 100644 --- a/languages/de.php +++ b/languages/de.php @@ -1592,7 +1592,12 @@ * Miscellaneous */ 'elgg:powered' => "Community-Seite erstellt mit Elgg", - + 'field:required' => "Erforderlich", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1802,8 +1807,9 @@ "zh_hans" => "Chinesisch (Kurzzeichen)", "zu" => "Zulu", - "field:required" => 'Erforderlich', - +/** + * Upgrades + */ "core:upgrade:2017080900:title" => "Umwandlung des Datenbank-Encodings für Multi-Byte-Support", "core:upgrade:2017080900:description" => "Damit wird das Encoding der Datenbank und der Datenbanktabellen auf UTF8mb4 umgestellt, damit Multi-Byte-Characters wie beispielsweise Emojies gespeichert werden können.", diff --git a/languages/es.php b/languages/es.php index ae92bd771da..313ad1f8946 100644 --- a/languages/es.php +++ b/languages/es.php @@ -1148,7 +1148,12 @@ * Miscellaneous */ 'elgg:powered' => "Creado con Elgg", - + 'field:required' => "Requerido", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1308,5 +1313,7 @@ "zh_hans" => "Chino Simplificado", "zu" => "Zulu", - "field:required" => 'Requerido', +/** + * Upgrades + */ ); diff --git a/languages/fr.php b/languages/fr.php index 1fe6c8e9e45..3e7d7d0388e 100644 --- a/languages/fr.php +++ b/languages/fr.php @@ -634,13 +634,6 @@ 'admin:widget:admin_welcome:intro' => 'Bienvenue sur Elgg ! Vous êtes actuellement sur le tableau de bord de l\'administration. Il permet de suivre ce qui se passe sur le site.', 'admin:widget:admin_welcome:registration' => "L'inscription de nouveaux utilisateurs est actuellement désactivée ! Vous pouvez l'activer sur la page %s.", - 'admin:widget:admin_welcome:admin_overview' => "La navigation dans la zone d'administration se fait à l'aide du menu de droite. Il est organisé en trois parties : -
    -
    Administrer
    Des tâches de base telles que suivre le contenu signalé et activer des plugins.
    -
    Configurer
    Des tâches occasionnelles comme définir le nom du site ou configurer les paramètres d'un plugin.
    -
    Information
    Des informations à propos de votre site, telles que des statistiques.
    -
    Développer
    Pour les développeurs qui créent des plugins ou conçoivent des thèmes. (Nécessite le plugin developer).
    -
    ", // argh, this is ugly 'admin:widget:admin_welcome:outro' => '
    Pensez à consulter les ressources disponibles via les liens de bas de page, et merci d\'utiliser Elgg !', @@ -1743,7 +1736,12 @@ * Miscellaneous */ 'elgg:powered' => "Propulsé par Elgg", - + 'field:required' => "Requis", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1961,8 +1959,9 @@ "zh_hans" => "Chinois simplifié", "zu" => "Zoulou", - "field:required" => 'Requis', - +/** + * Upgrades + */ "core:upgrade:2017080900:title" => "Modifier l'encodage de la base de données pour le support multi-byte", "core:upgrade:2017080900:description" => "Modifie l'encodage de la base de données et des tables pour utf8mb4, afin de supporter les caractères multi-bytes tels que des emojis", diff --git a/languages/it.php b/languages/it.php index f49b2236a15..fa12a4c91bc 100644 --- a/languages/it.php +++ b/languages/it.php @@ -1105,7 +1105,12 @@ * Miscellaneous */ 'elgg:powered' => "Generato da Elgg", - + 'field:required' => "Richiesto", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1279,7 +1284,8 @@ "zh_hans" => "Chinese Simplified", "zu" => "Zulu", - "field:required" => 'Richiesto', - +/** + * Upgrades + */ "core:upgrade:2017080900:title" => "Modifica la codifica del database per il supporto multibyte", ); diff --git a/languages/nl.php b/languages/nl.php index 9c075db36ba..49e2e1bd957 100644 --- a/languages/nl.php +++ b/languages/nl.php @@ -476,6 +476,7 @@ */ 'menu:page:header:administer' => 'Beheer', 'menu:page:header:configure' => 'Configureer', + 'menu:page:header:utilities' => 'Hulpmiddelen', 'menu:page:header:develop' => 'Ontwikkel', 'menu:page:header:information' => 'Informatie', 'menu:page:header:default' => 'Andere', @@ -590,6 +591,11 @@ 'admin:site_icons:font_awesome:zip:help' => "Upload hier je Font Awesome iconen. Je kunt deze downloaden van https://fontawesome.com/download. Het webfont wordt dan lokaal geserveerd.", 'admin:site_icons:font_awesome:zip:error' => "De ZIP kon niet worden uitgepakt", 'admin:site_icons:font_awesome:remove_zip' => "Verwijderd geüploade lettertype", + 'admin:theme' => "Theme", + 'admin:theme:info' => "Hier kunnen verschillende theme instellingen worden geconfigureerd. Deze configuratie zal de bestaande configuratie overschrijven.", + 'admin:theme:warning' => "Houdt er rekening mee dat deze wijzigingen je design onbruikbaar kunnen maken.", + 'admin:theme:css_variable:name' => "CSS variabelen", + 'admin:theme:css_variable:value' => "Waarde", 'admin:site_settings' => "Instellingen", 'admin:site:description' => "Via dit beheerpaneel kun je de algemene instellingen van de site beheren. Kies een optie om te beginnen.", 'admin:site:opt:linktext' => "Configureer site", @@ -779,6 +785,28 @@ 'admin:security:settings:min_password_special' => "Minimaal aantal speciale tekens in een wachtwoord", 'admin:security:settings:min_password_special:help' => "Configureer het minimaal aantal speciale tekens (!@$%^&*()<>,.?/[]{}-=_+) welke aanwezig moeten zijn in een wachtwoord. 0 betekent dat het er niet in mag zitten. Laat het leeg voor geen vereisten.", + 'admin:security:security_txt' => "Security.txt", + 'admin:security:security_txt:description' => "Wanneer er een beveiligingsprobleem op uw website wordt gevonden, waar moet dit dan worden gemeld? Security.txt is een standaard die helpt bij het structureren van de informatie die beveiligingsonderzoekers nodig hebben om contact op te kunnen nemen met de sitebeheerders met de gevonden kwetsbaarheid. Meer informatie over de standaard vindt u op %s. De inhoud van uw security.txt kunt u vinden op %s.", + 'admin:security:security_txt:expired' => "De inhoud van je security.txt is verlopen, controleer of alle informatie nog steeds up-to-date is.", + 'admin:security:security_txt:contact' => "Contactgegevens", + 'admin:security:security_txt:contact:help' => "Een link of e-mail adres voor mensen om contact op te kunnen nemen over beveiligingsproblemen. Vergeet niet om 'https://' voor URLs en 'mailto:' voor e-mails op te nemen. Zie %s", + 'admin:security:security_txt:expires' => "Verloopdatum", + 'admin:security:security_txt:expires:help' => "De datum en tijd waarop de inhoud van het security.txt-bestand als verouderd moet worden beschouwd (beveiligingsonderzoekers moeten het dus niet vertrouwen). Zorg ervoor dat u deze waarde regelmatig bijwerkt en uw bestand regelmatig controleert. Zie %s", + 'admin:security:security_txt:encryption' => "Encryptie", + 'admin:security:security_txt:encryption:help' => "Een link naar een beveiligingssleutel welke beveiligingsonderzoekers kunnen gebruiken om beveiligd met jou te kunnen communiceren. Vergeet niet om 'https://' op te nemen. Zie %s", + 'admin:security:security_txt:acknowledgments' => "Dankbetuigingen", + 'admin:security:security_txt:acknowledgments:help' => "Een link naar een webpagina waar de de beveiligingsonderzoekers bedankt voor hun bijdrage. Vergeet niet om 'https://' op te nemen. Zie %s", + 'admin:security:security_txt:language' => "Taal", + 'admin:security:security_txt:language:help' => "Een komma gescheiden lijst van taalcodes welke je beveiligingsteam spreek. Je kunt meer dan één taal opnemen. Zie %s", + 'admin:security:security_txt:canonical' => "Canonical", + 'admin:security:security_txt:canonical:help' => "De URL's voor toegang tot uw security.txt bestand. Het is belangrijk om dit mee te nemen als u het security.txt bestand digitaal ondertekent, zodat de locatie van het security.txt bestand ook digitaal ondertekend kan worden. Zie %s", + 'admin:security:security_txt:policy' => "Beleid", + 'admin:security:security_txt:policy:help' => "Een link naar een beleid waarin wordt beschreven wat beveiligingsonderzoekers moeten doen bij het zoeken naar of melden van beveiligingsproblemen. Vergeet niet 'https://' toe te voegen. Zie %s", + 'admin:security:security_txt:hiring' => "Werken bij", + 'admin:security:security_txt:hiring:help' => "Een link naar eventuele veiligheidsgerelateerde vacatures binnen uw organisatie. Vergeet niet 'https://' toe te voegen. Zie %s", + 'admin:security:security_txt:csaf' => "CSAF", + 'admin:security:security_txt:csaf:help' => "Een link naar de provider-metadata.json van uw CSAF-provider (Common Security Advisory Framework). Vergeet niet 'https://' toe te voegen. Zie %s", + 'admin:site:secret:regenerated' => "Het site secret is geregenereerd", 'admin:site:secret:prevented' => "Het genereren van een nieuw sitegeheim code werd geblokeerd", @@ -1069,6 +1097,7 @@ 'entity:edit:icon:crop_messages:generic' => "De geselecteerde afbeelding voldoet niet aan de aanbevolen afmetingen van de afbeelding. Het resultaat hiervan kan lage kwaliteit iconen zijn.", 'entity:edit:icon:crop_messages:width' => "Het is aanbevolen om een afbeelding met een minimale breedte van tenminste %dpx te gebruiken.", 'entity:edit:icon:crop_messages:height' => "Het is aanbevolen om een afbeelding met een minimale hoogte van tenminste %dpx te gebruiken.", + 'entity:edit:icon:crop:img:alt' => "Geüploade afbeelding", 'entity:edit:icon:file:label' => "Upload een nieuw icoon", 'entity:edit:icon:file:help' => "Laat dit leeg om het huidige icoon te behouden.", 'entity:edit:icon:remove:label' => "Verwijder het icoon", @@ -1194,6 +1223,8 @@ 'list:error:getter:admin' => "De getter '%s' resulteerde in een '%s', echter de viewer '%s' vereist een array", 'link:text' => 'bekijk link', + + 'scroll_to_top' => 'Scroll naar boven', /** * Generic questions @@ -1752,7 +1783,38 @@ * Miscellaneous */ 'elgg:powered' => "Aangedreven door Elgg", - + 'field:required' => "Vereist", + +/** + * Accessibility + */ + 'aria:label:admin:users:search' => "Gebruikers zoeken", + + 'menu:admin_footer:header' => "Beheer footer", + 'menu:admin_header:header' => "Beheer header", + 'menu:admin:users:bulk:header' => "Bulk gebruikers acties", + 'menu:annotation:header' => "Annotatie", + 'menu:breadcrumbs:header' => "Broodkruimelpad", + 'menu:comments:header' => "Reacties", + 'menu:entity:header' => "Entiteit", + 'menu:entity_navigation:header' => "Entiteit navigatie", + 'menu:filter:header' => "Filter", + 'menu:footer:header' => "Footer", + 'menu:login:header' => "Aanmelden", + 'menu:owner_block:header' => "Eigenaar blok", + 'menu:page:header' => "Pagina", + 'menu:relationship:header' => "Relatie", + 'menu:river:header' => "River", + 'menu:site:header' => "Site", + 'menu:social:header' => "Sociaal", + 'menu:title:header' => "Titel", + 'menu:title:widgets:header' => "Widget beheer", + 'menu:topbar:header' => "Topbar", + 'menu:user_hover:header' => "Gebruiker zweef", + 'menu:user:unvalidated:header' => "Niet-gevalideerde gebruiker", + 'menu:walled_garden:header' => "Privénetwerk", + 'menu:widget:header' => "Widget beheer", + /** * Cli commands */ @@ -1780,6 +1842,12 @@ 'cli:database:seed:option:create_until' => "Een PHP time string om de bovengrens van het creatie tijdstip van seeded entities in te stellen", 'cli:database:seed:log:error:faker' => "Dit is een functionaliteit voor ontwikkelaars ten behoeve van testen. Gelieve dit niet voor andere doeleinden te gebruiken.", 'cli:database:seed:log:error:logged_in' => "Het seeden van de database behoort niet uitgevoerd te worden met een aangemelde gebruiker", + 'cli:database:seed:ask:limit' => "Hoeveel items moeten er worden gecreëerd door de '%s' seeder", + + 'cli:database:seeders:description' => "Toon alle beschikbare database seeders met het huidige aantal gecreëerde entiteiten", + 'cli:database:seeders:handler' => "Seed handler", + 'cli:database:seeders:type' => "Seed type", + 'cli:database:seeders:count' => "Gecreëerde aantal", 'cli:database:unseed:description' => "Verwijder de nep entiteiten uit de database", @@ -1970,8 +2038,9 @@ "zh_hans" => "Vereenvoudigd Chinees", "zu" => "Zulu", - "field:required" => 'Vereist', - +/** + * Upgrades + */ "core:upgrade:2017080900:title" => "Wijzig de database codering om multi-byte te ondersteunen", "core:upgrade:2017080900:description" => "Wijzigt de database codering naar utf8mb4 om ondersteuning te bieden voor multi-byte karakters zoals emoji's", diff --git a/languages/zh_hans.php b/languages/zh_hans.php index 8e6cf6ac376..d90d78e02bc 100644 --- a/languages/zh_hans.php +++ b/languages/zh_hans.php @@ -1162,7 +1162,12 @@ /** * Miscellaneous */ - + 'field:required' => "需要的", + +/** + * Accessibility + */ + /** * Cli commands */ @@ -1320,5 +1325,7 @@ "zh_hans" => "简体中文", "zu" => "Zulu", - "field:required" => '需要的', +/** + * Upgrades + */ ); diff --git a/mod/blog/languages/nl.php b/mod/blog/languages/nl.php index 5fe03c2c92c..26c2ba90496 100644 --- a/mod/blog/languages/nl.php +++ b/mod/blog/languages/nl.php @@ -16,6 +16,7 @@ 'edit:object:blog' => 'Bewerk blog', 'notification:object:blog:publish' => "Stuur een notificatie wanneer een blog is gepubliceerd", 'notifications:mute:object:blog' => "over de blog '%s'", + 'menu:blog_archive:header' => "Blog archief", 'blog:revisions' => 'Revisies', 'blog:archives' => 'Archieven', diff --git a/mod/developers/languages/de.php b/mod/developers/languages/de.php index 8dded8a9327..cd3aff6ac99 100644 --- a/mod/developers/languages/de.php +++ b/mod/developers/languages/de.php @@ -9,7 +9,6 @@ 'admin:develop_tools' => 'Entwickler-Werkzeuge', // menu - 'admin:develop_tools:sandbox' => 'Theme-Sandbox', 'admin:develop_tools:inspect' => 'Prüfen', 'admin:inspect' => 'Prüfen', 'admin:develop_tools:unit_tests' => 'Modultests', @@ -37,12 +36,8 @@ 'developers:label:show_modules' => "Geladene AMD-Module in der JavaScript-Konsole anzeigen", 'developers:help:show_modules' => "Zeigt Informationen zu den auf der aktuellen Seite geladenen AMD-Modulen in der JavaScript-Konsole des Browsers an.", 'developers:label:wrap_views' => "Views einkapseln", - 'developers:help:wrap_views' => "Diese Einstellung aktiviert die Einkapselung fast aller Views in HTML-Kommentare. Dies kann hilfreich sein, um den erzeugten HTML-Code einer View zuzuordnen. -Diese Option kann die Ausgabe von nicht-HTML-Views mit Standard-Viewtype stören. Siehe developers_wrap_views() für weitere Informationen.", 'developers:label:log_events' => "Events protokollieren", 'developers:help:log_events' => "Einträge für Events ins Log schreiben. Warnung: es gibt sehr viele davon bei jedem Seitenaufruf.", - 'developers:label:show_gear' => "Verwende %s außerhalb des Admin-Backends", - 'developers:help:show_gear' => "Ein (nur für Admins sichtbares) Icon in der unteren rechten Ecke des Viewports, mit dessen Hilfe Zugriff auf Entwicklungseinstellungen und -links möglich ist.", 'developers:label:block_email' => "Alle ausgehenden Emails blockieren", 'developers:help:block_email' => "Du kannst alle Emails oder an normale Benutzer gehenden Emails blockieren.", 'developers:label:forward_email' => "Alle ausgehenden Emails an eine Email-Adresse umleiten", @@ -50,8 +45,6 @@ 'developers:label:enable_error_log' => "Error-Log aktivieren", 'developers:help:enable_error_log' => "Verwende ein separates Error-Log für Fehler und Meldungen, die von error_log() entsprechend dem eingestellten Log-Level erstellt werden. Du kannst dieses Log im Admin-Bereich einsehen.", - 'developers:label:submit' => "Speichern und Caches zurücksetzen", - 'developers:block_email:forward' => 'Alle Emails umleiten', 'developers:block_email:users' => 'Nur von normalen Benutzern', 'developers:block_email:all' => 'Von Admins und normalen Benutzern', @@ -111,29 +104,6 @@ 'developers:boot_cache_rebuilt' => "Der Boot-Cache wurde für diese Abfrage neu erzeugt.", 'developers:elapsed_time' => "Benötigte Zeit (s)", - // theme sandbox - 'theme_sandbox:intro' => 'Einführung', - 'theme_sandbox:breakout' => 'Theme-Preview in ganzen Browserfenster anzeigen', - 'theme_sandbox:buttons' => 'Knöpfe', - 'theme_sandbox:components' => 'Komponenten', - 'theme_sandbox:email' => 'Email', - 'theme_sandbox:forms' => 'Forms', - 'theme_sandbox:grid' => 'Grid', - 'theme_sandbox:icons' => 'Icons', - 'theme_sandbox:javascript' => 'JavaScript', - 'theme_sandbox:layouts' => 'Layouts', - 'theme_sandbox:modules' => 'Module', - 'theme_sandbox:navigation' => 'Navigation', - 'theme_sandbox:typography' => 'Typographie', - - 'theme_sandbox:icons:blurb' => 'Verwende elgg_view_icon($name) zur Ausgabe von Icons.', - - 'theme_sandbox:test_email:button' => "Sende Test-Email", - 'theme_sandbox:test_email:success' => "Test-Email wurde gesendet an: %s", - - // status messages - 'developers:settings:success' => 'Einstellungen gespeichert und Caches zurückgesetzt.', - 'developers:amd' => 'AMD', 'admin:develop_tools:error_log' => 'Error-Log', diff --git a/mod/developers/languages/es.php b/mod/developers/languages/es.php index 46915974f3b..5265c84b981 100644 --- a/mod/developers/languages/es.php +++ b/mod/developers/languages/es.php @@ -9,7 +9,6 @@ 'admin:develop_tools' => 'Herramientas', // menu - 'admin:develop_tools:sandbox' => 'Sanbox del Tema', 'admin:develop_tools:inspect' => 'Inspecciona', 'admin:inspect' => 'Inspecciona', 'admin:develop_tools:unit_tests' => 'Tests unitarios', @@ -36,10 +35,6 @@ 'developers:label:wrap_views' => "Wrap de vistas", 'developers:label:log_events' => "Eventos de Logs", 'developers:help:log_events' => "Escribir eventos en el log. Precaución: hay varios de estos por página.", - 'developers:label:show_gear' => "Usar %s fuera de la zona de administración", - 'developers:help:show_gear' => "Un icono en la parte inferior derecha de la ventana que permite el acceso de los administradores a la configuración y enlaces de desarrollo.", - - 'developers:label:submit' => "Guardar y liberar cachés", 'developers:debug:off' => 'Apagado', 'developers:debug:error' => 'Error', @@ -79,25 +74,5 @@ 'developers:boot_cache_rebuilt' => "El caché de arranque se reconstruyó para esta solicitud", 'developers:elapsed_time' => "Tiempo transcurrido (s)", - // theme sandbox - 'theme_sandbox:intro' => 'Introducción', - 'theme_sandbox:breakout' => 'Fuera de iframe', - 'theme_sandbox:buttons' => 'Botones', - 'theme_sandbox:components' => 'Componentes', - 'theme_sandbox:email' => 'Correo electrónico', - 'theme_sandbox:forms' => 'Formularios', - 'theme_sandbox:grid' => 'Grilla', - 'theme_sandbox:icons' => 'Iconos', - 'theme_sandbox:javascript' => 'JavaScript', - 'theme_sandbox:layouts' => 'Estructuras', - 'theme_sandbox:modules' => 'Módulos', - 'theme_sandbox:navigation' => 'Navegación', - 'theme_sandbox:typography' => 'Tipografías', - - 'theme_sandbox:icons:blurb' => 'Use elgg_view_icon($name) ola clase elgg-icon-$name para mostrar iconos.', - - // status messages - 'developers:settings:success' => 'Configuraciones almacenadas', - 'developers:amd' => 'AMD', ); diff --git a/mod/developers/languages/fr.php b/mod/developers/languages/fr.php index d0424eb7a47..8635820428f 100644 --- a/mod/developers/languages/fr.php +++ b/mod/developers/languages/fr.php @@ -9,7 +9,6 @@ 'admin:develop_tools' => 'Outils', // menu - 'admin:develop_tools:sandbox' => 'Bac à sable du thème', 'admin:develop_tools:inspect' => 'Inspecter', 'admin:inspect' => 'Inspecter', 'admin:develop_tools:unit_tests' => 'Tests unitaires', @@ -37,10 +36,6 @@ 'developers:label:show_modules' => "Montrer les modules AMD chargés dans la console", 'developers:help:show_modules' => "Envoie les modules chargés et les valeurs dans votre console JavaScript.", 'developers:label:wrap_views' => "Envelopper les Vues", - 'developers:help:wrap_views' => "Ceci enveloppe presque toutes les vues avec des commentaires HTML. Pratique pour identifier la vue responsable d'un bloc HTML particulier. - Ceci peut casser les vues non HTML de l'affichage principal : images, RSS, XML, JSON, etc. Voir developers_wrap_views() pour plus d'informations.", - 'developers:label:show_gear' => "Utiliser %s hors de la zone d'administration", - 'developers:help:show_gear' => "Une icône en bas à droite de l'affichage qui offre aux administrateurs un accès aux paramètres et liens pour développeurs.", 'developers:label:block_email' => "Bloquer tous les e-mails sortants", 'developers:help:block_email' => "Vous pouvez bloquer les e-mails sortants vers les simples membres, ou pour tous les utilisateurs", 'developers:label:forward_email' => "Faire suivre tous les e-mails sortants vers une seule adresse e-mail", @@ -48,8 +43,6 @@ 'developers:label:enable_error_log' => "Activer le journal des erreurs", 'developers:help:enable_error_log' => "Maintenir un journal séparé des erreurs et des messages enregistrés via error_log() sur la base de votre configuration de niveau de journalisation. Le journal peut être affiché via l'interface admin.", - 'developers:label:submit' => "Enregistrer et vider les caches", - 'developers:block_email:forward' => 'Faire suivre tous les e-mails', 'developers:block_email:users' => 'Seulement les membres', 'developers:block_email:all' => 'Admins et membres', @@ -107,29 +100,6 @@ 'developers:boot_cache_rebuilt' => "Le cache de démarrage a été reconstruit pour cette requête", 'developers:elapsed_time' => "Durée écoulée (s)", - // theme sandbox - 'theme_sandbox:intro' => 'Introduction', - 'theme_sandbox:breakout' => 'Sortir de l\'iframe', - 'theme_sandbox:buttons' => 'Boutons', - 'theme_sandbox:components' => 'Composants', - 'theme_sandbox:email' => 'E-mail', - 'theme_sandbox:forms' => 'Formulaires', - 'theme_sandbox:grid' => 'Grille', - 'theme_sandbox:icons' => 'Icônes', - 'theme_sandbox:javascript' => 'JavaScript', - 'theme_sandbox:layouts' => 'Mises en page', - 'theme_sandbox:modules' => 'Modules', - 'theme_sandbox:navigation' => 'Navigation', - 'theme_sandbox:typography' => 'Typographie', - - 'theme_sandbox:icons:blurb' => 'Utilisez elgg_view_icon($name) pour afficher des icônes. ', - - 'theme_sandbox:test_email:button' => "Envoyer un e-mail de test", - 'theme_sandbox:test_email:success' => "E-mail de test envoyé à : %s", - - // status messages - 'developers:settings:success' => 'Paramètres enregistrés et caches vidés', - 'developers:amd' => 'AMD', 'admin:develop_tools:error_log' => 'Journal des erreurs', diff --git a/mod/developers/languages/nl.php b/mod/developers/languages/nl.php index fea42da8c90..6b9ab477ba5 100644 --- a/mod/developers/languages/nl.php +++ b/mod/developers/languages/nl.php @@ -9,13 +9,14 @@ 'admin:develop_tools' => 'Tools', // menu - 'admin:develop_tools:sandbox' => 'Theme Sandbox', 'admin:develop_tools:inspect' => 'Inspecteer', 'admin:inspect' => 'Inspecteer', 'admin:develop_tools:unit_tests' => 'Unittesten', 'admin:develop_tools:entity_explorer' => 'Entiteiten Verkenner', 'admin:developers' => 'Ontwikkelaars', 'admin:developers:settings' => 'Instellingen', + 'menu:entity_explorer:header' => 'Entiteiten Verkenner', + 'menu:developers_inspect_viewtype:header' => 'Inspecteer view types', // settings 'elgg_dev_tools:settings:explanation' => 'Beheer je ontwikkel- en debuginstellingen hieronder. Sommige van de instellingen zijn ook beschikbaar op andere beheerpagina\'s.', @@ -39,11 +40,9 @@ 'developers:label:wrap_views' => "Omcirkel views", 'developers:help:wrap_views' => "Dit omwikkeld alle views met een HTML comment block. Dit kan je helpen indien je wilt weten welke view de HTML heeft gegenereerd. -Dit kan potentieel non-HTML views niet laten functioneren. Bekijk de developers_wrap_views() functie voor meer informatie.", +Dit kan potentieel non-HTML views niet laten functioneren.", 'developers:label:log_events' => "Log events", 'developers:help:log_events' => "Schrijf events naar de log. Waarschuwing: dit zijn er veel per pagina.", - 'developers:label:show_gear' => "Gebruik %s buiten de admin sectie", - 'developers:help:show_gear' => "Een icoon onderaan rechts van het venster dat administrators toegang geeft tot ontwikkelaars instellingen en links.", 'developers:label:block_email' => "Blokkeer alle uitgaande emails", 'developers:help:block_email' => "Het is mogelijk om alle uitgaande emails naar reguliere gebruikers of naar alle gebruikers", 'developers:label:forward_email' => "Stuur alle uitgaande emails naar één adres", @@ -51,8 +50,6 @@ 'developers:label:enable_error_log' => "Schakel error logging in", 'developers:help:enable_error_log' => "Maak een eigen logbestand aan met fouten en berichten welke gelogd worden via error_log() gebaseerd op je loglevel instellingen. Deze log is zichtbaar via de beheer pagina.", - 'developers:label:submit' => "Opslaan en cache wissen", - 'developers:block_email:forward' => 'Stuur alle emails door', 'developers:block_email:users' => 'Enkel voor gewone gebruikers', 'developers:block_email:all' => 'Beheerders en gewone gebruikers', @@ -82,6 +79,7 @@ 'developers:inspect:events' => 'Events', 'developers:inspect:menus' => 'Menu\'s', 'developers:inspect:priority' => 'Prioriteit', + 'developers:inspect:seeders' => 'Seeders', 'developers:inspect:simplecache' => 'Simple Cache', 'developers:inspect:routes' => 'Routes', 'developers:inspect:views' => 'Views', @@ -112,29 +110,6 @@ 'developers:boot_cache_rebuilt' => "De boot cache is herbouwd voor deze pagina", 'developers:elapsed_time' => "Tijd verstreken (s)", - // theme sandbox - 'theme_sandbox:intro' => 'Introductie', - 'theme_sandbox:breakout' => 'Verlaat het iframe', - 'theme_sandbox:buttons' => 'Knoppen', - 'theme_sandbox:components' => 'Componenten', - 'theme_sandbox:email' => 'Email', - 'theme_sandbox:forms' => 'Formulieren', - 'theme_sandbox:grid' => 'Raster', - 'theme_sandbox:icons' => 'Iconen', - 'theme_sandbox:javascript' => 'JavaScript', - 'theme_sandbox:layouts' => 'Lay-outs', - 'theme_sandbox:modules' => 'Modules', - 'theme_sandbox:navigation' => 'Paginanavigatie', - 'theme_sandbox:typography' => 'Typografie', - - 'theme_sandbox:icons:blurb' => 'Gebruik elgg_view_icon($name) of de klasse elgg-icon-$name om iconen weer te geven.', - - 'theme_sandbox:test_email:button' => "Stuur test email", - 'theme_sandbox:test_email:success' => "Test email verzonden naar: %s", - - // status messages - 'developers:settings:success' => 'Instellingen opgeslagen', - 'developers:amd' => 'AMD', 'admin:develop_tools:error_log' => 'Fouten logboek', diff --git a/mod/developers/languages/ru.php b/mod/developers/languages/ru.php new file mode 100644 index 00000000000..988e3198908 --- /dev/null +++ b/mod/developers/languages/ru.php @@ -0,0 +1,114 @@ + 'Инструменты', + + // menu + 'admin:develop_tools:inspect' => 'Проверить', + 'admin:inspect' => 'Проверить', + 'admin:develop_tools:unit_tests' => 'Модульные Тесты', + 'admin:develop_tools:entity_explorer' => 'Исследователь сущностей', + 'admin:developers' => 'Разработчики', + 'admin:developers:settings' => 'Настройки', + + // settings + 'elgg_dev_tools:settings:explanation' => 'Управление настройками разработки и отладки. Некоторые из этих настроек также доступны на других страницах администрирования.', + 'developers:label:simple_cache' => 'Использовать простой кэш', + 'developers:help:simple_cache' => 'Выключайте этот кэш во время разработки. Иначе изменения сделанные вами в CSS и JavaSctipt будут проигнорированы.', + 'developers:label:system_cache' => 'Использовать кэш системы', + 'developers:help:system_cache' => 'Выключайте во время разработки. Иначе изменения в ваших плагинах не будут зарегистрированы.', + 'developers:label:debug_level' => "Уровень отладки", + 'developers:help:debug_level' => "Эта опция управляет количеством информации попадающей в логи. Смотрите документацию по функции elgg_log() для большей информации.", + 'developers:label:display_errors' => 'Отображать критические ошибки PHP', + 'developers:help:display_errors' => "По умолчанию Elgg в .htaccess файле подавляет вывод критических ошибок.", + 'developers:label:screen_log' => "Отладка на экран", + 'developers:help:screen_log' => "Вывод функций elgg_log() и elgg_dump()и подсчет запросов к БД на страницу.", + 'developers:show_strings:default' => "Нормальный перевод", + 'developers:show_strings:key_append' => "Ключ перевода добавлен", + 'developers:show_strings:key_only' => "Показать только ключ перевода", + 'developers:label:show_strings' => "Показывать ключи перевода", + 'developers:help:show_strings' => "Вывод ключей для перевода используемых в функции elgg_echo() вместо самого перевода.", + 'developers:label:show_modules' => "Показать модули AMD, загруженные в консоль", + 'developers:help:show_modules' => "Передает загруженные модули и значения в вашу консоль JavaScript.", + 'developers:label:wrap_views' => "Оборачивать views", + 'developers:help:wrap_views' => "Это оборачивает почти каждое представление комментариями HTML. Полезно для поиска представления, создающего конкретный HTML. + Это может привести к поломке представлений, отличных от HTML, в типе представления по умолчанию.", + 'developers:label:log_events' => "Журнал событий", + 'developers:help:log_events' => "Запись событий в журнал. Предупреждение: их много на странице.", + 'developers:label:block_email' => "Блокировать все исходящие электронные письма", + 'developers:help:block_email' => "Вы можете заблокировать исходящие сообщения электронной почты обычным пользователям или всем пользователям.", + 'developers:label:forward_email' => "Пересылать все исходящие электронные письма на один адрес", + 'developers:help:forward_email' => "Все исходящие электронные письма будут отправляться на настроенный адрес электронной почты.", + 'developers:label:enable_error_log' => "Включить журнал ошибок", + 'developers:help:enable_error_log' => "Ведите отдельный журнал ошибок и сообщений, зарегистрированных в error_log(), в зависимости от настройки уровня трассировки. Журнал доступен для просмотра через интерфейс администратора.", + + 'developers:block_email:forward' => 'Переслать все электронные письма', + 'developers:block_email:users' => 'Только обычные пользователи', + 'developers:block_email:all' => 'Админы и обычные пользователи', + + 'developers:debug:off' => 'Выключено', + 'developers:debug:error' => 'Ошибка', + 'developers:debug:warning' => 'Предупреждение', + 'developers:debug:notice' => 'Замечание', + 'developers:debug:info' => 'Информация', + + // entity explorer + 'developers:entity_explorer:help' => 'Просмотр информации об объектах и выполнение некоторых основных действий над ними.', + 'developers:entity_explorer:guid:label' => 'Введите guid объекта для проверки', + 'developers:entity_explorer:info' => 'Информация об объекте', + 'developers:entity_explorer:info:attributes' => 'Атрибуты', + 'developers:entity_explorer:info:metadata' => 'Метаданные', + 'developers:entity_explorer:info:relationships' => 'Отношения', + 'developers:entity_explorer:info:owned_acls' => 'Коллекции собственного доступа', + 'developers:entity_explorer:info:acl_memberships' => 'Членство в коллекциях доступа', + 'developers:entity_explorer:delete_entity' => 'Удалить этот объект', + 'developers:entity_explorer:inspect_entity' => 'Проверить этот объект', + 'developers:entity_explorer:view_entity' => 'Посмотреть этот объект на сайте', + + // inspection + 'developers:inspect:help' => 'Проверить конфигурацию фреймворка Elgg', + 'developers:inspect:actions' => 'Действия', + 'developers:inspect:events' => 'События', + 'developers:inspect:menus' => 'Меню', + 'developers:inspect:priority' => 'Приоритет', + 'developers:inspect:seeders' => 'Seeders', + 'developers:inspect:simplecache' => 'Простой кэш', + 'developers:inspect:routes' => 'Маршруты', + 'developers:inspect:views' => 'Представления', + 'developers:inspect:views:all_filtered' => "Примечание! Весь ввод/вывод просмотра фильтруется через эти события:", + 'developers:inspect:views:input_filtered' => "(ввод отфильтрован обработчиком событий: %s)", + 'developers:inspect:views:filtered' => "(отфильтровано обработчиком событий: %s)", + 'developers:inspect:widgets' => 'Виджеты', + 'developers:inspect:widgets:context' => 'Контекст', + 'developers:inspect:functions' => 'Функции', + 'developers:inspect:file_location' => 'Путь к файлу из Elgg корня или контроллера', + 'developers:inspect:route' => 'Название маршрута', + 'developers:inspect:path' => 'Шаблон пути', + 'developers:inspect:resource' => 'Представление ресурсов', + 'developers:inspect:handler' => 'Обработчик', + 'developers:inspect:controller' => 'Контроллер', + 'developers:inspect:file' => 'Файл', + 'developers:inspect:middleware' => 'Файл', + 'developers:inspect:handler_type' => 'Обрабатывается', + 'developers:inspect:services' => 'Сервисы', + 'developers:inspect:service:name' => 'Наименование', + 'developers:inspect:service:path' => 'Определение', + 'developers:inspect:service:class' => 'Класс', + + // event logging + 'developers:request_stats' => "Статистика запросов (не включает событие выключения)", + 'developers:event_log_msg' => "%s: '%s, %s' в %s", + 'developers:log_queries' => "Запросы к БД: %s", + 'developers:boot_cache_rebuilt' => "Загрузочный кеш был перестроен для этого запроса", + 'developers:elapsed_time' => "Прошедшее время (сек)", + + 'developers:amd' => 'AMD', + + 'admin:develop_tools:error_log' => 'Журнал ошибок', + 'developers:logs:empty' => 'Журнал ошибок пуст', +); diff --git a/mod/externalpages/languages/cs.php b/mod/externalpages/languages/cs.php index cdfc744970e..6f4eb232188 100644 --- a/mod/externalpages/languages/cs.php +++ b/mod/externalpages/languages/cs.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Zobrazit na stránce", 'expages:about' => "O těchto stránkách", 'expages:terms' => "Podmínky", diff --git a/mod/externalpages/languages/de.php b/mod/externalpages/languages/de.php index 095731937c8..973443c003a 100644 --- a/mod/externalpages/languages/de.php +++ b/mod/externalpages/languages/de.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Externe Seiten", + 'expages:edit:viewpage' => "Diese externe Seite anzeigen", 'expages:about' => "Impressum", 'expages:terms' => "AGBs", diff --git a/mod/externalpages/languages/el.php b/mod/externalpages/languages/el.php index 5795dbb0d22..1f5aa5f15a0 100644 --- a/mod/externalpages/languages/el.php +++ b/mod/externalpages/languages/el.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Προβολή σελίδας", 'expages:about' => "Περί", 'expages:terms' => "Όροι Χρήσης", diff --git a/mod/externalpages/languages/es.php b/mod/externalpages/languages/es.php index dcb8ef17197..7f0668b227c 100644 --- a/mod/externalpages/languages/es.php +++ b/mod/externalpages/languages/es.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Ver página en el sitio", 'expages:about' => "Acerca de", 'expages:terms' => "Términos", diff --git a/mod/externalpages/languages/fi.php b/mod/externalpages/languages/fi.php index 26945b9c11c..6f39c936f49 100644 --- a/mod/externalpages/languages/fi.php +++ b/mod/externalpages/languages/fi.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Näytä sivu", 'expages:about' => "Tietoa", 'expages:terms' => "Käyttöehdot", diff --git a/mod/externalpages/languages/fr.php b/mod/externalpages/languages/fr.php index 82d0ea62efe..921d6aa66e8 100644 --- a/mod/externalpages/languages/fr.php +++ b/mod/externalpages/languages/fr.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Pages du site", + 'expages:edit:viewpage' => "Voir la page sur le site", 'expages:about' => "À propos", 'expages:terms' => "Mentions légales", diff --git a/mod/externalpages/languages/gd.php b/mod/externalpages/languages/gd.php index 6eedd103cb7..1aa56fa35d2 100644 --- a/mod/externalpages/languages/gd.php +++ b/mod/externalpages/languages/gd.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Duilleagan na Làraich", + 'expages:edit:viewpage' => "Seall an duilleag air an làrach", 'expages:about' => "Mu dheidhinn", 'expages:terms' => "Cumhaichean", diff --git a/mod/externalpages/languages/gl.php b/mod/externalpages/languages/gl.php index f9d99548e9d..0f3e0d91cea 100644 --- a/mod/externalpages/languages/gl.php +++ b/mod/externalpages/languages/gl.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Ver a páxina no sitio", 'expages:about' => "Información", 'expages:terms' => "Condicións", diff --git a/mod/externalpages/languages/it.php b/mod/externalpages/languages/it.php index d3a2a46d81f..4f5faace1bd 100644 --- a/mod/externalpages/languages/it.php +++ b/mod/externalpages/languages/it.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Pagine del sito", + 'expages:edit:viewpage' => "Visualizza pagina nel sito", 'expages:about' => "Informazioni", 'expages:terms' => "Termini", diff --git a/mod/externalpages/languages/ja.php b/mod/externalpages/languages/ja.php index 51dd9d9e285..dffb6382a37 100644 --- a/mod/externalpages/languages/ja.php +++ b/mod/externalpages/languages/ja.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "サイトページ", + 'expages:edit:viewpage' => "サイトのページを見る", 'expages:about' => "このサイトについて", 'expages:terms' => "利用条件", diff --git a/mod/externalpages/languages/ko.php b/mod/externalpages/languages/ko.php index d625aaecdae..111609b7bc6 100644 --- a/mod/externalpages/languages/ko.php +++ b/mod/externalpages/languages/ko.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "사이트 페이지", + 'expages:edit:viewpage' => "사이트의 페이지 보기", 'expages:about' => "정보", 'expages:terms' => "용어", diff --git a/mod/externalpages/languages/nl.php b/mod/externalpages/languages/nl.php index 4acc7c94d78..30e3e7a15ad 100644 --- a/mod/externalpages/languages/nl.php +++ b/mod/externalpages/languages/nl.php @@ -11,6 +11,8 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Externe pagina's", + 'menu:expages:header' => "Externe pagina's", + 'expages:edit:viewpage' => "Bekijk pagina op de site", 'expages:about' => "Over ons", 'expages:terms' => "Algemene voorwaarden", diff --git a/mod/externalpages/languages/pl.php b/mod/externalpages/languages/pl.php index 8b3aa30d93e..a40f257423f 100644 --- a/mod/externalpages/languages/pl.php +++ b/mod/externalpages/languages/pl.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Zobacz stronę na portalu", 'expages:about' => "O nas", 'expages:terms' => "Regulamin", diff --git a/mod/externalpages/languages/ro_ro.php b/mod/externalpages/languages/ro_ro.php index bf2ae19f1cb..5dd1dcd9120 100644 --- a/mod/externalpages/languages/ro_ro.php +++ b/mod/externalpages/languages/ro_ro.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Pagini de Site", + 'expages:edit:viewpage' => "Vezi pagina pe site", 'expages:about' => "Despre", 'expages:terms' => "Termeni", diff --git a/mod/externalpages/languages/ru.php b/mod/externalpages/languages/ru.php index 1860f31fdb8..41ff3539117 100644 --- a/mod/externalpages/languages/ru.php +++ b/mod/externalpages/languages/ru.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Страницы сайта", + 'expages:edit:viewpage' => "Просмотр страницы на сайте", 'expages:about' => "О сайте", 'expages:terms' => "Правила", diff --git a/mod/externalpages/languages/sr.php b/mod/externalpages/languages/sr.php index f9b7b29b777..596dfeaec4b 100644 --- a/mod/externalpages/languages/sr.php +++ b/mod/externalpages/languages/sr.php @@ -10,6 +10,7 @@ /** * Menu items and titles */ + 'expages:edit:viewpage' => "Погледај страницу на сајту", 'expages:about' => "О сајту", 'expages:terms' => "Услови коришћења", diff --git a/mod/externalpages/languages/sv.php b/mod/externalpages/languages/sv.php index b2fde477b91..0b3a65f6da9 100644 --- a/mod/externalpages/languages/sv.php +++ b/mod/externalpages/languages/sv.php @@ -11,6 +11,7 @@ * Menu items and titles */ 'admin:configure_utilities:expages' => "Webbplatsens Sidor", + 'expages:edit:viewpage' => "Visa sida på webbplatsen", 'expages:about' => "Om", 'expages:terms' => "Villkor", diff --git a/mod/friends_collections/languages/nl.php b/mod/friends_collections/languages/nl.php index fb12a42e151..3a29178df89 100644 --- a/mod/friends_collections/languages/nl.php +++ b/mod/friends_collections/languages/nl.php @@ -6,6 +6,7 @@ */ return array( + 'menu:friends:collection:header' => 'Vriendenlijst', 'friends:collections' => 'Vriendenlijsten', 'friends:collections:no_results' => 'Je hebt nog geen vriendenlijsten aangemaakt', 'friends:collection:members:no_results' => 'Deze vriendenlijst heeft nog geen leden', diff --git a/mod/groups/languages/cs.php b/mod/groups/languages/cs.php index 850eff436c2..aab24e954f8 100644 --- a/mod/groups/languages/cs.php +++ b/mod/groups/languages/cs.php @@ -137,4 +137,6 @@ 'groups:add:alreadymember' => "%s je již členem této skupiny", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/da.php b/mod/groups/languages/da.php index 9be34cbb885..d18210e3b8c 100644 --- a/mod/groups/languages/da.php +++ b/mod/groups/languages/da.php @@ -126,4 +126,6 @@ 'groups:joinrequestkilled' => 'Anmodningen om tilslutning er blevet slettet.', // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/de.php b/mod/groups/languages/de.php index fb3455b53d2..da960af48bd 100644 --- a/mod/groups/languages/de.php +++ b/mod/groups/languages/de.php @@ -180,4 +180,6 @@ 'groups:usersettings:notifications:title' => 'Gruppen-Benachrichtigungen', 'groups:usersettings:notifications:description' => 'Um Benachrichtigungen zu erhalten, wenn zu einer Gruppe, in der Du Mitglied bist, neue Inhalte hinzugefügt werden, kannst Du individuell für jede Gruppe im Folgenden die Methode(n) festlegen, die verwendet werden soll(en).', + + // accessibility ); diff --git a/mod/groups/languages/el.php b/mod/groups/languages/el.php index f276dbb4543..c3f132dfb39 100644 --- a/mod/groups/languages/el.php +++ b/mod/groups/languages/el.php @@ -133,4 +133,6 @@ 'groups:add:alreadymember' => "Ο/η %s είναι ήδη μέλος της ομάδας", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/es.php b/mod/groups/languages/es.php index 523cf74a3dc..4aa6e01fbed 100644 --- a/mod/groups/languages/es.php +++ b/mod/groups/languages/es.php @@ -137,4 +137,6 @@ 'groups:add:alreadymember' => "%s ya forma parte del grupo.", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/fi.php b/mod/groups/languages/fi.php index 14e9c0eaec6..1b1e12c4816 100644 --- a/mod/groups/languages/fi.php +++ b/mod/groups/languages/fi.php @@ -137,4 +137,6 @@ 'groups:add:alreadymember' => "%s on jo tämän ryhmän jäsen", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/fr.php b/mod/groups/languages/fr.php index b6833795789..fea0787793d 100644 --- a/mod/groups/languages/fr.php +++ b/mod/groups/languages/fr.php @@ -178,4 +178,6 @@ 'groups:usersettings:notifications:title' => 'Notifications du groupe', 'groups:usersettings:notifications:description' => 'Pour recevoir des notifications quand de nouveaux contenus sont publiés dans un groupe dont vous êtes membre, cherchez et choisissez ci-dessous la ou les méthodes de notification que vous souhaitez utiliser.', + + // accessibility ); diff --git a/mod/groups/languages/gl.php b/mod/groups/languages/gl.php index 4f5f4bbb0f1..d54f90ff268 100644 --- a/mod/groups/languages/gl.php +++ b/mod/groups/languages/gl.php @@ -136,4 +136,6 @@ 'groups:add:alreadymember' => "%s xa pertence ao grupo.", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/it.php b/mod/groups/languages/it.php index 2fda7e745c5..6ec7b4dc30c 100644 --- a/mod/groups/languages/it.php +++ b/mod/groups/languages/it.php @@ -146,4 +146,6 @@ 'groups:add:alreadymember' => "%s è già membro di questo gruppo", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/ja.php b/mod/groups/languages/ja.php index bb9653ad4cc..76b46e39d16 100644 --- a/mod/groups/languages/ja.php +++ b/mod/groups/languages/ja.php @@ -175,4 +175,6 @@ 'groups:usersettings:notifications:title' => 'グループの通知', 'groups:usersettings:notifications:description' => 'あなたの参加しているグループに新しいコンテンツが追加されたときの通知の受け取り方を、下から選択してください。(複数可)', + + // accessibility ); diff --git a/mod/groups/languages/nl.php b/mod/groups/languages/nl.php index f32d62515e0..2f7ebe3a50f 100644 --- a/mod/groups/languages/nl.php +++ b/mod/groups/languages/nl.php @@ -178,4 +178,8 @@ 'groups:usersettings:notifications:title' => 'Groepsnotificaties', 'groups:usersettings:notifications:description' => 'Om notificaties te ontvangen uit groepen waar je lid van bent kun je in onderstaande lijst aangeven of en hoe je op de hoogte moet worden gebracht', + + // accessibility + 'groups:aria:label:group_search' => "Zoek naar groepen", + 'groups:aria:label:search_in_group' => "Zoek in deze groep", ); diff --git a/mod/groups/languages/pl.php b/mod/groups/languages/pl.php index d9c55837e55..e915fd986ae 100644 --- a/mod/groups/languages/pl.php +++ b/mod/groups/languages/pl.php @@ -136,4 +136,6 @@ 'groups:add:alreadymember' => "%s jest już członkiem tej grupy", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/ro_ro.php b/mod/groups/languages/ro_ro.php index 8d184662fdf..d6ece19911f 100644 --- a/mod/groups/languages/ro_ro.php +++ b/mod/groups/languages/ro_ro.php @@ -176,4 +176,6 @@ 'groups:usersettings:notifications:title' => 'Notificări de Grup', 'groups:usersettings:notifications:description' => 'Pentru a primii notificări atunci când se adaugă conținut nou pe un grup al cărui membru ești, găsește-l mai jos și selectează metoda(ele) de notificare pe care dorești să o(le) folosești.', + + // accessibility ); diff --git a/mod/groups/languages/ru.php b/mod/groups/languages/ru.php index 40342cc183f..188a7e326d7 100644 --- a/mod/groups/languages/ru.php +++ b/mod/groups/languages/ru.php @@ -178,4 +178,6 @@ 'groups:usersettings:notifications:title' => 'Уведомления группы', 'groups:usersettings:notifications:description' => 'Чтобы получать уведомления, когда новый контент добавляется в группу, членом которой вы являетесь, найдите его ниже и выберите способ(ы) уведомления, который вы хотите использовать.', + + // accessibility ); diff --git a/mod/groups/languages/sr.php b/mod/groups/languages/sr.php index 8797e98cde6..7c023cc2756 100644 --- a/mod/groups/languages/sr.php +++ b/mod/groups/languages/sr.php @@ -135,4 +135,6 @@ 'groups:add:alreadymember' => "%s је већ члан ове групе", // Notification settings + + // accessibility ); diff --git a/mod/groups/languages/sv.php b/mod/groups/languages/sv.php index 071201d0ed7..4c710d1bb64 100644 --- a/mod/groups/languages/sv.php +++ b/mod/groups/languages/sv.php @@ -156,4 +156,6 @@ 'groups:add:alreadymember' => "%s är redan medlem i den här gruppen", // Notification settings + + // accessibility ); diff --git a/mod/members/languages/nl.php b/mod/members/languages/nl.php index f0cf97b4e96..97070beeffb 100644 --- a/mod/members/languages/nl.php +++ b/mod/members/languages/nl.php @@ -9,6 +9,7 @@ 'members:label:online' => 'Online', 'members:label:search' => 'Zoekresultaten', 'members:search' => 'Zoek leden', + 'members:aria:label:member_search' => "Zoeken naar leden", 'members:title:search' => "Leden gezocht op '%s'", 'members:total' => 'Totaal aantal leden: %s', 'members:title:all' => 'Alle leden', diff --git a/mod/pages/languages/nl.php b/mod/pages/languages/nl.php index 5d409794ea6..d766df684de 100644 --- a/mod/pages/languages/nl.php +++ b/mod/pages/languages/nl.php @@ -19,6 +19,7 @@ 'collection:object:page:group' => "Groepspagina's", 'add:object:page' => "Nieuwe pagina", 'edit:object:page' => "Bewerk deze pagina", + 'menu:pages_nav:header' => "Subpagina's", 'notification:object:page:create' => "Stuur een notificatie wanneer een pagina is gemaakt", 'notifications:mute:object:page' => "over de pagina '%s'", diff --git a/mod/profile/languages/nl.php b/mod/profile/languages/nl.php index 51934cd8c57..92a9a4c6d11 100644 --- a/mod/profile/languages/nl.php +++ b/mod/profile/languages/nl.php @@ -10,6 +10,7 @@ 'profile:notfound' => 'Sorry. Het opgegeven profiel kon niet gevonden worden.', 'admin:configure_utilities:profile_fields' => 'Bewerk profielvelden', + 'menu:profile_admin:header' => 'Profielbeheer', 'profile:edit' => 'Bewerk profiel', 'profile:edit:header' => 'Bewerk kopafbeelding profiel', diff --git a/mod/search/languages/nl.php b/mod/search/languages/nl.php index 6233a4f06b0..1edf0bb7a29 100644 --- a/mod/search/languages/nl.php +++ b/mod/search/languages/nl.php @@ -12,4 +12,6 @@ 'search:comment_on' => 'Reacties op "%s"', 'search:unknown_entity' => 'Onbekend Entity type', 'search:empty_query' => 'Voer een geldige zoekopdracht in', + + 'search:aria:label:site_search' => "Zoeken op de site", ); From c11e9f841efdad8c7bbc8ab1cd9dc3a45a5a4de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 18 Oct 2023 11:47:46 +0200 Subject: [PATCH 087/240] chore(i18n): updated Transifex configuration to include theme_sandbox --- .tx/config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.tx/config b/.tx/config index f2e9a7ec0ab..ef56337741c 100644 --- a/.tx/config +++ b/.tx/config @@ -164,6 +164,12 @@ source_file = mod/tagcloud/languages/en.php source_lang = en type = PHP_ARRAY +[o:elgg:p:elgg-core-5:r:theme_sandbox] +file_filter = mod/theme_sandbox/languages/.php +source_file = mod/theme_sandbox/languages/en.php +source_lang = en +type = PHP_ARRAY + [o:elgg:p:elgg-core-5:r:thewire] file_filter = mod/thewire/languages/.php source_file = mod/thewire/languages/en.php From 0652d030a390b63aec580483a4f6ac22958d5693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 18 Oct 2023 11:50:52 +0200 Subject: [PATCH 088/240] chore(i18n): update translations --- mod/theme_sandbox/languages/fr.php | 28 ++++++++++++++++++++++++++++ mod/theme_sandbox/languages/nl.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 mod/theme_sandbox/languages/fr.php create mode 100644 mod/theme_sandbox/languages/nl.php diff --git a/mod/theme_sandbox/languages/fr.php b/mod/theme_sandbox/languages/fr.php new file mode 100644 index 00000000000..c66f60ac34f --- /dev/null +++ b/mod/theme_sandbox/languages/fr.php @@ -0,0 +1,28 @@ + 'Bac à sable du thème', + + 'theme_sandbox:intro' => 'Introduction', + 'theme_sandbox:breakout' => 'Sortir de l\'iframe', + 'theme_sandbox:buttons' => 'Boutons', + 'theme_sandbox:components' => 'Composants', + 'theme_sandbox:email' => 'E-mail', + 'theme_sandbox:forms' => 'Formulaires', + 'theme_sandbox:grid' => 'Grille', + 'theme_sandbox:icons' => 'Icônes', + 'theme_sandbox:javascript' => 'JavaScript', + 'theme_sandbox:layouts' => 'Mises en page', + 'theme_sandbox:modules' => 'Modules', + 'theme_sandbox:typography' => 'Typographie', + + 'theme_sandbox:icons:blurb' => 'Utilisez elgg_view_icon($name) pour afficher des icônes. ', + + 'theme_sandbox:test_email:button' => "Envoyer un e-mail de test", + 'theme_sandbox:test_email:success' => "E-mail de test envoyé à : %s", +); diff --git a/mod/theme_sandbox/languages/nl.php b/mod/theme_sandbox/languages/nl.php new file mode 100644 index 00000000000..e5846ba1aec --- /dev/null +++ b/mod/theme_sandbox/languages/nl.php @@ -0,0 +1,29 @@ + 'Theme Sandbox', + + 'theme_sandbox:intro' => 'Introductie', + 'theme_sandbox:breakout' => 'Verlaat het iframe', + 'theme_sandbox:buttons' => 'Knoppen', + 'theme_sandbox:components' => 'Componenten', + 'theme_sandbox:email' => 'Email', + 'theme_sandbox:forms' => 'Formulieren', + 'theme_sandbox:grid' => 'Raster', + 'theme_sandbox:icons' => 'Iconen', + 'theme_sandbox:javascript' => 'JavaScript', + 'theme_sandbox:layouts' => 'Lay-outs', + 'theme_sandbox:modules' => 'Modules', + 'theme_sandbox:navigation' => 'Navigatie', + 'theme_sandbox:typography' => 'Typografie', + + 'theme_sandbox:icons:blurb' => 'Gebruik elgg_view_icon($name) om iconen weer te geven.', + + 'theme_sandbox:test_email:button' => "Stuur test email", + 'theme_sandbox:test_email:success' => "Test email verzonden naar: %s", +); From a18ad0057c4d79286768e77c14943315350c350d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 20 Oct 2023 09:41:44 +0200 Subject: [PATCH 089/240] fix(a11y): keep focus on toggled menu item fixed #14470 --- mod/likes/views/default/elgg/likes.js | 8 ++++++-- views/default/navigation/menu/elements/item_toggle.js | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mod/likes/views/default/elgg/likes.js b/mod/likes/views/default/elgg/likes.js index fdd8ee48e1d..efe1a52917d 100644 --- a/mod/likes/views/default/elgg/likes.js +++ b/mod/likes/views/default/elgg/likes.js @@ -27,10 +27,14 @@ define(['jquery', 'elgg', 'elgg/Ajax', 'elgg/hooks'], function ($, elgg, Ajax, h // warning: data is "live" and reflects changes from set_liked_state() var data = $(this).data(), guid = data.likesGuid, - current_state = data.likesState; + current_state = data.likesState, + $parent_menu = $(this).closest('.elgg-menu'); ajax.action(STATES[current_state].action, { - data: {guid: guid} + data: {guid: guid}, + success: function() { + $parent_menu.find('.elgg-menu-item-likes > a[data-likes-guid=' + guid + ']').focus(); + } }); return false; diff --git a/views/default/navigation/menu/elements/item_toggle.js b/views/default/navigation/menu/elements/item_toggle.js index 16f03a41d6b..d22d79997c5 100644 --- a/views/default/navigation/menu/elements/item_toggle.js +++ b/views/default/navigation/menu/elements/item_toggle.js @@ -16,7 +16,7 @@ define(['jquery', 'elgg/hooks', 'elgg/Ajax'], function ($, hooks, Ajax) { var $both_items = $item_clicked.add($other_item); // Be optimistic about success $both_items.toggleClass('hidden'); - $other_item.focus(); + $other_item.children('a').focus(); // Send the ajax request @@ -34,7 +34,7 @@ define(['jquery', 'elgg/hooks', 'elgg/Ajax'], function ($, hooks, Ajax) { error: function() { // Something went wrong, so undo the optimistic changes $both_items.toggleClass('hidden'); - $item_clicked.focus(); + $item_clicked.children('a').focus(); } }); From 47764673071fd8301042569f672cd9d92c37578b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 20 Oct 2023 10:21:58 +0200 Subject: [PATCH 090/240] fix(a11y): edit comment form sets focus to comment textarea fixed #14469 --- views/default/elgg/comments.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/views/default/elgg/comments.js b/views/default/elgg/comments.js index dd9fbe7f2a1..75a6faa01d4 100644 --- a/views/default/elgg/comments.js +++ b/views/default/elgg/comments.js @@ -141,6 +141,8 @@ define(['jquery', 'elgg'], function ($, elgg) { showForm: function () { this.getForm().toggleClass('hidden'); this.getForm().prev().toggleClass('hidden'); + + this.getForm().find('textarea, [contenteditable]').filter(':visible').first().focus(); }, loadForm: function () { From 487d7370a2edb4971ab6a66e1cb08d75c9dc0d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 20 Oct 2023 12:15:17 +0200 Subject: [PATCH 091/240] fix(a11y): tab to first item in opened dropdown menu Also set focus back to the popup trigger when it's closed and the focus was inside the popup --- views/default/elgg/menus/dropdown.js | 1 + views/default/elgg/popup.js | 19 +++++++++++++++++++ views/default/icon/user/default.js | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/views/default/elgg/menus/dropdown.js b/views/default/elgg/menus/dropdown.js index fe7d4def904..41194299887 100644 --- a/views/default/elgg/menus/dropdown.js +++ b/views/default/elgg/menus/dropdown.js @@ -21,6 +21,7 @@ define(['jquery', 'elgg', 'elgg/popup'], function ($, elgg, popup) { $trigger.addClass('elgg-menu-opened') .removeClass('elgg-menu-closed'); $trigger.parent().addClass('elgg-state-selected'); + $target.find('a:first').focus(); }); $target.on('close', function () { diff --git a/views/default/elgg/popup.js b/views/default/elgg/popup.js index 83b96341b69..80cb60061ad 100644 --- a/views/default/elgg/popup.js +++ b/views/default/elgg/popup.js @@ -17,6 +17,7 @@ define('elgg/popup', ['jquery', 'elgg', 'elgg/hooks', 'jquery-ui/position', 'jqu */ init: function () { $(document).on('click', function (e) { + // close the popup when clicked outside the popup if (e.isDefaultPrevented()) { return; } @@ -28,6 +29,16 @@ define('elgg/popup', ['jquery', 'elgg', 'elgg/hooks', 'jquery-ui/position', 'jqu popup.close(); }); + + $(document).on('keydown', function (e) { + // close the popup when the escape key is pressed + if (e.isDefaultPrevented() || e.key !== "Escape") { + return; + } + + popup.close(); + }); + // Bind events only once popup.init = function() {}; }, @@ -142,6 +153,14 @@ define('elgg/popup', ['jquery', 'elgg', 'elgg/hooks', 'jquery-ui/position', 'jqu $trigger.addClass('elgg-state-active'); $target.trigger('open'); + + if ($trigger.is('a')) { + $target.on('close', function() { + if ($target.find(':focus').length) { + $trigger.focus(); + } + }); + } }, /** * Hides a set of $targets. If not defined, closes all visible popup modules. diff --git a/views/default/icon/user/default.js b/views/default/icon/user/default.js index 063a7034792..6103e76e823 100644 --- a/views/default/icon/user/default.js +++ b/views/default/icon/user/default.js @@ -51,6 +51,10 @@ define(['jquery'], function ($) { $icon.data('hovermenu', $hovermenu); } + $hovermenu.on('open', function() { + $hovermenu.find('a:first').focus(); + }); + require(['elgg/popup'], function(popup) { if ($hovermenu.is(':visible')) { // close hovermenu if arrow is clicked & menu already open From 441c0f442f87f43eef5c277708316f33a3a8091d Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 23 Oct 2023 10:00:04 +0200 Subject: [PATCH 092/240] feat(ckeditor): updated to v40.0.0 --- mod/ckeditor/vendors/ckeditor5/.gitignore | 1 + .../vendors/ckeditor5/build/ckeditor.js | 8 +- .../ckeditor5/build/ckeditor.js.LICENSE.txt | 28 + .../vendors/ckeditor5/build/ckeditor.js.map | 2 +- .../vendors/ckeditor5/build/styles.css | 55 +- .../vendors/ckeditor5/build/styles.css.map | 2 +- .../ckeditor5/build/translations/af.js | 2 +- .../ckeditor5/build/translations/ar.js | 2 +- .../ckeditor5/build/translations/ast.js | 2 +- .../ckeditor5/build/translations/az.js | 2 +- .../ckeditor5/build/translations/bg.js | 2 +- .../ckeditor5/build/translations/bn.js | 2 +- .../ckeditor5/build/translations/bs.js | 2 +- .../ckeditor5/build/translations/ca.js | 2 +- .../ckeditor5/build/translations/cs.js | 2 +- .../ckeditor5/build/translations/da.js | 2 +- .../ckeditor5/build/translations/de-ch.js | 2 +- .../ckeditor5/build/translations/de.js | 2 +- .../ckeditor5/build/translations/el.js | 2 +- .../ckeditor5/build/translations/en-au.js | 2 +- .../ckeditor5/build/translations/en-gb.js | 2 +- .../ckeditor5/build/translations/eo.js | 2 +- .../ckeditor5/build/translations/es-co.js | 2 +- .../ckeditor5/build/translations/es.js | 2 +- .../ckeditor5/build/translations/et.js | 2 +- .../ckeditor5/build/translations/eu.js | 2 +- .../ckeditor5/build/translations/fa.js | 2 +- .../ckeditor5/build/translations/fi.js | 2 +- .../ckeditor5/build/translations/fr.js | 2 +- .../ckeditor5/build/translations/gl.js | 2 +- .../ckeditor5/build/translations/gu.js | 2 +- .../ckeditor5/build/translations/he.js | 2 +- .../ckeditor5/build/translations/hi.js | 2 +- .../ckeditor5/build/translations/hr.js | 2 +- .../ckeditor5/build/translations/hu.js | 2 +- .../ckeditor5/build/translations/hy.js | 1 + .../ckeditor5/build/translations/id.js | 2 +- .../ckeditor5/build/translations/it.js | 2 +- .../ckeditor5/build/translations/ja.js | 2 +- .../ckeditor5/build/translations/jv.js | 2 +- .../ckeditor5/build/translations/km.js | 2 +- .../ckeditor5/build/translations/kn.js | 2 +- .../ckeditor5/build/translations/ko.js | 2 +- .../ckeditor5/build/translations/ku.js | 2 +- .../ckeditor5/build/translations/lt.js | 2 +- .../ckeditor5/build/translations/lv.js | 2 +- .../ckeditor5/build/translations/ms.js | 2 +- .../ckeditor5/build/translations/nb.js | 2 +- .../ckeditor5/build/translations/ne.js | 2 +- .../ckeditor5/build/translations/nl.js | 2 +- .../ckeditor5/build/translations/no.js | 2 +- .../ckeditor5/build/translations/oc.js | 2 +- .../ckeditor5/build/translations/pl.js | 2 +- .../ckeditor5/build/translations/pt-br.js | 2 +- .../ckeditor5/build/translations/pt.js | 2 +- .../ckeditor5/build/translations/ro.js | 2 +- .../ckeditor5/build/translations/ru.js | 2 +- .../ckeditor5/build/translations/si.js | 2 +- .../ckeditor5/build/translations/sk.js | 2 +- .../ckeditor5/build/translations/sl.js | 2 +- .../ckeditor5/build/translations/sq.js | 2 +- .../ckeditor5/build/translations/sr-latn.js | 2 +- .../ckeditor5/build/translations/sr.js | 2 +- .../ckeditor5/build/translations/sv.js | 2 +- .../ckeditor5/build/translations/th.js | 2 +- .../ckeditor5/build/translations/tk.js | 2 +- .../ckeditor5/build/translations/tr.js | 2 +- .../ckeditor5/build/translations/tt.js | 2 +- .../ckeditor5/build/translations/ug.js | 2 +- .../ckeditor5/build/translations/uk.js | 2 +- .../ckeditor5/build/translations/ur.js | 2 +- .../ckeditor5/build/translations/uz.js | 2 +- .../ckeditor5/build/translations/vi.js | 2 +- .../ckeditor5/build/translations/zh-cn.js | 2 +- .../ckeditor5/build/translations/zh.js | 2 +- .../vendors/ckeditor5/package-lock.json | 2692 +++++---- mod/ckeditor/vendors/ckeditor5/package.json | 76 +- .../vendors/ckeditor5/webpack.config.js | 23 +- .../views/default/ckeditor/content.css | 715 ++- .../views/default/ckeditor/editor.css | 4843 +---------------- 80 files changed, 2281 insertions(+), 6301 deletions(-) create mode 100644 mod/ckeditor/vendors/ckeditor5/.gitignore create mode 100644 mod/ckeditor/vendors/ckeditor5/build/ckeditor.js.LICENSE.txt create mode 100644 mod/ckeditor/vendors/ckeditor5/build/translations/hy.js diff --git a/mod/ckeditor/vendors/ckeditor5/.gitignore b/mod/ckeditor/vendors/ckeditor5/.gitignore new file mode 100644 index 00000000000..2ccbe4656c6 --- /dev/null +++ b/mod/ckeditor/vendors/ckeditor5/.gitignore @@ -0,0 +1 @@ +/node_modules/ diff --git a/mod/ckeditor/vendors/ckeditor5/build/ckeditor.js b/mod/ckeditor/vendors/ckeditor5/build/ckeditor.js index 31ac68733bd..8ed35632a2d 100644 --- a/mod/ckeditor/vendors/ckeditor5/build/ckeditor.js +++ b/mod/ckeditor/vendors/ckeditor5/build/ckeditor.js @@ -1,7 +1,3 @@ -!function(e){const t=e.en=e.en||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"%0 of %1","Align cell text to the bottom":"Align cell text to the bottom","Align cell text to the center":"Align cell text to the center","Align cell text to the left":"Align cell text to the left","Align cell text to the middle":"Align cell text to the middle","Align cell text to the right":"Align cell text to the right","Align cell text to the top":"Align cell text to the top","Align center":"Align center","Align left":"Align left","Align right":"Align right","Align table to the left":"Align table to the left","Align table to the right":"Align table to the right",Alignment:"Alignment","Almost equal to":"Almost equal to",Angle:"Angle","Approximately equal to":"Approximately equal to",Aquamarine:"Aquamarine","Asterisk operator":"Asterisk operator","Austral sign":"Austral sign","back with leftwards arrow above":"back with leftwards arrow above",Background:"Background",Big:"Big","Bitcoin sign":"Bitcoin sign",Black:"Black","Block quote":"Block quote","Block styles":"Block styles",Blue:"Blue",Bold:"Bold",Border:"Border","Break text":"Break text","Bulleted List":"Bulleted List","Bulleted list styles toolbar":"Bulleted list styles toolbar",Cancel:"Cancel","Caption for image: %0":"Caption for image: %0","Caption for the image":"Caption for the image","Cedi sign":"Cedi sign","Cell properties":"Cell properties","Cent sign":"Cent sign","Center table":"Center table","Centered image":"Centered image","Change image text alternative":"Change image text alternative","Character categories":"Character categories","Characters: %0":"Characters: %0","Choose heading":"Choose heading",Circle:"Circle",Code:"Code","Colon sign":"Colon sign",Color:"Color","Color picker":"Color picker",Column:"Column","Contains as member":"Contains as member","Copyright sign":"Copyright sign","Cruzeiro sign":"Cruzeiro sign","Currency sign":"Currency sign",Dashed:"Dashed",Decimal:"Decimal","Decimal with leading zero":"Decimal with leading zero","Decrease indent":"Decrease indent",Default:"Default","Degree sign":"Degree sign","Delete column":"Delete column","Delete row":"Delete row","Dim grey":"Dim grey",Dimensions:"Dimensions",Disc:"Disc","Division sign":"Division sign","Dollar sign":"Dollar sign","Dong sign":"Dong sign",Dotted:"Dotted",Double:"Double","Double dagger":"Double dagger","Double exclamation mark":"Double exclamation mark","Double low-9 quotation mark":"Double low-9 quotation mark","Double question mark":"Double question mark",Downloadable:"Downloadable","downwards arrow to bar":"downwards arrow to bar","downwards dashed arrow":"downwards dashed arrow","downwards double arrow":"downwards double arrow","downwards simple arrow":"downwards simple arrow","Drachma sign":"Drachma sign","Dropdown toolbar":"Dropdown toolbar","Edit block":"Edit block","Edit link":"Edit link","Edit source":"Edit source","Editor block content toolbar":"Editor block content toolbar","Editor contextual toolbar":"Editor contextual toolbar","Editor editing area: %0":"Editor editing area: %0","Editor toolbar":"Editor toolbar","Element of":"Element of","Em dash":"Em dash","Empty set":"Empty set","Empty snippet content":"Empty snippet content","En dash":"En dash","end with leftwards arrow above":"end with leftwards arrow above","Enter image caption":"Enter image caption","Enter table caption":"Enter table caption","Euro sign":"Euro sign","Euro-currency sign":"Euro-currency sign","Exclamation question mark":"Exclamation question mark",Find:"Find","Find and replace":"Find and replace","Find in text…":"Find in text…","Font Size":"Font Size","For all":"For all","Fraction slash":"Fraction slash","French franc sign":"French franc sign","Full size image":"Full size image","German penny sign":"German penny sign","Greater-than or equal to":"Greater-than or equal to","Greater-than sign":"Greater-than sign",Green:"Green",Grey:"Grey",Groove:"Groove","Guarani sign":"Guarani sign","Header column":"Header column","Header row":"Header row",Heading:"Heading","Heading 1":"Heading 1","Heading 2":"Heading 2","Heading 3":"Heading 3","Heading 4":"Heading 4","Heading 5":"Heading 5","Heading 6":"Heading 6",Height:"Height","Horizontal ellipsis":"Horizontal ellipsis","Horizontal line":"Horizontal line","Horizontal text alignment toolbar":"Horizontal text alignment toolbar","Hryvnia sign":"Hryvnia sign","HTML object":"HTML object","HTML snippet":"HTML snippet",Huge:"Huge","Identical to":"Identical to","Image resize list":"Image resize list","Image toolbar":"Image toolbar","image widget":"image widget","In line":"In line","Increase indent":"Increase indent","Indian rupee sign":"Indian rupee sign",Infinity:"Infinity",Insert:"Insert","Insert code block":"Insert code block","Insert column left":"Insert column left","Insert column right":"Insert column right","Insert HTML":"Insert HTML","Insert image":"Insert image","Insert image via URL":"Insert image via URL","Insert media":"Insert media","Insert paragraph after block":"Insert paragraph after block","Insert paragraph before block":"Insert paragraph before block","Insert row above":"Insert row above","Insert row below":"Insert row below","Insert table":"Insert table",Inset:"Inset",Integral:"Integral",Intersection:"Intersection","Inverted exclamation mark":"Inverted exclamation mark","Inverted question mark":"Inverted question mark",Italic:"Italic",Justify:"Justify","Justify cell text":"Justify cell text","Kip sign":"Kip sign","Latin capital letter a with breve":"Latin capital letter a with breve","Latin capital letter a with macron":"Latin capital letter a with macron","Latin capital letter a with ogonek":"Latin capital letter a with ogonek","Latin capital letter c with acute":"Latin capital letter c with acute","Latin capital letter c with caron":"Latin capital letter c with caron","Latin capital letter c with circumflex":"Latin capital letter c with circumflex","Latin capital letter c with dot above":"Latin capital letter c with dot above","Latin capital letter d with caron":"Latin capital letter d with caron","Latin capital letter d with stroke":"Latin capital letter d with stroke","Latin capital letter e with breve":"Latin capital letter e with breve","Latin capital letter e with caron":"Latin capital letter e with caron","Latin capital letter e with dot above":"Latin capital letter e with dot above","Latin capital letter e with macron":"Latin capital letter e with macron","Latin capital letter e with ogonek":"Latin capital letter e with ogonek","Latin capital letter eng":"Latin capital letter eng","Latin capital letter g with breve":"Latin capital letter g with breve","Latin capital letter g with cedilla":"Latin capital letter g with cedilla","Latin capital letter g with circumflex":"Latin capital letter g with circumflex","Latin capital letter g with dot above":"Latin capital letter g with dot above","Latin capital letter h with circumflex":"Latin capital letter h with circumflex","Latin capital letter h with stroke":"Latin capital letter h with stroke","Latin capital letter i with breve":"Latin capital letter i with breve","Latin capital letter i with dot above":"Latin capital letter i with dot above","Latin capital letter i with macron":"Latin capital letter i with macron","Latin capital letter i with ogonek":"Latin capital letter i with ogonek","Latin capital letter i with tilde":"Latin capital letter i with tilde","Latin capital letter j with circumflex":"Latin capital letter j with circumflex","Latin capital letter k with cedilla":"Latin capital letter k with cedilla","Latin capital letter l with acute":"Latin capital letter l with acute","Latin capital letter l with caron":"Latin capital letter l with caron","Latin capital letter l with cedilla":"Latin capital letter l with cedilla","Latin capital letter l with middle dot":"Latin capital letter l with middle dot","Latin capital letter l with stroke":"Latin capital letter l with stroke","Latin capital letter n with acute":"Latin capital letter n with acute","Latin capital letter n with caron":"Latin capital letter n with caron","Latin capital letter n with cedilla":"Latin capital letter n with cedilla","Latin capital letter o with breve":"Latin capital letter o with breve","Latin capital letter o with double acute":"Latin capital letter o with double acute","Latin capital letter o with macron":"Latin capital letter o with macron","Latin capital letter r with acute":"Latin capital letter r with acute","Latin capital letter r with caron":"Latin capital letter r with caron","Latin capital letter r with cedilla":"Latin capital letter r with cedilla","Latin capital letter s with acute":"Latin capital letter s with acute","Latin capital letter s with caron":"Latin capital letter s with caron","Latin capital letter s with cedilla":"Latin capital letter s with cedilla","Latin capital letter s with circumflex":"Latin capital letter s with circumflex","Latin capital letter t with caron":"Latin capital letter t with caron","Latin capital letter t with cedilla":"Latin capital letter t with cedilla","Latin capital letter t with stroke":"Latin capital letter t with stroke","Latin capital letter u with breve":"Latin capital letter u with breve","Latin capital letter u with double acute":"Latin capital letter u with double acute","Latin capital letter u with macron":"Latin capital letter u with macron","Latin capital letter u with ogonek":"Latin capital letter u with ogonek","Latin capital letter u with ring above":"Latin capital letter u with ring above","Latin capital letter u with tilde":"Latin capital letter u with tilde","Latin capital letter w with circumflex":"Latin capital letter w with circumflex","Latin capital letter y with circumflex":"Latin capital letter y with circumflex","Latin capital letter y with diaeresis":"Latin capital letter y with diaeresis","Latin capital letter z with acute":"Latin capital letter z with acute","Latin capital letter z with caron":"Latin capital letter z with caron","Latin capital letter z with dot above":"Latin capital letter z with dot above","Latin capital ligature ij":"Latin capital ligature ij","Latin capital ligature oe":"Latin capital ligature oe","Latin small letter a with breve":"Latin small letter a with breve","Latin small letter a with macron":"Latin small letter a with macron","Latin small letter a with ogonek":"Latin small letter a with ogonek","Latin small letter c with acute":"Latin small letter c with acute","Latin small letter c with caron":"Latin small letter c with caron","Latin small letter c with circumflex":"Latin small letter c with circumflex","Latin small letter c with dot above":"Latin small letter c with dot above","Latin small letter d with caron":"Latin small letter d with caron","Latin small letter d with stroke":"Latin small letter d with stroke","Latin small letter dotless i":"Latin small letter dotless i","Latin small letter e with breve":"Latin small letter e with breve","Latin small letter e with caron":"Latin small letter e with caron","Latin small letter e with dot above":"Latin small letter e with dot above","Latin small letter e with macron":"Latin small letter e with macron","Latin small letter e with ogonek":"Latin small letter e with ogonek","Latin small letter eng":"Latin small letter eng","Latin small letter f with hook":"Latin small letter f with hook","Latin small letter g with breve":"Latin small letter g with breve","Latin small letter g with cedilla":"Latin small letter g with cedilla","Latin small letter g with circumflex":"Latin small letter g with circumflex","Latin small letter g with dot above":"Latin small letter g with dot above","Latin small letter h with circumflex":"Latin small letter h with circumflex","Latin small letter h with stroke":"Latin small letter h with stroke","Latin small letter i with breve":"Latin small letter i with breve","Latin small letter i with macron":"Latin small letter i with macron","Latin small letter i with ogonek":"Latin small letter i with ogonek","Latin small letter i with tilde":"Latin small letter i with tilde","Latin small letter j with circumflex":"Latin small letter j with circumflex","Latin small letter k with cedilla":"Latin small letter k with cedilla","Latin small letter kra":"Latin small letter kra","Latin small letter l with acute":"Latin small letter l with acute","Latin small letter l with caron":"Latin small letter l with caron","Latin small letter l with cedilla":"Latin small letter l with cedilla","Latin small letter l with middle dot":"Latin small letter l with middle dot","Latin small letter l with stroke":"Latin small letter l with stroke","Latin small letter long s":"Latin small letter long s","Latin small letter n preceded by apostrophe":"Latin small letter n preceded by apostrophe","Latin small letter n with acute":"Latin small letter n with acute","Latin small letter n with caron":"Latin small letter n with caron","Latin small letter n with cedilla":"Latin small letter n with cedilla","Latin small letter o with breve":"Latin small letter o with breve","Latin small letter o with double acute":"Latin small letter o with double acute","Latin small letter o with macron":"Latin small letter o with macron","Latin small letter r with acute":"Latin small letter r with acute","Latin small letter r with caron":"Latin small letter r with caron","Latin small letter r with cedilla":"Latin small letter r with cedilla","Latin small letter s with acute":"Latin small letter s with acute","Latin small letter s with caron":"Latin small letter s with caron","Latin small letter s with cedilla":"Latin small letter s with cedilla","Latin small letter s with circumflex":"Latin small letter s with circumflex","Latin small letter t with caron":"Latin small letter t with caron","Latin small letter t with cedilla":"Latin small letter t with cedilla","Latin small letter t with stroke":"Latin small letter t with stroke","Latin small letter u with breve":"Latin small letter u with breve","Latin small letter u with double acute":"Latin small letter u with double acute","Latin small letter u with macron":"Latin small letter u with macron","Latin small letter u with ogonek":"Latin small letter u with ogonek","Latin small letter u with ring above":"Latin small letter u with ring above","Latin small letter u with tilde":"Latin small letter u with tilde","Latin small letter w with circumflex":"Latin small letter w with circumflex","Latin small letter y with circumflex":"Latin small letter y with circumflex","Latin small letter z with acute":"Latin small letter z with acute","Latin small letter z with caron":"Latin small letter z with caron","Latin small letter z with dot above":"Latin small letter z with dot above","Latin small ligature ij":"Latin small ligature ij","Latin small ligature oe":"Latin small ligature oe","Left aligned image":"Left aligned image","Left double quotation mark":"Left double quotation mark","Left single quotation mark":"Left single quotation mark","Left-pointing double angle quotation mark":"Left-pointing double angle quotation mark","leftwards arrow to bar":"leftwards arrow to bar","leftwards dashed arrow":"leftwards dashed arrow","leftwards double arrow":"leftwards double arrow","leftwards simple arrow":"leftwards simple arrow","Less-than or equal to":"Less-than or equal to","Less-than sign":"Less-than sign","Light blue":"Light blue","Light green":"Light green","Light grey":"Light grey",Link:"Link","Link image":"Link image","Link URL":"Link URL","Lira sign":"Lira sign","List properties":"List properties","Livre tournois sign":"Livre tournois sign","Logical and":"Logical and","Logical or":"Logical or","Lower-latin":"Lower-latin","Lower–roman":"Lower–roman",Macron:"Macron","Manat sign":"Manat sign","Match case":"Match case","Media toolbar":"Media toolbar","Media URL":"Media URL","media widget":"media widget","Merge cell down":"Merge cell down","Merge cell left":"Merge cell left","Merge cell right":"Merge cell right","Merge cell up":"Merge cell up","Merge cells":"Merge cells","Mill sign":"Mill sign","Minus sign":"Minus sign","Multiple styles":"Multiple styles","Multiplication sign":"Multiplication sign","N-ary product":"N-ary product","N-ary summation":"N-ary summation",Nabla:"Nabla","Naira sign":"Naira sign","New sheqel sign":"New sheqel sign",Next:"Next","Next result":"Next result","No preview available":"No preview available",None:"None","Nordic mark sign":"Nordic mark sign","Not an element of":"Not an element of","Not equal to":"Not equal to","Not sign":"Not sign","Numbered List":"Numbered List","Numbered list styles toolbar":"Numbered list styles toolbar","on with exclamation mark with left right arrow above":"on with exclamation mark with left right arrow above","Open in a new tab":"Open in a new tab","Open link in new tab":"Open link in new tab","Open media in new tab":"Open media in new tab",Orange:"Orange",Original:"Original",Outset:"Outset",Overline:"Overline",Padding:"Padding",Paragraph:"Paragraph","Paragraph sign":"Paragraph sign","Partial differential":"Partial differential","Paste raw HTML here...":"Paste raw HTML here...","Paste the media URL in the input.":"Paste the media URL in the input.","Per mille sign":"Per mille sign","Per ten thousand sign":"Per ten thousand sign","Peseta sign":"Peseta sign","Peso sign":"Peso sign","Plain text":"Plain text","Plus-minus sign":"Plus-minus sign","Pound sign":"Pound sign","Press Enter to type after or press Shift + Enter to type before the widget":"Press Enter to type after or press Shift + Enter to type before the widget",Previous:"Previous","Previous result":"Previous result","Proportional to":"Proportional to",Purple:"Purple","Question exclamation mark":"Question exclamation mark",Red:"Red",Redo:"Redo","Registered sign":"Registered sign","Remove color":"Remove color","Remove Format":"Remove Format",Replace:"Replace","Replace all":"Replace all","Replace with…":"Replace with…","Resize image":"Resize image","Resize image to %0":"Resize image to %0","Resize image to the original size":"Resize image to the original size","Restore default":"Restore default","Reversed order":"Reversed order","Reversed paragraph sign":"Reversed paragraph sign","Rich Text Editor":"Rich Text Editor",Ridge:"Ridge","Right aligned image":"Right aligned image","Right double quotation mark":"Right double quotation mark","Right single quotation mark":"Right single quotation mark","Right-pointing double angle quotation mark":"Right-pointing double angle quotation mark","rightwards arrow to bar":"rightwards arrow to bar","rightwards dashed arrow":"rightwards dashed arrow","rightwards double arrow":"rightwards double arrow","rightwards simple arrow":"rightwards simple arrow",Row:"Row","Ruble sign":"Ruble sign","Rupee sign":"Rupee sign",Save:"Save","Save changes":"Save changes","Section sign":"Section sign","Select all":"Select all","Select column":"Select column","Select row":"Select row","Show more items":"Show more items","Show options":"Show options","Side image":"Side image","Single left-pointing angle quotation mark":"Single left-pointing angle quotation mark","Single low-9 quotation mark":"Single low-9 quotation mark","Single right-pointing angle quotation mark":"Single right-pointing angle quotation mark",Small:"Small",Solid:"Solid","soon with rightwards arrow above":"soon with rightwards arrow above",Source:"Source","Special characters":"Special characters","Spesmilo sign":"Spesmilo sign","Split cell horizontally":"Split cell horizontally","Split cell vertically":"Split cell vertically",Square:"Square","Square root":"Square root","Start at":"Start at","Start index must be greater than 0.":"Start index must be greater than 0.",Strikethrough:"Strikethrough",Style:"Style",Styles:"Styles",Subscript:"Subscript",Superscript:"Superscript","Table alignment toolbar":"Table alignment toolbar","Table cell text alignment":"Table cell text alignment","Table properties":"Table properties","Table toolbar":"Table toolbar","Tenge sign":"Tenge sign","Text alignment":"Text alignment","Text alignment toolbar":"Text alignment toolbar","Text alternative":"Text alternative","Text styles":"Text styles","Text to find must not be empty.":"Text to find must not be empty.",'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".':'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".',"The URL must not be empty.":"The URL must not be empty.",'The value is invalid. Try "10px" or "2em" or simply "2".':'The value is invalid. Try "10px" or "2em" or simply "2".',"There exists":"There exists","This link has no URL":"This link has no URL","This media URL is not supported.":"This media URL is not supported.","Tilde operator":"Tilde operator",Tiny:"Tiny","Tip: Find some text first in order to replace it.":"Tip: Find some text first in order to replace it.","Tip: Paste the URL into the content to embed faster.":"Tip: Paste the URL into the content to embed faster.","To-do List":"To-do List","Toggle caption off":"Toggle caption off","Toggle caption on":"Toggle caption on","Toggle the circle list style":"Toggle the circle list style","Toggle the decimal list style":"Toggle the decimal list style","Toggle the decimal with leading zero list style":"Toggle the decimal with leading zero list style","Toggle the disc list style":"Toggle the disc list style","Toggle the lower–latin list style":"Toggle the lower–latin list style","Toggle the lower–roman list style":"Toggle the lower–roman list style","Toggle the square list style":"Toggle the square list style","Toggle the upper–latin list style":"Toggle the upper–latin list style","Toggle the upper–roman list style":"Toggle the upper–roman list style","top with upwards arrow above":"top with upwards arrow above","Trade mark sign":"Trade mark sign","Tugrik sign":"Tugrik sign","Turkish lira sign":"Turkish lira sign",Turquoise:"Turquoise","Two dot leader":"Two dot leader",Underline:"Underline",Undo:"Undo",Union:"Union",Unlink:"Unlink","up down arrow with base":"up down arrow with base",Update:"Update","Update image URL":"Update image URL","Upload failed":"Upload failed","Upload in progress":"Upload in progress","Upper-latin":"Upper-latin","Upper-roman":"Upper-roman","upwards arrow to bar":"upwards arrow to bar","upwards dashed arrow":"upwards dashed arrow","upwards double arrow":"upwards double arrow","upwards simple arrow":"upwards simple arrow","Vertical text alignment toolbar":"Vertical text alignment toolbar","Vulgar fraction one half":"Vulgar fraction one half","Vulgar fraction one quarter":"Vulgar fraction one quarter","Vulgar fraction three quarters":"Vulgar fraction three quarters",White:"White","Whole words only":"Whole words only","Widget toolbar":"Widget toolbar",Width:"Width","Won sign":"Won sign","Words: %0":"Words: %0","Wrap text":"Wrap text",Yellow:"Yellow","Yen sign":"Yen sign"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})), -/*! - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ -function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ClassicEditor=t():e.ClassicEditor=t()}(self,(()=>(()=>{"use strict";var e={d:(t,i)=>{for(var n in i)e.o(i,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:i[n]})}};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var t={};e.d(t,{default:()=>sE});const i=function(){try{return navigator.userAgent.toLowerCase()}catch(e){return""}}(),n={isMac:o(i),isWindows:function(e){return e.indexOf("windows")>-1}(i),isGecko:function(e){return!!e.match(/gecko\/\d+/)}(i),isSafari:function(e){return e.indexOf(" applewebkit/")>-1&&-1===e.indexOf("chrome")}(i),isiOS:function(e){return!!e.match(/iphone|ipad/i)||o(e)&&navigator.maxTouchPoints>0}(i),isAndroid:function(e){return e.indexOf("android")>-1}(i),isBlink:function(e){return e.indexOf("chrome/")>-1&&e.indexOf("edge/")<0}(i),features:{isRegExpUnicodePropertySupported:function(){let e=!1;try{e=0==="ć".search(new RegExp("[\\p{L}]","u"))}catch(e){}return e}()}},s=n;function o(e){return e.indexOf("macintosh")>-1}function r(e,t,i,n){i=i||function(e,t){return e===t};const s=Array.isArray(e)?e:Array.prototype.slice.call(e),o=Array.isArray(t)?t:Array.prototype.slice.call(t),r=function(e,t,i){const n=a(e,t,i);if(-1===n)return{firstIndex:-1,lastIndexOld:-1,lastIndexNew:-1};const s=l(e,n),o=l(t,n),r=a(s,o,i),c=e.length-r,d=t.length-r;return{firstIndex:n,lastIndexOld:c,lastIndexNew:d}}(s,o,i),c=n?function(e,t){const{firstIndex:i,lastIndexOld:n,lastIndexNew:s}=e;if(-1===i)return Array(t).fill("equal");let o=[];i>0&&(o=o.concat(Array(i).fill("equal")));s-i>0&&(o=o.concat(Array(s-i).fill("insert")));n-i>0&&(o=o.concat(Array(n-i).fill("delete")));s0&&i.push({index:n,type:"insert",values:e.slice(n,o)});s-n>0&&i.push({index:n+(o-n),type:"delete",howMany:s-n});return i}(o,r);return c}function a(e,t,i){for(let n=0;n200||s>200||n+s>300)return c.fastDiff(e,t,i,!0);let o,r;if(sc?-1:1;h[n+d]&&(h[n]=h[n+d].slice(0)),h[n]||(h[n]=[]),h[n].push(s>c?o:r);let m=Math.max(s,c),g=m-n;for(;gd;g--)u[g]=m(g);u[d]=m(d),f++}while(u[d]!==l);return h[d].slice(1)}function d(e,...t){t.forEach((t=>{const i=Object.getOwnPropertyNames(t),n=Object.getOwnPropertySymbols(t);i.concat(n).forEach((i=>{if(i in e.prototype)return;if("function"==typeof t&&("length"==i||"name"==i||"prototype"==i))return;const n=Object.getOwnPropertyDescriptor(t,i);n.enumerable=!1,Object.defineProperty(e.prototype,i,n)}))}))}c.fastDiff=r;const h=function(){return function e(){e.called=!0}};class u{constructor(e,t){this.source=e,this.name=t,this.path=[],this.stop=h(),this.off=h()}}const m=new Array(256).fill("").map(((e,t)=>("0"+t.toString(16)).slice(-2)));function g(){const e=4294967296*Math.random()>>>0,t=4294967296*Math.random()>>>0,i=4294967296*Math.random()>>>0,n=4294967296*Math.random()>>>0;return"e"+m[e>>0&255]+m[e>>8&255]+m[e>>16&255]+m[e>>24&255]+m[t>>0&255]+m[t>>8&255]+m[t>>16&255]+m[t>>24&255]+m[i>>0&255]+m[i>>8&255]+m[i>>16&255]+m[i>>24&255]+m[n>>0&255]+m[n>>8&255]+m[n>>16&255]+m[n>>24&255]}const f={get(e="normal"){return"number"!=typeof e?this[e]||this.normal:e},highest:1e5,high:1e3,normal:0,low:-1e3,lowest:-1e5};function p(e,t){const i=f.get(t.priority);for(let n=0;n{if("object"==typeof t&&null!==t){if(i.has(t))return`[object ${t.constructor.name}]`;i.add(t)}return t},s=t?` ${JSON.stringify(t,n)}`:"",o=_(e);return e+s+o}(e,i)),this.name="CKEditorError",this.context=t,this.data=i}is(e){return"CKEditorError"===e}static rethrowUnexpectedError(e,t){if(e.is&&e.is("CKEditorError"))throw e;const i=new b(e.message,t);throw i.stack=e.stack,i}}function v(e,t){console.warn(...y(e,t))}function _(e){return`\nRead more: ${w}#error-${e}`}function y(e,t){const i=_(e);return t?[e,t,i]:[e,i]}const k="35.4.0",C="object"==typeof window?window:e.g;if(C.CKEDITOR_VERSION)throw new b("ckeditor-duplicated-modules",null);C.CKEDITOR_VERSION=k;const A=Symbol("listeningTo"),x=Symbol("emitterId"),T=Symbol("delegations"),E=S(Object);function S(e){if(!e)return E;return class extends e{on(e,t,i){this.listenTo(this,e,t,i)}once(e,t,i){let n=!1;this.listenTo(this,e,((e,...i)=>{n||(n=!0,e.off(),t.call(this,e,...i))}),i)}off(e,t){this.stopListening(this,e,t)}listenTo(e,t,i,n={}){let s,o;this[A]||(this[A]={});const r=this[A];I(e)||P(e);const a=I(e);(s=r[a])||(s=r[a]={emitter:e,callbacks:{}}),(o=s.callbacks[t])||(o=s.callbacks[t]=[]),o.push(i),function(e,t,i,n,s){t._addEventListener?t._addEventListener(i,n,s):e._addEventListener.call(t,i,n,s)}(this,e,t,i,n)}stopListening(e,t,i){const n=this[A];let s=e&&I(e);const o=n&&s?n[s]:void 0,r=o&&t?o.callbacks[t]:void 0;if(!(!n||e&&!o||t&&!r))if(i){B(this,e,t,i);-1!==r.indexOf(i)&&(1===r.length?delete o.callbacks[t]:B(this,e,t,i))}else if(r){for(;i=r.pop();)B(this,e,t,i);delete o.callbacks[t]}else if(o){for(t in o.callbacks)this.stopListening(e,t);delete n[s]}else{for(s in n)this.stopListening(n[s].emitter);delete this[A]}}fire(e,...t){try{const i=e instanceof u?e:new u(this,e),n=i.name;let s=L(this,n);if(i.path.push(this),s){const e=[i,...t];s=Array.from(s);for(let t=0;t{this[T]||(this[T]=new Map),e.forEach((e=>{const n=this[T].get(e);n?n.set(t,i):this[T].set(e,new Map([[t,i]]))}))}}}stopDelegating(e,t){if(this[T])if(e)if(t){const i=this[T].get(e);i&&i.delete(t)}else this[T].delete(e);else this[T].clear()}_addEventListener(e,t,i){!function(e,t){const i=R(e);if(i[t])return;let n=t,s=null;const o=[];for(;""!==n&&!i[n];)i[n]={callbacks:[],childEvents:[]},o.push(i[n]),s&&i[n].childEvents.push(s),s=n,n=n.substr(0,n.lastIndexOf(":"));if(""!==n){for(const e of o)e.callbacks=i[n].callbacks.slice();i[n].childEvents.push(s)}}(this,e);const n=V(this,e),s={callback:t,priority:f.get(i.priority)};for(const e of n)p(e,s)}_removeEventListener(e,t){const i=V(this,e);for(const e of i)for(let i=0;i-1?L(e,t.substr(0,t.lastIndexOf(":"))):null}function O(e,t,i){for(let[n,s]of e){s?"function"==typeof s&&(s=s(t.name)):s=t.name;const e=new u(t.source,s);e.path=[...t.path],n.fire(e,...i)}}function B(e,t,i,n){t._removeEventListener?t._removeEventListener(i,n):e._removeEventListener.call(t,i,n)}["on","once","off","listenTo","stopListening","fire","delegate","stopDelegating","_addEventListener","_removeEventListener"].forEach((e=>{S[e]=E.prototype[e]}));const M=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)},N=Symbol("observableProperties"),D=Symbol("boundObservables"),F=Symbol("boundProperties"),z=Symbol("decoratedMethods"),H=Symbol("decoratedOriginal"),$=W(S());function W(e){if(!e)return $;return class extends e{set(e,t){if(M(e))return void Object.keys(e).forEach((t=>{this.set(t,e[t])}),this);j(this);const i=this[N];if(e in this&&!i.has(e))throw new b("observable-set-cannot-override",this);Object.defineProperty(this,e,{enumerable:!0,configurable:!0,get:()=>i.get(e),set(t){const n=i.get(e);let s=this.fire(`set:${e}`,e,t,n);void 0===s&&(s=t),n===s&&i.has(e)||(i.set(e,s),this.fire(`change:${e}`,e,s,n))}}),this[e]=t}bind(...e){if(!e.length||!G(e))throw new b("observable-bind-wrong-properties",this);if(new Set(e).size!==e.length)throw new b("observable-bind-duplicate-properties",this);j(this);const t=this[F];e.forEach((e=>{if(t.has(e))throw new b("observable-bind-rebind",this)}));const i=new Map;return e.forEach((e=>{const n={property:e,to:[]};t.set(e,n),i.set(e,n)})),{to:q,toMany:U,_observable:this,_bindProperties:e,_to:[],_bindings:i}}unbind(...e){if(!this[N])return;const t=this[F],i=this[D];if(e.length){if(!G(e))throw new b("observable-unbind-wrong-properties",this);e.forEach((e=>{const n=t.get(e);n&&(n.to.forEach((([e,t])=>{const s=i.get(e),o=s[t];o.delete(n),o.size||delete s[t],Object.keys(s).length||(i.delete(e),this.stopListening(e,"change"))})),t.delete(e))}))}else i.forEach(((e,t)=>{this.stopListening(t,"change")})),i.clear(),t.clear()}decorate(e){j(this);const t=this[e];if(!t)throw new b("observablemixin-cannot-decorate-undefined",this,{object:this,methodName:e});this.on(e,((e,i)=>{e.return=t.apply(this,i)})),this[e]=function(...t){return this.fire(e,t)},this[e][H]=t,this[z]||(this[z]=[]),this[z].push(e)}stopListening(e,t,i){if(!e&&this[z]){for(const e of this[z])this[e]=this[e][H];delete this[z]}super.stopListening(e,t,i)}}}function j(e){e[N]||(Object.defineProperty(e,N,{value:new Map}),Object.defineProperty(e,D,{value:new Map}),Object.defineProperty(e,F,{value:new Map}))}function q(...e){const t=function(...e){if(!e.length)throw new b("observable-bind-to-parse-error",null);const t={to:[]};let i;"function"==typeof e[e.length-1]&&(t.callback=e.pop());return e.forEach((e=>{if("string"==typeof e)i.properties.push(e);else{if("object"!=typeof e)throw new b("observable-bind-to-parse-error",null);i={observable:e,properties:[]},t.to.push(i)}})),t}(...e),i=Array.from(this._bindings.keys()),n=i.length;if(!t.callback&&t.to.length>1)throw new b("observable-bind-to-no-callback",this);if(n>1&&t.callback)throw new b("observable-bind-to-extra-callback",this);var s;t.to.forEach((e=>{if(e.properties.length&&e.properties.length!==n)throw new b("observable-bind-to-properties-length",this);e.properties.length||(e.properties=this._bindProperties)})),this._to=t.to,t.callback&&(this._bindings.get(i[0]).callback=t.callback),s=this._observable,this._to.forEach((e=>{const t=s[D];let i;t.get(e.observable)||s.listenTo(e.observable,"change",((n,o)=>{i=t.get(e.observable)[o],i&&i.forEach((e=>{K(s,e.property)}))}))})),function(e){let t;e._bindings.forEach(((i,n)=>{e._to.forEach((s=>{t=s.properties[i.callback?0:e._bindProperties.indexOf(n)],i.to.push([s.observable,t]),function(e,t,i,n){const s=e[D],o=s.get(i),r=o||{};r[n]||(r[n]=new Set);r[n].add(t),o||s.set(i,r)}(e._observable,i,s.observable,t)}))}))}(this),this._bindProperties.forEach((e=>{K(this._observable,e)}))}function U(e,t,i){if(this._bindings.size>1)throw new b("observable-bind-to-many-not-one-binding",this);this.to(...function(e,t){const i=e.map((e=>[e,t]));return Array.prototype.concat.apply([],i)}(e,t),i)}function G(e){return e.every((e=>"string"==typeof e))}function K(e,t){const i=e[F].get(t);let n;i.callback?n=i.callback.apply(e,i.to.map((e=>e[0][e[1]]))):(n=i.to[0],n=n[0][n[1]]),Object.prototype.hasOwnProperty.call(e,t)?e[t]=n:e.set(t,n)}["set","bind","unbind","decorate","on","once","off","listenTo","stopListening","fire","delegate","stopDelegating","_addEventListener","_removeEventListener"].forEach((e=>{W[e]=$.prototype[e]}));class J{constructor(){this._replacedElements=[]}replace(e,t){this._replacedElements.push({element:e,newElement:t}),e.style.display="none",t&&e.parentNode.insertBefore(t,e.nextSibling)}restore(){this._replacedElements.forEach((({element:e,newElement:t})=>{e.style.display="",t&&t.remove()})),this._replacedElements=[]}}function Q(e){let t=0;for(const i of e)t++;return t}function Y(e,t){const i=Math.min(e.length,t.length);for(let n=0;n-1};const Re=function(e,t){var i=this.__data__,n=Te(i,e);return n<0?(++this.size,i.push([e,t])):i[n][1]=t,this};function Ve(e){var t=-1,i=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991};var $t={};$t["[object Float32Array]"]=$t["[object Float64Array]"]=$t["[object Int8Array]"]=$t["[object Int16Array]"]=$t["[object Int32Array]"]=$t["[object Uint8Array]"]=$t["[object Uint8ClampedArray]"]=$t["[object Uint16Array]"]=$t["[object Uint32Array]"]=!0,$t["[object Arguments]"]=$t["[object Array]"]=$t["[object ArrayBuffer]"]=$t["[object Boolean]"]=$t["[object DataView]"]=$t["[object Date]"]=$t["[object Error]"]=$t["[object Function]"]=$t["[object Map]"]=$t["[object Number]"]=$t["[object Object]"]=$t["[object RegExp]"]=$t["[object Set]"]=$t["[object String]"]=$t["[object WeakMap]"]=!1;const Wt=function(e){return me(e)&&Ht(e.length)&&!!$t[he(e)]};const jt=function(e){return function(t){return e(t)}};var qt="object"==typeof exports&&exports&&!exports.nodeType&&exports,Ut=qt&&"object"==typeof module&&module&&!module.nodeType&&module,Gt=Ut&&Ut.exports===qt&&Z.process;const Kt=function(){try{var e=Ut&&Ut.require&&Ut.require("util").types;return e||Gt&&Gt.binding&&Gt.binding("util")}catch(e){}}();var Jt=Kt&&Kt.isTypedArray;const Qt=Jt?jt(Jt):Wt;var Yt=Object.prototype.hasOwnProperty;const Xt=function(e,t){var i=ue(e),n=!i&&Lt(e),s=!i&&!n&&Dt(e),o=!i&&!n&&!s&&Qt(e),r=i||n||s||o,a=r?St(e.length,String):[],l=a.length;for(var c in e)!t&&!Yt.call(e,c)||r&&("length"==c||s&&("offset"==c||"parent"==c)||o&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||zt(c,l))||a.push(c);return a};var Zt=Object.prototype;const ei=function(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||Zt)};const ti=pe(Object.keys,Object);var ii=Object.prototype.hasOwnProperty;const ni=function(e){if(!ei(e))return ti(e);var t=[];for(var i in Object(e))ii.call(e,i)&&"constructor"!=i&&t.push(i);return t};const si=function(e){return null!=e&&Ht(e.length)&&!De(e)};const oi=function(e){return si(e)?Xt(e):ni(e)};const ri=function(e,t){return e&&Et(t,oi(t),e)};const ai=function(e){var t=[];if(null!=e)for(var i in Object(e))t.push(i);return t};var li=Object.prototype.hasOwnProperty;const ci=function(e){if(!M(e))return ai(e);var t=ei(e),i=[];for(var n in e)("constructor"!=n||!t&&li.call(e,n))&&i.push(n);return i};const di=function(e){return si(e)?Xt(e,!0):ci(e)};const hi=function(e,t){return e&&Et(t,di(t),e)};var ui="object"==typeof exports&&exports&&!exports.nodeType&&exports,mi=ui&&"object"==typeof module&&module&&!module.nodeType&&module,gi=mi&&mi.exports===ui?te.Buffer:void 0,fi=gi?gi.allocUnsafe:void 0;const pi=function(e,t){if(t)return e.slice();var i=e.length,n=fi?fi(i):new e.constructor(i);return e.copy(n),n};const wi=function(e,t){var i=-1,n=e.length;for(t||(t=Array(n));++i{this._setToTarget(e,n,t[n],i)}))}}function kn(e){return vn(e,Cn)}function Cn(e){return _n(e)?e:void 0}function An(e){if(e){if(e.defaultView)return e instanceof e.defaultView.Document;if(e.ownerDocument&&e.ownerDocument.defaultView)return e instanceof e.ownerDocument.defaultView.Node}return!1}function xn(e){const t=Object.prototype.toString.apply(e);return"[object Window]"==t||"[object global]"==t}const Tn=En(S());function En(e){if(!e)return Tn;return class extends e{listenTo(e,t,i,n={}){if(An(e)||xn(e)){const s={capture:!!n.useCapture,passive:!!n.usePassive},o=this._getProxyEmitter(e,s)||new Sn(e,s);this.listenTo(o,t,i,n)}else super.listenTo(e,t,i,n)}stopListening(e,t,i){if(An(e)||xn(e)){const n=this._getAllProxyEmitters(e);for(const e of n)this.stopListening(e,t,i)}else super.stopListening(e,t,i)}_getProxyEmitter(e,t){return function(e,t){const i=e[A];return i&&i[t]?i[t].emitter:null}(this,Pn(e,t))}_getAllProxyEmitters(e){return[{capture:!1,passive:!1},{capture:!1,passive:!0},{capture:!0,passive:!1},{capture:!0,passive:!0}].map((t=>this._getProxyEmitter(e,t))).filter((e=>!!e))}}}["_getProxyEmitter","_getAllProxyEmitters","on","once","off","listenTo","stopListening","fire","delegate","stopDelegating","_addEventListener","_removeEventListener"].forEach((e=>{En[e]=Tn.prototype[e]}));class Sn extends(S()){constructor(e,t){super(),P(this,Pn(e,t)),this._domNode=e,this._options=t}attach(e){if(this._domListeners&&this._domListeners[e])return;const t=this._createDomListener(e);this._domNode.addEventListener(e,t,this._options),this._domListeners||(this._domListeners={}),this._domListeners[e]=t}detach(e){let t;!this._domListeners[e]||(t=this._events[e])&&t.callbacks.length||this._domListeners[e].removeListener()}_addEventListener(e,t,i){this.attach(e),S().prototype._addEventListener.call(this,e,t,i)}_removeEventListener(e,t){S().prototype._removeEventListener.call(this,e,t),this.detach(e)}_createDomListener(e){const t=t=>{this.fire(e,t)};return t.removeListener=()=>{this._domNode.removeEventListener(e,t,this._options),delete this._domListeners[e]},t}}function Pn(e,t){let i=function(e){return e["data-ck-expando"]||(e["data-ck-expando"]=g())}(e);for(const e of Object.keys(t).sort())t[e]&&(i+="-"+e);return i}let In;try{In={window,document}}catch(e){In={window:{},document:{}}}const Rn=In;function Vn(e){const t=[];let i=e;for(;i&&i.nodeType!=Node.DOCUMENT_NODE;)t.unshift(i),i=i.parentNode;return t}function Ln(e){return"[object Text]"==Object.prototype.toString.call(e)}function On(e){return"[object Range]"==Object.prototype.toString.apply(e)}function Bn(e){const t=e.ownerDocument.defaultView.getComputedStyle(e);return{top:parseInt(t.borderTopWidth,10),right:parseInt(t.borderRightWidth,10),bottom:parseInt(t.borderBottomWidth,10),left:parseInt(t.borderLeftWidth,10)}}const Mn=["top","right","bottom","left","width","height"];class Nn{constructor(e){const t=On(e);if(Object.defineProperty(this,"_source",{value:e._source||e,writable:!0,enumerable:!1}),zn(e)||t)if(t){const t=Nn.getDomRangeRects(e);Dn(this,Nn.getBoundingRect(t))}else Dn(this,e.getBoundingClientRect());else if(xn(e)){const{innerWidth:t,innerHeight:i}=e;Dn(this,{top:0,right:t,bottom:i,left:0,width:t,height:i})}else Dn(this,e)}clone(){return new Nn(this)}moveTo(e,t){return this.top=t,this.right=e+this.width,this.bottom=t+this.height,this.left=e,this}moveBy(e,t){return this.top+=t,this.right+=e,this.left+=e,this.bottom+=t,this}getIntersection(e){const t={top:Math.max(this.top,e.top),right:Math.min(this.right,e.right),bottom:Math.min(this.bottom,e.bottom),left:Math.max(this.left,e.left),width:0,height:0};return t.width=t.right-t.left,t.height=t.bottom-t.top,t.width<0||t.height<0?null:new Nn(t)}getIntersectionArea(e){const t=this.getIntersection(e);return t?t.getArea():0}getArea(){return this.width*this.height}getVisible(){const e=this._source;let t=this.clone();if(!Fn(e)){let i=e.parentNode||e.commonAncestorContainer;for(;i&&!Fn(i);){const e=new Nn(i),n=t.getIntersection(e);if(!n)return null;n.getArea(){for(const t of e){const e=Hn._getElementCallbacks(t.target);if(e)for(const i of e)i(t)}}))}}function $n(e,t){e instanceof HTMLTextAreaElement&&(e.value=t),e.innerHTML=t}function Wn(e){return t=>t+e}function jn(e){let t=0;for(;e.previousSibling;)e=e.previousSibling,t++;return t}function qn(e,t,i){e.insertBefore(i,e.childNodes[t]||null)}function Un(e){return e&&e.nodeType===Node.COMMENT_NODE}function Gn(e){return!!(e&&e.getClientRects&&e.getClientRects().length)}function Kn({element:e,target:t,positions:i,limiter:n,fitInViewport:s,viewportOffsetConfig:o}){De(t)&&(t=t()),De(n)&&(n=n());const r=function(e){return e&&e.parentNode?e.offsetParent===Rn.document.body?null:e.offsetParent:null}(e),a=new Nn(e),l=new Nn(t);let c;const d=s&&function(e){e=Object.assign({top:0,bottom:0,left:0,right:0},e);const t=new Nn(Rn.window);return t.top+=e.top,t.height-=e.top,t.bottom-=e.bottom,t.height-=e.bottom,t}(o)||null,h={targetRect:l,elementRect:a,positionedElementAncestor:r,viewportRect:d};if(n||s){const e=n&&new Nn(n).getVisible();Object.assign(h,{limiterRect:e,viewportRect:d}),c=function(e,t){const{elementRect:i}=t,n=i.getArea(),s=e.map((e=>new Qn(e,t))).filter((e=>!!e.name));let o=0,r=null;for(const e of s){const{limiterIntersectionArea:t,viewportIntersectionArea:i}=e;if(t===n)return e;const s=i**2+t**2;s>o&&(o=s,r=e)}return r}(i,h)||new Qn(i[0],h)}else c=new Qn(i[0],h);return c}function Jn(e){const{scrollX:t,scrollY:i}=Rn.window;return e.clone().moveBy(t,i)}Hn._observerInstance=null,Hn._elementCallbacks=null;class Qn{constructor(e,t){const i=e(t.targetRect,t.elementRect,t.viewportRect);if(!i)return;const{left:n,top:s,name:o,config:r}=i;this.name=o,this.config=r,this._positioningFunctionCorrdinates={left:n,top:s},this._options=t}get left(){return this._absoluteRect.left}get top(){return this._absoluteRect.top}get limiterIntersectionArea(){const e=this._options.limiterRect;if(e){const t=this._options.viewportRect;if(!t)return e.getIntersectionArea(this._rect);{const i=e.getIntersection(t);if(i)return i.getIntersectionArea(this._rect)}}return 0}get viewportIntersectionArea(){const e=this._options.viewportRect;return e?e.getIntersectionArea(this._rect):0}get _rect(){return this._cachedRect||(this._cachedRect=this._options.elementRect.clone().moveTo(this._positioningFunctionCorrdinates.left,this._positioningFunctionCorrdinates.top)),this._cachedRect}get _absoluteRect(){return this._cachedAbsoluteRect||(this._cachedAbsoluteRect=Jn(this._rect),this._options.positionedElementAncestor&&function(e,t){const i=Jn(new Nn(t)),n=Bn(t);let s=0,o=0;s-=i.left,o-=i.top,s+=t.scrollLeft,o+=t.scrollTop,s-=n.left,o-=n.top,e.moveBy(s,o)}(this._cachedAbsoluteRect,this._options.positionedElementAncestor)),this._cachedAbsoluteRect}}function Yn(e){const t=e.parentNode;t&&t.removeChild(e)}function Xn({target:e,viewportOffset:t=0}){const i=os(e);let n=i,s=null;for(;n;){let o;o=rs(n==i?e:s),es(o,(()=>as(e,n)));const r=as(e,n);if(Zn(n,r,t),n.parent!=n){if(s=n.frameElement,n=n.parent,!s)return}else n=null}}function Zn(e,t,i){const n=t.clone().moveBy(0,i),s=t.clone().moveBy(0,-i),o=new Nn(e).excludeScrollbarsAndBorders();if(![s,n].every((e=>o.contains(e)))){let{scrollX:r,scrollY:a}=e;is(s,o)?a-=o.top-t.top+i:ts(n,o)&&(a+=t.bottom-o.bottom+i),ns(t,o)?r-=o.left-t.left+i:ss(t,o)&&(r+=t.right-o.right+i),e.scrollTo(r,a)}}function es(e,t){const i=os(e);let n,s;for(;e!=i.document.body;)s=t(),n=new Nn(e).excludeScrollbarsAndBorders(),n.contains(s)||(is(s,n)?e.scrollTop-=n.top-s.top:ts(s,n)&&(e.scrollTop+=s.bottom-n.bottom),ns(s,n)?e.scrollLeft-=n.left-s.left:ss(s,n)&&(e.scrollLeft+=s.right-n.right)),e=e.parentNode}function ts(e,t){return e.bottom>t.bottom}function is(e,t){return e.topt.right}function os(e){return On(e)?e.startContainer.ownerDocument.defaultView:e.ownerDocument.defaultView}function rs(e){if(On(e)){let t=e.commonAncestorContainer;return Ln(t)&&(t=t.parentNode),t}return e.parentNode}function as(e,t){const i=os(e),n=new Nn(e);if(i===t)return n;{let e=i;for(;e!=t;){const t=e.frameElement,i=new Nn(t).excludeScrollbarsAndBorders();n.moveBy(i.left,i.top),e=e.parent}}return n}const ls={ctrl:"⌃",cmd:"⌘",alt:"⌥",shift:"⇧"},cs={ctrl:"Ctrl+",alt:"Alt+",shift:"Shift+"},ds=function(){const e={arrowleft:37,arrowup:38,arrowright:39,arrowdown:40,backspace:8,delete:46,enter:13,space:32,esc:27,tab:9,ctrl:1114112,shift:2228224,alt:4456448,cmd:8912896};for(let t=65;t<=90;t++){e[String.fromCharCode(t).toLowerCase()]=t}for(let t=48;t<=57;t++)e[t-48]=t;for(let t=112;t<=123;t++)e["f"+(t-111)]=t;for(const t of"`-=[];',./\\")e[t]=t.charCodeAt(0);return e}(),hs=Object.fromEntries(Object.entries(ds).map((([e,t])=>[t,e.charAt(0).toUpperCase()+e.slice(1)])));function us(e){let t;if("string"==typeof e){if(t=ds[e.toLowerCase()],!t)throw new b("keyboard-unknown-key",null,{key:e})}else t=e.keyCode+(e.altKey?ds.alt:0)+(e.ctrlKey?ds.ctrl:0)+(e.shiftKey?ds.shift:0)+(e.metaKey?ds.cmd:0);return t}function ms(e){return"string"==typeof e&&(e=function(e){return e.split("+").map((e=>e.trim()))}(e)),e.map((e=>"string"==typeof e?function(e){if(e.endsWith("!"))return us(e.slice(0,-1));const t=us(e);return s.isMac&&t==ds.ctrl?ds.cmd:t}(e):e)).reduce(((e,t)=>t+e),0)}function gs(e){let t=ms(e);return Object.entries(s.isMac?ls:cs).reduce(((e,[i,n])=>(0!=(t&ds[i])&&(t&=~ds[i],e+=n),e)),"")+(t?hs[t]:"")}function fs(e,t){const i="ltr"===t;switch(e){case ds.arrowleft:return i?"left":"right";case ds.arrowright:return i?"right":"left";case ds.arrowup:return"up";case ds.arrowdown:return"down"}}function ps(e){return Array.isArray(e)?e:[e]}function ws(e,t,i=1){if("number"!=typeof i)throw new b("translation-service-quantity-not-a-number",null,{quantity:i});const n=Object.keys(Rn.window.CKEDITOR_TRANSLATIONS).length;1===n&&(e=Object.keys(Rn.window.CKEDITOR_TRANSLATIONS)[0]);const s=t.id||t.string;if(0===n||!function(e,t){return!!Rn.window.CKEDITOR_TRANSLATIONS[e]&&!!Rn.window.CKEDITOR_TRANSLATIONS[e].dictionary[t]}(e,s))return 1!==i?t.plural:t.string;const o=Rn.window.CKEDITOR_TRANSLATIONS[e].dictionary,r=Rn.window.CKEDITOR_TRANSLATIONS[e].getPluralForm||(e=>1===e?0:1),a=o[s];if("string"==typeof a)return a;return a[Number(r(i))]}Rn.window.CKEDITOR_TRANSLATIONS||(Rn.window.CKEDITOR_TRANSLATIONS={});const bs=["ar","ara","fa","per","fas","he","heb","ku","kur","ug","uig"];function vs(e){return bs.includes(e)?"rtl":"ltr"}class _s{constructor({uiLanguage:e="en",contentLanguage:t}={}){this.uiLanguage=e,this.contentLanguage=t||this.uiLanguage,this.uiLanguageDirection=vs(this.uiLanguage),this.contentLanguageDirection=vs(this.contentLanguage),this.t=(e,t)=>this._t(e,t)}get language(){return console.warn("locale-deprecated-language-property: The Locale#language property has been deprecated and will be removed in the near future. Please use #uiLanguage and #contentLanguage properties instead."),this.uiLanguage}_t(e,t=[]){t=ps(t),"string"==typeof e&&(e={string:e});const i=!!e.plural?t[0]:1;return function(e,t){return e.replace(/%(\d+)/g,((e,i)=>ithis._items.length||t<0)throw new b("collection-add-item-invalid-index",this);let i=0;for(const n of e){const e=this._getItemIdBeforeAdding(n),s=t+i;this._items.splice(s,0,n),this._itemMap.set(e,n),this.fire("add",n,s),i++}return this.fire("change",{added:e,removed:[],index:t}),this}get(e){let t;if("string"==typeof e)t=this._itemMap.get(e);else{if("number"!=typeof e)throw new b("collection-get-invalid-arg",this);t=this._items[e]}return t||null}has(e){if("string"==typeof e)return this._itemMap.has(e);{const t=e[this._idProperty];return t&&this._itemMap.has(t)}}getIndex(e){let t;return t="string"==typeof e?this._itemMap.get(e):e,t?this._items.indexOf(t):-1}remove(e){const[t,i]=this._remove(e);return this.fire("change",{added:[],removed:[t],index:i}),t}map(e,t){return this._items.map(e,t)}find(e,t){return this._items.find(e,t)}filter(e,t){return this._items.filter(e,t)}clear(){this._bindToCollection&&(this.stopListening(this._bindToCollection),this._bindToCollection=null);const e=Array.from(this._items);for(;this.length;)this._remove(0);this.fire("change",{added:[],removed:e,index:0})}bindTo(e){if(this._bindToCollection)throw new b("collection-bind-to-rebind",this);return this._bindToCollection=e,{as:e=>{this._setUpBindToBinding((t=>new e(t)))},using:e=>{"function"==typeof e?this._setUpBindToBinding(e):this._setUpBindToBinding((t=>t[e]))}}}_setUpBindToBinding(e){const t=this._bindToCollection,i=(i,n,s)=>{const o=t._bindToCollection==this,r=t._bindToInternalToExternalMap.get(n);if(o&&r)this._bindToExternalToInternalMap.set(n,r),this._bindToInternalToExternalMap.set(r,n);else{const i=e(n);if(!i)return void this._skippedIndexesFromExternal.push(s);let o=s;for(const e of this._skippedIndexesFromExternal)s>e&&o--;for(const e of t._skippedIndexesFromExternal)o>=e&&o++;this._bindToExternalToInternalMap.set(n,i),this._bindToInternalToExternalMap.set(i,n),this.add(i,o);for(let e=0;e{const n=this._bindToExternalToInternalMap.get(t);n&&this.remove(n),this._skippedIndexesFromExternal=this._skippedIndexesFromExternal.reduce(((e,t)=>(it&&e.push(t),e)),[])}))}_getItemIdBeforeAdding(e){const t=this._idProperty;let i;if(t in e){if(i=e[t],"string"!=typeof i)throw new b("collection-add-invalid-id",this);if(this.get(i))throw new b("collection-add-item-already-exists",this)}else e[t]=i=g();return i}_remove(e){let t,i,n,s=!1;const o=this._idProperty;if("string"==typeof e?(i=e,n=this._itemMap.get(i),s=!n,n&&(t=this._items.indexOf(n))):"number"==typeof e?(t=e,n=this._items[t],s=!n,n&&(i=n[o])):(n=e,i=n[o],t=this._items.indexOf(n),s=-1==t||!this._itemMap.get(i)),s)throw new b("collection-remove-404",this);this._items.splice(t,1),this._itemMap.delete(i);const r=this._bindToInternalToExternalMap.get(n);return this._bindToInternalToExternalMap.delete(n),this._bindToExternalToInternalMap.delete(r),this.fire("remove",n,t),[n,t]}[Symbol.iterator](){return this._items[Symbol.iterator]()}}function ks(e){const t=e.next();return t.done?null:t.value}class Cs extends(En(W())){constructor(){super(),this._elements=new Set,this._nextEventLoopTimeout=null,this.set("isFocused",!1),this.set("focusedElement",null)}add(e){if(this._elements.has(e))throw new b("focustracker-add-element-already-exist",this);this.listenTo(e,"focus",(()=>this._focus(e)),{useCapture:!0}),this.listenTo(e,"blur",(()=>this._blur()),{useCapture:!0}),this._elements.add(e)}remove(e){e===this.focusedElement&&this._blur(),this._elements.has(e)&&(this.stopListening(e),this._elements.delete(e))}destroy(){this.stopListening()}_focus(e){clearTimeout(this._nextEventLoopTimeout),this.focusedElement=e,this.isFocused=!0}_blur(){clearTimeout(this._nextEventLoopTimeout),this._nextEventLoopTimeout=setTimeout((()=>{this.focusedElement=null,this.isFocused=!1}),0)}}class As{constructor(){this._listener=new(En())}listenTo(e){this._listener.listenTo(e,"keydown",((e,t)=>{this._listener.fire("_keydown:"+us(t),t)}))}set(e,t,i={}){const n=ms(e),s=i.priority;this._listener.listenTo(this._listener,"_keydown:"+n,((e,i)=>{t(i,(()=>{i.preventDefault(),i.stopPropagation(),e.stop()})),e.return=!0}),{priority:s})}press(e){return!!this._listener.fire("_keydown:"+us(e),e)}destroy(){this._listener.stopListening()}}function xs(e){return X(e)?new Map(e):function(e){const t=new Map;for(const i in e)t.set(i,e[i]);return t}(e)}function Ts(e,t){return!!(i=e.charAt(t-1))&&1==i.length&&/[\ud800-\udbff]/.test(i)&&function(e){return!!e&&1==e.length&&/[\udc00-\udfff]/.test(e)}(e.charAt(t));var i}function Es(e,t){return!!(i=e.charAt(t))&&1==i.length&&/[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/.test(i);var i}const Ss=function(){const e=/\p{Regional_Indicator}{2}/u.source,t="(?:"+[/\p{Emoji}[\u{E0020}-\u{E007E}]+\u{E007F}/u,/\p{Emoji}\u{FE0F}?\u{20E3}/u,/\p{Emoji}\u{FE0F}/u,/(?=\p{General_Category=Other_Symbol})\p{Emoji}\p{Emoji_Modifier}*/u].map((e=>e.source)).join("|")+")";return new RegExp(`${e}|${t}(?:‍${t})*`,"ug")}();function Ps(e,t){const i=String(e).matchAll(Ss);return Array.from(i).some((e=>e.index{this.refresh()})),this.on("execute",(e=>{this.isEnabled||e.stop()}),{priority:"high"}),this.listenTo(e,"change:isReadOnly",((e,t,i)=>{i&&this.affectsData?this.forceDisabled("readOnlyMode"):this.clearForceDisabled("readOnlyMode")}))}get affectsData(){return this._affectsData}set affectsData(e){this._affectsData=e}refresh(){this.isEnabled=!0}forceDisabled(e){this._disableStack.add(e),1==this._disableStack.size&&(this.on("set:isEnabled",Ls,{priority:"highest"}),this.isEnabled=!1)}clearForceDisabled(e){this._disableStack.delete(e),0==this._disableStack.size&&(this.off("set:isEnabled",Ls),this.refresh())}execute(...e){}destroy(){this.stopListening()}}function Ls(e){e.return=!1,e.stop()}class Os extends Vs{constructor(e){super(e),this._childCommandsDefinitions=[]}refresh(){}execute(...e){const t=this._getFirstEnabledCommand();return!!t&&t.execute(e)}registerChildCommand(e,t={}){p(this._childCommandsDefinitions,{command:e,priority:t.priority||"normal"}),e.on("change:isEnabled",(()=>this._checkEnabled())),this._checkEnabled()}_checkEnabled(){this.isEnabled=!!this._getFirstEnabledCommand()}_getFirstEnabledCommand(){const e=this._childCommandsDefinitions.find((({command:e})=>e.isEnabled));return e&&e.command}}class Bs extends(S()){constructor(e,t=[],i=[]){super(),this._context=e,this._plugins=new Map,this._availablePlugins=new Map;for(const e of t)e.pluginName&&this._availablePlugins.set(e.pluginName,e);this._contextPlugins=new Map;for(const[e,t]of i)this._contextPlugins.set(e,t),this._contextPlugins.set(t,e),e.pluginName&&this._availablePlugins.set(e.pluginName,e)}*[Symbol.iterator](){for(const e of this._plugins)"function"==typeof e[0]&&(yield e)}get(e){const t=this._plugins.get(e);if(!t){let t=e;throw"function"==typeof e&&(t=e.pluginName||e.name),new b("plugincollection-plugin-not-loaded",this._context,{plugin:t})}return t}has(e){return this._plugins.has(e)}init(e,t=[],i=[]){const n=this,s=this._context;!function e(t,i=new Set){t.forEach((t=>{a(t)&&(i.has(t)||(i.add(t),t.pluginName&&!n._availablePlugins.has(t.pluginName)&&n._availablePlugins.set(t.pluginName,t),t.requires&&e(t.requires,i)))}))}(e),h(e);const o=[...function e(t,i=new Set){return t.map((e=>a(e)?e:n._availablePlugins.get(e))).reduce(((t,n)=>i.has(n)?t:(i.add(n),n.requires&&(h(n.requires,n),e(n.requires,i).forEach((e=>t.add(e)))),t.add(n))),new Set)}(e.filter((e=>!c(e,t))))];!function(e,t){for(const i of t){if("function"!=typeof i)throw new b("plugincollection-replace-plugin-invalid-type",null,{pluginItem:i});const t=i.pluginName;if(!t)throw new b("plugincollection-replace-plugin-missing-name",null,{pluginItem:i});if(i.requires&&i.requires.length)throw new b("plugincollection-plugin-for-replacing-cannot-have-dependencies",null,{pluginName:t});const s=n._availablePlugins.get(t);if(!s)throw new b("plugincollection-plugin-for-replacing-not-exist",null,{pluginName:t});const o=e.indexOf(s);if(-1===o){if(n._contextPlugins.has(s))return;throw new b("plugincollection-plugin-for-replacing-not-loaded",null,{pluginName:t})}if(s.requires&&s.requires.length)throw new b("plugincollection-replaced-plugin-cannot-have-dependencies",null,{pluginName:t});e.splice(o,1,i),n._availablePlugins.set(t,i)}}(o,i);const r=function(e){return e.map((e=>{let t=n._contextPlugins.get(e);return t=t||new e(s),n._add(e,t),t}))}(o);return u(r,"init").then((()=>u(r,"afterInit"))).then((()=>r));function a(e){return"function"==typeof e}function l(e){return a(e)&&e.isContextPlugin}function c(e,t){return t.some((t=>t===e||(d(e)===t||d(t)===e)))}function d(e){return a(e)?e.pluginName||e.name:e}function h(e,i=null){e.map((e=>a(e)?e:n._availablePlugins.get(e)||e)).forEach((e=>{!function(e,t){if(a(e))return;if(t)throw new b("plugincollection-soft-required",s,{missingPlugin:e,requiredBy:d(t)});throw new b("plugincollection-plugin-not-found",s,{plugin:e})}(e,i),function(e,t){if(!l(t))return;if(l(e))return;throw new b("plugincollection-context-required",s,{plugin:d(e),requiredBy:d(t)})}(e,i),function(e,i){if(!i)return;if(!c(e,t))return;throw new b("plugincollection-required",s,{plugin:d(e),requiredBy:d(i)})}(e,i)}))}function u(e,t){return e.reduce(((e,i)=>i[t]?n._contextPlugins.has(i)?e:e.then(i[t].bind(i)):e),Promise.resolve())}}destroy(){const e=[];for(const[,t]of this)"function"!=typeof t.destroy||this._contextPlugins.has(t)||e.push(t.destroy());return Promise.all(e)}_add(e,t){this._plugins.set(e,t);const i=e.pluginName;if(i){if(this._plugins.has(i))throw new b("plugincollection-plugin-name-conflict",null,{pluginName:i,plugin1:this._plugins.get(i).constructor,plugin2:e});this._plugins.set(i,t)}}}class Ms{constructor(e){this.config=new yn(e,this.constructor.defaultConfig);const t=this.constructor.builtinPlugins;this.config.define("plugins",t),this.plugins=new Bs(this,t);const i=this.config.get("language")||{};this.locale=new _s({uiLanguage:"string"==typeof i?i:i.ui,contentLanguage:this.config.get("language.content")}),this.t=this.locale.t,this.editors=new ys,this._contextOwner=null}initPlugins(){const e=this.config.get("plugins")||[],t=this.config.get("substitutePlugins")||[];for(const i of e.concat(t)){if("function"!=typeof i)throw new b("context-initplugins-constructor-only",null,{Plugin:i});if(!0!==i.isContextPlugin)throw new b("context-initplugins-invalid-plugin",null,{Plugin:i})}return this.plugins.init(e,[],t)}destroy(){return Promise.all(Array.from(this.editors,(e=>e.destroy()))).then((()=>this.plugins.destroy()))}_addEditor(e,t){if(this._contextOwner)throw new b("context-addeditor-private-context");this.editors.add(e),t&&(this._contextOwner=e)}_removeEditor(e){return this.editors.has(e)&&this.editors.remove(e),this._contextOwner===e?this.destroy():Promise.resolve()}_getEditorConfig(){const e={};for(const t of this.config.names())["plugins","removePlugins","extraPlugins"].includes(t)||(e[t]=this.config.get(t));return e}static create(e){return new Promise((t=>{const i=new this(e);t(i.initPlugins().then((()=>i)))}))}}class Ns extends(W()){constructor(e){super(),this.context=e}destroy(){this.stopListening()}static get isContextPlugin(){return!0}}const Ds=new WeakMap;function Fs(e){const{view:t,element:i,text:n,isDirectHost:s=!0,keepOnFocus:o=!1}=e,r=t.document;Ds.has(r)||(Ds.set(r,new Map),r.registerPostFixer((e=>Hs(r,e))),r.on("change:isComposing",(()=>{t.change((e=>Hs(r,e)))}),{priority:"high"})),Ds.get(r).set(i,{text:n,isDirectHost:s,keepOnFocus:o,hostElement:s?i:null}),t.change((e=>Hs(r,e)))}function zs(e,t){return!!t.hasClass("ck-placeholder")&&(e.removeClass("ck-placeholder",t),!0)}function Hs(e,t){const i=Ds.get(e),n=[];let s=!1;for(const[e,o]of i)o.isDirectHost&&(n.push(e),$s(t,e,o)&&(s=!0));for(const[e,o]of i){if(o.isDirectHost)continue;const i=Ws(e);i&&(n.includes(i)||(o.hostElement=i,$s(t,e,o)&&(s=!0)))}return s}function $s(e,t,i){const{text:n,isDirectHost:s,hostElement:o}=i;let r=!1;o.getAttribute("data-placeholder")!==n&&(e.setAttribute("data-placeholder",n,o),r=!0);return(s||1==t.childCount)&&function(e,t){if(!e.isAttached())return!1;const i=Array.from(e.getChildren()).some((e=>!e.is("uiElement")));if(i)return!1;const n=e.document,s=n.selection.anchor;return!(n.isComposing&&s&&s.parent===e||!t&&n.isFocused&&(!s||s.parent===e))}(o,i.keepOnFocus)?function(e,t){return!t.hasClass("ck-placeholder")&&(e.addClass("ck-placeholder",t),!0)}(e,o)&&(r=!0):zs(e,o)&&(r=!0),r}function Ws(e){if(e.childCount){const t=e.getChild(0);if(t.is("element")&&!t.is("uiElement")&&!t.is("attributeElement"))return t}return null}class js{is(){throw new Error("is() method is abstract")}}const qs=function(e){return bn(e,4)};class Us extends(S(js)){constructor(e){super(),this.document=e,this.parent=null}get index(){let e;if(!this.parent)return null;if(-1==(e=this.parent.getChildIndex(this)))throw new b("view-node-not-found-in-parent",this);return e}get nextSibling(){const e=this.index;return null!==e&&this.parent.getChild(e+1)||null}get previousSibling(){const e=this.index;return null!==e&&this.parent.getChild(e-1)||null}get root(){let e=this;for(;e.parent;)e=e.parent;return e}isAttached(){return this.root.is("rootElement")}getPath(){const e=[];let t=this;for(;t.parent;)e.unshift(t.index),t=t.parent;return e}getAncestors(e={}){const t=[];let i=e.includeSelf?this:this.parent;for(;i;)t[e.parentFirst?"push":"unshift"](i),i=i.parent;return t}getCommonAncestor(e,t={}){const i=this.getAncestors(t),n=e.getAncestors(t);let s=0;for(;i[s]==n[s]&&i[s];)s++;return 0===s?null:i[s-1]}isBefore(e){if(this==e)return!1;if(this.root!==e.root)return!1;const t=this.getPath(),i=e.getPath(),n=Y(t,i);switch(n){case"prefix":return!0;case"extension":return!1;default:return t[n]e.data.length)throw new b("view-textproxy-wrong-offsetintext",this);if(i<0||t+i>e.data.length)throw new b("view-textproxy-wrong-length",this);this.data=e.data.substring(t,t+i),this.offsetInText=t}get offsetSize(){return this.data.length}get isPartial(){return this.data.length!==this.textNode.data.length}get parent(){return this.textNode.parent}get root(){return this.textNode.root}get document(){return this.textNode.document}getAncestors(e={}){const t=[];let i=e.includeSelf?this.textNode:this.parent;for(;null!==i;)t[e.parentFirst?"push":"unshift"](i),i=i.parent;return t}}Ks.prototype.is=function(e){return"$textProxy"===e||"view:$textProxy"===e||"textProxy"===e||"view:textProxy"===e};class Js{constructor(...e){this._patterns=[],this.add(...e)}add(...e){for(let t of e)("string"==typeof t||t instanceof RegExp)&&(t={name:t}),this._patterns.push(t)}match(...e){for(const t of e)for(const e of this._patterns){const i=Qs(t,e);if(i)return{element:t,pattern:e,match:i}}return null}matchAll(...e){const t=[];for(const i of e)for(const e of this._patterns){const n=Qs(i,e);n&&t.push({element:i,pattern:e,match:n})}return t.length>0?t:null}getElementName(){if(1!==this._patterns.length)return null;const e=this._patterns[0],t=e.name;return"function"==typeof e||!t||t instanceof RegExp?null:t}}function Qs(e,t){if("function"==typeof t)return t(e);const i={};return t.name&&(i.name=function(e,t){if(e instanceof RegExp)return!!t.match(e);return e===t}(t.name,e.name),!i.name)||t.attributes&&(i.attributes=function(e,t){const i=new Set(t.getAttributeKeys());Ce(e)?(void 0!==e.style&&v("matcher-pattern-deprecated-attributes-style-key",e),void 0!==e.class&&v("matcher-pattern-deprecated-attributes-class-key",e)):(i.delete("style"),i.delete("class"));return Ys(e,i,(e=>t.getAttribute(e)))}(t.attributes,e),!i.attributes)||t.classes&&(i.classes=function(e,t){return Ys(e,t.getClassNames(),(()=>{}))}(t.classes,e),!i.classes)||t.styles&&(i.styles=function(e,t){return Ys(e,t.getStyleNames(!0),(e=>t.getStyle(e)))}(t.styles,e),!i.styles)?null:i}function Ys(e,t,i){const n=function(e){if(Array.isArray(e))return e.map((e=>Ce(e)?(void 0!==e.key&&void 0!==e.value||v("matcher-pattern-missing-key-or-value",e),[e.key,e.value]):[e,!0]));if(Ce(e))return Object.entries(e);return[[e,!0]]}(e),s=Array.from(t),o=[];if(n.forEach((([e,t])=>{s.forEach((n=>{(function(e,t){return!0===e||e===t||e instanceof RegExp&&t.match(e)})(e,n)&&function(e,t,i){if(!0===e)return!0;const n=i(t);return e===n||e instanceof RegExp&&!!String(n).match(e)}(t,n,i)&&o.push(n)}))})),n.length&&!(o.lengths?0:s+t),(i=i>s?s:i)<0&&(i+=s),s=t>i?0:i-t>>>0,t>>>=0;for(var o=Array(s);++n0){if(++t>=800)return arguments[0]}else t=0;return e.apply(void 0,arguments)}};const Do=No(Bo);const Fo=function(e,t){return Do(Lo(e,t,Io),e+"")};const zo=function(e,t,i){if(!M(i))return!1;var n=typeof t;return!!("number"==n?si(i)&&zt(t,i.length):"string"==n&&t in i)&&xe(i[t],e)};const Ho=function(e){return Fo((function(t,i){var n=-1,s=i.length,o=s>1?i[s-1]:void 0,r=s>2?i[2]:void 0;for(o=e.length>3&&"function"==typeof o?(s--,o):void 0,r&&zo(i[0],i[1],r)&&(o=s<3?void 0:o,s=1),t=Object(t);++nt===e));return Array.isArray(t)}set(e,t){if(M(e))for(const[t,i]of Object.entries(e))this._styleProcessor.toNormalizedForm(t,i,this._styles);else this._styleProcessor.toNormalizedForm(e,t,this._styles)}remove(e){const t=Go(e);yo(this._styles,t),delete this._styles[e],this._cleanEmptyObjectsOnPath(t)}getNormalized(e){return this._styleProcessor.getNormalized(e,this._styles)}toString(){return this.isEmpty?"":this._getStylesEntries().map((e=>e.join(":"))).sort().join(";")+";"}getAsString(e){if(this.isEmpty)return;if(this._styles[e]&&!M(this._styles[e]))return this._styles[e];const t=this._styleProcessor.getReducedForm(e,this._styles).find((([t])=>t===e));return Array.isArray(t)?t[1]:void 0}getStyleNames(e=!1){if(this.isEmpty)return[];if(e)return this._styleProcessor.getStyleNames(this._styles);return this._getStylesEntries().map((([e])=>e))}clear(){this._styles={}}_getStylesEntries(){const e=[],t=Object.keys(this._styles);for(const i of t)e.push(...this._styleProcessor.getReducedForm(i,this._styles));return e}_cleanEmptyObjectsOnPath(e){const t=e.split(".");if(!(t.length>1))return;const i=t.splice(0,t.length-1).join("."),n=ko(this._styles,i);if(!n)return;!Array.from(Object.keys(n)).length&&this.remove(i)}}class Uo{constructor(){this._normalizers=new Map,this._extractors=new Map,this._reducers=new Map,this._consumables=new Map}toNormalizedForm(e,t,i){if(M(t))Ko(i,Go(e),t);else if(this._normalizers.has(e)){const n=this._normalizers.get(e),{path:s,value:o}=n(t);Ko(i,s,o)}else Ko(i,e,t)}getNormalized(e,t){if(!e)return $o({},t);if(void 0!==t[e])return t[e];if(this._extractors.has(e)){const i=this._extractors.get(e);if("string"==typeof i)return ko(t,i);const n=i(e,t);if(n)return n}return ko(t,Go(e))}getReducedForm(e,t){const i=this.getNormalized(e,t);if(void 0===i)return[];if(this._reducers.has(e)){return this._reducers.get(e)(i)}return[[e,i]]}getStyleNames(e){const t=Array.from(this._consumables.keys()).filter((t=>{const i=this.getNormalized(t,e);return i&&"object"==typeof i?Object.keys(i).length:i})),i=new Set([...t,...Object.keys(e)]);return Array.from(i.values())}getRelatedStyles(e){return this._consumables.get(e)||[]}setNormalizer(e,t){this._normalizers.set(e,t)}setExtractor(e,t){this._extractors.set(e,t)}setReducer(e,t){this._reducers.set(e,t)}setStyleRelation(e,t){this._mapStyleNames(e,t);for(const i of t)this._mapStyleNames(i,[e])}_mapStyleNames(e,t){this._consumables.has(e)||this._consumables.set(e,[]),this._consumables.get(e).push(...t)}}function Go(e){return e.replace("-",".")}function Ko(e,t,i){let n=i;M(i)&&(n=$o({},ko(e,t),i)),jo(e,t,n)}class Jo extends Us{constructor(e,t,i,n){if(super(e),this.name=t,this._attrs=function(e){const t=xs(e);for(const[e,i]of t)null===i?t.delete(e):"string"!=typeof i&&t.set(e,String(i));return t}(i),this._children=[],n&&this._insertChild(0,n),this._classes=new Set,this._attrs.has("class")){const e=this._attrs.get("class");Qo(this._classes,e),this._attrs.delete("class")}this._styles=new qo(this.document.stylesProcessor),this._attrs.has("style")&&(this._styles.setTo(this._attrs.get("style")),this._attrs.delete("style")),this._customProperties=new Map,this._unsafeAttributesToRender=[]}get childCount(){return this._children.length}get isEmpty(){return 0===this._children.length}getChild(e){return this._children[e]}getChildIndex(e){return this._children.indexOf(e)}getChildren(){return this._children[Symbol.iterator]()}*getAttributeKeys(){this._classes.size>0&&(yield"class"),this._styles.isEmpty||(yield"style"),yield*this._attrs.keys()}*getAttributes(){yield*this._attrs.entries(),this._classes.size>0&&(yield["class",this.getAttribute("class")]),this._styles.isEmpty||(yield["style",this.getAttribute("style")])}getAttribute(e){if("class"==e)return this._classes.size>0?[...this._classes].join(" "):void 0;if("style"==e){const e=this._styles.toString();return""==e?void 0:e}return this._attrs.get(e)}hasAttribute(e){return"class"==e?this._classes.size>0:"style"==e?!this._styles.isEmpty:this._attrs.has(e)}isSimilar(e){if(!(e instanceof Jo))return!1;if(this===e)return!0;if(this.name!=e.name)return!1;if(this._attrs.size!==e._attrs.size||this._classes.size!==e._classes.size||this._styles.size!==e._styles.size)return!1;for(const[t,i]of this._attrs)if(!e._attrs.has(t)||e._attrs.get(t)!==i)return!1;for(const t of this._classes)if(!e._classes.has(t))return!1;for(const t of this._styles.getStyleNames())if(!e._styles.has(t)||e._styles.getAsString(t)!==this._styles.getAsString(t))return!1;return!0}hasClass(...e){for(const t of e)if(!this._classes.has(t))return!1;return!0}getClassNames(){return this._classes.keys()}getStyle(e){return this._styles.getAsString(e)}getNormalizedStyle(e){return this._styles.getNormalized(e)}getStyleNames(e){return this._styles.getStyleNames(e)}hasStyle(...e){for(const t of e)if(!this._styles.has(t))return!1;return!0}findAncestor(...e){const t=new Js(...e);let i=this.parent;for(;i&&!i.is("documentFragment");){if(t.match(i))return i;i=i.parent}return null}getCustomProperty(e){return this._customProperties.get(e)}*getCustomProperties(){yield*this._customProperties.entries()}getIdentity(){const e=Array.from(this._classes).sort().join(","),t=this._styles.toString(),i=Array.from(this._attrs).map((e=>`${e[0]}="${e[1]}"`)).sort().join(" ");return this.name+(""==e?"":` class="${e}"`)+(t?` style="${t}"`:"")+(""==i?"":` ${i}`)}shouldRenderUnsafeAttribute(e){return this._unsafeAttributesToRender.includes(e)}_clone(e=!1){const t=[];if(e)for(const i of this.getChildren())t.push(i._clone(e));const i=new this.constructor(this.document,this.name,this._attrs,t);return i._classes=new Set(this._classes),i._styles.set(this._styles.getNormalized()),i._customProperties=new Map(this._customProperties),i.getFillerOffset=this.getFillerOffset,i._unsafeAttributesToRender=this._unsafeAttributesToRender,i}_appendChild(e){return this._insertChild(this.childCount,e)}_insertChild(e,t){this._fireChange("children",this);let i=0;const n=function(e,t){if("string"==typeof t)return[new Gs(e,t)];X(t)||(t=[t]);return Array.from(t).map((t=>"string"==typeof t?new Gs(e,t):t instanceof Ks?new Gs(e,t.data):t))}(this.document,t);for(const t of n)null!==t.parent&&t._remove(),t.parent=this,t.document=this.document,this._children.splice(e,0,t),e++,i++;return i}_removeChildren(e,t=1){this._fireChange("children",this);for(let i=e;i0&&(this._classes.clear(),!0):"style"==e?!this._styles.isEmpty&&(this._styles.clear(),!0):this._attrs.delete(e)}_addClass(e){this._fireChange("attributes",this);for(const t of ps(e))this._classes.add(t)}_removeClass(e){this._fireChange("attributes",this);for(const t of ps(e))this._classes.delete(t)}_setStyle(e,t){this._fireChange("attributes",this),Ce(e)?this._styles.set(e):this._styles.set(e,t)}_removeStyle(e){this._fireChange("attributes",this);for(const t of ps(e))this._styles.remove(t)}_setCustomProperty(e,t){this._customProperties.set(e,t)}_removeCustomProperty(e){return this._customProperties.delete(e)}}function Qo(e,t){const i=t.split(/\s+/);e.clear(),i.forEach((t=>e.add(t)))}Jo.prototype.is=function(e,t){return t?t===this.name&&("element"===e||"view:element"===e):"element"===e||"view:element"===e||"node"===e||"view:node"===e};class Yo extends Jo{constructor(...e){super(...e),this.getFillerOffset=Xo}}function Xo(){const e=[...this.getChildren()],t=e[this.childCount-1];if(t&&t.is("element","br"))return this.childCount;for(const t of e)if(!t.is("uiElement"))return null;return this.childCount}Yo.prototype.is=function(e,t){return t?t===this.name&&("containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e):"containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class Zo extends(W(Yo)){constructor(...e){super(...e);const t=e[0];this.set("isReadOnly",!1),this.set("isFocused",!1),this.bind("isReadOnly").to(t),this.bind("isFocused").to(t,"isFocused",(e=>e&&t.selection.editableElement==this)),this.listenTo(t.selection,"change",(()=>{this.isFocused=t.isFocused&&t.selection.editableElement==this}))}destroy(){this.stopListening()}}Zo.prototype.is=function(e,t){return t?t===this.name&&("editableElement"===e||"view:editableElement"===e||"containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e):"editableElement"===e||"view:editableElement"===e||"containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};const er=Symbol("rootName");class tr extends Zo{constructor(e,t){super(e,t),this.rootName="main"}get rootName(){return this.getCustomProperty(er)}set rootName(e){this._setCustomProperty(er,e)}set _name(e){this.name=e}}tr.prototype.is=function(e,t){return t?t===this.name&&("rootElement"===e||"view:rootElement"===e||"editableElement"===e||"view:editableElement"===e||"containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e):"rootElement"===e||"view:rootElement"===e||"editableElement"===e||"view:editableElement"===e||"containerElement"===e||"view:containerElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class ir{constructor(e={}){if(!e.boundaries&&!e.startPosition)throw new b("view-tree-walker-no-start-position",null);if(e.direction&&"forward"!=e.direction&&"backward"!=e.direction)throw new b("view-tree-walker-unknown-direction",e.startPosition,{direction:e.direction});this.boundaries=e.boundaries||null,e.startPosition?this.position=nr._createAt(e.startPosition):this.position=nr._createAt(e.boundaries["backward"==e.direction?"end":"start"]),this.direction=e.direction||"forward",this.singleCharacters=!!e.singleCharacters,this.shallow=!!e.shallow,this.ignoreElementEnd=!!e.ignoreElementEnd,this._boundaryStartParent=this.boundaries?this.boundaries.start.parent:null,this._boundaryEndParent=this.boundaries?this.boundaries.end.parent:null}[Symbol.iterator](){return this}skip(e){let t,i,n;do{n=this.position,({done:t,value:i}=this.next())}while(!t&&e(i));t||(this.position=n)}next(){return"forward"==this.direction?this._next():this._previous()}_next(){let e=this.position.clone();const t=this.position,i=e.parent;if(null===i.parent&&e.offset===i.childCount)return{done:!0,value:void 0};if(i===this._boundaryEndParent&&e.offset==this.boundaries.end.offset)return{done:!0,value:void 0};let n;if(i instanceof Gs){if(e.isAtEnd)return this.position=nr._createAfter(i),this._next();n=i.data[e.offset]}else n=i.getChild(e.offset);if(n instanceof Jo)return this.shallow?e.offset++:e=new nr(n,0),this.position=e,this._formatReturnValue("elementStart",n,t,e,1);if(n instanceof Gs){if(this.singleCharacters)return e=new nr(n,0),this.position=e,this._next();{let i,s=n.data.length;return n==this._boundaryEndParent?(s=this.boundaries.end.offset,i=new Ks(n,0,s),e=nr._createAfter(i)):(i=new Ks(n,0,n.data.length),e.offset++),this.position=e,this._formatReturnValue("text",i,t,e,s)}}if("string"==typeof n){let n;if(this.singleCharacters)n=1;else{n=(i===this._boundaryEndParent?this.boundaries.end.offset:i.data.length)-e.offset}const s=new Ks(i,e.offset,n);return e.offset+=n,this.position=e,this._formatReturnValue("text",s,t,e,n)}return e=nr._createAfter(i),this.position=e,this.ignoreElementEnd?this._next():this._formatReturnValue("elementEnd",i,t,e)}_previous(){let e=this.position.clone();const t=this.position,i=e.parent;if(null===i.parent&&0===e.offset)return{done:!0,value:void 0};if(i==this._boundaryStartParent&&e.offset==this.boundaries.start.offset)return{done:!0,value:void 0};let n;if(i instanceof Gs){if(e.isAtStart)return this.position=nr._createBefore(i),this._previous();n=i.data[e.offset-1]}else n=i.getChild(e.offset-1);if(n instanceof Jo)return this.shallow?(e.offset--,this.position=e,this._formatReturnValue("elementStart",n,t,e,1)):(e=new nr(n,n.childCount),this.position=e,this.ignoreElementEnd?this._previous():this._formatReturnValue("elementEnd",n,t,e));if(n instanceof Gs){if(this.singleCharacters)return e=new nr(n,n.data.length),this.position=e,this._previous();{let i,s=n.data.length;if(n==this._boundaryStartParent){const t=this.boundaries.start.offset;i=new Ks(n,t,n.data.length-t),s=i.data.length,e=nr._createBefore(i)}else i=new Ks(n,0,n.data.length),e.offset--;return this.position=e,this._formatReturnValue("text",i,t,e,s)}}if("string"==typeof n){let n;if(this.singleCharacters)n=1;else{const t=i===this._boundaryStartParent?this.boundaries.start.offset:0;n=e.offset-t}e.offset-=n;const s=new Ks(i,e.offset,n);return this.position=e,this._formatReturnValue("text",s,t,e,n)}return e=nr._createBefore(i),this.position=e,this._formatReturnValue("elementStart",i,t,e,1)}_formatReturnValue(e,t,i,n,s){return t instanceof Ks&&(t.offsetInText+t.data.length==t.textNode.data.length&&("forward"!=this.direction||this.boundaries&&this.boundaries.end.isEqual(this.position)?i=nr._createAfter(t.textNode):(n=nr._createAfter(t.textNode),this.position=n)),0===t.offsetInText&&("backward"!=this.direction||this.boundaries&&this.boundaries.start.isEqual(this.position)?i=nr._createBefore(t.textNode):(n=nr._createBefore(t.textNode),this.position=n))),{done:!1,value:{type:e,item:t,previousPosition:i,nextPosition:n,length:s}}}}class nr extends js{constructor(e,t){super(),this.parent=e,this.offset=t}get nodeAfter(){return this.parent.is("$text")?null:this.parent.getChild(this.offset)||null}get nodeBefore(){return this.parent.is("$text")?null:this.parent.getChild(this.offset-1)||null}get isAtStart(){return 0===this.offset}get isAtEnd(){const e=this.parent.is("$text")?this.parent.data.length:this.parent.childCount;return this.offset===e}get root(){return this.parent.root}get editableElement(){let e=this.parent;for(;!(e instanceof Zo);){if(!e.parent)return null;e=e.parent}return e}getShiftedBy(e){const t=nr._createAt(this),i=t.offset+e;return t.offset=i<0?0:i,t}getLastMatchingPosition(e,t={}){t.startPosition=this;const i=new ir(t);return i.skip(e),i.position}getAncestors(){return this.parent.is("documentFragment")?[this.parent]:this.parent.getAncestors({includeSelf:!0})}getCommonAncestor(e){const t=this.getAncestors(),i=e.getAncestors();let n=0;for(;t[n]==i[n]&&t[n];)n++;return 0===n?null:t[n-1]}isEqual(e){return this.parent==e.parent&&this.offset==e.offset}isBefore(e){return"before"==this.compareWith(e)}isAfter(e){return"after"==this.compareWith(e)}compareWith(e){if(this.root!==e.root)return"different";if(this.isEqual(e))return"same";const t=this.parent.is("node")?this.parent.getPath():[],i=e.parent.is("node")?e.parent.getPath():[];t.push(this.offset),i.push(e.offset);const n=Y(t,i);switch(n){case"prefix":return"before";case"extension":return"after";default:return t[n]0?new this(i,n):new this(n,i)}static _createIn(e){return this._createFromParentsAndOffsets(e,0,e,e.childCount)}static _createOn(e){const t=e.is("$textProxy")?e.offsetSize:1;return this._createFromPositionAndShift(nr._createBefore(e),t)}}function or(e){return!(!e.item.is("attributeElement")&&!e.item.is("uiElement"))}sr.prototype.is=function(e){return"range"===e||"view:range"===e};class rr extends(S(js)){constructor(...e){super(),this._ranges=[],this._lastRangeBackward=!1,this._isFake=!1,this._fakeSelectionLabel="",e.length&&this.setTo(...e)}get isFake(){return this._isFake}get fakeSelectionLabel(){return this._fakeSelectionLabel}get anchor(){if(!this._ranges.length)return null;const e=this._ranges[this._ranges.length-1];return(this._lastRangeBackward?e.end:e.start).clone()}get focus(){if(!this._ranges.length)return null;const e=this._ranges[this._ranges.length-1];return(this._lastRangeBackward?e.start:e.end).clone()}get isCollapsed(){return 1===this.rangeCount&&this._ranges[0].isCollapsed}get rangeCount(){return this._ranges.length}get isBackward(){return!this.isCollapsed&&this._lastRangeBackward}get editableElement(){return this.anchor?this.anchor.editableElement:null}*getRanges(){for(const e of this._ranges)yield e.clone()}getFirstRange(){let e=null;for(const t of this._ranges)e&&!t.start.isBefore(e.start)||(e=t);return e?e.clone():null}getLastRange(){let e=null;for(const t of this._ranges)e&&!t.end.isAfter(e.end)||(e=t);return e?e.clone():null}getFirstPosition(){const e=this.getFirstRange();return e?e.start.clone():null}getLastPosition(){const e=this.getLastRange();return e?e.end.clone():null}isEqual(e){if(this.isFake!=e.isFake)return!1;if(this.isFake&&this.fakeSelectionLabel!=e.fakeSelectionLabel)return!1;if(this.rangeCount!=e.rangeCount)return!1;if(0===this.rangeCount)return!0;if(!this.anchor.isEqual(e.anchor)||!this.focus.isEqual(e.focus))return!1;for(const t of this._ranges){let i=!1;for(const n of e._ranges)if(t.isEqual(n)){i=!0;break}if(!i)return!1}return!0}isSimilar(e){if(this.isBackward!=e.isBackward)return!1;const t=Q(this.getRanges());if(t!=Q(e.getRanges()))return!1;if(0==t)return!0;for(let t of this.getRanges()){t=t.getTrimmed();let i=!1;for(let n of e.getRanges())if(n=n.getTrimmed(),t.start.isEqual(n.start)&&t.end.isEqual(n.end)){i=!0;break}if(!i)return!1}return!0}getSelectedElement(){return 1!==this.rangeCount?null:this.getFirstRange().getContainedElement()}setTo(...e){let[t,i,n]=e;if("object"==typeof i&&(n=i,i=void 0),null===t)this._setRanges([]),this._setFakeOptions(n);else if(t instanceof rr||t instanceof ar)this._setRanges(t.getRanges(),t.isBackward),this._setFakeOptions({fake:t.isFake,label:t.fakeSelectionLabel});else if(t instanceof sr)this._setRanges([t],n&&n.backward),this._setFakeOptions(n);else if(t instanceof nr)this._setRanges([new sr(t)]),this._setFakeOptions(n);else if(t instanceof Us){const e=!!n&&!!n.backward;let s;if(void 0===i)throw new b("view-selection-setto-required-second-parameter",this);s="in"==i?sr._createIn(t):"on"==i?sr._createOn(t):new sr(nr._createAt(t,i)),this._setRanges([s],e),this._setFakeOptions(n)}else{if(!X(t))throw new b("view-selection-setto-not-selectable",this);this._setRanges(t,n&&n.backward),this._setFakeOptions(n)}this.fire("change")}setFocus(e,t){if(null===this.anchor)throw new b("view-selection-setfocus-no-ranges",this);const i=nr._createAt(e,t);if("same"==i.compareWith(this.focus))return;const n=this.anchor;this._ranges.pop(),"before"==i.compareWith(n)?this._addRange(new sr(i,n),!0):this._addRange(new sr(n,i)),this.fire("change")}_setRanges(e,t=!1){e=Array.from(e),this._ranges=[];for(const t of e)this._addRange(t);this._lastRangeBackward=!!t}_setFakeOptions(e={}){this._isFake=!!e.fake,this._fakeSelectionLabel=e.fake&&e.label||""}_addRange(e,t=!1){if(!(e instanceof sr))throw new b("view-selection-add-range-not-range",this);this._pushRange(e),this._lastRangeBackward=!!t}_pushRange(e){for(const t of this._ranges)if(e.isIntersecting(t))throw new b("view-selection-range-intersects",this,{addedRange:e,intersectingRange:t});this._ranges.push(new sr(e.start,e.end))}}rr.prototype.is=function(e){return"selection"===e||"view:selection"===e};class ar extends(S(js)){constructor(...e){super(),this._selection=new rr,this._selection.delegate("change").to(this),e.length&&this._selection.setTo(...e)}get isFake(){return this._selection.isFake}get fakeSelectionLabel(){return this._selection.fakeSelectionLabel}get anchor(){return this._selection.anchor}get focus(){return this._selection.focus}get isCollapsed(){return this._selection.isCollapsed}get rangeCount(){return this._selection.rangeCount}get isBackward(){return this._selection.isBackward}get editableElement(){return this._selection.editableElement}get _ranges(){return this._selection._ranges}*getRanges(){yield*this._selection.getRanges()}getFirstRange(){return this._selection.getFirstRange()}getLastRange(){return this._selection.getLastRange()}getFirstPosition(){return this._selection.getFirstPosition()}getLastPosition(){return this._selection.getLastPosition()}getSelectedElement(){return this._selection.getSelectedElement()}isEqual(e){return this._selection.isEqual(e)}isSimilar(e){return this._selection.isSimilar(e)}_setTo(...e){this._selection.setTo(...e)}_setFocus(e,t){this._selection.setFocus(e,t)}}ar.prototype.is=function(e){return"selection"===e||"documentSelection"==e||"view:selection"==e||"view:documentSelection"==e};class lr extends u{constructor(e,t,i){super(e,t),this.startRange=i,this._eventPhase="none",this._currentTarget=null}get eventPhase(){return this._eventPhase}get currentTarget(){return this._currentTarget}}const cr=Symbol("bubbling contexts");function dr(e){return class extends e{fire(e,...t){try{const i=e instanceof u?e:new u(this,e),n=gr(this);if(!n.size)return;if(hr(i,"capturing",this),ur(n,"$capture",i,...t))return i.return;const s=i.startRange||this.selection.getFirstRange(),o=s?s.getContainedElement():null,r=!!o&&Boolean(mr(n,o));let a=o||function(e){if(!e)return null;const t=e.start.parent,i=e.end.parent,n=t.getPath(),s=i.getPath();return n.length>s.length?t:i}(s);if(hr(i,"atTarget",a),!r){if(ur(n,"$text",i,...t))return i.return;hr(i,"bubbling",a)}for(;a;){if(a.is("rootElement")){if(ur(n,"$root",i,...t))return i.return}else if(a.is("element")&&ur(n,a.name,i,...t))return i.return;if(ur(n,a,i,...t))return i.return;a=a.parent,hr(i,"bubbling",a)}return hr(i,"bubbling",this),ur(n,"$document",i,...t),i.return}catch(e){b.rethrowUnexpectedError(e,this)}}_addEventListener(e,t,i){const n=ps(i.context||"$document"),s=gr(this);for(const o of n){let n=s.get(o);n||(n=new(S()),s.set(o,n)),this.listenTo(n,e,t,i)}}_removeEventListener(e,t){const i=gr(this);for(const n of i.values())this.stopListening(n,e,t)}}}{const e=dr(Object);["fire","_addEventListener","_removeEventListener"].forEach((t=>{dr[t]=e.prototype[t]}))}function hr(e,t,i){e instanceof lr&&(e._eventPhase=t,e._currentTarget=i)}function ur(e,t,i,...n){const s="string"==typeof t?e.get(t):mr(e,t);return!!s&&(s.fire(i,...n),i.stop.called)}function mr(e,t){for(const[i,n]of e)if("function"==typeof i&&i(t))return n;return null}function gr(e){return e[cr]||(e[cr]=new Map),e[cr]}class fr extends(dr(W())){constructor(e){super(),this.selection=new ar,this.roots=new ys({idProperty:"rootName"}),this.stylesProcessor=e,this.set("isReadOnly",!1),this.set("isFocused",!1),this.set("_isFocusChanging",!1),this.set("isSelecting",!1),this.set("isComposing",!1),this._postFixers=new Set}getRoot(e="main"){return this.roots.get(e)}registerPostFixer(e){this._postFixers.add(e)}destroy(){this.roots.map((e=>e.destroy())),this.stopListening()}_callPostFixers(e){let t=!1;do{for(const i of this._postFixers)if(t=i(e),t)break}while(t)}}class pr extends Jo{constructor(...e){super(...e),this.getFillerOffset=wr,this._priority=10,this._id=null,this._clonesGroup=null}get priority(){return this._priority}get id(){return this._id}getElementsWithSameId(){if(null===this.id)throw new b("attribute-element-get-elements-with-same-id-no-id",this);return new Set(this._clonesGroup)}isSimilar(e){return null!==this.id||null!==e.id?this.id===e.id:super.isSimilar(e)&&this.priority==e.priority}_clone(e=!1){const t=super._clone(e);return t._priority=this._priority,t._id=this._id,t}}function wr(){if(br(this))return null;let e=this.parent;for(;e&&e.is("attributeElement");){if(br(e)>1)return null;e=e.parent}return!e||br(e)>1?null:this.childCount}function br(e){return Array.from(e.getChildren()).filter((e=>!e.is("uiElement"))).length}pr.DEFAULT_PRIORITY=10,pr.prototype.is=function(e,t){return t?t===this.name&&("attributeElement"===e||"view:attributeElement"===e||"element"===e||"view:element"===e):"attributeElement"===e||"view:attributeElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class vr extends Jo{constructor(e,t,i,n){super(e,t,i,n),this.getFillerOffset=_r}_insertChild(e,t){if(t&&(t instanceof Us||Array.from(t).length>0))throw new b("view-emptyelement-cannot-add",[this,t]);return 0}}function _r(){return null}vr.prototype.is=function(e,t){return t?t===this.name&&("emptyElement"===e||"view:emptyElement"===e||"element"===e||"view:element"===e):"emptyElement"===e||"view:emptyElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class yr extends Jo{constructor(...e){super(...e),this.getFillerOffset=Cr}_insertChild(e,t){if(t&&(t instanceof Us||Array.from(t).length>0))throw new b("view-uielement-cannot-add",[this,t]);return 0}render(e,t){return this.toDomElement(e)}toDomElement(e){const t=e.createElement(this.name);for(const e of this.getAttributeKeys())t.setAttribute(e,this.getAttribute(e));return t}}function kr(e){e.document.on("arrowKey",((t,i)=>function(e,t,i){if(t.keyCode==ds.arrowright){const e=t.domTarget.ownerDocument.defaultView.getSelection(),n=1==e.rangeCount&&e.getRangeAt(0).collapsed;if(n||t.shiftKey){const t=e.focusNode,s=e.focusOffset,o=i.domPositionToView(t,s);if(null===o)return;let r=!1;const a=o.getLastMatchingPosition((e=>(e.item.is("uiElement")&&(r=!0),!(!e.item.is("uiElement")&&!e.item.is("attributeElement")))));if(r){const t=i.viewPositionToDom(a);n?e.collapse(t.parent,t.offset):e.extend(t.parent,t.offset)}}}}(0,i,e.domConverter)),{priority:"low"})}function Cr(){return null}yr.prototype.is=function(e,t){return t?t===this.name&&("uiElement"===e||"view:uiElement"===e||"element"===e||"view:element"===e):"uiElement"===e||"view:uiElement"===e||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class Ar extends Jo{constructor(...e){super(...e),this.getFillerOffset=xr}_insertChild(e,t){if(t&&(t instanceof Us||Array.from(t).length>0))throw new b("view-rawelement-cannot-add",[this,t]);return 0}render(){}}function xr(){return null}Ar.prototype.is=function(e,t){return t?t===this.name&&("rawElement"===e||"view:rawElement"===e||"element"===e||"view:element"===e):"rawElement"===e||"view:rawElement"===e||e===this.name||e==="view:"+this.name||"element"===e||"view:element"===e||"node"===e||"view:node"===e};class Tr extends(S(js)){constructor(e,t){super(),this.document=e,this._children=[],t&&this._insertChild(0,t)}[Symbol.iterator](){return this._children[Symbol.iterator]()}get childCount(){return this._children.length}get isEmpty(){return 0===this.childCount}get root(){return this}get parent(){return null}_appendChild(e){return this._insertChild(this.childCount,e)}getChild(e){return this._children[e]}getChildIndex(e){return this._children.indexOf(e)}getChildren(){return this._children[Symbol.iterator]()}_insertChild(e,t){this._fireChange("children",this);let i=0;const n=function(e,t){if("string"==typeof t)return[new Gs(e,t)];X(t)||(t=[t]);return Array.from(t).map((t=>"string"==typeof t?new Gs(e,t):t instanceof Ks?new Gs(e,t.data):t))}(this.document,t);for(const t of n)null!==t.parent&&t._remove(),t.parent=this,this._children.splice(e,0,t),e++,i++;return i}_removeChildren(e,t=1){this._fireChange("children",this);for(let i=e;i{const i=e[e.length-1],n=!t.is("uiElement");return i&&i.breakAttributes==n?i.nodes.push(t):e.push({breakAttributes:n,nodes:[t]}),e}),[]);let n=null,s=e;for(const{nodes:e,breakAttributes:t}of i){const i=this._insertNodes(s,e,t);n||(n=i.start),s=i.end}return n?new sr(n,s):new sr(e)}remove(e){const t=e instanceof sr?e:sr._createOn(e);if(Mr(t,this.document),t.isCollapsed)return new Tr(this.document);const{start:i,end:n}=this._breakAttributesRange(t,!0),s=i.parent,o=n.offset-i.offset,r=s._removeChildren(i.offset,o);for(const e of r)this._removeFromClonedElementsGroup(e);const a=this.mergeAttributes(i);return t.start=a,t.end=a.clone(),new Tr(this.document,r)}clear(e,t){Mr(e,this.document);const i=e.getWalker({direction:"backward",ignoreElementEnd:!0});for(const n of i){const i=n.item;let s;if(i.is("element")&&t.isSimilar(i))s=sr._createOn(i);else if(!n.nextPosition.isAfter(e.start)&&i.is("$textProxy")){const e=i.getAncestors().find((e=>e.is("element")&&t.isSimilar(e)));e&&(s=sr._createIn(e))}s&&(s.end.isAfter(e.end)&&(s.end=e.end),s.start.isBefore(e.start)&&(s.start=e.start),this.remove(s))}}move(e,t){let i;if(t.isAfter(e.end)){const n=(t=this._breakAttributes(t,!0)).parent,s=n.childCount;e=this._breakAttributesRange(e,!0),i=this.remove(e),t.offset+=n.childCount-s}else i=this.remove(e);return this.insert(t,i)}wrap(e,t){if(!(t instanceof pr))throw new b("view-writer-wrap-invalid-attribute",this.document);if(Mr(e,this.document),e.isCollapsed){let n=e.start;n.parent.is("element")&&(i=n.parent,!Array.from(i.getChildren()).some((e=>!e.is("uiElement"))))&&(n=n.getLastMatchingPosition((e=>e.item.is("uiElement")))),n=this._wrapPosition(n,t);const s=this.document.selection;return s.isCollapsed&&s.getFirstPosition().isEqual(e.start)&&this.setSelection(n),new sr(n)}return this._wrapRange(e,t);var i}unwrap(e,t){if(!(t instanceof pr))throw new b("view-writer-unwrap-invalid-attribute",this.document);if(Mr(e,this.document),e.isCollapsed)return e;const{start:i,end:n}=this._breakAttributesRange(e,!0),s=i.parent,o=this._unwrapChildren(s,i.offset,n.offset,t),r=this.mergeAttributes(o.start);r.isEqual(o.start)||o.end.offset--;const a=this.mergeAttributes(o.end);return new sr(r,a)}rename(e,t){const i=new Yo(this.document,e,t.getAttributes());return this.insert(nr._createAfter(t),i),this.move(sr._createIn(t),nr._createAt(i,0)),this.remove(sr._createOn(t)),i}clearClonedElementsGroup(e){this._cloneGroups.delete(e)}createPositionAt(e,t){return nr._createAt(e,t)}createPositionAfter(e){return nr._createAfter(e)}createPositionBefore(e){return nr._createBefore(e)}createRange(...e){return new sr(...e)}createRangeOn(e){return sr._createOn(e)}createRangeIn(e){return sr._createIn(e)}createSelection(...e){return new rr(...e)}createSlot(e){if(!this._slotFactory)throw new b("view-writer-invalid-create-slot-context",this.document);return this._slotFactory(this,e)}_registerSlotFactory(e){this._slotFactory=e}_clearSlotFactory(){this._slotFactory=null}_insertNodes(e,t,i){let n,s;if(n=i?Sr(e):e.parent.is("$text")?e.parent.parent:e.parent,!n)throw new b("view-writer-invalid-position-container",this.document);s=i?this._breakAttributes(e,!0):e.parent.is("$text")?Rr(e):e;const o=n._insertChild(s.offset,t);for(const e of t)this._addToClonedElementsGroup(e);const r=s.getShiftedBy(o),a=this.mergeAttributes(s);a.isEqual(s)||r.offset--;const l=this.mergeAttributes(r);return new sr(a,l)}_wrapChildren(e,t,i,n){let s=t;const o=[];for(;s!1,e.parent._insertChild(e.offset,i);const n=new sr(e,e.getShiftedBy(1));this.wrap(n,t);const s=new nr(i.parent,i.index);i._remove();const o=s.nodeBefore,r=s.nodeAfter;return o instanceof Gs&&r instanceof Gs?Vr(o,r):Ir(s)}_wrapAttributeElement(e,t){if(!Nr(e,t))return!1;if(e.name!==t.name||e.priority!==t.priority)return!1;for(const i of e.getAttributeKeys())if("class"!==i&&"style"!==i&&t.hasAttribute(i)&&t.getAttribute(i)!==e.getAttribute(i))return!1;for(const i of e.getStyleNames())if(t.hasStyle(i)&&t.getStyle(i)!==e.getStyle(i))return!1;for(const i of e.getAttributeKeys())"class"!==i&&"style"!==i&&(t.hasAttribute(i)||this.setAttribute(i,e.getAttribute(i),t));for(const i of e.getStyleNames())t.hasStyle(i)||this.setStyle(i,e.getStyle(i),t);for(const i of e.getClassNames())t.hasClass(i)||this.addClass(i,t);return!0}_unwrapAttributeElement(e,t){if(!Nr(e,t))return!1;if(e.name!==t.name||e.priority!==t.priority)return!1;for(const i of e.getAttributeKeys())if("class"!==i&&"style"!==i&&(!t.hasAttribute(i)||t.getAttribute(i)!==e.getAttribute(i)))return!1;if(!t.hasClass(...e.getClassNames()))return!1;for(const i of e.getStyleNames())if(!t.hasStyle(i)||t.getStyle(i)!==e.getStyle(i))return!1;for(const i of e.getAttributeKeys())"class"!==i&&"style"!==i&&this.removeAttribute(i,t);return this.removeClass(Array.from(e.getClassNames()),t),this.removeStyle(Array.from(e.getStyleNames()),t),!0}_breakAttributesRange(e,t=!1){const i=e.start,n=e.end;if(Mr(e,this.document),e.isCollapsed){const i=this._breakAttributes(e.start,t);return new sr(i,i)}const s=this._breakAttributes(n,t),o=s.parent.childCount,r=this._breakAttributes(i,t);return s.offset+=s.parent.childCount-o,new sr(r,s)}_breakAttributes(e,t=!1){const i=e.offset,n=e.parent;if(e.parent.is("emptyElement"))throw new b("view-writer-cannot-break-empty-element",this.document);if(e.parent.is("uiElement"))throw new b("view-writer-cannot-break-ui-element",this.document);if(e.parent.is("rawElement"))throw new b("view-writer-cannot-break-raw-element",this.document);if(!t&&n.is("$text")&&Br(n.parent))return e.clone();if(Br(n))return e.clone();if(n.is("$text"))return this._breakAttributes(Rr(e),t);if(i==n.childCount){const e=new nr(n.parent,n.index+1);return this._breakAttributes(e,t)}if(0===i){const e=new nr(n.parent,n.index);return this._breakAttributes(e,t)}{const e=n.index+1,s=n._clone();n.parent._insertChild(e,s),this._addToClonedElementsGroup(s);const o=n.childCount-i,r=n._removeChildren(i,o);s._appendChild(r);const a=new nr(n.parent,e);return this._breakAttributes(a,t)}}_addToClonedElementsGroup(e){if(!e.root.is("rootElement"))return;if(e.is("element"))for(const t of e.getChildren())this._addToClonedElementsGroup(t);const t=e.id;if(!t)return;let i=this._cloneGroups.get(t);i||(i=new Set,this._cloneGroups.set(t,i)),i.add(e),e._clonesGroup=i}_removeFromClonedElementsGroup(e){if(e.is("element"))for(const t of e.getChildren())this._removeFromClonedElementsGroup(t);const t=e.id;if(!t)return;const i=this._cloneGroups.get(t);i&&i.delete(e)}}function Sr(e){let t=e.parent;for(;!Br(t);){if(!t)return;t=t.parent}return t}function Pr(e,t){return e.priorityt.priority)&&e.getIdentity()i instanceof e)))throw new b("view-writer-insert-invalid-node-type",t);i.is("$text")||Or(i.getChildren(),t)}}function Br(e){return e&&(e.is("containerElement")||e.is("documentFragment"))}function Mr(e,t){const i=Sr(e.start),n=Sr(e.end);if(!i||!n||i!==n)throw new b("view-writer-invalid-range-container",t)}function Nr(e,t){return null===e.id&&null===t.id}const Dr=e=>e.createTextNode(" "),Fr=e=>{const t=e.createElement("span");return t.dataset.ckeFiller="true",t.innerText=" ",t},zr=e=>{const t=e.createElement("br");return t.dataset.ckeFiller="true",t},Hr=7,$r="⁠".repeat(Hr);function Wr(e){return Ln(e)&&e.data.substr(0,Hr)===$r}function jr(e){return e.data.length==Hr&&Wr(e)}function qr(e){return Wr(e)?e.data.slice(Hr):e.data}function Ur(e,t){if(t.keyCode==ds.arrowleft){const e=t.domTarget.ownerDocument.defaultView.getSelection();if(1==e.rangeCount&&e.getRangeAt(0).collapsed){const t=e.getRangeAt(0).startContainer,i=e.getRangeAt(0).startOffset;Wr(t)&&i<=Hr&&e.collapse(t,0)}}}class Gr extends(W()){constructor(e,t){super(),this.domDocuments=new Set,this.domConverter=e,this.markedAttributes=new Set,this.markedChildren=new Set,this.markedTexts=new Set,this.selection=t,this.set("isFocused",!1),this.set("_isFocusChanging",!1),this.set("isSelecting",!1),s.isBlink&&!s.isAndroid&&this.on("change:isSelecting",(()=>{this.isSelecting||this.render()})),this.set("isComposing",!1),this.on("change:isComposing",(()=>{this.isComposing||this.render()})),this._inlineFiller=null,this._fakeSelectionContainer=null}markToSync(e,t){if("text"===e)this.domConverter.mapViewToDom(t.parent)&&this.markedTexts.add(t);else{if(!this.domConverter.mapViewToDom(t))return;if("attributes"===e)this.markedAttributes.add(t);else{if("children"!==e)throw new b("view-renderer-unknown-type",this);this.markedChildren.add(t)}}}render(){if(this.isComposing&&!s.isAndroid)return;let e=null;const t=!(s.isBlink&&!s.isAndroid)||!this.isSelecting;for(const e of this.markedChildren)this._updateChildrenMappings(e);t?(this._inlineFiller&&!this._isSelectionInInlineFiller()&&this._removeInlineFiller(),this._inlineFiller?e=this._getInlineFillerPosition():this._needsInlineFillerAtSelection()&&(e=this.selection.getFirstPosition(),this.markedChildren.add(e.parent))):this._inlineFiller&&this._inlineFiller.parentNode&&(e=this.domConverter.domPositionToView(this._inlineFiller),e&&e.parent.is("$text")&&(e=nr._createBefore(e.parent)));for(const e of this.markedAttributes)this._updateAttrs(e);for(const t of this.markedChildren)this._updateChildren(t,{inlineFillerPosition:e});for(const t of this.markedTexts)!this.markedChildren.has(t.parent)&&this.domConverter.mapViewToDom(t.parent)&&this._updateText(t,{inlineFillerPosition:e});if(t)if(e){const t=this.domConverter.viewPositionToDom(e),i=t.parent.ownerDocument;Wr(t.parent)?this._inlineFiller=t.parent:this._inlineFiller=Kr(i,t.parent,t.offset)}else this._inlineFiller=null;this._updateFocus(),this._updateSelection(),this.markedTexts.clear(),this.markedAttributes.clear(),this.markedChildren.clear()}_updateChildrenMappings(e){if(!this.domConverter.mapViewToDom(e))return;const t=Array.from(this.domConverter.mapViewToDom(e).childNodes),i=Array.from(this.domConverter.viewChildrenToDom(e,{withChildren:!1})),n=this._diffNodeLists(t,i),s=this._findReplaceActions(n,t,i);if(-1!==s.indexOf("replace")){const n={equal:0,insert:0,delete:0};for(const o of s)if("replace"===o){const s=n.equal+n.insert,o=n.equal+n.delete,r=e.getChild(s);!r||r.is("uiElement")||r.is("rawElement")||this._updateElementMappings(r,t[o]),Yn(i[s]),n.equal++}else n[o]++}}_updateElementMappings(e,t){this.domConverter.unbindDomElement(t),this.domConverter.bindElements(t,e),this.markedChildren.add(e),this.markedAttributes.add(e)}_getInlineFillerPosition(){const e=this.selection.getFirstPosition();return e.parent.is("$text")?nr._createBefore(e.parent):e}_isSelectionInInlineFiller(){if(1!=this.selection.rangeCount||!this.selection.isCollapsed)return!1;const e=this.selection.getFirstPosition(),t=this.domConverter.viewPositionToDom(e);return!!(t&&Ln(t.parent)&&Wr(t.parent))}_removeInlineFiller(){const e=this._inlineFiller;if(!Wr(e))throw new b("view-renderer-filler-was-lost",this);jr(e)?e.remove():e.data=e.data.substr(Hr),this._inlineFiller=null}_needsInlineFillerAtSelection(){if(1!=this.selection.rangeCount||!this.selection.isCollapsed)return!1;const e=this.selection.getFirstPosition(),t=e.parent,i=e.offset;if(!this.domConverter.mapViewToDom(t.root))return!1;if(!t.is("element"))return!1;if(!function(e){if("false"==e.getAttribute("contenteditable"))return!1;const t=e.findAncestor((e=>e.hasAttribute("contenteditable")));return!t||"true"==t.getAttribute("contenteditable")}(t))return!1;if(i===t.getFillerOffset())return!1;const n=e.nodeBefore,o=e.nodeAfter;return!(n instanceof Gs||o instanceof Gs)&&(!s.isAndroid||!n&&!o)}_updateText(e,t){const i=this.domConverter.findCorrespondingDomText(e);let n=this.domConverter.viewToDom(e).data;const s=t.inlineFillerPosition;s&&s.parent==e.parent&&s.offset==e.index&&(n=$r+n),Xr(i,n)}_updateAttrs(e){const t=this.domConverter.mapViewToDom(e);if(!t)return;const i=Array.from(t.attributes).map((e=>e.name)),n=e.getAttributeKeys();for(const i of n)this.domConverter.setDomElementAttribute(t,i,e.getAttribute(i),e);for(const n of i)e.hasAttribute(n)||this.domConverter.removeDomElementAttribute(t,n)}_updateChildren(e,t){const i=this.domConverter.mapViewToDom(e);if(!i)return;if(s.isAndroid){let e=null;for(const t of Array.from(i.childNodes)){if(e&&Ln(e)&&Ln(t)){i.normalize();break}e=t}}const n=t.inlineFillerPosition,o=i.childNodes,r=Array.from(this.domConverter.viewChildrenToDom(e,{bind:!0}));n&&n.parent===e&&Kr(i.ownerDocument,r,n.offset);const a=this._diffNodeLists(o,r),l=s.isAndroid?this._findReplaceActions(a,o,r,{replaceText:!0}):a;let c=0;const d=new Set;for(const e of l)"delete"===e?(d.add(o[c]),Yn(o[c])):"equal"!==e&&"replace"!==e||c++;c=0;for(const e of l)"insert"===e?(qn(i,c,r[c]),c++):"replace"===e?(Xr(o[c],r[c].data),c++):"equal"===e&&(this._markDescendantTextToSync(this.domConverter.domToView(r[c])),c++);for(const e of d)e.parentNode||this.domConverter.unbindDomElement(e)}_diffNodeLists(e,t){return e=function(e,t){const i=Array.from(e);if(0==i.length||!t)return i;const n=i[i.length-1];n==t&&i.pop();return i}(e,this._fakeSelectionContainer),c(e,t,Yr.bind(null,this.domConverter))}_findReplaceActions(e,t,i,n={}){if(-1===e.indexOf("insert")||-1===e.indexOf("delete"))return e;let s=[],o=[],r=[];const a={equal:0,insert:0,delete:0};for(const l of e)"insert"===l?r.push(i[a.equal+a.insert]):"delete"===l?o.push(t[a.equal+a.delete]):(s=s.concat(c(o,r,n.replaceText?Qr:Jr).map((e=>"equal"===e?"replace":e))),s.push("equal"),o=[],r=[]),a[l]++;return s.concat(c(o,r,n.replaceText?Qr:Jr).map((e=>"equal"===e?"replace":e)))}_markDescendantTextToSync(e){if(e)if(e.is("$text"))this.markedTexts.add(e);else if(e.is("element"))for(const t of e.getChildren())this._markDescendantTextToSync(t)}_updateSelection(){if(s.isBlink&&!s.isAndroid&&this.isSelecting&&!this.markedChildren.size)return;if(this._isFocusChanging)return;if(0===this.selection.rangeCount)return this._removeDomSelection(),void this._removeFakeSelection();const e=this.domConverter.mapViewToDom(this.selection.editableElement);this.isFocused&&e&&(this.selection.isFake?this._updateFakeSelection(e):this._fakeSelectionContainer&&this._fakeSelectionContainer.isConnected?(this._removeFakeSelection(),this._updateDomSelection(e)):this.isComposing&&s.isAndroid||this._updateDomSelection(e))}_updateFakeSelection(e){const t=e.ownerDocument;this._fakeSelectionContainer||(this._fakeSelectionContainer=function(e){const t=e.createElement("div");return t.className="ck-fake-selection-container",Object.assign(t.style,{position:"fixed",top:0,left:"-9999px",width:"42px"}),t.textContent=" ",t}(t));const i=this._fakeSelectionContainer;if(this.domConverter.bindFakeSelection(i,this.selection),!this._fakeSelectionNeedsUpdate(e))return;i.parentElement&&i.parentElement==e||e.appendChild(i),i.textContent=this.selection.fakeSelectionLabel||" ";const n=t.getSelection(),s=t.createRange();n.removeAllRanges(),s.selectNodeContents(i),n.addRange(s)}_updateDomSelection(e){const t=e.ownerDocument.defaultView.getSelection();if(!this._domSelectionNeedsUpdate(t))return;const i=this.domConverter.viewPositionToDom(this.selection.anchor),n=this.domConverter.viewPositionToDom(this.selection.focus);t.collapse(i.parent,i.offset),t.extend(n.parent,n.offset),s.isGecko&&function(e,t){const i=e.parent;if(i.nodeType!=Node.ELEMENT_NODE||e.offset!=i.childNodes.length-1)return;const n=i.childNodes[e.offset];n&&"BR"==n.tagName&&t.addRange(t.getRangeAt(0))}(n,t)}_domSelectionNeedsUpdate(e){if(!this.domConverter.isDomSelectionCorrect(e))return!0;const t=e&&this.domConverter.domSelectionToView(e);return(!t||!this.selection.isEqual(t))&&!(!this.selection.isCollapsed&&this.selection.isSimilar(t))}_fakeSelectionNeedsUpdate(e){const t=this._fakeSelectionContainer,i=e.ownerDocument.getSelection();return!t||t.parentElement!==e||(i.anchorNode!==t&&!t.contains(i.anchorNode)||t.textContent!==this.selection.fakeSelectionLabel)}_removeDomSelection(){for(const e of this.domDocuments){const t=e.getSelection();if(t.rangeCount){const i=e.activeElement,n=this.domConverter.mapDomToView(i);i&&n&&t.removeAllRanges()}}}_removeFakeSelection(){const e=this._fakeSelectionContainer;e&&e.remove()}_updateFocus(){if(this.isFocused){const e=this.selection.editableElement;e&&this.domConverter.focus(e)}}}function Kr(e,t,i){const n=t instanceof Array?t:t.childNodes,s=n[i];if(Ln(s))return s.data=$r+s.data,s;{const s=e.createTextNode($r);return Array.isArray(t)?n.splice(i,0,s):qn(t,i,s),s}}function Jr(e,t){return An(e)&&An(t)&&!Ln(e)&&!Ln(t)&&!Un(e)&&!Un(t)&&e.tagName.toLowerCase()===t.tagName.toLowerCase()}function Qr(e,t){return An(e)&&An(t)&&Ln(e)&&Ln(t)}function Yr(e,t,i){return t===i||(Ln(t)&&Ln(i)?t.data===i.data:!(!e.isBlockFiller(t)||!e.isBlockFiller(i)))}function Xr(e,t){const i=e.data;if(i==t)return;const n=r(i,t);for(const t of n)"insert"===t.type?e.insertData(t.index,t.values.join("")):e.deleteData(t.index,t.howMany)}const Zr=zr(Rn.document),ea=Dr(Rn.document),ta=Fr(Rn.document),ia="data-ck-unsafe-attribute-",na="data-ck-unsafe-element";class sa{constructor(e,t={}){this.document=e,this.renderingMode=t.renderingMode||"editing",this.blockFillerMode=t.blockFillerMode||("editing"===this.renderingMode?"br":"nbsp"),this.preElements=["pre"],this.blockElements=["address","article","aside","blockquote","caption","center","dd","details","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","legend","li","main","menu","nav","ol","p","pre","section","summary","table","tbody","td","tfoot","th","thead","tr","ul"],this.inlineObjectElements=["object","iframe","input","button","textarea","select","option","video","embed","audio","img","canvas"],this.unsafeElements=["script","style"],this._domDocument="editing"===this.renderingMode?Rn.document:Rn.document.implementation.createHTMLDocument(""),this._domToViewMapping=new WeakMap,this._viewToDomMapping=new WeakMap,this._fakeSelectionMapping=new WeakMap,this._rawContentElementMatcher=new Js,this._encounteredRawContentDomNodes=new WeakSet}bindFakeSelection(e,t){this._fakeSelectionMapping.set(e,new rr(t))}fakeSelectionToView(e){return this._fakeSelectionMapping.get(e)}bindElements(e,t){this._domToViewMapping.set(e,t),this._viewToDomMapping.set(t,e)}unbindDomElement(e){const t=this._domToViewMapping.get(e);if(t){this._domToViewMapping.delete(e),this._viewToDomMapping.delete(t);for(const t of Array.from(e.children))this.unbindDomElement(t)}}bindDocumentFragments(e,t){this._domToViewMapping.set(e,t),this._viewToDomMapping.set(t,e)}shouldRenderAttribute(e,t,i){return"data"===this.renderingMode||!(e=e.toLowerCase()).startsWith("on")&&(("srcdoc"!==e||!t.match(/\bon\S+\s*=|javascript:|<\s*\/*script/i))&&("img"===i&&("src"===e||"srcset"===e)||("source"===i&&"srcset"===e||!t.match(/^\s*(javascript:|data:(image\/svg|text\/x?html))/i))))}setContentOf(e,t){if("data"===this.renderingMode)return void(e.innerHTML=t);const i=(new DOMParser).parseFromString(t,"text/html"),n=i.createDocumentFragment(),s=i.body.childNodes;for(;s.length>0;)n.appendChild(s[0]);const o=i.createTreeWalker(n,NodeFilter.SHOW_ELEMENT),r=[];let a;for(;a=o.nextNode();)r.push(a);for(const e of r){for(const t of e.getAttributeNames())this.setDomElementAttribute(e,t,e.getAttribute(t));const t=e.tagName.toLowerCase();this._shouldRenameElement(t)&&(aa(t),e.replaceWith(this._createReplacementDomElement(t,e)))}for(;e.firstChild;)e.firstChild.remove();e.append(n)}viewToDom(e,t={}){if(e.is("$text")){const t=this._processDataFromViewText(e);return this._domDocument.createTextNode(t)}{if(this.mapViewToDom(e))return this.mapViewToDom(e);let i;if(e.is("documentFragment"))i=this._domDocument.createDocumentFragment(),t.bind&&this.bindDocumentFragments(i,e);else{if(e.is("uiElement"))return i="$comment"===e.name?this._domDocument.createComment(e.getCustomProperty("$rawContent")):e.render(this._domDocument,this),t.bind&&this.bindElements(i,e),i;this._shouldRenameElement(e.name)?(aa(e.name),i=this._createReplacementDomElement(e.name)):i=e.hasAttribute("xmlns")?this._domDocument.createElementNS(e.getAttribute("xmlns"),e.name):this._domDocument.createElement(e.name),e.is("rawElement")&&e.render(i,this),t.bind&&this.bindElements(i,e);for(const t of e.getAttributeKeys())this.setDomElementAttribute(i,t,e.getAttribute(t),e)}if(!1!==t.withChildren)for(const n of this.viewChildrenToDom(e,t))i.appendChild(n);return i}}setDomElementAttribute(e,t,i,n){const s=this.shouldRenderAttribute(t,i,e.tagName.toLowerCase())||n&&n.shouldRenderUnsafeAttribute(t);s||v("domconverter-unsafe-attribute-detected",{domElement:e,key:t,value:i}),e.hasAttribute(t)&&!s?e.removeAttribute(t):e.hasAttribute(ia+t)&&s&&e.removeAttribute(ia+t),e.setAttribute(s?t:ia+t,i)}removeDomElementAttribute(e,t){t!=na&&(e.removeAttribute(t),e.removeAttribute(ia+t))}*viewChildrenToDom(e,t={}){const i=e.getFillerOffset&&e.getFillerOffset();let n=0;for(const s of e.getChildren()){i===n&&(yield this._getBlockFiller());const e=s.is("element")&&s.getCustomProperty("dataPipeline:transparentRendering");e&&"data"==this.renderingMode?yield*this.viewChildrenToDom(s,t):(e&&v("domconverter-transparent-rendering-unsupported-in-editing-pipeline",{viewElement:s}),yield this.viewToDom(s,t)),n++}i===n&&(yield this._getBlockFiller())}viewRangeToDom(e){const t=this.viewPositionToDom(e.start),i=this.viewPositionToDom(e.end),n=this._domDocument.createRange();return n.setStart(t.parent,t.offset),n.setEnd(i.parent,i.offset),n}viewPositionToDom(e){const t=e.parent;if(t.is("$text")){const i=this.findCorrespondingDomText(t);if(!i)return null;let n=e.offset;return Wr(i)&&(n+=Hr),{parent:i,offset:n}}{let i,n,s;if(0===e.offset){if(i=this.mapViewToDom(t),!i)return null;s=i.childNodes[0]}else{const t=e.nodeBefore;if(n=t.is("$text")?this.findCorrespondingDomText(t):this.mapViewToDom(t),!n)return null;i=n.parentNode,s=n.nextSibling}if(Ln(s)&&Wr(s))return{parent:s,offset:Hr};return{parent:i,offset:n?jn(n)+1:0}}}domToView(e,t={}){if(this.isBlockFiller(e))return null;const i=this.getHostViewElement(e);if(i)return i;if(Un(e)&&t.skipComments)return null;if(Ln(e)){if(jr(e))return null;{const t=this._processDataFromDomText(e);return""===t?null:new Gs(this.document,t)}}{if(this.mapDomToView(e))return this.mapDomToView(e);let i;if(this.isDocumentFragment(e))i=new Tr(this.document),t.bind&&this.bindDocumentFragments(e,i);else{i=this._createViewElement(e,t),t.bind&&this.bindElements(e,i);const n=e.attributes;if(n)for(let e=n.length,t=0;t{const{scrollLeft:t,scrollTop:i}=e;n.push([t,i])})),t.focus(),oa(t,(e=>{const[t,i]=n.shift();e.scrollLeft=t,e.scrollTop=i})),Rn.window.scrollTo(e,i)}}isElement(e){return e&&e.nodeType==Node.ELEMENT_NODE}isDocumentFragment(e){return e&&e.nodeType==Node.DOCUMENT_FRAGMENT_NODE}isBlockFiller(e){return"br"==this.blockFillerMode?e.isEqualNode(Zr):!("BR"!==e.tagName||!ra(e,this.blockElements)||1!==e.parentNode.childNodes.length)||(e.isEqualNode(ta)||function(e,t){const i=e.isEqualNode(ea);return i&&ra(e,t)&&1===e.parentNode.childNodes.length}(e,this.blockElements))}isDomSelectionBackward(e){if(e.isCollapsed)return!1;const t=this._domDocument.createRange();try{t.setStart(e.anchorNode,e.anchorOffset),t.setEnd(e.focusNode,e.focusOffset)}catch(e){return!1}const i=t.collapsed;return t.detach(),i}getHostViewElement(e){const t=Vn(e);for(t.pop();t.length;){const e=t.pop(),i=this._domToViewMapping.get(e);if(i&&(i.is("uiElement")||i.is("rawElement")))return i}return null}isDomSelectionCorrect(e){return this._isDomSelectionPositionCorrect(e.anchorNode,e.anchorOffset)&&this._isDomSelectionPositionCorrect(e.focusNode,e.focusOffset)}registerRawContentMatcher(e){this._rawContentElementMatcher.add(e)}_getBlockFiller(){switch(this.blockFillerMode){case"nbsp":return Dr(this._domDocument);case"markedNbsp":return Fr(this._domDocument);case"br":return zr(this._domDocument)}}_isDomSelectionPositionCorrect(e,t){if(Ln(e)&&Wr(e)&&tthis.preElements.includes(e.name))))return t;if(" "==t.charAt(0)){const i=this._getTouchingInlineViewNode(e,!1);!(i&&i.is("$textProxy")&&this._nodeEndsWithSpace(i))&&i||(t=" "+t.substr(1))}if(" "==t.charAt(t.length-1)){const i=this._getTouchingInlineViewNode(e,!0),n=i&&i.is("$textProxy")&&" "==i.data.charAt(0);" "!=t.charAt(t.length-2)&&i&&!n||(t=t.substr(0,t.length-1)+" ")}return t.replace(/ {2}/g,"  ")}_nodeEndsWithSpace(e){if(e.getAncestors().some((e=>this.preElements.includes(e.name))))return!1;const t=this._processDataFromViewText(e);return" "==t.charAt(t.length-1)}_processDataFromDomText(e){let t=e.data;if(function(e,t){const i=Vn(e);return i.some((e=>e.tagName&&t.includes(e.tagName.toLowerCase())))}(e,this.preElements))return qr(e);t=t.replace(/[ \n\t\r]{1,}/g," ");const i=this._getTouchingInlineDomNode(e,!1),n=this._getTouchingInlineDomNode(e,!0),s=this._checkShouldLeftTrimDomText(e,i),o=this._checkShouldRightTrimDomText(e,n);s&&(t=t.replace(/^ /,"")),o&&(t=t.replace(/ $/,"")),t=qr(new Text(t)),t=t.replace(/ \u00A0/g," ");const r=n&&this.isElement(n)&&"BR"!=n.tagName,a=n&&Ln(n)&&" "==n.data.charAt(0);return(/( |\u00A0)\u00A0$/.test(t)||!n||r||a)&&(t=t.replace(/\u00A0$/," ")),(s||i&&this.isElement(i)&&"BR"!=i.tagName)&&(t=t.replace(/^\u00A0/," ")),t}_checkShouldLeftTrimDomText(e,t){return!t||(this.isElement(t)?"BR"===t.tagName:!this._encounteredRawContentDomNodes.has(e.previousSibling)&&/[^\S\u00A0]/.test(t.data.charAt(t.data.length-1)))}_checkShouldRightTrimDomText(e,t){return!t&&!Wr(e)}_getTouchingInlineViewNode(e,t){const i=new ir({startPosition:t?nr._createAfter(e):nr._createBefore(e),direction:t?"forward":"backward"});for(const e of i){if(e.item.is("element")&&this.inlineObjectElements.includes(e.item.name))return e.item;if(e.item.is("containerElement"))return null;if(e.item.is("element","br"))return null;if(e.item.is("$textProxy"))return e.item}return null}_getTouchingInlineDomNode(e,t){if(!e.parentNode)return null;const i=t?"firstChild":"lastChild",n=t?"nextSibling":"previousSibling";let s=!0,o=e;do{if(!s&&o[i]?o=o[i]:o[n]?(o=o[n],s=!1):(o=o.parentNode,s=!0),!o||this._isBlockElement(o))return null}while(!Ln(o)&&"BR"!=o.tagName&&!this._isInlineObjectElement(o));return o}_isBlockElement(e){return this.isElement(e)&&this.blockElements.includes(e.tagName.toLowerCase())}_isInlineObjectElement(e){return this.isElement(e)&&this.inlineObjectElements.includes(e.tagName.toLowerCase())}_createViewElement(e,t){if(Un(e))return new yr(this.document,"$comment");const i=t.keepOriginalCase?e.tagName:e.tagName.toLowerCase();return new Jo(this.document,i)}_isViewElementWithRawContent(e,t){return!1!==t.withChildren&&!!this._rawContentElementMatcher.match(e)}_shouldRenameElement(e){const t=e.toLowerCase();return"editing"===this.renderingMode&&this.unsafeElements.includes(t)}_createReplacementDomElement(e,t){const i=this._domDocument.createElement("span");if(i.setAttribute(na,e),t){for(;t.firstChild;)i.appendChild(t.firstChild);for(const e of t.getAttributeNames())i.setAttribute(e,t.getAttribute(e))}return i}}function oa(e,t){let i=e;for(;i;)t(i),i=i.parentElement}function ra(e,t){const i=e.parentNode;return!!i&&!!i.tagName&&t.includes(i.tagName.toLowerCase())}function aa(e){"script"===e&&v("domconverter-unsafe-script-element-detected"),"style"===e&&v("domconverter-unsafe-style-element-detected")}class la extends(En()){constructor(e){super(),this.view=e,this.document=e.document,this.isEnabled=!1}enable(){this.isEnabled=!0}disable(){this.isEnabled=!1}destroy(){this.disable(),this.stopListening()}checkShouldIgnoreEventFromTarget(e){return e&&3===e.nodeType&&(e=e.parentNode),!(!e||1!==e.nodeType)&&e.matches("[data-cke-ignore-events], [data-cke-ignore-events] *")}}const ca=Ho((function(e,t){Et(t,di(t),e)}));class da{constructor(e,t,i){this.view=e,this.document=e.document,this.domEvent=t,this.domTarget=t.target,ca(this,i)}get target(){return this.view.domConverter.mapDomToView(this.domTarget)}preventDefault(){this.domEvent.preventDefault()}stopPropagation(){this.domEvent.stopPropagation()}}class ha extends la{constructor(e){super(e),this.useCapture=!1}observe(e){("string"==typeof this.domEventType?[this.domEventType]:this.domEventType).forEach((t=>{this.listenTo(e,t,((e,t)=>{this.isEnabled&&!this.checkShouldIgnoreEventFromTarget(t.target)&&this.onDomEvent(t)}),{useCapture:this.useCapture})}))}fire(e,t,i){this.isEnabled&&this.document.fire(e,new da(this.view,t,i))}}class ua extends ha{constructor(e){super(e),this.domEventType=["keydown","keyup"]}onDomEvent(e){const t={keyCode:e.keyCode,altKey:e.altKey,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,metaKey:e.metaKey,get keystroke(){return us(this)}};this.fire(e.type,e,t)}}const ma=function(){return te.Date.now()};var ga=/\s/;const fa=function(e){for(var t=e.length;t--&&ga.test(e.charAt(t)););return t};var pa=/^\s+/;const wa=function(e){return e?e.slice(0,fa(e)+1).replace(pa,""):e};var ba=/^[-+]0x[0-9a-f]+$/i,va=/^0b[01]+$/i,_a=/^0o[0-7]+$/i,ya=parseInt;const ka=function(e){if("number"==typeof e)return e;if(Xs(e))return NaN;if(M(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=M(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=wa(e);var i=va.test(e);return i||_a.test(e)?ya(e.slice(2),i?2:8):ba.test(e)?NaN:+e};var Ca=Math.max,Aa=Math.min;const xa=function(e,t,i){var n,s,o,r,a,l,c=0,d=!1,h=!1,u=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function m(t){var i=n,o=s;return n=s=void 0,c=t,r=e.apply(o,i)}function g(e){var i=e-l;return void 0===l||i>=t||i<0||h&&e-c>=o}function f(){var e=ma();if(g(e))return p(e);a=setTimeout(f,function(e){var i=t-(e-l);return h?Aa(i,o-(e-c)):i}(e))}function p(e){return a=void 0,u&&n?m(e):(n=s=void 0,r)}function w(){var e=ma(),i=g(e);if(n=arguments,s=this,l=e,i){if(void 0===a)return function(e){return c=e,a=setTimeout(f,t),d?m(e):r}(l);if(h)return clearTimeout(a),a=setTimeout(f,t),m(l)}return void 0===a&&(a=setTimeout(f,t)),r}return t=ka(t)||0,M(i)&&(d=!!i.leading,o=(h="maxWait"in i)?Ca(ka(i.maxWait)||0,t):o,u="trailing"in i?!!i.trailing:u),w.cancel=function(){void 0!==a&&clearTimeout(a),c=0,n=l=s=a=void 0},w.flush=function(){return void 0===a?r:p(ma())},w};class Ta extends la{constructor(e){super(e),this._fireSelectionChangeDoneDebounced=xa((e=>{this.document.fire("selectionChangeDone",e)}),200)}observe(){const e=this.document;e.on("arrowKey",((t,i)=>{e.selection.isFake&&this.isEnabled&&i.preventDefault()}),{context:"$capture"}),e.on("arrowKey",((t,i)=>{e.selection.isFake&&this.isEnabled&&this._handleSelectionMove(i.keyCode)}),{priority:"lowest"})}destroy(){super.destroy(),this._fireSelectionChangeDoneDebounced.cancel()}_handleSelectionMove(e){const t=this.document.selection,i=new rr(t.getRanges(),{backward:t.isBackward,fake:!1});e!=ds.arrowleft&&e!=ds.arrowup||i.setTo(i.getFirstPosition()),e!=ds.arrowright&&e!=ds.arrowdown||i.setTo(i.getLastPosition());const n={oldSelection:t,newSelection:i,domSelection:null};this.document.fire("selectionChange",n),this._fireSelectionChangeDoneDebounced(n)}}const Ea=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this};const Sa=function(e){return this.__data__.has(e)};function Pa(e){var t=-1,i=null==e?0:e.length;for(this.__data__=new bt;++ta))return!1;var c=o.get(e),d=o.get(t);if(c&&d)return c==t&&d==e;var h=-1,u=!0,m=2&i?new Ia:void 0;for(o.set(e,t),o.set(t,e);++h{this.document.fire("selectionChangeDone",e)}),200),this._clearInfiniteLoopInterval=setInterval((()=>this._clearInfiniteLoop()),1e3),this._documentIsSelectingInactivityTimeoutDebounced=xa((()=>this.document.isSelecting=!1),5e3),this._loopbackCounter=0}observe(e){const t=e.ownerDocument,i=()=>{this.document.isSelecting&&(this._handleSelectionChange(null,t),this.document.isSelecting=!1,this._documentIsSelectingInactivityTimeoutDebounced.cancel())};this.listenTo(e,"selectstart",(()=>{this.document.isSelecting=!0,this._documentIsSelectingInactivityTimeoutDebounced()}),{priority:"highest"}),this.listenTo(e,"keydown",i,{priority:"highest",useCapture:!0}),this.listenTo(e,"keyup",i,{priority:"highest",useCapture:!0}),this._documents.has(t)||(this.listenTo(t,"mouseup",i,{priority:"highest",useCapture:!0}),this.listenTo(t,"selectionchange",((e,i)=>{this.document.isComposing&&!s.isAndroid||(this._handleSelectionChange(i,t),this._documentIsSelectingInactivityTimeoutDebounced())})),this._documents.add(t))}destroy(){super.destroy(),clearInterval(this._clearInfiniteLoopInterval),this._fireSelectionChangeDoneDebounced.cancel(),this._documentIsSelectingInactivityTimeoutDebounced.cancel()}_handleSelectionChange(e,t){if(!this.isEnabled)return;const i=t.defaultView.getSelection();if(this.checkShouldIgnoreEventFromTarget(i.anchorNode))return;this.mutationObserver.flush();const n=this.domConverter.domSelectionToView(i);if(0!=n.rangeCount){if(this.view.hasDomSelection=!0,!(this.selection.isEqual(n)&&this.domConverter.isDomSelectionCorrect(i)||++this._loopbackCounter>60))if(this.selection.isSimilar(n))this.view.forceRender();else{const e={oldSelection:this.selection,newSelection:n,domSelection:i};this.document._isFocusChanging=!1,this.document.fire("selectionChange",e),this._fireSelectionChangeDoneDebounced(e)}}else this.view.hasDomSelection=!1}_clearInfiniteLoop(){this._loopbackCounter=0}}class Ya extends ha{constructor(e){super(e),this.domEventType=["focus","blur"],this.useCapture=!0;const t=this.document;t.on("focus",(()=>{t.isFocused=!0,t._isFocusChanging=!0,this._renderTimeoutId=setTimeout((()=>{t._isFocusChanging=!1,e.change((()=>{}))}),50)})),t.on("blur",((i,n)=>{const s=t.selection.editableElement;null!==s&&s!==n.target||(t.isFocused=!1,e.change((()=>{})))}))}onDomEvent(e){this.fire(e.type,e)}destroy(){this._renderTimeoutId&&clearTimeout(this._renderTimeoutId),super.destroy()}}class Xa extends ha{constructor(e){super(e),this.domEventType=["compositionstart","compositionupdate","compositionend"];const t=this.document;t.on("compositionstart",(()=>{t.isComposing=!0}),{priority:"low"}),t.on("compositionend",(()=>{t.isComposing=!1}),{priority:"low"})}onDomEvent(e){this.fire(e.type,e,{data:e.data})}}class Za{constructor(e){this.files=function(e){const t=Array.from(e.files||[]),i=Array.from(e.items||[]);if(t.length)return t;return i.filter((e=>"file"===e.kind)).map((e=>e.getAsFile()))}(e),this._native=e}get types(){return this._native.types}getData(e){return this._native.getData(e)}setData(e,t){this._native.setData(e,t)}set effectAllowed(e){this._native.effectAllowed=e}get effectAllowed(){return this._native.effectAllowed}set dropEffect(e){this._native.dropEffect=e}get dropEffect(){return this._native.dropEffect}get isCanceled(){return"none"==this._native.dropEffect||!!this._native.mozUserCancelled}}class el extends ha{constructor(e){super(e),this.domEventType=["beforeinput"]}onDomEvent(e){const t=e.getTargetRanges(),i=this.view,n=i.document;let o=null,r=null,a=[];if(e.dataTransfer&&(o=new Za(e.dataTransfer)),null!==e.data?r=e.data:o&&(r=o.getData("text/plain")),n.selection.isFake)a=Array.from(n.selection.getRanges());else if(t.length)a=t.map((e=>i.domConverter.domRangeToView(e)));else if(s.isAndroid){const t=e.target.ownerDocument.defaultView.getSelection();a=Array.from(i.domConverter.domSelectionToView(t).getRanges())}if(s.isAndroid&&"insertCompositionText"==e.inputType&&r&&r.endsWith("\n"))this.fire(e.type,e,{inputType:"insertParagraph",targetRanges:[i.createRange(a[0].end)]});else if("insertText"==e.inputType&&r&&r.includes("\n")){const t=r.split(/\n{1,2}/g);let i=a;for(let s=0;s{if(this.isEnabled&&((i=t.keyCode)==ds.arrowright||i==ds.arrowleft||i==ds.arrowup||i==ds.arrowdown)){const i=new lr(this.document,"arrowKey",this.document.selection.getFirstRange());this.document.fire(i,t),i.stop.called&&e.stop()}var i}))}observe(){}}class il extends la{constructor(e){super(e);const t=this.document;t.on("keydown",((e,i)=>{if(!this.isEnabled||i.keyCode!=ds.tab||i.ctrlKey)return;const n=new lr(t,"tab",t.selection.getFirstRange());t.fire(n,i),n.stop.called&&e.stop()}))}observe(){}}class nl extends(W()){constructor(e){super(),this.document=new fr(e),this.domConverter=new sa(this.document),this.domRoots=new Map,this.set("isRenderingInProgress",!1),this.set("hasDomSelection",!1),this._renderer=new Gr(this.domConverter,this.document.selection),this._renderer.bind("isFocused","isSelecting","isComposing","_isFocusChanging").to(this.document,"isFocused","isSelecting","isComposing","_isFocusChanging"),this._initialDomRootAttributes=new WeakMap,this._observers=new Map,this._ongoingChange=!1,this._postFixersInProgress=!1,this._renderingDisabled=!1,this._hasChangedSinceTheLastRendering=!1,this._writer=new Er(this.document),this.addObserver(Ka),this.addObserver(Qa),this.addObserver(Ya),this.addObserver(ua),this.addObserver(Ta),this.addObserver(Xa),this.addObserver(tl),this.addObserver(el),this.addObserver(il),this.document.on("arrowKey",Ur,{priority:"low"}),kr(this),this.on("render",(()=>{this._render(),this.document.fire("layoutChanged"),this._hasChangedSinceTheLastRendering=!1})),this.listenTo(this.document.selection,"change",(()=>{this._hasChangedSinceTheLastRendering=!0})),this.listenTo(this.document,"change:isFocused",(()=>{this._hasChangedSinceTheLastRendering=!0}))}attachDomRoot(e,t="main"){const i=this.document.getRoot(t);i._name=e.tagName.toLowerCase();const n={};for(const{name:t,value:s}of Array.from(e.attributes))n[t]=s,"class"===t?this._writer.addClass(s.split(" "),i):this._writer.setAttribute(t,s,i);this._initialDomRootAttributes.set(e,n);const s=()=>{this._writer.setAttribute("contenteditable",(!i.isReadOnly).toString(),i),i.isReadOnly?this._writer.addClass("ck-read-only",i):this._writer.removeClass("ck-read-only",i)};s(),this.domRoots.set(t,e),this.domConverter.bindElements(e,i),this._renderer.markToSync("children",i),this._renderer.markToSync("attributes",i),this._renderer.domDocuments.add(e.ownerDocument),i.on("change:children",((e,t)=>this._renderer.markToSync("children",t))),i.on("change:attributes",((e,t)=>this._renderer.markToSync("attributes",t))),i.on("change:text",((e,t)=>this._renderer.markToSync("text",t))),i.on("change:isReadOnly",(()=>this.change(s))),i.on("change",(()=>{this._hasChangedSinceTheLastRendering=!0}));for(const i of this._observers.values())i.observe(e,t)}detachDomRoot(e){const t=this.domRoots.get(e);Array.from(t.attributes).forEach((({name:e})=>t.removeAttribute(e)));const i=this._initialDomRootAttributes.get(t);for(const e in i)t.setAttribute(e,i[e]);this.domRoots.delete(e),this.domConverter.unbindDomElement(t)}getDomRoot(e="main"){return this.domRoots.get(e)}addObserver(e){let t=this._observers.get(e);if(t)return t;t=new e(this),this._observers.set(e,t);for(const[e,i]of this.domRoots)t.observe(i,e);return t.enable(),t}getObserver(e){return this._observers.get(e)}disableObservers(){for(const e of this._observers.values())e.disable()}enableObservers(){for(const e of this._observers.values())e.enable()}scrollToTheSelection(){const e=this.document.selection.getFirstRange();e&&Xn({target:this.domConverter.viewRangeToDom(e),viewportOffset:20})}focus(){if(!this.document.isFocused){const e=this.document.selection.editableElement;e&&(this.domConverter.focus(e),this.forceRender())}}change(e){if(this.isRenderingInProgress||this._postFixersInProgress)throw new b("cannot-change-view-tree",this);try{if(this._ongoingChange)return e(this._writer);this._ongoingChange=!0;const t=e(this._writer);return this._ongoingChange=!1,!this._renderingDisabled&&this._hasChangedSinceTheLastRendering&&(this._postFixersInProgress=!0,this.document._callPostFixers(this._writer),this._postFixersInProgress=!1,this.fire("render")),t}catch(e){b.rethrowUnexpectedError(e,this)}}forceRender(){this._hasChangedSinceTheLastRendering=!0,this.document._isFocusChanging=!1,this.change((()=>{}))}destroy(){for(const e of this._observers.values())e.destroy();this.document.destroy(),this.stopListening()}createPositionAt(e,t){return nr._createAt(e,t)}createPositionAfter(e){return nr._createAfter(e)}createPositionBefore(e){return nr._createBefore(e)}createRange(...e){return new sr(...e)}createRangeOn(e){return sr._createOn(e)}createRangeIn(e){return sr._createIn(e)}createSelection(...e){return new rr(...e)}_disableRendering(e){this._renderingDisabled=e,0==e&&this.change((()=>{}))}_render(){this.isRenderingInProgress=!0,this.disableObservers(),this._renderer.render(),this.enableObservers(),this.isRenderingInProgress=!1}}class sl{is(){throw new Error("is() method is abstract")}}class ol extends sl{constructor(e){super(),this.parent=null,this._attrs=xs(e)}get document(){return null}get index(){let e;if(!this.parent)return null;if(null===(e=this.parent.getChildIndex(this)))throw new b("model-node-not-found-in-parent",this);return e}get startOffset(){let e;if(!this.parent)return null;if(null===(e=this.parent.getChildStartOffset(this)))throw new b("model-node-not-found-in-parent",this);return e}get offsetSize(){return 1}get endOffset(){return this.parent?this.startOffset+this.offsetSize:null}get nextSibling(){const e=this.index;return null!==e&&this.parent.getChild(e+1)||null}get previousSibling(){const e=this.index;return null!==e&&this.parent.getChild(e-1)||null}get root(){let e=this;for(;e.parent;)e=e.parent;return e}isAttached(){return this.root.is("rootElement")}getPath(){const e=[];let t=this;for(;t.parent;)e.unshift(t.startOffset),t=t.parent;return e}getAncestors(e={}){const t=[];let i=e.includeSelf?this:this.parent;for(;i;)t[e.parentFirst?"push":"unshift"](i),i=i.parent;return t}getCommonAncestor(e,t={}){const i=this.getAncestors(t),n=e.getAncestors(t);let s=0;for(;i[s]==n[s]&&i[s];)s++;return 0===s?null:i[s-1]}isBefore(e){if(this==e)return!1;if(this.root!==e.root)return!1;const t=this.getPath(),i=e.getPath(),n=Y(t,i);switch(n){case"prefix":return!0;case"extension":return!1;default:return t[n](e[t[0]]=t[1],e)),{})),e}_clone(e){return new ol(this._attrs)}_remove(){this.parent._removeChildren(this.index)}_setAttribute(e,t){this._attrs.set(e,t)}_setAttributesTo(e){this._attrs=xs(e)}_removeAttribute(e){return this._attrs.delete(e)}_clearAttributes(){this._attrs.clear()}}ol.prototype.is=function(e){return"node"===e||"model:node"===e};class rl{constructor(e){this._nodes=[],e&&this._insertNodes(0,e)}[Symbol.iterator](){return this._nodes[Symbol.iterator]()}get length(){return this._nodes.length}get maxOffset(){return this._nodes.reduce(((e,t)=>e+t.offsetSize),0)}getNode(e){return this._nodes[e]||null}getNodeIndex(e){const t=this._nodes.indexOf(e);return-1==t?null:t}getNodeStartOffset(e){const t=this.getNodeIndex(e);return null===t?null:this._nodes.slice(0,t).reduce(((e,t)=>e+t.offsetSize),0)}indexToOffset(e){if(e==this._nodes.length)return this.maxOffset;const t=this._nodes[e];if(!t)throw new b("model-nodelist-index-out-of-bounds",this);return this.getNodeStartOffset(t)}offsetToIndex(e){let t=0;for(const i of this._nodes){if(e>=t&&e1e4)return e.slice(0,i).concat(t).concat(e.slice(i+n,e.length));{const s=Array.from(e);return s.splice(i,n,...t),s}}(this._nodes,Array.from(t),e,0)}_removeNodes(e,t=1){return this._nodes.splice(e,t)}toJSON(){return this._nodes.map((e=>e.toJSON()))}}class al extends ol{constructor(e,t){super(t),this._data=e||""}get offsetSize(){return this.data.length}get data(){return this._data}toJSON(){const e=super.toJSON();return e.data=this.data,e}_clone(){return new al(this.data,this.getAttributes())}static fromJSON(e){return new al(e.data,e.attributes)}}al.prototype.is=function(e){return"$text"===e||"model:$text"===e||"text"===e||"model:text"===e||"node"===e||"model:node"===e};class ll extends sl{constructor(e,t,i){if(super(),this.textNode=e,t<0||t>e.offsetSize)throw new b("model-textproxy-wrong-offsetintext",this);if(i<0||t+i>e.offsetSize)throw new b("model-textproxy-wrong-length",this);this.data=e.data.substring(t,t+i),this.offsetInText=t}get startOffset(){return null!==this.textNode.startOffset?this.textNode.startOffset+this.offsetInText:null}get offsetSize(){return this.data.length}get endOffset(){return null!==this.startOffset?this.startOffset+this.offsetSize:null}get isPartial(){return this.offsetSize!==this.textNode.offsetSize}get parent(){return this.textNode.parent}get root(){return this.textNode.root}getPath(){const e=this.textNode.getPath();return e.length>0&&(e[e.length-1]+=this.offsetInText),e}getAncestors(e={}){const t=[];let i=e.includeSelf?this:this.parent;for(;i;)t[e.parentFirst?"push":"unshift"](i),i=i.parent;return t}hasAttribute(e){return this.textNode.hasAttribute(e)}getAttribute(e){return this.textNode.getAttribute(e)}getAttributes(){return this.textNode.getAttributes()}getAttributeKeys(){return this.textNode.getAttributeKeys()}}ll.prototype.is=function(e){return"$textProxy"===e||"model:$textProxy"===e||"textProxy"===e||"model:textProxy"===e};class cl extends ol{constructor(e,t,i){super(t),this.name=e,this._children=new rl,i&&this._insertChild(0,i)}get childCount(){return this._children.length}get maxOffset(){return this._children.maxOffset}get isEmpty(){return 0===this.childCount}getChild(e){return this._children.getNode(e)}getChildren(){return this._children[Symbol.iterator]()}getChildIndex(e){return this._children.getNodeIndex(e)}getChildStartOffset(e){return this._children.getNodeStartOffset(e)}offsetToIndex(e){return this._children.offsetToIndex(e)}getNodeByPath(e){let t=this;for(const i of e)t=t.getChild(t.offsetToIndex(i));return t}findAncestor(e,t={}){let i=t.includeSelf?this:this.parent;for(;i;){if(i.name===e)return i;i=i.parent}return null}toJSON(){const e=super.toJSON();if(e.name=this.name,this._children.length>0){e.children=[];for(const t of this._children)e.children.push(t.toJSON())}return e}_clone(e=!1){const t=e?Array.from(this._children).map((e=>e._clone(!0))):void 0;return new cl(this.name,this.getAttributes(),t)}_appendChild(e){this._insertChild(this.childCount,e)}_insertChild(e,t){const i=function(e){if("string"==typeof e)return[new al(e)];X(e)||(e=[e]);return Array.from(e).map((e=>"string"==typeof e?new al(e):e instanceof ll?new al(e.data,e.getAttributes()):e))}(t);for(const e of i)null!==e.parent&&e._remove(),e.parent=this;this._children._insertNodes(e,i)}_removeChildren(e,t=1){const i=this._children._removeNodes(e,t);for(const e of i)e.parent=null;return i}static fromJSON(e){let t;if(e.children){t=[];for(const i of e.children)i.name?t.push(cl.fromJSON(i)):t.push(al.fromJSON(i))}return new cl(e.name,e.attributes,t)}}cl.prototype.is=function(e,t){return t?t===this.name&&("element"===e||"model:element"===e):"element"===e||"model:element"===e||"node"===e||"model:node"===e};class dl{constructor(e={}){if(!e.boundaries&&!e.startPosition)throw new b("model-tree-walker-no-start-position",null);const t=e.direction||"forward";if("forward"!=t&&"backward"!=t)throw new b("model-tree-walker-unknown-direction",e,{direction:t});this.direction=t,this.boundaries=e.boundaries||null,e.startPosition?this.position=e.startPosition.clone():this.position=ul._createAt(this.boundaries["backward"==this.direction?"end":"start"]),this.position.stickiness="toNone",this.singleCharacters=!!e.singleCharacters,this.shallow=!!e.shallow,this.ignoreElementEnd=!!e.ignoreElementEnd,this._boundaryStartParent=this.boundaries?this.boundaries.start.parent:null,this._boundaryEndParent=this.boundaries?this.boundaries.end.parent:null,this._visitedParent=this.position.parent}[Symbol.iterator](){return this}skip(e){let t,i,n,s;do{n=this.position,s=this._visitedParent,({done:t,value:i}=this.next())}while(!t&&e(i));t||(this.position=n,this._visitedParent=s)}next(){return"forward"==this.direction?this._next():this._previous()}_next(){const e=this.position,t=this.position.clone(),i=this._visitedParent;if(null===i.parent&&t.offset===i.maxOffset)return{done:!0,value:void 0};if(i===this._boundaryEndParent&&t.offset==this.boundaries.end.offset)return{done:!0,value:void 0};const n=ml(t,i),s=n||gl(t,i,n);if(s instanceof cl)return this.shallow?t.offset++:(t.path.push(0),this._visitedParent=s),this.position=t,hl("elementStart",s,e,t,1);if(s instanceof al){let n;if(this.singleCharacters)n=1;else{let e=s.endOffset;this._boundaryEndParent==i&&this.boundaries.end.offsete&&(e=this.boundaries.start.offset),n=t.offset-e}const s=t.offset-o.startOffset,r=new ll(o,s-n,n);return t.offset-=n,this.position=t,hl("text",r,e,t,n)}return t.path.pop(),this.position=t,this._visitedParent=i.parent,hl("elementStart",i,e,t,1)}}function hl(e,t,i,n,s){return{done:!1,value:{type:e,item:t,previousPosition:i,nextPosition:n,length:s}}}class ul extends sl{constructor(e,t,i="toNone"){if(super(),!e.is("element")&&!e.is("documentFragment"))throw new b("model-position-root-invalid",e);if(!(t instanceof Array)||0===t.length)throw new b("model-position-path-incorrect-format",e,{path:t});e.is("rootElement")?t=t.slice():(t=[...e.getPath(),...t],e=e.root),this.root=e,this.path=t,this.stickiness=i}get offset(){return this.path[this.path.length-1]}set offset(e){this.path[this.path.length-1]=e}get parent(){let e=this.root;for(let t=0;t1)return!1;if(1===t)return pl(e,this,i);if(-1===t)return pl(this,e,i)}return this.path.length===e.path.length||(this.path.length>e.path.length?wl(this.path,t):wl(e.path,t))}hasSameParentAs(e){if(this.root!==e.root)return!1;return"same"==Y(this.getParentPath(),e.getParentPath())}getTransformedByOperation(e){let t;switch(e.type){case"insert":t=this._getTransformedByInsertOperation(e);break;case"move":case"remove":case"reinsert":t=this._getTransformedByMoveOperation(e);break;case"split":t=this._getTransformedBySplitOperation(e);break;case"merge":t=this._getTransformedByMergeOperation(e);break;default:t=ul._createAt(this)}return t}_getTransformedByInsertOperation(e){return this._getTransformedByInsertion(e.position,e.howMany)}_getTransformedByMoveOperation(e){return this._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany)}_getTransformedBySplitOperation(e){const t=e.movedRange;return t.containsPosition(this)||t.start.isEqual(this)&&"toNext"==this.stickiness?this._getCombined(e.splitPosition,e.moveTargetPosition):e.graveyardPosition?this._getTransformedByMove(e.graveyardPosition,e.insertionPosition,1):this._getTransformedByInsertion(e.insertionPosition,1)}_getTransformedByMergeOperation(e){const t=e.movedRange;let i;return t.containsPosition(this)||t.start.isEqual(this)?(i=this._getCombined(e.sourcePosition,e.targetPosition),e.sourcePosition.isBefore(e.targetPosition)&&(i=i._getTransformedByDeletion(e.deletionPosition,1))):i=this.isEqual(e.deletionPosition)?ul._createAt(e.deletionPosition):this._getTransformedByMove(e.deletionPosition,e.graveyardPosition,1),i}_getTransformedByDeletion(e,t){const i=ul._createAt(this);if(this.root!=e.root)return i;if("same"==Y(e.getParentPath(),this.getParentPath())){if(e.offsetthis.offset)return null;i.offset-=t}}else if("prefix"==Y(e.getParentPath(),this.getParentPath())){const n=e.path.length-1;if(e.offset<=this.path[n]){if(e.offset+t>this.path[n])return null;i.path[n]-=t}}return i}_getTransformedByInsertion(e,t){const i=ul._createAt(this);if(this.root!=e.root)return i;if("same"==Y(e.getParentPath(),this.getParentPath()))(e.offset=t;){if(e.path[n]+s!==i.maxOffset)return!1;s=1,n--,i=i.parent}return!0}(e,i+1))}function wl(e,t){for(;tt+1;){const t=n.maxOffset-i.offset;0!==t&&e.push(new bl(i,i.getShiftedBy(t))),i.path=i.path.slice(0,-1),i.offset++,n=n.parent}for(;i.path.length<=this.end.path.length;){const t=this.end.path[i.path.length-1],n=t-i.offset;0!==n&&e.push(new bl(i,i.getShiftedBy(n))),i.offset=t,i.path.push(0)}return e}getWalker(e={}){return e.boundaries=this,new dl(e)}*getItems(e={}){e.boundaries=this,e.ignoreElementEnd=!0;const t=new dl(e);for(const e of t)yield e.item}*getPositions(e={}){e.boundaries=this;const t=new dl(e);yield t.position;for(const e of t)yield e.nextPosition}getTransformedByOperation(e){switch(e.type){case"insert":return this._getTransformedByInsertOperation(e);case"move":case"remove":case"reinsert":return this._getTransformedByMoveOperation(e);case"split":return[this._getTransformedBySplitOperation(e)];case"merge":return[this._getTransformedByMergeOperation(e)]}return[new bl(this.start,this.end)]}getTransformedByOperations(e){const t=[new bl(this.start,this.end)];for(const i of e)for(let e=0;e0?new this(i,n):new this(n,i)}static _createIn(e){return new this(ul._createAt(e,0),ul._createAt(e,e.maxOffset))}static _createOn(e){return this._createFromPositionAndShift(ul._createBefore(e),e.offsetSize)}static _createFromRanges(e){if(0===e.length)throw new b("range-create-from-ranges-empty-array",null);if(1==e.length)return e[0].clone();const t=e[0];e.sort(((e,t)=>e.start.isAfter(t.start)?1:-1));const i=e.indexOf(t),n=new this(t.start,t.end);if(i>0)for(let t=i-1;e[t].end.isEqual(n.start);t++)n.start=ul._createAt(e[t].start);for(let t=i+1;t{if(t.viewPosition)return;const i=this._modelToViewMapping.get(t.modelPosition.parent);if(!i)throw new b("mapping-model-position-view-parent-not-found",this,{modelPosition:t.modelPosition});t.viewPosition=this.findPositionIn(i,t.modelPosition.offset)}),{priority:"low"}),this.on("viewToModelPosition",((e,t)=>{if(t.modelPosition)return;const i=this.findMappedViewAncestor(t.viewPosition),n=this._viewToModelMapping.get(i),s=this._toModelOffset(t.viewPosition.parent,t.viewPosition.offset,i);t.modelPosition=ul._createAt(n,s)}),{priority:"low"})}bindElements(e,t){this._modelToViewMapping.set(e,t),this._viewToModelMapping.set(t,e)}unbindViewElement(e,t={}){const i=this.toModelElement(e);if(this._elementToMarkerNames.has(e))for(const t of this._elementToMarkerNames.get(e))this._unboundMarkerNames.add(t);t.defer?this._deferredBindingRemovals.set(e,e.root):(this._viewToModelMapping.delete(e),this._modelToViewMapping.get(i)==e&&this._modelToViewMapping.delete(i))}unbindModelElement(e){const t=this.toViewElement(e);this._modelToViewMapping.delete(e),this._viewToModelMapping.get(t)==e&&this._viewToModelMapping.delete(t)}bindElementToMarker(e,t){const i=this._markerNameToElements.get(t)||new Set;i.add(e);const n=this._elementToMarkerNames.get(e)||new Set;n.add(t),this._markerNameToElements.set(t,i),this._elementToMarkerNames.set(e,n)}unbindElementFromMarkerName(e,t){const i=this._markerNameToElements.get(t);i&&(i.delete(e),0==i.size&&this._markerNameToElements.delete(t));const n=this._elementToMarkerNames.get(e);n&&(n.delete(t),0==n.size&&this._elementToMarkerNames.delete(e))}flushUnboundMarkerNames(){const e=Array.from(this._unboundMarkerNames);return this._unboundMarkerNames.clear(),e}flushDeferredBindings(){for(const[e,t]of this._deferredBindingRemovals)e.root==t&&this.unbindViewElement(e);this._deferredBindingRemovals=new Map}clearBindings(){this._modelToViewMapping=new WeakMap,this._viewToModelMapping=new WeakMap,this._markerNameToElements=new Map,this._elementToMarkerNames=new Map,this._unboundMarkerNames=new Set,this._deferredBindingRemovals=new Map}toModelElement(e){return this._viewToModelMapping.get(e)}toViewElement(e){return this._modelToViewMapping.get(e)}toModelRange(e){return new bl(this.toModelPosition(e.start),this.toModelPosition(e.end))}toViewRange(e){return new sr(this.toViewPosition(e.start),this.toViewPosition(e.end))}toModelPosition(e){const t={viewPosition:e,mapper:this};return this.fire("viewToModelPosition",t),t.modelPosition}toViewPosition(e,t={}){const i={modelPosition:e,mapper:this,isPhantom:t.isPhantom};return this.fire("modelToViewPosition",i),i.viewPosition}markerNameToElements(e){const t=this._markerNameToElements.get(e);if(!t)return null;const i=new Set;for(const e of t)if(e.is("attributeElement"))for(const t of e.getElementsWithSameId())i.add(t);else i.add(e);return i}registerViewToModelLength(e,t){this._viewToModelLengthCallbacks.set(e,t)}findMappedViewAncestor(e){let t=e.parent;for(;!this._viewToModelMapping.has(t);)t=t.parent;return t}_toModelOffset(e,t,i){if(i!=e){return this._toModelOffset(e.parent,e.index,i)+this._toModelOffset(e,t,e)}if(e.is("$text"))return t;let n=0;for(let i=0;i1?t[0]+":"+t[1]:t[0]}class kl extends(S()){constructor(e){super(),this._conversionApi={dispatcher:this,...e},this._firedEventsMap=new WeakMap}convertChanges(e,t,i){const n=this._createConversionApi(i,e.getRefreshedItems());for(const t of e.getMarkersToRemove())this._convertMarkerRemove(t.name,t.range,n);const s=this._reduceChanges(e.getChanges());for(const e of s)"insert"===e.type?this._convertInsert(bl._createFromPositionAndShift(e.position,e.length),n):"reinsert"===e.type?this._convertReinsert(bl._createFromPositionAndShift(e.position,e.length),n):"remove"===e.type?this._convertRemove(e.position,e.length,e.name,n):this._convertAttribute(e.range,e.attributeKey,e.attributeOldValue,e.attributeNewValue,n);for(const e of n.mapper.flushUnboundMarkerNames()){const i=t.get(e).getRange();this._convertMarkerRemove(e,i,n),this._convertMarkerAdd(e,i,n)}for(const t of e.getMarkersToAdd())this._convertMarkerAdd(t.name,t.range,n);n.mapper.flushDeferredBindings(),n.consumable.verifyAllConsumed("insert")}convert(e,t,i,n={}){const s=this._createConversionApi(i,void 0,n);this._convertInsert(e,s);for(const[e,i]of t)this._convertMarkerAdd(e,i,s);s.consumable.verifyAllConsumed("insert")}convertSelection(e,t,i){const n=Array.from(t.getMarkersAtPosition(e.getFirstPosition())),s=this._createConversionApi(i);if(this._addConsumablesForSelection(s.consumable,e,n),this.fire("selection",{selection:e},s),e.isCollapsed){for(const t of n){const i=t.getRange();if(!Cl(e.getFirstPosition(),t,s.mapper))continue;const n={item:e,markerName:t.name,markerRange:i};s.consumable.test(e,"addMarker:"+t.name)&&this.fire(`addMarker:${t.name}`,n,s)}for(const t of e.getAttributeKeys()){const i={item:e,range:e.getFirstRange(),attributeKey:t,attributeOldValue:null,attributeNewValue:e.getAttribute(t)};s.consumable.test(e,"attribute:"+i.attributeKey)&&this.fire(`attribute:${i.attributeKey}:$text`,i,s)}}}_convertInsert(e,t,i={}){i.doNotAddConsumables||this._addConsumablesForInsert(t.consumable,Array.from(e));for(const i of Array.from(e.getWalker({shallow:!0})).map(Al))this._testAndFire("insert",i,t)}_convertRemove(e,t,i,n){this.fire(`remove:${i}`,{position:e,length:t},n)}_convertAttribute(e,t,i,n,s){this._addConsumablesForRange(s.consumable,e,`attribute:${t}`);for(const o of e){const e={item:o.item,range:bl._createFromPositionAndShift(o.previousPosition,o.length),attributeKey:t,attributeOldValue:i,attributeNewValue:n};this._testAndFire(`attribute:${t}`,e,s)}}_convertReinsert(e,t){const i=Array.from(e.getWalker({shallow:!0}));this._addConsumablesForInsert(t.consumable,i);for(const e of i.map(Al))this._testAndFire("insert",{...e,reconversion:!0},t)}_convertMarkerAdd(e,t,i){if("$graveyard"==t.root.rootName)return;const n=`addMarker:${e}`;if(i.consumable.add(t,n),this.fire(n,{markerName:e,markerRange:t},i),i.consumable.consume(t,n)){this._addConsumablesForRange(i.consumable,t,n);for(const s of t.getItems()){if(!i.consumable.test(s,n))continue;const o={item:s,range:bl._createOn(s),markerName:e,markerRange:t};this.fire(n,o,i)}}}_convertMarkerRemove(e,t,i){"$graveyard"!=t.root.rootName&&this.fire(`removeMarker:${e}`,{markerName:e,markerRange:t},i)}_reduceChanges(e){const t={changes:e};return this.fire("reduceChanges",t),t.changes}_addConsumablesForInsert(e,t){for(const i of t){const t=i.item;if(null===e.test(t,"insert")){e.add(t,"insert");for(const i of t.getAttributeKeys())e.add(t,"attribute:"+i)}}return e}_addConsumablesForRange(e,t,i){for(const n of t.getItems())e.add(n,i);return e}_addConsumablesForSelection(e,t,i){e.add(t,"selection");for(const n of i)e.add(t,"addMarker:"+n.name);for(const i of t.getAttributeKeys())e.add(t,"attribute:"+i);return e}_testAndFire(e,t,i){const n=function(e,t){const i=t.item.is("element")?t.item.name:"$text";return`${e}:${i}`}(e,t),s=t.item.is("$textProxy")?i.consumable._getSymbolForTextProxy(t.item):t.item,o=this._firedEventsMap.get(i),r=o.get(s);if(r){if(r.has(n))return;r.add(n)}else o.set(s,new Set([n]));this.fire(n,t,i)}_testAndFireAddAttributes(e,t){const i={item:e,range:bl._createOn(e)};for(const e of i.item.getAttributeKeys())i.attributeKey=e,i.attributeOldValue=null,i.attributeNewValue=i.item.getAttribute(e),this._testAndFire(`attribute:${e}`,i,t)}_createConversionApi(e,t=new Set,i={}){const n={...this._conversionApi,consumable:new _l,writer:e,options:i,convertItem:e=>this._convertInsert(bl._createOn(e),n),convertChildren:e=>this._convertInsert(bl._createIn(e),n,{doNotAddConsumables:!0}),convertAttributes:e=>this._testAndFireAddAttributes(e,n),canReuseView:e=>!t.has(n.mapper.toModelElement(e))};return this._firedEventsMap.set(n,new Map),n}}function Cl(e,t,i){const n=t.getRange(),s=Array.from(e.getAncestors());s.shift(),s.reverse();return!s.some((e=>{if(n.containsItem(e)){return!!i.toViewElement(e).getCustomProperty("addHighlight")}}))}function Al(e){return{item:e.item,range:bl._createFromPositionAndShift(e.previousPosition,e.length)}}class xl extends(S(sl)){constructor(...e){super(),this._lastRangeBackward=!1,this._ranges=[],this._attrs=new Map,e.length&&this.setTo(...e)}get anchor(){if(this._ranges.length>0){const e=this._ranges[this._ranges.length-1];return this._lastRangeBackward?e.end:e.start}return null}get focus(){if(this._ranges.length>0){const e=this._ranges[this._ranges.length-1];return this._lastRangeBackward?e.start:e.end}return null}get isCollapsed(){return 1===this._ranges.length&&this._ranges[0].isCollapsed}get rangeCount(){return this._ranges.length}get isBackward(){return!this.isCollapsed&&this._lastRangeBackward}isEqual(e){if(this.rangeCount!=e.rangeCount)return!1;if(0===this.rangeCount)return!0;if(!this.anchor.isEqual(e.anchor)||!this.focus.isEqual(e.focus))return!1;for(const t of this._ranges){let i=!1;for(const n of e._ranges)if(t.isEqual(n)){i=!0;break}if(!i)return!1}return!0}*getRanges(){for(const e of this._ranges)yield new bl(e.start,e.end)}getFirstRange(){let e=null;for(const t of this._ranges)e&&!t.start.isBefore(e.start)||(e=t);return e?new bl(e.start,e.end):null}getLastRange(){let e=null;for(const t of this._ranges)e&&!t.end.isAfter(e.end)||(e=t);return e?new bl(e.start,e.end):null}getFirstPosition(){const e=this.getFirstRange();return e?e.start.clone():null}getLastPosition(){const e=this.getLastRange();return e?e.end.clone():null}setTo(...e){let[t,i,n]=e;if("object"==typeof i&&(n=i,i=void 0),null===t)this._setRanges([]);else if(t instanceof xl)this._setRanges(t.getRanges(),t.isBackward);else if(t&&"function"==typeof t.getRanges)this._setRanges(t.getRanges(),t.isBackward);else if(t instanceof bl)this._setRanges([t],!!n&&!!n.backward);else if(t instanceof ul)this._setRanges([new bl(t)]);else if(t instanceof ol){const e=!!n&&!!n.backward;let s;if("in"==i)s=bl._createIn(t);else if("on"==i)s=bl._createOn(t);else{if(void 0===i)throw new b("model-selection-setto-required-second-parameter",[this,t]);s=new bl(ul._createAt(t,i))}this._setRanges([s],e)}else{if(!X(t))throw new b("model-selection-setto-not-selectable",[this,t]);this._setRanges(t,n&&!!n.backward)}}_setRanges(e,t=!1){const i=Array.from(e),n=i.some((t=>{if(!(t instanceof bl))throw new b("model-selection-set-ranges-not-range",[this,e]);return this._ranges.every((e=>!e.isEqual(t)))}));(i.length!==this._ranges.length||n)&&(this._replaceAllRanges(i),this._lastRangeBackward=!!t,this.fire("change:range",{directChange:!0}))}setFocus(e,t){if(null===this.anchor)throw new b("model-selection-setfocus-no-ranges",[this,e]);const i=ul._createAt(e,t);if("same"==i.compareWith(this.focus))return;const n=this.anchor;this._ranges.length&&this._popRange(),"before"==i.compareWith(n)?(this._pushRange(new bl(i,n)),this._lastRangeBackward=!0):(this._pushRange(new bl(n,i)),this._lastRangeBackward=!1),this.fire("change:range",{directChange:!0})}getAttribute(e){return this._attrs.get(e)}getAttributes(){return this._attrs.entries()}getAttributeKeys(){return this._attrs.keys()}hasAttribute(e){return this._attrs.has(e)}removeAttribute(e){this.hasAttribute(e)&&(this._attrs.delete(e),this.fire("change:attribute",{attributeKeys:[e],directChange:!0}))}setAttribute(e,t){this.getAttribute(e)!==t&&(this._attrs.set(e,t),this.fire("change:attribute",{attributeKeys:[e],directChange:!0}))}getSelectedElement(){return 1!==this.rangeCount?null:this.getFirstRange().getContainedElement()}*getSelectedBlocks(){const e=new WeakSet;for(const t of this.getRanges()){const i=Sl(t.start,e);i&&Pl(i,t)&&(yield i);for(const i of t.getWalker()){const n=i.item;"elementEnd"==i.type&&El(n,e,t)&&(yield n)}const n=Sl(t.end,e);n&&!t.end.isTouching(ul._createAt(n,0))&&Pl(n,t)&&(yield n)}}containsEntireContent(e=this.anchor.root){const t=ul._createAt(e,0),i=ul._createAt(e,"end");return t.isTouching(this.getFirstPosition())&&i.isTouching(this.getLastPosition())}_pushRange(e){this._checkRange(e),this._ranges.push(new bl(e.start,e.end))}_checkRange(e){for(let t=0;t0;)this._popRange()}_popRange(){this._ranges.pop()}}function Tl(e,t){return!t.has(e)&&(t.add(e),e.root.document.model.schema.isBlock(e)&&!!e.parent)}function El(e,t,i){return Tl(e,t)&&Pl(e,i)}function Sl(e,t){const i=e.parent.root.document.model.schema,n=e.parent.getAncestors({parentFirst:!0,includeSelf:!0});let s=!1;const o=n.find((e=>!s&&(s=i.isLimit(e),!s&&Tl(e,t))));return n.forEach((e=>t.add(e))),o}function Pl(e,t){const i=function(e){const t=e.root.document.model.schema;let i=e.parent;for(;i;){if(t.isBlock(i))return i;i=i.parent}}(e);if(!i)return!0;return!t.containsRange(bl._createOn(i),!0)}xl.prototype.is=function(e){return"selection"===e||"model:selection"===e};class Il extends(S(bl)){constructor(e,t){super(e,t),Rl.call(this)}detach(){this.stopListening()}toRange(){return new bl(this.start,this.end)}static fromRange(e){return new Il(e.start,e.end)}}function Rl(){this.listenTo(this.root.document.model,"applyOperation",((e,t)=>{const i=t[0];i.isDocumentOperation&&Vl.call(this,i)}),{priority:"low"})}function Vl(e){const t=this.getTransformedByOperation(e),i=bl._createFromRanges(t),n=!i.isEqual(this),s=function(e,t){switch(t.type){case"insert":return e.containsPosition(t.position);case"move":case"remove":case"reinsert":case"merge":return e.containsPosition(t.sourcePosition)||e.start.isEqual(t.sourcePosition)||e.containsPosition(t.targetPosition);case"split":return e.containsPosition(t.splitPosition)||e.containsPosition(t.insertionPosition)}return!1}(this,e);let o=null;if(n){"$graveyard"==i.root.rootName&&(o="remove"==e.type?e.sourcePosition:e.deletionPosition);const t=this.toRange();this.start=i.start,this.end=i.end,this.fire("change:range",t,{deletionPosition:o})}else s&&this.fire("change:content",this.toRange(),{deletionPosition:o})}Il.prototype.is=function(e){return"liveRange"===e||"model:liveRange"===e||"range"==e||"model:range"===e};const Ll="selection:";class Ol extends(S(sl)){constructor(e){super(),this._selection=new Bl(e),this._selection.delegate("change:range").to(this),this._selection.delegate("change:attribute").to(this),this._selection.delegate("change:marker").to(this)}get isCollapsed(){return this._selection.isCollapsed}get anchor(){return this._selection.anchor}get focus(){return this._selection.focus}get rangeCount(){return this._selection.rangeCount}get hasOwnRange(){return this._selection.hasOwnRange}get isBackward(){return this._selection.isBackward}get isGravityOverridden(){return this._selection.isGravityOverridden}get markers(){return this._selection.markers}get _ranges(){return this._selection._ranges}getRanges(){return this._selection.getRanges()}getFirstPosition(){return this._selection.getFirstPosition()}getLastPosition(){return this._selection.getLastPosition()}getFirstRange(){return this._selection.getFirstRange()}getLastRange(){return this._selection.getLastRange()}getSelectedBlocks(){return this._selection.getSelectedBlocks()}getSelectedElement(){return this._selection.getSelectedElement()}containsEntireContent(e){return this._selection.containsEntireContent(e)}destroy(){this._selection.destroy()}getAttributeKeys(){return this._selection.getAttributeKeys()}getAttributes(){return this._selection.getAttributes()}getAttribute(e){return this._selection.getAttribute(e)}hasAttribute(e){return this._selection.hasAttribute(e)}refresh(){this._selection.updateMarkers(),this._selection._updateAttributes(!1)}observeMarkers(e){this._selection.observeMarkers(e)}_setFocus(e,t){this._selection.setFocus(e,t)}_setTo(...e){this._selection.setTo(...e)}_setAttribute(e,t){this._selection.setAttribute(e,t)}_removeAttribute(e){this._selection.removeAttribute(e)}_getStoredAttributes(){return this._selection.getStoredAttributes()}_overrideGravity(){return this._selection.overrideGravity()}_restoreGravity(e){this._selection.restoreGravity(e)}static _getStoreAttributeKey(e){return Ll+e}static _isStoreAttributeKey(e){return e.startsWith(Ll)}}Ol.prototype.is=function(e){return"selection"===e||"model:selection"==e||"documentSelection"==e||"model:documentSelection"==e};class Bl extends xl{constructor(e){super(),this.markers=new ys({idProperty:"name"}),this._model=e.model,this._document=e,this._attributePriority=new Map,this._selectionRestorePosition=null,this._hasChangedRange=!1,this._overriddenGravityRegister=new Set,this._observedMarkers=new Set,this.listenTo(this._model,"applyOperation",((e,t)=>{const i=t[0];i.isDocumentOperation&&"marker"!=i.type&&"rename"!=i.type&&"noop"!=i.type&&(0==this._ranges.length&&this._selectionRestorePosition&&this._fixGraveyardSelection(this._selectionRestorePosition),this._selectionRestorePosition=null,this._hasChangedRange&&(this._hasChangedRange=!1,this.fire("change:range",{directChange:!1})))}),{priority:"lowest"}),this.on("change:range",(()=>{this._validateSelectionRanges(this.getRanges())})),this.listenTo(this._model.markers,"update",((e,t,i,n)=>{this._updateMarker(t,n)})),this.listenTo(this._document,"change",((e,t)=>{!function(e,t){const i=e.document.differ;for(const n of i.getChanges()){if("insert"!=n.type)continue;const i=n.position.parent;n.length===i.maxOffset&&e.enqueueChange(t,(e=>{const t=Array.from(i.getAttributeKeys()).filter((e=>e.startsWith(Ll)));for(const n of t)e.removeAttribute(n,i)}))}}(this._model,t)}))}get isCollapsed(){return 0===this._ranges.length?this._document._getDefaultRange().isCollapsed:super.isCollapsed}get anchor(){return super.anchor||this._document._getDefaultRange().start}get focus(){return super.focus||this._document._getDefaultRange().end}get rangeCount(){return this._ranges.length?this._ranges.length:1}get hasOwnRange(){return this._ranges.length>0}get isGravityOverridden(){return!!this._overriddenGravityRegister.size}destroy(){for(let e=0;e{if(this._hasChangedRange=!0,t.root==this._document.graveyard){this._selectionRestorePosition=n.deletionPosition;const e=this._ranges.indexOf(t);this._ranges.splice(e,1),t.detach()}})),t}updateMarkers(){if(!this._observedMarkers.size)return;const e=[];let t=!1;for(const t of this._model.markers){const i=t.name.split(":",1)[0];if(!this._observedMarkers.has(i))continue;const n=t.getRange();for(const i of this.getRanges())n.containsRange(i,!i.isCollapsed)&&e.push(t)}const i=Array.from(this.markers);for(const i of e)this.markers.has(i)||(this.markers.add(i),t=!0);for(const i of Array.from(this.markers))e.includes(i)||(this.markers.remove(i),t=!0);t&&this.fire("change:marker",{oldMarkers:i,directChange:!1})}_updateMarker(e,t){const i=e.name.split(":",1)[0];if(!this._observedMarkers.has(i))return;let n=!1;const s=Array.from(this.markers),o=this.markers.has(e);if(t){let i=!1;for(const e of this.getRanges())if(t.containsRange(e,!e.isCollapsed)){i=!0;break}i&&!o?(this.markers.add(e),n=!0):!i&&o&&(this.markers.remove(e),n=!0)}else o&&(this.markers.remove(e),n=!0);n&&this.fire("change:marker",{oldMarkers:s,directChange:!1})}_updateAttributes(e){const t=xs(this._getSurroundingAttributes()),i=xs(this.getAttributes());if(e)this._attributePriority=new Map,this._attrs=new Map;else for(const[e,t]of this._attributePriority)"low"==t&&(this._attrs.delete(e),this._attributePriority.delete(e));this._setAttributesTo(t);const n=[];for(const[e,t]of this.getAttributes())i.has(e)&&i.get(e)===t||n.push(e);for(const[e]of i)this.hasAttribute(e)||n.push(e);n.length>0&&this.fire("change:attribute",{attributeKeys:n,directChange:!1})}_setAttribute(e,t,i=!0){const n=i?"normal":"low";if("low"==n&&"normal"==this._attributePriority.get(e))return!1;return super.getAttribute(e)!==t&&(this._attrs.set(e,t),this._attributePriority.set(e,n),!0)}_removeAttribute(e,t=!0){const i=t?"normal":"low";return("low"!=i||"normal"!=this._attributePriority.get(e))&&(this._attributePriority.set(e,i),!!super.hasAttribute(e)&&(this._attrs.delete(e),!0))}_setAttributesTo(e){const t=new Set;for(const[t,i]of this.getAttributes())e.get(t)!==i&&this._removeAttribute(t,!1);for(const[i,n]of e){this._setAttribute(i,n,!1)&&t.add(i)}return t}*getStoredAttributes(){const e=this.getFirstPosition().parent;if(this.isCollapsed&&e.isEmpty)for(const t of e.getAttributeKeys())if(t.startsWith(Ll)){const i=t.substr(Ll.length);yield[i,e.getAttribute(t)]}}_getSurroundingAttributes(){const e=this.getFirstPosition(),t=this._model.schema;let i=null;if(this.isCollapsed){const n=e.textNode?e.textNode:e.nodeBefore,s=e.textNode?e.textNode:e.nodeAfter;if(this.isGravityOverridden||(i=Ml(n)),i||(i=Ml(s)),!this.isGravityOverridden&&!i){let e=n;for(;e&&!t.isInline(e)&&!i;)e=e.previousSibling,i=Ml(e)}if(!i){let e=s;for(;e&&!t.isInline(e)&&!i;)e=e.nextSibling,i=Ml(e)}i||(i=this.getStoredAttributes())}else{const e=this.getFirstRange();for(const n of e){if(n.item.is("element")&&t.isObject(n.item))break;if("text"==n.type){i=n.item.getAttributes();break}}}return i}_fixGraveyardSelection(e){const t=this._model.schema.getNearestSelectionRange(e);t&&this._pushRange(t)}}function Ml(e){return e instanceof ll||e instanceof al?e.getAttributes():null}class Nl{constructor(e){this._dispatchers=e}add(e){for(const t of this._dispatchers)e(t);return this}}const Dl=function(e){return bn(e,5)};class Fl extends Nl{elementToElement(e){return this.add(function(e){const t=$l(e.model),i=Wl(e.view,"container");t.attributes.length&&(t.children=!0);return n=>{n.on(`insert:${t.name}`,function(e,t=Yl){return(i,n,s)=>{if(!t(n.item,s.consumable,{preflight:!0}))return;const o=e(n.item,s,n);if(!o)return;t(n.item,s.consumable);const r=s.mapper.toViewPosition(n.range.start);s.mapper.bindElements(n.item,o),s.writer.insert(r,o),s.convertAttributes(n.item),Jl(o,n.item.getChildren(),s,{reconversion:n.reconversion})}}(i,Kl(t)),{priority:e.converterPriority||"normal"}),(t.children||t.attributes.length)&&n.on("reduceChanges",Gl(t),{priority:"low"})}}(e))}elementToStructure(e){return this.add(function(e){const t=$l(e.model),i=Wl(e.view,"container");return t.children=!0,n=>{if(n._conversionApi.schema.checkChild(t.name,"$text"))throw new b("conversion-element-to-structure-disallowed-text",n,{elementName:t.name});var s,o;n.on(`insert:${t.name}`,(s=i,o=Kl(t),(e,t,i)=>{if(!o(t.item,i.consumable,{preflight:!0}))return;const n=new Map;i.writer._registerSlotFactory(function(e,t,i){return(n,s="children")=>{const o=n.createContainerElement("$slot");let r=null;if("children"===s)r=Array.from(e.getChildren());else{if("function"!=typeof s)throw new b("conversion-slot-mode-unknown",i.dispatcher,{modeOrFilter:s});r=Array.from(e.getChildren()).filter((e=>s(e)))}return t.set(o,r),o}}(t.item,n,i));const r=s(t.item,i,t);if(i.writer._clearSlotFactory(),!r)return;!function(e,t,i){const n=Array.from(t.values()).flat(),s=new Set(n);if(s.size!=n.length)throw new b("conversion-slot-filter-overlap",i.dispatcher,{element:e});if(s.size!=e.childCount)throw new b("conversion-slot-filter-incomplete",i.dispatcher,{element:e})}(t.item,n,i),o(t.item,i.consumable);const a=i.mapper.toViewPosition(t.range.start);i.mapper.bindElements(t.item,r),i.writer.insert(a,r),i.convertAttributes(t.item),function(e,t,i,n){i.mapper.on("modelToViewPosition",r,{priority:"highest"});let s=null,o=null;for([s,o]of t)Jl(e,o,i,n),i.writer.move(i.writer.createRangeIn(s),i.writer.createPositionBefore(s)),i.writer.remove(s);function r(e,t){const i=t.modelPosition.nodeAfter,n=o.indexOf(i);n<0||(t.viewPosition=t.mapper.findPositionIn(s,n))}i.mapper.off("modelToViewPosition",r)}(r,n,i,{reconversion:t.reconversion})}),{priority:e.converterPriority||"normal"}),n.on("reduceChanges",Gl(t),{priority:"low"})}}(e))}attributeToElement(e){return this.add(function(e){e=Dl(e);let t=e.model;"string"==typeof t&&(t={key:t});let i=`attribute:${t.key}`;t.name&&(i+=":"+t.name);if(t.values)for(const i of t.values)e.view[i]=Wl(e.view[i],"attribute");else e.view=Wl(e.view,"attribute");const n=jl(e);return t=>{t.on(i,function(e){return(t,i,n)=>{if(!n.consumable.test(i.item,t.name))return;const s=e(i.attributeOldValue,n,i),o=e(i.attributeNewValue,n,i);if(!s&&!o)return;n.consumable.consume(i.item,t.name);const r=n.writer,a=r.document.selection;if(i.item instanceof xl||i.item instanceof Ol)r.wrap(a.getFirstRange(),o);else{let e=n.mapper.toViewRange(i.range);null!==i.attributeOldValue&&s&&(e=r.unwrap(e,s)),null!==i.attributeNewValue&&o&&r.wrap(e,o)}}}(n),{priority:e.converterPriority||"normal"})}}(e))}attributeToAttribute(e){return this.add(function(e){e=Dl(e);let t=e.model;"string"==typeof t&&(t={key:t});let i=`attribute:${t.key}`;t.name&&(i+=":"+t.name);if(t.values)for(const i of t.values)e.view[i]=ql(e.view[i]);else e.view=ql(e.view);const n=jl(e);return t=>{var s;t.on(i,(s=n,(e,t,i)=>{if(!i.consumable.test(t.item,e.name))return;const n=s(t.attributeOldValue,i,t),o=s(t.attributeNewValue,i,t);if(!n&&!o)return;i.consumable.consume(t.item,e.name);const r=i.mapper.toViewElement(t.item),a=i.writer;if(!r)throw new b("conversion-attribute-to-attribute-on-text",i.dispatcher,t);if(null!==t.attributeOldValue&&n)if("class"==n.key){const e=ps(n.value);for(const t of e)a.removeClass(t,r)}else if("style"==n.key){const e=Object.keys(n.value);for(const t of e)a.removeStyle(t,r)}else a.removeAttribute(n.key,r);if(null!==t.attributeNewValue&&o)if("class"==o.key){const e=ps(o.value);for(const t of e)a.addClass(t,r)}else if("style"==o.key){const e=Object.keys(o.value);for(const t of e)a.setStyle(t,o.value[t],r)}else a.setAttribute(o.key,o.value,r)}),{priority:e.converterPriority||"normal"})}}(e))}markerToElement(e){return this.add(function(e){const t=Wl(e.view,"ui");return i=>{var n;i.on(`addMarker:${e.model}`,(n=t,(e,t,i)=>{t.isOpening=!0;const s=n(t,i);t.isOpening=!1;const o=n(t,i);if(!s||!o)return;const r=t.markerRange;if(r.isCollapsed&&!i.consumable.consume(r,e.name))return;for(const t of r)if(!i.consumable.consume(t.item,e.name))return;const a=i.mapper,l=i.writer;l.insert(a.toViewPosition(r.start),s),i.mapper.bindElementToMarker(s,t.markerName),r.isCollapsed||(l.insert(a.toViewPosition(r.end),o),i.mapper.bindElementToMarker(o,t.markerName)),e.stop()}),{priority:e.converterPriority||"normal"}),i.on(`removeMarker:${e.model}`,((e,t,i)=>{const n=i.mapper.markerNameToElements(t.markerName);if(n){for(const e of n)i.mapper.unbindElementFromMarkerName(e,t.markerName),i.writer.clear(i.writer.createRangeOn(e),e);i.writer.clearClonedElementsGroup(t.markerName),e.stop()}}),{priority:e.converterPriority||"normal"})}}(e))}markerToHighlight(e){return this.add(function(e){return t=>{var i;t.on(`addMarker:${e.model}`,(i=e.view,(e,t,n)=>{if(!t.item)return;if(!(t.item instanceof xl||t.item instanceof Ol||t.item.is("$textProxy")))return;const s=Ul(i,t,n);if(!s)return;if(!n.consumable.consume(t.item,e.name))return;const o=n.writer,r=zl(o,s),a=o.document.selection;if(t.item instanceof xl||t.item instanceof Ol)o.wrap(a.getFirstRange(),r);else{const e=n.mapper.toViewRange(t.range),i=o.wrap(e,r);for(const e of i.getItems())if(e.is("attributeElement")&&e.isSimilar(r)){n.mapper.bindElementToMarker(e,t.markerName);break}}}),{priority:e.converterPriority||"normal"}),t.on(`addMarker:${e.model}`,function(e){return(t,i,n)=>{if(!i.item)return;if(!(i.item instanceof cl))return;const s=Ul(e,i,n);if(!s)return;if(!n.consumable.test(i.item,t.name))return;const o=n.mapper.toViewElement(i.item);if(o&&o.getCustomProperty("addHighlight")){n.consumable.consume(i.item,t.name);for(const e of bl._createIn(i.item))n.consumable.consume(e.item,t.name);o.getCustomProperty("addHighlight")(o,s,n.writer),n.mapper.bindElementToMarker(o,i.markerName)}}}(e.view),{priority:e.converterPriority||"normal"}),t.on(`removeMarker:${e.model}`,function(e){return(t,i,n)=>{if(i.markerRange.isCollapsed)return;const s=Ul(e,i,n);if(!s)return;const o=zl(n.writer,s),r=n.mapper.markerNameToElements(i.markerName);if(r){for(const e of r)if(n.mapper.unbindElementFromMarkerName(e,i.markerName),e.is("attributeElement"))n.writer.unwrap(n.writer.createRangeOn(e),o);else{e.getCustomProperty("removeHighlight")(e,s.id,n.writer)}n.writer.clearClonedElementsGroup(i.markerName),t.stop()}}}(e.view),{priority:e.converterPriority||"normal"})}}(e))}markerToData(e){return this.add(function(e){e=Dl(e);const t=e.model;let i=e.view;i||(i=i=>({group:t,name:i.substr(e.model.length+1)}));return n=>{var s;n.on(`addMarker:${t}`,(s=i,(e,t,i)=>{const n=s(t.markerName,i);if(!n)return;const o=t.markerRange;i.consumable.consume(o,e.name)&&(Hl(o,!1,i,t,n),Hl(o,!0,i,t,n),e.stop())}),{priority:e.converterPriority||"normal"}),n.on(`removeMarker:${t}`,function(e){return(t,i,n)=>{const s=e(i.markerName,n);if(!s)return;const o=n.mapper.markerNameToElements(i.markerName);if(o){for(const e of o)n.mapper.unbindElementFromMarkerName(e,i.markerName),e.is("containerElement")?(r(`data-${s.group}-start-before`,e),r(`data-${s.group}-start-after`,e),r(`data-${s.group}-end-before`,e),r(`data-${s.group}-end-after`,e)):n.writer.clear(n.writer.createRangeOn(e),e);n.writer.clearClonedElementsGroup(i.markerName),t.stop()}function r(e,t){if(t.hasAttribute(e)){const i=new Set(t.getAttribute(e).split(","));i.delete(s.name),0==i.size?n.writer.removeAttribute(e,t):n.writer.setAttribute(e,Array.from(i).join(","),t)}}}}(i),{priority:e.converterPriority||"normal"})}}(e))}}function zl(e,t){const i=e.createAttributeElement("span",t.attributes);return t.classes&&i._addClass(t.classes),"number"==typeof t.priority&&(i._priority=t.priority),i._id=t.id,i}function Hl(e,t,i,n,s){const o=t?e.start:e.end,r=o.nodeAfter&&o.nodeAfter.is("element")?o.nodeAfter:null,a=o.nodeBefore&&o.nodeBefore.is("element")?o.nodeBefore:null;if(r||a){let e,o;t&&r||!t&&!a?(e=r,o=!0):(e=a,o=!1);const l=i.mapper.toViewElement(e);if(l)return void function(e,t,i,n,s,o){const r=`data-${o.group}-${t?"start":"end"}-${i?"before":"after"}`,a=e.hasAttribute(r)?e.getAttribute(r).split(","):[];a.unshift(o.name),n.writer.setAttribute(r,a.join(","),e),n.mapper.bindElementToMarker(e,s.markerName)}(l,t,o,i,n,s)}!function(e,t,i,n,s){const o=`${s.group}-${t?"start":"end"}`,r=s.name?{name:s.name}:null,a=i.writer.createUIElement(o,r);i.writer.insert(e,a),i.mapper.bindElementToMarker(a,n.markerName)}(i.mapper.toViewPosition(o),t,i,n,s)}function $l(e){return"string"==typeof e&&(e={name:e}),e.attributes?Array.isArray(e.attributes)||(e.attributes=[e.attributes]):e.attributes=[],e.children=!!e.children,e}function Wl(e,t){return"function"==typeof e?e:(i,n)=>function(e,t,i){"string"==typeof e&&(e={name:e});let n;const s=t.writer,o=Object.assign({},e.attributes);if("container"==i)n=s.createContainerElement(e.name,o);else if("attribute"==i){const t={priority:e.priority||pr.DEFAULT_PRIORITY};n=s.createAttributeElement(e.name,o,t)}else n=s.createUIElement(e.name,o);if(e.styles){const t=Object.keys(e.styles);for(const i of t)s.setStyle(i,e.styles[i],n)}if(e.classes){const t=e.classes;if("string"==typeof t)s.addClass(t,n);else for(const e of t)s.addClass(e,n)}return n}(e,n,t)}function jl(e){return e.model.values?(t,i,n)=>{const s=e.view[t];return s?s(t,i,n):null}:e.view}function ql(e){return"string"==typeof e?t=>({key:e,value:t}):"object"==typeof e?e.value?()=>e:t=>({key:e.key,value:t}):e}function Ul(e,t,i){const n="function"==typeof e?e(t,i):e;return n?(n.priority||(n.priority=10),n.id||(n.id=t.markerName),n):null}function Gl(e){const t=function(e){return(t,i)=>{if(!t.is("element",e.name))return!1;if("attribute"==i.type){if(e.attributes.includes(i.attributeKey))return!0}else if(e.children)return!0;return!1}}(e);return(e,i)=>{const n=[];i.reconvertedElements||(i.reconvertedElements=new Set);for(const e of i.changes){const s="attribute"==e.type?e.range.start.nodeAfter:e.position.parent;if(s&&t(s,e)){if(!i.reconvertedElements.has(s)){i.reconvertedElements.add(s);const e=ul._createBefore(s);n.push({type:"remove",name:s.name,position:e,length:1},{type:"reinsert",name:s.name,position:e,length:1})}}else n.push(e)}i.changes=n}}function Kl(e){return(t,i,n={})=>{const s=["insert"];for(const i of e.attributes)t.hasAttribute(i)&&s.push(`attribute:${i}`);return!!s.every((e=>i.test(t,e)))&&(n.preflight||s.forEach((e=>i.consume(t,e))),!0)}}function Jl(e,t,i,n){for(const s of t)Ql(e.root,s,i,n)||i.convertItem(s)}function Ql(e,t,i,n){const{writer:s,mapper:o}=i;if(!n.reconversion)return!1;const r=o.toViewElement(t);return!(!r||r.root==e)&&(!!i.canReuseView(r)&&(s.move(s.createRangeOn(r),o.toViewPosition(ul._createBefore(t))),!0))}function Yl(e,t,{preflight:i}={}){return i?t.test(e,"insert"):t.consume(e,"insert")}function Xl(e){const{schema:t,document:i}=e.model;for(const n of i.getRootNames()){const s=i.getRoot(n);if(s.isEmpty&&!t.checkChild(s,"$text")&&t.checkChild(s,"paragraph"))return e.insertElement("paragraph",s),!0}return!1}function Zl(e,t,i){const n=i.createContext(e);return!!i.checkChild(n,"paragraph")&&!!i.checkChild(n.push("paragraph"),t)}function ec(e,t){const i=t.createElement("paragraph");return t.insert(i,e),t.createPositionAt(i,0)}class tc extends Nl{elementToElement(e){return this.add(ic(e))}elementToAttribute(e){return this.add(function(e){e=Dl(e),oc(e);const t=rc(e,!1),i=nc(e.view),n=i?`element:${i}`:"element";return i=>{i.on(n,t,{priority:e.converterPriority||"low"})}}(e))}attributeToAttribute(e){return this.add(function(e){e=Dl(e);let t=null;("string"==typeof e.view||e.view.key)&&(t=function(e){"string"==typeof e.view&&(e.view={key:e.view});const t=e.view.key;let i;if("class"==t||"style"==t){i={["class"==t?"classes":"styles"]:e.view.value}}else{i={attributes:{[t]:void 0===e.view.value?/[\s\S]*/:e.view.value}}}e.view.name&&(i.name=e.view.name);return e.view=i,t}(e));oc(e,t);const i=rc(e,!0);return t=>{t.on("element",i,{priority:e.converterPriority||"low"})}}(e))}elementToMarker(e){return this.add(function(e){const t=function(e){return(t,i)=>{const n="string"==typeof e?e:e(t,i);return i.writer.createElement("$marker",{"data-name":n})}}(e.model);return ic({...e,model:t})}(e))}dataToMarker(e){return this.add(function(e){e=Dl(e),e.model||(e.model=t=>t?e.view+":"+t:e.view);const t={view:e.view,model:e.model},i=sc(ac(t,"start")),n=sc(ac(t,"end"));return s=>{s.on(`element:${e.view}-start`,i,{priority:e.converterPriority||"normal"}),s.on(`element:${e.view}-end`,n,{priority:e.converterPriority||"normal"});const o=f.get("low"),r=f.get("highest"),a=f.get(e.converterPriority)/r;s.on("element",function(e){return(t,i,n)=>{const s=`data-${e.view}`;function o(t,s){for(const o of s){const s=e.model(o,n),r=n.writer.createElement("$marker",{"data-name":s});n.writer.insert(r,t),i.modelCursor.isEqual(t)?i.modelCursor=i.modelCursor.getShiftedBy(1):i.modelCursor=i.modelCursor._getTransformedByInsertion(t,1),i.modelRange=i.modelRange._getTransformedByInsertion(t,1)[0]}}(n.consumable.test(i.viewItem,{attributes:s+"-end-after"})||n.consumable.test(i.viewItem,{attributes:s+"-start-after"})||n.consumable.test(i.viewItem,{attributes:s+"-end-before"})||n.consumable.test(i.viewItem,{attributes:s+"-start-before"}))&&(i.modelRange||Object.assign(i,n.convertChildren(i.viewItem,i.modelCursor)),n.consumable.consume(i.viewItem,{attributes:s+"-end-after"})&&o(i.modelRange.end,i.viewItem.getAttribute(s+"-end-after").split(",")),n.consumable.consume(i.viewItem,{attributes:s+"-start-after"})&&o(i.modelRange.end,i.viewItem.getAttribute(s+"-start-after").split(",")),n.consumable.consume(i.viewItem,{attributes:s+"-end-before"})&&o(i.modelRange.start,i.viewItem.getAttribute(s+"-end-before").split(",")),n.consumable.consume(i.viewItem,{attributes:s+"-start-before"})&&o(i.modelRange.start,i.viewItem.getAttribute(s+"-start-before").split(",")))}}(t),{priority:o+a})}}(e))}}function ic(e){const t=sc(e=Dl(e)),i=nc(e.view),n=i?`element:${i}`:"element";return i=>{i.on(n,t,{priority:e.converterPriority||"normal"})}}function nc(e){return"string"==typeof e?e:"object"==typeof e&&"string"==typeof e.name?e.name:null}function sc(e){const t=new Js(e.view);return(i,n,s)=>{const o=t.match(n.viewItem);if(!o)return;const r=o.match;if(r.name=!0,!s.consumable.test(n.viewItem,r))return;const a=function(e,t,i){return e instanceof Function?e(t,i):i.writer.createElement(e)}(e.model,n.viewItem,s);a&&s.safeInsert(a,n.modelCursor)&&(s.consumable.consume(n.viewItem,r),s.convertChildren(n.viewItem,a),s.updateConversionResult(a,n))}}function oc(e,t=null){const i=null===t||(e=>e.getAttribute(t)),n="object"!=typeof e.model?e.model:e.model.key,s="object"!=typeof e.model||void 0===e.model.value?i:e.model.value;e.model={key:n,value:s}}function rc(e,t){const i=new Js(e.view);return(n,s,o)=>{if(!s.modelRange&&t)return;const r=i.match(s.viewItem);if(!r)return;if(!function(e,t){const i="function"==typeof e?e(t):e;if("object"==typeof i&&!nc(i))return!1;return!i.classes&&!i.attributes&&!i.styles}(e.view,s.viewItem)?delete r.match.name:r.match.name=!0,!o.consumable.test(s.viewItem,r.match))return;const a=e.model.key,l="function"==typeof e.model.value?e.model.value(s.viewItem,o):e.model.value;if(null===l)return;s.modelRange||Object.assign(s,o.convertChildren(s.viewItem,s.modelCursor));const c=function(e,t,i,n){let s=!1;for(const o of Array.from(e.getItems({shallow:i})))n.schema.checkAttribute(o,t.key)&&(s=!0,o.hasAttribute(t.key)||n.writer.setAttribute(t.key,t.value,o));return s}(s.modelRange,{key:a,value:l},t,o);c&&(o.consumable.test(s.viewItem,{name:!0})&&(r.match.name=!0),o.consumable.consume(s.viewItem,r.match))}}function ac(e,t){return{view:`${e.view}-${t}`,model:(t,i)=>{const n=t.getAttribute("name"),s=e.model(n,i);return i.writer.createElement("$marker",{"data-name":s})}}}class lc extends(W()){constructor(e,t){super(),this.model=e,this.view=new nl(t),this.mapper=new vl,this.downcastDispatcher=new kl({mapper:this.mapper,schema:e.schema});const i=this.model.document,n=i.selection,s=this.model.markers;this.listenTo(this.model,"_beforeChanges",(()=>{this.view._disableRendering(!0)}),{priority:"highest"}),this.listenTo(this.model,"_afterChanges",(()=>{this.view._disableRendering(!1)}),{priority:"lowest"}),this.listenTo(i,"change",(()=>{this.view.change((e=>{this.downcastDispatcher.convertChanges(i.differ,s,e),this.downcastDispatcher.convertSelection(n,s,e)}))}),{priority:"low"}),this.listenTo(this.view.document,"selectionChange",function(e,t){return(i,n)=>{const s=n.newSelection,o=[];for(const e of s.getRanges())o.push(t.toModelRange(e));const r=e.createSelection(o,{backward:s.isBackward});r.isEqual(e.document.selection)||e.change((e=>{e.setSelection(r)}))}}(this.model,this.mapper)),this.downcastDispatcher.on("insert:$text",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.writer,s=i.mapper.toViewPosition(t.range.start),o=n.createText(t.item.data);n.insert(s,o)}),{priority:"lowest"}),this.downcastDispatcher.on("insert",((e,t,i)=>{i.convertAttributes(t.item),t.reconversion||!t.item.is("element")||t.item.isEmpty||i.convertChildren(t.item)}),{priority:"lowest"}),this.downcastDispatcher.on("remove",((e,t,i)=>{const n=i.mapper.toViewPosition(t.position),s=t.position.getShiftedBy(t.length),o=i.mapper.toViewPosition(s,{isPhantom:!0}),r=i.writer.createRange(n,o),a=i.writer.remove(r.getTrimmed());for(const e of i.writer.createRangeIn(a).getItems())i.mapper.unbindViewElement(e,{defer:!0})}),{priority:"low"}),this.downcastDispatcher.on("selection",((e,t,i)=>{const n=i.writer,s=n.document.selection;for(const e of s.getRanges())e.isCollapsed&&e.end.parent.isAttached()&&i.writer.mergeAttributes(e.start);n.setSelection(null)}),{priority:"high"}),this.downcastDispatcher.on("selection",((e,t,i)=>{const n=t.selection;if(n.isCollapsed)return;if(!i.consumable.consume(n,"selection"))return;const s=[];for(const e of n.getRanges())s.push(i.mapper.toViewRange(e));i.writer.setSelection(s,{backward:n.isBackward})}),{priority:"low"}),this.downcastDispatcher.on("selection",((e,t,i)=>{const n=t.selection;if(!n.isCollapsed)return;if(!i.consumable.consume(n,"selection"))return;const s=i.writer,o=n.getFirstPosition(),r=i.mapper.toViewPosition(o),a=s.breakAttributes(r);s.setSelection(a)}),{priority:"low"}),this.view.document.roots.bindTo(this.model.document.roots).using((e=>{if("$graveyard"==e.rootName)return null;const t=new tr(this.view.document,e.name);return t.rootName=e.rootName,this.mapper.bindElements(e,t),t}))}destroy(){this.view.destroy(),this.stopListening()}reconvertMarker(e){const t="string"==typeof e?e:e.name,i=this.model.markers.get(t);if(!i)throw new b("editingcontroller-reconvertmarker-marker-not-exist",this,{markerName:t});this.model.change((()=>{this.model.markers._refresh(i)}))}reconvertItem(e){this.model.change((()=>{this.model.document.differ._refreshItem(e)}))}}class cc{constructor(){this._consumables=new Map}add(e,t){let i;e.is("$text")||e.is("documentFragment")?this._consumables.set(e,!0):(this._consumables.has(e)?i=this._consumables.get(e):(i=new hc(e),this._consumables.set(e,i)),i.add(t))}test(e,t){const i=this._consumables.get(e);return void 0===i?null:e.is("$text")||e.is("documentFragment")?i:i.test(t)}consume(e,t){return!!this.test(e,t)&&(e.is("$text")||e.is("documentFragment")?this._consumables.set(e,!1):this._consumables.get(e).consume(t),!0)}revert(e,t){const i=this._consumables.get(e);void 0!==i&&(e.is("$text")||e.is("documentFragment")?this._consumables.set(e,!0):i.revert(t))}static consumablesFromElement(e){const t={element:e,name:!0,attributes:[],classes:[],styles:[]},i=e.getAttributeKeys();for(const e of i)"style"!=e&&"class"!=e&&t.attributes.push(e);const n=e.getClassNames();for(const e of n)t.classes.push(e);const s=e.getStyleNames();for(const e of s)t.styles.push(e);return t}static createFrom(e,t){if(t||(t=new cc),e.is("$text"))return t.add(e),t;e.is("element")&&t.add(e,cc.consumablesFromElement(e)),e.is("documentFragment")&&t.add(e);for(const i of e.getChildren())t=cc.createFrom(i,t);return t}}const dc=["attributes","classes","styles"];class hc{constructor(e){this.element=e,this._canConsumeName=null,this._consumables={attributes:new Map,styles:new Map,classes:new Map}}add(e){e.name&&(this._canConsumeName=!0);for(const t of dc)t in e&&this._add(t,e[t])}test(e){if(e.name&&!this._canConsumeName)return this._canConsumeName;for(const t of dc)if(t in e){const i=this._test(t,e[t]);if(!0!==i)return i}return!0}consume(e){e.name&&(this._canConsumeName=!1);for(const t of dc)t in e&&this._consume(t,e[t])}revert(e){e.name&&(this._canConsumeName=!0);for(const t of dc)t in e&&this._revert(t,e[t])}_add(e,t){const i=ue(t)?t:[t],n=this._consumables[e];for(const t of i){if("attributes"===e&&("class"===t||"style"===t))throw new b("viewconsumable-invalid-attribute",this);if(n.set(t,!0),"styles"===e)for(const e of this.element.document.stylesProcessor.getRelatedStyles(t))n.set(e,!0)}}_test(e,t){const i=ue(t)?t:[t],n=this._consumables[e];for(const t of i)if("attributes"!==e||"class"!==t&&"style"!==t){const e=n.get(t);if(void 0===e)return null;if(!e)return!1}else{const e="class"==t?"classes":"styles",i=this._test(e,[...this._consumables[e].keys()]);if(!0!==i)return i}return!0}_consume(e,t){const i=ue(t)?t:[t],n=this._consumables[e];for(const t of i)if("attributes"!==e||"class"!==t&&"style"!==t){if(n.set(t,!1),"styles"==e)for(const e of this.element.document.stylesProcessor.getRelatedStyles(t))n.set(e,!1)}else{const e="class"==t?"classes":"styles";this._consume(e,[...this._consumables[e].keys()])}}_revert(e,t){const i=ue(t)?t:[t],n=this._consumables[e];for(const t of i)if("attributes"!==e||"class"!==t&&"style"!==t){!1===n.get(t)&&n.set(t,!0)}else{const e="class"==t?"classes":"styles";this._revert(e,[...this._consumables[e].keys()])}}}class uc extends(W()){constructor(){super(),this._sourceDefinitions={},this._attributeProperties={},this.decorate("checkChild"),this.decorate("checkAttribute"),this.on("checkAttribute",((e,t)=>{t[0]=new mc(t[0])}),{priority:"highest"}),this.on("checkChild",((e,t)=>{t[0]=new mc(t[0]),t[1]=this.getDefinition(t[1])}),{priority:"highest"})}register(e,t){if(this._sourceDefinitions[e])throw new b("schema-cannot-register-item-twice",this,{itemName:e});this._sourceDefinitions[e]=[Object.assign({},t)],this._clearCache()}extend(e,t){if(!this._sourceDefinitions[e])throw new b("schema-cannot-extend-missing-item",this,{itemName:e});this._sourceDefinitions[e].push(Object.assign({},t)),this._clearCache()}getDefinitions(){return this._compiledDefinitions||this._compile(),this._compiledDefinitions}getDefinition(e){let t;return t="string"==typeof e?e:"is"in e&&(e.is("$text")||e.is("$textProxy"))?"$text":e.name,this.getDefinitions()[t]}isRegistered(e){return!!this.getDefinition(e)}isBlock(e){const t=this.getDefinition(e);return!(!t||!t.isBlock)}isLimit(e){const t=this.getDefinition(e);return!!t&&!(!t.isLimit&&!t.isObject)}isObject(e){const t=this.getDefinition(e);return!!t&&!!(t.isObject||t.isLimit&&t.isSelectable&&t.isContent)}isInline(e){const t=this.getDefinition(e);return!(!t||!t.isInline)}isSelectable(e){const t=this.getDefinition(e);return!!t&&!(!t.isSelectable&&!t.isObject)}isContent(e){const t=this.getDefinition(e);return!!t&&!(!t.isContent&&!t.isObject)}checkChild(e,t){return!!t&&this._checkContextMatch(t,e)}checkAttribute(e,t){const i=this.getDefinition(e.last);return!!i&&i.allowAttributes.includes(t)}checkMerge(e,t){if(e instanceof ul){const t=e.nodeBefore,i=e.nodeAfter;if(!(t instanceof cl))throw new b("schema-check-merge-no-element-before",this);if(!(i instanceof cl))throw new b("schema-check-merge-no-element-after",this);return this.checkMerge(t,i)}for(const i of t.getChildren())if(!this.checkChild(e,i))return!1;return!0}addChildCheck(e){this.on("checkChild",((t,[i,n])=>{if(!n)return;const s=e(i,n);"boolean"==typeof s&&(t.stop(),t.return=s)}),{priority:"high"})}addAttributeCheck(e){this.on("checkAttribute",((t,[i,n])=>{const s=e(i,n);"boolean"==typeof s&&(t.stop(),t.return=s)}),{priority:"high"})}setAttributeProperties(e,t){this._attributeProperties[e]=Object.assign(this.getAttributeProperties(e),t)}getAttributeProperties(e){return this._attributeProperties[e]||{}}getLimitElement(e){let t;if(e instanceof ul)t=e.parent;else{t=(e instanceof bl?[e]:Array.from(e.getRanges())).reduce(((e,t)=>{const i=t.getCommonAncestor();return e?e.getCommonAncestor(i,{includeSelf:!0}):i}),null)}for(;!this.isLimit(t)&&t.parent;)t=t.parent;return t}checkAttributeInSelection(e,t){if(e.isCollapsed){const i=[...e.getFirstPosition().getAncestors(),new al("",e.getAttributes())];return this.checkAttribute(i,t)}{const i=e.getRanges();for(const e of i)for(const i of e)if(this.checkAttribute(i.item,t))return!0}return!1}*getValidRanges(e,t){e=function*(e){for(const t of e)yield*t.getMinimalFlatRanges()}(e);for(const i of e)yield*this._getValidRangesForRange(i,t)}getNearestSelectionRange(e,t="both"){if(this.checkChild(e,"$text"))return new bl(e);let i,n;const s=e.getAncestors().reverse().find((e=>this.isLimit(e)))||e.root;"both"!=t&&"backward"!=t||(i=new dl({boundaries:bl._createIn(s),startPosition:e,direction:"backward"})),"both"!=t&&"forward"!=t||(n=new dl({boundaries:bl._createIn(s),startPosition:e}));for(const e of function*(e,t){let i=!1;for(;!i;){if(i=!0,e){const t=e.next();t.done||(i=!1,yield{walker:e,value:t.value})}if(t){const e=t.next();e.done||(i=!1,yield{walker:t,value:e.value})}}}(i,n)){const t=e.walker==i?"elementEnd":"elementStart",n=e.value;if(n.type==t&&this.isObject(n.item))return bl._createOn(n.item);if(this.checkChild(n.nextPosition,"$text"))return new bl(n.nextPosition)}return null}findAllowedParent(e,t){let i=e.parent;for(;i;){if(this.checkChild(i,t))return i;if(this.isLimit(i))return null;i=i.parent}return null}setAllowedAttributes(e,t,i){const n=i.model;for(const[s,o]of Object.entries(t))n.schema.checkAttribute(e,s)&&i.setAttribute(s,o,e)}removeDisallowedAttributes(e,t){for(const i of e)if(i.is("$text"))Tc(this,i,t);else{const e=bl._createIn(i).getPositions();for(const i of e){Tc(this,i.nodeBefore||i.parent,t)}}}getAttributesWithProperty(e,t,i){const n={};for(const[s,o]of e.getAttributes()){const e=this.getAttributeProperties(s);void 0!==e[t]&&(void 0!==i&&i!==e[t]||(n[s]=o))}return n}createContext(e){return new mc(e)}_clearCache(){this._compiledDefinitions=null}_compile(){const e={},t=this._sourceDefinitions,i=Object.keys(t);for(const n of i)e[n]=gc(t[n],n);for(const t of i)fc(e,t);for(const t of i)pc(e,t);for(const t of i)wc(e,t);for(const t of i)bc(e,t),vc(e,t);for(const t of i)_c(e,t),yc(e,t),kc(e,t);this._compiledDefinitions=e}_checkContextMatch(e,t,i=t.length-1){const n=t.getItem(i);if(e.allowIn.includes(n.name)){if(0==i)return!0;{const e=this.getDefinition(n);return this._checkContextMatch(e,t,i-1)}}return!1}*_getValidRangesForRange(e,t){let i=e.start,n=e.start;for(const s of e.getItems({shallow:!0}))s.is("element")&&(yield*this._getValidRangesForRange(bl._createIn(s),t)),this.checkAttribute(s,t)||(i.isEqual(n)||(yield new bl(i,n)),i=ul._createAfter(s)),n=ul._createAfter(s);i.isEqual(n)||(yield new bl(i,n))}}class mc{constructor(e){if(e instanceof mc)return e;let t;t="string"==typeof e?[e]:Array.isArray(e)?e:e.getAncestors({includeSelf:!0}),this._items=t.map(xc)}get length(){return this._items.length}get last(){return this._items[this._items.length-1]}[Symbol.iterator](){return this._items[Symbol.iterator]()}push(e){const t=new mc([e]);return t._items=[...this._items,...t._items],t}getItem(e){return this._items[e]}*getNames(){yield*this._items.map((e=>e.name))}endsWith(e){return Array.from(this.getNames()).join(" ").endsWith(e)}startsWith(e){return Array.from(this.getNames()).join(" ").startsWith(e)}}function gc(e,t){const i={name:t,allowIn:[],allowContentOf:[],allowWhere:[],allowAttributes:[],allowAttributesOf:[],allowChildren:[],inheritTypesFrom:[]};return function(e,t){for(const i of e){const e=Object.keys(i).filter((e=>e.startsWith("is")));for(const n of e)t[n]=!!i[n]}}(e,i),Cc(e,i,"allowIn"),Cc(e,i,"allowContentOf"),Cc(e,i,"allowWhere"),Cc(e,i,"allowAttributes"),Cc(e,i,"allowAttributesOf"),Cc(e,i,"allowChildren"),Cc(e,i,"inheritTypesFrom"),function(e,t){for(const i of e){const e=i.inheritAllFrom;e&&(t.allowContentOf.push(e),t.allowWhere.push(e),t.allowAttributesOf.push(e),t.inheritTypesFrom.push(e))}}(e,i),i}function fc(e,t){const i=e[t];for(const n of i.allowChildren){const i=e[n];i&&i.allowIn.push(t)}i.allowChildren.length=0}function pc(e,t){for(const i of e[t].allowContentOf)if(e[i]){Ac(e,i).forEach((e=>{e.allowIn.push(t)}))}delete e[t].allowContentOf}function wc(e,t){for(const i of e[t].allowWhere){const n=e[i];if(n){const i=n.allowIn;e[t].allowIn.push(...i)}}delete e[t].allowWhere}function bc(e,t){for(const i of e[t].allowAttributesOf){const n=e[i];if(n){const i=n.allowAttributes;e[t].allowAttributes.push(...i)}}delete e[t].allowAttributesOf}function vc(e,t){const i=e[t];for(const t of i.inheritTypesFrom){const n=e[t];if(n){const e=Object.keys(n).filter((e=>e.startsWith("is")));for(const t of e)t in i||(i[t]=n[t])}}delete i.inheritTypesFrom}function _c(e,t){const i=e[t],n=i.allowIn.filter((t=>e[t]));i.allowIn=Array.from(new Set(n))}function yc(e,t){const i=e[t];for(const n of i.allowIn){e[n].allowChildren.push(t)}}function kc(e,t){const i=e[t];i.allowAttributes=Array.from(new Set(i.allowAttributes))}function Cc(e,t,i){for(const n of e){const e=n[i];"string"==typeof e?t[i].push(e):Array.isArray(e)&&t[i].push(...e)}}function Ac(e,t){const i=e[t];return(n=e,Object.keys(n).map((e=>n[e]))).filter((e=>e.allowIn.includes(i.name)));var n}function xc(e){return"string"==typeof e||e.is("documentFragment")?{name:"string"==typeof e?e:"$documentFragment",*getAttributeKeys(){},getAttribute(){}}:{name:e.is("element")?e.name:"$text",*getAttributeKeys(){yield*e.getAttributeKeys()},getAttribute:t=>e.getAttribute(t)}}function Tc(e,t,i){for(const n of t.getAttributeKeys())e.checkAttribute(t,n)||i.removeAttribute(n,t)}class Ec extends(S()){constructor(e){super(),this._splitParts=new Map,this._cursorParents=new Map,this._modelCursor=null,this._emptyElementsToKeep=new Set,this.conversionApi={...e,consumable:null,writer:null,store:null,convertItem:(e,t)=>this._convertItem(e,t),convertChildren:(e,t)=>this._convertChildren(e,t),safeInsert:(e,t)=>this._safeInsert(e,t),updateConversionResult:(e,t)=>this._updateConversionResult(e,t),splitToAllowedParent:(e,t)=>this._splitToAllowedParent(e,t),getSplitParts:e=>this._getSplitParts(e),keepEmptyElement:e=>this._keepEmptyElement(e)}}convert(e,t,i=["$root"]){this.fire("viewCleanup",e),this._modelCursor=function(e,t){let i;for(const n of new mc(e)){const e={};for(const t of n.getAttributeKeys())e[t]=n.getAttribute(t);const s=t.createElement(n.name,e);i&&t.insert(s,i),i=ul._createAt(s,0)}return i}(i,t),this.conversionApi.writer=t,this.conversionApi.consumable=cc.createFrom(e),this.conversionApi.store={};const{modelRange:n}=this._convertItem(e,this._modelCursor),s=t.createDocumentFragment();if(n){this._removeEmptyElements();for(const e of Array.from(this._modelCursor.parent.getChildren()))t.append(e,s);s.markers=function(e,t){const i=new Set,n=new Map,s=bl._createIn(e).getItems();for(const e of s)e.is("element","$marker")&&i.add(e);for(const e of i){const i=e.getAttribute("data-name"),s=t.createPositionBefore(e);n.has(i)?n.get(i).end=s.clone():n.set(i,new bl(s.clone())),t.remove(e)}return n}(s,t)}return this._modelCursor=null,this._splitParts.clear(),this._cursorParents.clear(),this._emptyElementsToKeep.clear(),this.conversionApi.writer=null,this.conversionApi.store=null,s}_convertItem(e,t){const i={viewItem:e,modelCursor:t,modelRange:null};if(e.is("element")?this.fire(`element:${e.name}`,i,this.conversionApi):e.is("$text")?this.fire("text",i,this.conversionApi):this.fire("documentFragment",i,this.conversionApi),i.modelRange&&!(i.modelRange instanceof bl))throw new b("view-conversion-dispatcher-incorrect-result",this);return{modelRange:i.modelRange,modelCursor:i.modelCursor}}_convertChildren(e,t){let i=t.is("position")?t:ul._createAt(t,0);const n=new bl(i);for(const t of Array.from(e.getChildren())){const e=this._convertItem(t,i);e.modelRange instanceof bl&&(n.end=e.modelRange.end,i=e.modelCursor)}return{modelRange:n,modelCursor:i}}_safeInsert(e,t){const i=this._splitToAllowedParent(e,t);return!!i&&(this.conversionApi.writer.insert(e,i.position),!0)}_updateConversionResult(e,t){const i=this._getSplitParts(e),n=this.conversionApi.writer;t.modelRange||(t.modelRange=n.createRange(n.createPositionBefore(e),n.createPositionAfter(i[i.length-1])));const s=this._cursorParents.get(e);t.modelCursor=s?n.createPositionAt(s,0):t.modelRange.end}_splitToAllowedParent(e,t){const{schema:i,writer:n}=this.conversionApi;let s=i.findAllowedParent(t,e);if(s){if(s===t.parent)return{position:t};this._modelCursor.parent.getAncestors().includes(s)&&(s=null)}if(!s)return Zl(t,e,i)?{position:ec(t,n)}:null;const o=this.conversionApi.writer.split(t,s),r=[];for(const e of o.range.getWalker())if("elementEnd"==e.type)r.push(e.item);else{const t=r.pop(),i=e.item;this._registerSplitPair(t,i)}const a=o.range.end.parent;return this._cursorParents.set(e,a),{position:o.position,cursorParent:a}}_registerSplitPair(e,t){this._splitParts.has(e)||this._splitParts.set(e,[e]);const i=this._splitParts.get(e);this._splitParts.set(t,i),i.push(t)}_getSplitParts(e){let t;return t=this._splitParts.has(e)?this._splitParts.get(e):[e],t}_keepEmptyElement(e){this._emptyElementsToKeep.add(e)}_removeEmptyElements(){let e=!1;for(const t of this._splitParts.keys())t.isEmpty&&!this._emptyElementsToKeep.has(t)&&(this.conversionApi.writer.remove(t),this._splitParts.delete(t),e=!0);e&&this._removeEmptyElements()}}class Sc{getHtml(e){const t=document.implementation.createHTMLDocument("").createElement("div");return t.appendChild(e),t.innerHTML}}class Pc{constructor(e){this.skipComments=!0,this.domParser=new DOMParser,this.domConverter=new sa(e,{renderingMode:"data"}),this.htmlWriter=new Sc}toData(e){const t=this.domConverter.viewToDom(e);return this.htmlWriter.getHtml(t)}toView(e){const t=this._toDom(e);return this.domConverter.domToView(t,{skipComments:this.skipComments})}registerRawContentMatcher(e){this.domConverter.registerRawContentMatcher(e)}useFillerType(e){this.domConverter.blockFillerMode="marked"==e?"markedNbsp":"nbsp"}_toDom(e){e.match(/<(?:html|body|head|meta)(?:\s[^>]*)?>/i)||(e=`${e}`);const t=this.domParser.parseFromString(e,"text/html"),i=t.createDocumentFragment(),n=t.body.childNodes;for(;n.length>0;)i.appendChild(n[0]);return i}}class Ic extends(S()){constructor(e,t){super(),this.model=e,this.mapper=new vl,this.downcastDispatcher=new kl({mapper:this.mapper,schema:e.schema}),this.downcastDispatcher.on("insert:$text",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.writer,s=i.mapper.toViewPosition(t.range.start),o=n.createText(t.item.data);n.insert(s,o)}),{priority:"lowest"}),this.downcastDispatcher.on("insert",((e,t,i)=>{i.convertAttributes(t.item),t.reconversion||!t.item.is("element")||t.item.isEmpty||i.convertChildren(t.item)}),{priority:"lowest"}),this.upcastDispatcher=new Ec({schema:e.schema}),this.viewDocument=new fr(t),this.stylesProcessor=t,this.htmlProcessor=new Pc(this.viewDocument),this.processor=this.htmlProcessor,this._viewWriter=new Er(this.viewDocument),this.upcastDispatcher.on("text",((e,t,{schema:i,consumable:n,writer:s})=>{let o=t.modelCursor;if(!n.test(t.viewItem))return;if(!i.checkChild(o,"$text")){if(!Zl(o,"$text",i))return;if(0==t.viewItem.data.trim().length)return;o=ec(o,s)}n.consume(t.viewItem);const r=s.createText(t.viewItem.data);s.insert(r,o),t.modelRange=s.createRange(o,o.getShiftedBy(r.offsetSize)),t.modelCursor=t.modelRange.end}),{priority:"lowest"}),this.upcastDispatcher.on("element",((e,t,i)=>{if(!t.modelRange&&i.consumable.consume(t.viewItem,{name:!0})){const{modelRange:e,modelCursor:n}=i.convertChildren(t.viewItem,t.modelCursor);t.modelRange=e,t.modelCursor=n}}),{priority:"lowest"}),this.upcastDispatcher.on("documentFragment",((e,t,i)=>{if(!t.modelRange&&i.consumable.consume(t.viewItem,{name:!0})){const{modelRange:e,modelCursor:n}=i.convertChildren(t.viewItem,t.modelCursor);t.modelRange=e,t.modelCursor=n}}),{priority:"lowest"}),W().prototype.decorate.call(this,"init"),W().prototype.decorate.call(this,"set"),W().prototype.decorate.call(this,"get"),this.on("init",(()=>{this.fire("ready")}),{priority:"lowest"}),this.on("ready",(()=>{this.model.enqueueChange({isUndoable:!1},Xl)}),{priority:"lowest"})}get(e={}){const{rootName:t="main",trim:i="empty"}=e;if(!this._checkIfRootsExists([t]))throw new b("datacontroller-get-non-existent-root",this);const n=this.model.document.getRoot(t);return"empty"!==i||this.model.hasContent(n,{ignoreWhitespaces:!0})?this.stringify(n,e):""}stringify(e,t={}){const i=this.toView(e,t);return this.processor.toData(i)}toView(e,t={}){const i=this.viewDocument,n=this._viewWriter;this.mapper.clearBindings();const s=bl._createIn(e),o=new Tr(i);this.mapper.bindElements(e,o);const r=e.is("documentFragment")?e.markers:function(e){const t=[],i=e.root.document;if(!i)return new Map;const n=bl._createIn(e);for(const e of i.model.markers){const i=e.getRange(),s=i.isCollapsed,o=i.start.isEqual(n.start)||i.end.isEqual(n.end);if(s&&o)t.push([e.name,i]);else{const s=n.getIntersection(i);s&&t.push([e.name,s])}}return t.sort((([e,t],[i,n])=>{if("after"!==t.end.compareWith(n.start))return 1;if("before"!==t.start.compareWith(n.end))return-1;switch(t.start.compareWith(n.start)){case"before":return 1;case"after":return-1;default:switch(t.end.compareWith(n.end)){case"before":return 1;case"after":return-1;default:return i.localeCompare(e)}}})),new Map(t)}(e);return this.downcastDispatcher.convert(s,r,n,t),o}init(e){if(this.model.document.version)throw new b("datacontroller-init-document-not-empty",this);let t={};if("string"==typeof e?t.main=e:t=e,!this._checkIfRootsExists(Object.keys(t)))throw new b("datacontroller-init-non-existent-root",this);return this.model.enqueueChange({isUndoable:!1},(e=>{for(const i of Object.keys(t)){const n=this.model.document.getRoot(i);e.insert(this.parse(t[i],n),n,0)}})),Promise.resolve()}set(e,t={}){let i={};if("string"==typeof e?i.main=e:i=e,!this._checkIfRootsExists(Object.keys(i)))throw new b("datacontroller-set-non-existent-root",this);this.model.enqueueChange(t.batchType||{},(e=>{e.setSelection(null),e.removeSelectionAttribute(this.model.document.selection.getAttributeKeys());for(const t of Object.keys(i)){const n=this.model.document.getRoot(t);e.remove(e.createRangeIn(n)),e.insert(this.parse(i[t],n),n,0)}}))}parse(e,t="$root"){const i=this.processor.toView(e);return this.toModel(i,t)}toModel(e,t="$root"){return this.model.change((i=>this.upcastDispatcher.convert(e,i,t)))}addStyleProcessorRules(e){e(this.stylesProcessor)}registerRawContentMatcher(e){this.processor&&this.processor!==this.htmlProcessor&&this.processor.registerRawContentMatcher(e),this.htmlProcessor.registerRawContentMatcher(e)}destroy(){this.stopListening()}_checkIfRootsExists(e){for(const t of e)if(!this.model.document.getRootNames().includes(t))return!1;return!0}}class Rc{constructor(e,t){this._helpers=new Map,this._downcast=ps(e),this._createConversionHelpers({name:"downcast",dispatchers:this._downcast,isDowncast:!0}),this._upcast=ps(t),this._createConversionHelpers({name:"upcast",dispatchers:this._upcast,isDowncast:!1})}addAlias(e,t){const i=this._downcast.includes(t);if(!this._upcast.includes(t)&&!i)throw new b("conversion-add-alias-dispatcher-not-registered",this);this._createConversionHelpers({name:e,dispatchers:[t],isDowncast:i})}for(e){if(!this._helpers.has(e))throw new b("conversion-for-unknown-group",this);return this._helpers.get(e)}elementToElement(e){this.for("downcast").elementToElement(e);for(const{model:t,view:i}of Vc(e))this.for("upcast").elementToElement({model:t,view:i,converterPriority:e.converterPriority})}attributeToElement(e){this.for("downcast").attributeToElement(e);for(const{model:t,view:i}of Vc(e))this.for("upcast").elementToAttribute({view:i,model:t,converterPriority:e.converterPriority})}attributeToAttribute(e){this.for("downcast").attributeToAttribute(e);for(const{model:t,view:i}of Vc(e))this.for("upcast").attributeToAttribute({view:i,model:t})}_createConversionHelpers({name:e,dispatchers:t,isDowncast:i}){if(this._helpers.has(e))throw new b("conversion-group-exists",this);const n=i?new Fl(t):new tc(t);this._helpers.set(e,n)}}function*Vc(e){if(e.model.values)for(const t of e.model.values){const i={key:e.model.key,value:t},n=e.view[t],s=e.upcastAlso?e.upcastAlso[t]:void 0;yield*Lc(i,n,s)}else yield*Lc(e.model,e.view,e.upcastAlso)}function*Lc(e,t,i){if(yield{model:e,view:t},i)for(const t of ps(i))yield{model:e,view:t}}class Oc{constructor(e){this.baseVersion=e,this.isDocumentOperation=null!==this.baseVersion,this.batch=null}_validate(){}toJSON(){const e=Object.assign({},this);return e.__className=this.constructor.className,delete e.batch,delete e.isDocumentOperation,e}static get className(){return"Operation"}static fromJSON(e,t){return new this(e.baseVersion)}}function Bc(e,t){const i=Dc(t),n=i.reduce(((e,t)=>e+t.offsetSize),0),s=e.parent;zc(e);const o=e.index;return s._insertChild(o,i),Fc(s,o+i.length),Fc(s,o),new bl(e,e.getShiftedBy(n))}function Mc(e){if(!e.isFlat)throw new b("operation-utils-remove-range-not-flat",this);const t=e.start.parent;zc(e.start),zc(e.end);const i=t._removeChildren(e.start.index,e.end.index-e.start.index);return Fc(t,e.start.index),i}function Nc(e,t){if(!e.isFlat)throw new b("operation-utils-move-range-not-flat",this);const i=Mc(e);return Bc(t=t._getTransformedByDeletion(e.start,e.end.offset-e.start.offset),i)}function Dc(e){const t=[];!function e(i){if("string"==typeof i)t.push(new al(i));else if(i instanceof ll)t.push(new al(i.data,i.getAttributes()));else if(i instanceof ol)t.push(i);else if(X(i))for(const t of i)e(t)}(e);for(let e=1;ee.maxOffset)throw new b("move-operation-nodes-do-not-exist",this);if(e===t&&i=i&&this.targetPosition.path[e]e._clone(!0)))),t=new Wc(this.position,e,this.baseVersion);return t.shouldReceiveAttributes=this.shouldReceiveAttributes,t}getReversed(){const e=this.position.root.document.graveyard,t=new ul(e,[0]);return new $c(this.position,this.nodes.maxOffset,t,this.baseVersion+1)}_validate(){const e=this.position.parent;if(!e||e.maxOffsete._clone(!0)))),Bc(this.position,e)}toJSON(){const e=super.toJSON();return e.position=this.position.toJSON(),e.nodes=this.nodes.toJSON(),e}static get className(){return"InsertOperation"}static fromJSON(e,t){const i=[];for(const t of e.nodes)t.name?i.push(cl.fromJSON(t)):i.push(al.fromJSON(t));const n=new Wc(ul.fromJSON(e.position,t),i,e.baseVersion);return n.shouldReceiveAttributes=e.shouldReceiveAttributes,n}}class jc extends Oc{constructor(e,t,i,n,s,o){super(o),this.name=e,this.oldRange=t?t.clone():null,this.newRange=i?i.clone():null,this.affectsData=s,this._markers=n}get type(){return"marker"}clone(){return new jc(this.name,this.oldRange,this.newRange,this._markers,this.affectsData,this.baseVersion)}getReversed(){return new jc(this.name,this.newRange,this.oldRange,this._markers,this.affectsData,this.baseVersion+1)}_execute(){this.newRange?this._markers._set(this.name,this.newRange,!0,this.affectsData):this._markers._remove(this.name)}toJSON(){const e=super.toJSON();return this.oldRange&&(e.oldRange=this.oldRange.toJSON()),this.newRange&&(e.newRange=this.newRange.toJSON()),delete e._markers,e}static get className(){return"MarkerOperation"}static fromJSON(e,t){return new jc(e.name,e.oldRange?bl.fromJSON(e.oldRange,t):null,e.newRange?bl.fromJSON(e.newRange,t):null,t.model.markers,e.affectsData,e.baseVersion)}}const qc=function(e,t){return Ua(e,t)};class Uc extends Oc{constructor(e,t,i,n,s){super(s),this.range=e.clone(),this.key=t,this.oldValue=void 0===i?null:i,this.newValue=void 0===n?null:n}get type(){return null===this.oldValue?"addAttribute":null===this.newValue?"removeAttribute":"changeAttribute"}clone(){return new Uc(this.range,this.key,this.oldValue,this.newValue,this.baseVersion)}getReversed(){return new Uc(this.range,this.key,this.newValue,this.oldValue,this.baseVersion+1)}toJSON(){const e=super.toJSON();return e.range=this.range.toJSON(),e}_validate(){if(!this.range.isFlat)throw new b("attribute-operation-range-not-flat",this);for(const e of this.range.getItems({shallow:!0})){if(null!==this.oldValue&&!qc(e.getAttribute(this.key),this.oldValue))throw new b("attribute-operation-wrong-old-value",this,{item:e,key:this.key,value:this.oldValue});if(null===this.oldValue&&null!==this.newValue&&e.hasAttribute(this.key))throw new b("attribute-operation-attribute-exists",this,{node:e,key:this.key})}}_execute(){qc(this.oldValue,this.newValue)||function(e,t,i){zc(e.start),zc(e.end);for(const n of e.getItems({shallow:!0})){const e=n.is("$textProxy")?n.textNode:n;null!==i?e._setAttribute(t,i):e._removeAttribute(t),Fc(e.parent,e.index)}Fc(e.end.parent,e.end.index)}(this.range,this.key,this.newValue)}static get className(){return"AttributeOperation"}static fromJSON(e,t){return new Uc(bl.fromJSON(e.range,t),e.key,e.oldValue,e.newValue,e.baseVersion)}}class Gc extends Oc{get type(){return"noop"}clone(){return new Gc(this.baseVersion)}getReversed(){return new Gc(this.baseVersion+1)}_execute(){}static get className(){return"NoOperation"}}class Kc extends Oc{constructor(e,t,i,n){super(n),this.position=e,this.position.stickiness="toNext",this.oldName=t,this.newName=i}get type(){return"rename"}clone(){return new Kc(this.position.clone(),this.oldName,this.newName,this.baseVersion)}getReversed(){return new Kc(this.position.clone(),this.newName,this.oldName,this.baseVersion+1)}_validate(){const e=this.position.nodeAfter;if(!(e instanceof cl))throw new b("rename-operation-wrong-position",this);if(e.name!==this.oldName)throw new b("rename-operation-wrong-name",this)}_execute(){this.position.nodeAfter.name=this.newName}toJSON(){const e=super.toJSON();return e.position=this.position.toJSON(),e}static get className(){return"RenameOperation"}static fromJSON(e,t){return new Kc(ul.fromJSON(e.position,t),e.oldName,e.newName,e.baseVersion)}}class Jc extends Oc{constructor(e,t,i,n,s){super(s),this.root=e,this.key=t,this.oldValue=i,this.newValue=n}get type(){return null===this.oldValue?"addRootAttribute":null===this.newValue?"removeRootAttribute":"changeRootAttribute"}clone(){return new Jc(this.root,this.key,this.oldValue,this.newValue,this.baseVersion)}getReversed(){return new Jc(this.root,this.key,this.newValue,this.oldValue,this.baseVersion+1)}_validate(){if(this.root!=this.root.root||this.root.is("documentFragment"))throw new b("rootattribute-operation-not-a-root",this,{root:this.root,key:this.key});if(null!==this.oldValue&&this.root.getAttribute(this.key)!==this.oldValue)throw new b("rootattribute-operation-wrong-old-value",this,{root:this.root,key:this.key});if(null===this.oldValue&&null!==this.newValue&&this.root.hasAttribute(this.key))throw new b("rootattribute-operation-attribute-exists",this,{root:this.root,key:this.key})}_execute(){null!==this.newValue?this.root._setAttribute(this.key,this.newValue):this.root._removeAttribute(this.key)}toJSON(){const e=super.toJSON();return e.root=this.root.toJSON(),e}static get className(){return"RootAttributeOperation"}static fromJSON(e,t){if(!t.getRoot(e.root))throw new b("rootattribute-operation-fromjson-no-root",this,{rootName:e.root});return new Jc(t.getRoot(e.root),e.key,e.oldValue,e.newValue,e.baseVersion)}}class Qc extends Oc{constructor(e,t,i,n,s){super(s),this.sourcePosition=e.clone(),this.sourcePosition.stickiness="toPrevious",this.howMany=t,this.targetPosition=i.clone(),this.targetPosition.stickiness="toNext",this.graveyardPosition=n.clone()}get type(){return"merge"}get deletionPosition(){return new ul(this.sourcePosition.root,this.sourcePosition.path.slice(0,-1))}get movedRange(){const e=this.sourcePosition.getShiftedBy(Number.POSITIVE_INFINITY);return new bl(this.sourcePosition,e)}clone(){return new Qc(this.sourcePosition,this.howMany,this.targetPosition,this.graveyardPosition,this.baseVersion)}getReversed(){const e=this.targetPosition._getTransformedByMergeOperation(this),t=this.sourcePosition.path.slice(0,-1),i=new ul(this.sourcePosition.root,t)._getTransformedByMergeOperation(this);return new Yc(e,this.howMany,i,this.graveyardPosition,this.baseVersion+1)}_validate(){const e=this.sourcePosition.parent,t=this.targetPosition.parent;if(!e.parent)throw new b("merge-operation-source-position-invalid",this);if(!t.parent)throw new b("merge-operation-target-position-invalid",this);if(this.howMany!=e.maxOffset)throw new b("merge-operation-how-many-invalid",this)}_execute(){const e=this.sourcePosition.parent;Nc(bl._createIn(e),this.targetPosition),Nc(bl._createOn(e),this.graveyardPosition)}toJSON(){const e=super.toJSON();return e.sourcePosition=e.sourcePosition.toJSON(),e.targetPosition=e.targetPosition.toJSON(),e.graveyardPosition=e.graveyardPosition.toJSON(),e}static get className(){return"MergeOperation"}static fromJSON(e,t){const i=ul.fromJSON(e.sourcePosition,t),n=ul.fromJSON(e.targetPosition,t),s=ul.fromJSON(e.graveyardPosition,t);return new this(i,e.howMany,n,s,e.baseVersion)}}class Yc extends Oc{constructor(e,t,i,n,s){super(s),this.splitPosition=e.clone(),this.splitPosition.stickiness="toNext",this.howMany=t,this.insertionPosition=i,this.graveyardPosition=n?n.clone():null,this.graveyardPosition&&(this.graveyardPosition.stickiness="toNext")}get type(){return"split"}get moveTargetPosition(){const e=this.insertionPosition.path.slice();return e.push(0),new ul(this.insertionPosition.root,e)}get movedRange(){const e=this.splitPosition.getShiftedBy(Number.POSITIVE_INFINITY);return new bl(this.splitPosition,e)}clone(){return new Yc(this.splitPosition,this.howMany,this.insertionPosition,this.graveyardPosition,this.baseVersion)}getReversed(){const e=this.splitPosition.root.document.graveyard,t=new ul(e,[0]);return new Qc(this.moveTargetPosition,this.howMany,this.splitPosition,t,this.baseVersion+1)}_validate(){const e=this.splitPosition.parent,t=this.splitPosition.offset;if(!e||e.maxOffset{if(e.key===t.key&&e.range.start.hasSameParentAs(t.range.start)){const n=e.range.getDifference(t.range).map((t=>new Uc(t,e.key,e.oldValue,e.newValue,0))),s=e.range.getIntersection(t.range);return s&&i.aIsStrong&&n.push(new Uc(s,t.key,t.newValue,e.newValue,0)),0==n.length?[new Gc(0)]:n}return[e]})),td(Uc,Wc,((e,t)=>{if(e.range.start.hasSameParentAs(t.position)&&e.range.containsPosition(t.position)){const i=e.range._getTransformedByInsertion(t.position,t.howMany,!t.shouldReceiveAttributes).map((t=>new Uc(t,e.key,e.oldValue,e.newValue,e.baseVersion)));if(t.shouldReceiveAttributes){const n=ld(t,e.key,e.oldValue);n&&i.unshift(n)}return i}return e.range=e.range._getTransformedByInsertion(t.position,t.howMany,!1)[0],[e]})),td(Uc,Qc,((e,t)=>{const i=[];e.range.start.hasSameParentAs(t.deletionPosition)&&(e.range.containsPosition(t.deletionPosition)||e.range.start.isEqual(t.deletionPosition))&&i.push(bl._createFromPositionAndShift(t.graveyardPosition,1));const n=e.range._getTransformedByMergeOperation(t);return n.isCollapsed||i.push(n),i.map((t=>new Uc(t,e.key,e.oldValue,e.newValue,e.baseVersion)))})),td(Uc,$c,((e,t)=>{const i=function(e,t){const i=bl._createFromPositionAndShift(t.sourcePosition,t.howMany);let n=null,s=[];i.containsRange(e,!0)?n=e:e.start.hasSameParentAs(i.start)?(s=e.getDifference(i),n=e.getIntersection(i)):s=[e];const o=[];for(let e of s){e=e._getTransformedByDeletion(t.sourcePosition,t.howMany);const i=t.getMovedRangeStart(),n=e.start.hasSameParentAs(i),s=e._getTransformedByInsertion(i,t.howMany,n);o.push(...s)}n&&o.push(n._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany,!1)[0]);return o}(e.range,t);return i.map((t=>new Uc(t,e.key,e.oldValue,e.newValue,e.baseVersion)))})),td(Uc,Yc,((e,t)=>{if(e.range.end.isEqual(t.insertionPosition))return t.graveyardPosition||e.range.end.offset++,[e];if(e.range.start.hasSameParentAs(t.splitPosition)&&e.range.containsPosition(t.splitPosition)){const i=e.clone();return i.range=new bl(t.moveTargetPosition.clone(),e.range.end._getCombined(t.splitPosition,t.moveTargetPosition)),e.range.end=t.splitPosition.clone(),e.range.end.stickiness="toPrevious",[e,i]}return e.range=e.range._getTransformedBySplitOperation(t),[e]})),td(Wc,Uc,((e,t)=>{const i=[e];if(e.shouldReceiveAttributes&&e.position.hasSameParentAs(t.range.start)&&t.range.containsPosition(e.position)){const n=ld(e,t.key,t.newValue);n&&i.push(n)}return i})),td(Wc,Wc,((e,t,i)=>(e.position.isEqual(t.position)&&i.aIsStrong||(e.position=e.position._getTransformedByInsertOperation(t)),[e]))),td(Wc,$c,((e,t)=>(e.position=e.position._getTransformedByMoveOperation(t),[e]))),td(Wc,Yc,((e,t)=>(e.position=e.position._getTransformedBySplitOperation(t),[e]))),td(Wc,Qc,((e,t)=>(e.position=e.position._getTransformedByMergeOperation(t),[e]))),td(jc,Wc,((e,t)=>(e.oldRange&&(e.oldRange=e.oldRange._getTransformedByInsertOperation(t)[0]),e.newRange&&(e.newRange=e.newRange._getTransformedByInsertOperation(t)[0]),[e]))),td(jc,jc,((e,t,i)=>{if(e.name==t.name){if(!i.aIsStrong)return[new Gc(0)];e.oldRange=t.newRange?t.newRange.clone():null}return[e]})),td(jc,Qc,((e,t)=>(e.oldRange&&(e.oldRange=e.oldRange._getTransformedByMergeOperation(t)),e.newRange&&(e.newRange=e.newRange._getTransformedByMergeOperation(t)),[e]))),td(jc,$c,((e,t,i)=>{if(e.oldRange&&(e.oldRange=bl._createFromRanges(e.oldRange._getTransformedByMoveOperation(t))),e.newRange){if(i.abRelation){const n=bl._createFromRanges(e.newRange._getTransformedByMoveOperation(t));if("left"==i.abRelation.side&&t.targetPosition.isEqual(e.newRange.start))return e.newRange.end=n.end,e.newRange.start.path=i.abRelation.path,[e];if("right"==i.abRelation.side&&t.targetPosition.isEqual(e.newRange.end))return e.newRange.start=n.start,e.newRange.end.path=i.abRelation.path,[e]}e.newRange=bl._createFromRanges(e.newRange._getTransformedByMoveOperation(t))}return[e]})),td(jc,Yc,((e,t,i)=>{if(e.oldRange&&(e.oldRange=e.oldRange._getTransformedBySplitOperation(t)),e.newRange){if(i.abRelation){const n=e.newRange._getTransformedBySplitOperation(t);return e.newRange.start.isEqual(t.splitPosition)&&i.abRelation.wasStartBeforeMergedElement?e.newRange.start=ul._createAt(t.insertionPosition):e.newRange.start.isEqual(t.splitPosition)&&!i.abRelation.wasInLeftElement&&(e.newRange.start=ul._createAt(t.moveTargetPosition)),e.newRange.end.isEqual(t.splitPosition)&&i.abRelation.wasInRightElement?e.newRange.end=ul._createAt(t.moveTargetPosition):e.newRange.end.isEqual(t.splitPosition)&&i.abRelation.wasEndBeforeMergedElement?e.newRange.end=ul._createAt(t.insertionPosition):e.newRange.end=n.end,[e]}e.newRange=e.newRange._getTransformedBySplitOperation(t)}return[e]})),td(Qc,Wc,((e,t)=>(e.sourcePosition.hasSameParentAs(t.position)&&(e.howMany+=t.howMany),e.sourcePosition=e.sourcePosition._getTransformedByInsertOperation(t),e.targetPosition=e.targetPosition._getTransformedByInsertOperation(t),[e]))),td(Qc,Qc,((e,t,i)=>{if(e.sourcePosition.isEqual(t.sourcePosition)&&e.targetPosition.isEqual(t.targetPosition)){if(i.bWasUndone){const i=t.graveyardPosition.path.slice();return i.push(0),e.sourcePosition=new ul(t.graveyardPosition.root,i),e.howMany=0,[e]}return[new Gc(0)]}if(e.sourcePosition.isEqual(t.sourcePosition)&&!e.targetPosition.isEqual(t.targetPosition)&&!i.bWasUndone&&"splitAtSource"!=i.abRelation){const n="$graveyard"==e.targetPosition.root.rootName,s="$graveyard"==t.targetPosition.root.rootName;if(s&&!n||!(n&&!s)&&i.aIsStrong){const i=t.targetPosition._getTransformedByMergeOperation(t),n=e.targetPosition._getTransformedByMergeOperation(t);return[new $c(i,e.howMany,n,0)]}return[new Gc(0)]}return e.sourcePosition.hasSameParentAs(t.targetPosition)&&(e.howMany+=t.howMany),e.sourcePosition=e.sourcePosition._getTransformedByMergeOperation(t),e.targetPosition=e.targetPosition._getTransformedByMergeOperation(t),e.graveyardPosition.isEqual(t.graveyardPosition)&&i.aIsStrong||(e.graveyardPosition=e.graveyardPosition._getTransformedByMergeOperation(t)),[e]})),td(Qc,$c,((e,t,i)=>{const n=bl._createFromPositionAndShift(t.sourcePosition,t.howMany);return"remove"==t.type&&!i.bWasUndone&&!i.forceWeakRemove&&e.deletionPosition.hasSameParentAs(t.sourcePosition)&&n.containsPosition(e.sourcePosition)?[new Gc(0)]:(e.sourcePosition.hasSameParentAs(t.targetPosition)&&(e.howMany+=t.howMany),e.sourcePosition.hasSameParentAs(t.sourcePosition)&&(e.howMany-=t.howMany),e.sourcePosition=e.sourcePosition._getTransformedByMoveOperation(t),e.targetPosition=e.targetPosition._getTransformedByMoveOperation(t),e.graveyardPosition.isEqual(t.targetPosition)||(e.graveyardPosition=e.graveyardPosition._getTransformedByMoveOperation(t)),[e])})),td(Qc,Yc,((e,t,i)=>{if(t.graveyardPosition&&(e.graveyardPosition=e.graveyardPosition._getTransformedByDeletion(t.graveyardPosition,1),e.deletionPosition.isEqual(t.graveyardPosition)&&(e.howMany=t.howMany)),e.targetPosition.isEqual(t.splitPosition)){const n=0!=t.howMany,s=t.graveyardPosition&&e.deletionPosition.isEqual(t.graveyardPosition);if(n||s||"mergeTargetNotMoved"==i.abRelation)return e.sourcePosition=e.sourcePosition._getTransformedBySplitOperation(t),[e]}if(e.sourcePosition.isEqual(t.splitPosition)){if("mergeSourceNotMoved"==i.abRelation)return e.howMany=0,e.targetPosition=e.targetPosition._getTransformedBySplitOperation(t),[e];if("mergeSameElement"==i.abRelation||e.sourcePosition.offset>0)return e.sourcePosition=t.moveTargetPosition.clone(),e.targetPosition=e.targetPosition._getTransformedBySplitOperation(t),[e]}return e.sourcePosition.hasSameParentAs(t.splitPosition)&&(e.howMany=t.splitPosition.offset),e.sourcePosition=e.sourcePosition._getTransformedBySplitOperation(t),e.targetPosition=e.targetPosition._getTransformedBySplitOperation(t),[e]})),td($c,Wc,((e,t)=>{const i=bl._createFromPositionAndShift(e.sourcePosition,e.howMany)._getTransformedByInsertOperation(t,!1)[0];return e.sourcePosition=i.start,e.howMany=i.end.offset-i.start.offset,e.targetPosition.isEqual(t.position)||(e.targetPosition=e.targetPosition._getTransformedByInsertOperation(t)),[e]})),td($c,$c,((e,t,i)=>{const n=bl._createFromPositionAndShift(e.sourcePosition,e.howMany),s=bl._createFromPositionAndShift(t.sourcePosition,t.howMany);let o,r=i.aIsStrong,a=!i.aIsStrong;if("insertBefore"==i.abRelation||"insertAfter"==i.baRelation?a=!0:"insertAfter"!=i.abRelation&&"insertBefore"!=i.baRelation||(a=!1),o=e.targetPosition.isEqual(t.targetPosition)&&a?e.targetPosition._getTransformedByDeletion(t.sourcePosition,t.howMany):e.targetPosition._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany),cd(e,t)&&cd(t,e))return[t.getReversed()];if(n.containsPosition(t.targetPosition)&&n.containsRange(s,!0))return n.start=n.start._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany),n.end=n.end._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany),dd([n],o);if(s.containsPosition(e.targetPosition)&&s.containsRange(n,!0))return n.start=n.start._getCombined(t.sourcePosition,t.getMovedRangeStart()),n.end=n.end._getCombined(t.sourcePosition,t.getMovedRangeStart()),dd([n],o);const l=Y(e.sourcePosition.getParentPath(),t.sourcePosition.getParentPath());if("prefix"==l||"extension"==l)return n.start=n.start._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany),n.end=n.end._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany),dd([n],o);"remove"!=e.type||"remove"==t.type||i.aWasUndone||i.forceWeakRemove?"remove"==e.type||"remove"!=t.type||i.bWasUndone||i.forceWeakRemove||(r=!1):r=!0;const c=[],d=n.getDifference(s);for(const e of d){e.start=e.start._getTransformedByDeletion(t.sourcePosition,t.howMany),e.end=e.end._getTransformedByDeletion(t.sourcePosition,t.howMany);const i="same"==Y(e.start.getParentPath(),t.getMovedRangeStart().getParentPath()),n=e._getTransformedByInsertion(t.getMovedRangeStart(),t.howMany,i);c.push(...n)}const h=n.getIntersection(s);return null!==h&&r&&(h.start=h.start._getCombined(t.sourcePosition,t.getMovedRangeStart()),h.end=h.end._getCombined(t.sourcePosition,t.getMovedRangeStart()),0===c.length?c.push(h):1==c.length?s.start.isBefore(n.start)||s.start.isEqual(n.start)?c.unshift(h):c.push(h):c.splice(1,0,h)),0===c.length?[new Gc(e.baseVersion)]:dd(c,o)})),td($c,Yc,((e,t,i)=>{let n=e.targetPosition.clone();e.targetPosition.isEqual(t.insertionPosition)&&t.graveyardPosition&&"moveTargetAfter"!=i.abRelation||(n=e.targetPosition._getTransformedBySplitOperation(t));const s=bl._createFromPositionAndShift(e.sourcePosition,e.howMany);if(s.end.isEqual(t.insertionPosition))return t.graveyardPosition||e.howMany++,e.targetPosition=n,[e];if(s.start.hasSameParentAs(t.splitPosition)&&s.containsPosition(t.splitPosition)){let e=new bl(t.splitPosition,s.end);e=e._getTransformedBySplitOperation(t);return dd([new bl(s.start,t.splitPosition),e],n)}e.targetPosition.isEqual(t.splitPosition)&&"insertAtSource"==i.abRelation&&(n=t.moveTargetPosition),e.targetPosition.isEqual(t.insertionPosition)&&"insertBetween"==i.abRelation&&(n=e.targetPosition);const o=[s._getTransformedBySplitOperation(t)];if(t.graveyardPosition){const n=s.start.isEqual(t.graveyardPosition)||s.containsPosition(t.graveyardPosition);e.howMany>1&&n&&!i.aWasUndone&&o.push(bl._createFromPositionAndShift(t.insertionPosition,1))}return dd(o,n)})),td($c,Qc,((e,t,i)=>{const n=bl._createFromPositionAndShift(e.sourcePosition,e.howMany);if(t.deletionPosition.hasSameParentAs(e.sourcePosition)&&n.containsPosition(t.sourcePosition))if("remove"!=e.type||i.forceWeakRemove){if(1==e.howMany)return i.bWasUndone?(e.sourcePosition=t.graveyardPosition.clone(),e.targetPosition=e.targetPosition._getTransformedByMergeOperation(t),[e]):[new Gc(0)]}else if(!i.aWasUndone){const i=[];let n=t.graveyardPosition.clone(),s=t.targetPosition._getTransformedByMergeOperation(t);e.howMany>1&&(i.push(new $c(e.sourcePosition,e.howMany-1,e.targetPosition,0)),n=n._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany-1),s=s._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany-1));const o=t.deletionPosition._getCombined(e.sourcePosition,e.targetPosition),r=new $c(n,1,o,0),a=r.getMovedRangeStart().path.slice();a.push(0);const l=new ul(r.targetPosition.root,a);s=s._getTransformedByMove(n,o,1);const c=new $c(s,t.howMany,l,0);return i.push(r),i.push(c),i}const s=bl._createFromPositionAndShift(e.sourcePosition,e.howMany)._getTransformedByMergeOperation(t);return e.sourcePosition=s.start,e.howMany=s.end.offset-s.start.offset,e.targetPosition=e.targetPosition._getTransformedByMergeOperation(t),[e]})),td(Kc,Wc,((e,t)=>(e.position=e.position._getTransformedByInsertOperation(t),[e]))),td(Kc,Qc,((e,t)=>e.position.isEqual(t.deletionPosition)?(e.position=t.graveyardPosition.clone(),e.position.stickiness="toNext",[e]):(e.position=e.position._getTransformedByMergeOperation(t),[e]))),td(Kc,$c,((e,t)=>(e.position=e.position._getTransformedByMoveOperation(t),[e]))),td(Kc,Kc,((e,t,i)=>{if(e.position.isEqual(t.position)){if(!i.aIsStrong)return[new Gc(0)];e.oldName=t.newName}return[e]})),td(Kc,Yc,((e,t)=>{if("same"==Y(e.position.path,t.splitPosition.getParentPath())&&!t.graveyardPosition){const t=new Kc(e.position.getShiftedBy(1),e.oldName,e.newName,0);return[e,t]}return e.position=e.position._getTransformedBySplitOperation(t),[e]})),td(Jc,Jc,((e,t,i)=>{if(e.root===t.root&&e.key===t.key){if(!i.aIsStrong||e.newValue===t.newValue)return[new Gc(0)];e.oldValue=t.newValue}return[e]})),td(Yc,Wc,((e,t)=>(e.splitPosition.hasSameParentAs(t.position)&&e.splitPosition.offset{if(!e.graveyardPosition&&!i.bWasUndone&&e.splitPosition.hasSameParentAs(t.sourcePosition)){const i=t.graveyardPosition.path.slice();i.push(0);const n=new ul(t.graveyardPosition.root,i),s=Yc.getInsertionPosition(new ul(t.graveyardPosition.root,i)),o=new Yc(n,0,s,null,0);return e.splitPosition=e.splitPosition._getTransformedByMergeOperation(t),e.insertionPosition=Yc.getInsertionPosition(e.splitPosition),e.graveyardPosition=o.insertionPosition.clone(),e.graveyardPosition.stickiness="toNext",[o,e]}return e.splitPosition.hasSameParentAs(t.deletionPosition)&&!e.splitPosition.isAfter(t.deletionPosition)&&e.howMany--,e.splitPosition.hasSameParentAs(t.targetPosition)&&(e.howMany+=t.howMany),e.splitPosition=e.splitPosition._getTransformedByMergeOperation(t),e.insertionPosition=Yc.getInsertionPosition(e.splitPosition),e.graveyardPosition&&(e.graveyardPosition=e.graveyardPosition._getTransformedByMergeOperation(t)),[e]})),td(Yc,$c,((e,t,i)=>{const n=bl._createFromPositionAndShift(t.sourcePosition,t.howMany);if(e.graveyardPosition){const s=n.start.isEqual(e.graveyardPosition)||n.containsPosition(e.graveyardPosition);if(!i.bWasUndone&&s){const i=e.splitPosition._getTransformedByMoveOperation(t),n=e.graveyardPosition._getTransformedByMoveOperation(t),s=n.path.slice();s.push(0);const o=new ul(n.root,s);return[new $c(i,e.howMany,o,0)]}e.graveyardPosition=e.graveyardPosition._getTransformedByMoveOperation(t)}const s=e.splitPosition.isEqual(t.targetPosition);if(s&&("insertAtSource"==i.baRelation||"splitBefore"==i.abRelation))return e.howMany+=t.howMany,e.splitPosition=e.splitPosition._getTransformedByDeletion(t.sourcePosition,t.howMany),e.insertionPosition=Yc.getInsertionPosition(e.splitPosition),[e];if(s&&i.abRelation&&i.abRelation.howMany){const{howMany:t,offset:n}=i.abRelation;return e.howMany+=t,e.splitPosition=e.splitPosition.getShiftedBy(n),[e]}if(e.splitPosition.hasSameParentAs(t.sourcePosition)&&n.containsPosition(e.splitPosition)){const i=t.howMany-(e.splitPosition.offset-t.sourcePosition.offset);return e.howMany-=i,e.splitPosition.hasSameParentAs(t.targetPosition)&&e.splitPosition.offset{if(e.splitPosition.isEqual(t.splitPosition)){if(!e.graveyardPosition&&!t.graveyardPosition)return[new Gc(0)];if(e.graveyardPosition&&t.graveyardPosition&&e.graveyardPosition.isEqual(t.graveyardPosition))return[new Gc(0)];if("splitBefore"==i.abRelation)return e.howMany=0,e.graveyardPosition=e.graveyardPosition._getTransformedBySplitOperation(t),[e]}if(e.graveyardPosition&&t.graveyardPosition&&e.graveyardPosition.isEqual(t.graveyardPosition)){const n="$graveyard"==e.splitPosition.root.rootName,s="$graveyard"==t.splitPosition.root.rootName;if(s&&!n||!(n&&!s)&&i.aIsStrong){const i=[];return t.howMany&&i.push(new $c(t.moveTargetPosition,t.howMany,t.splitPosition,0)),e.howMany&&i.push(new $c(e.splitPosition,e.howMany,e.moveTargetPosition,0)),i}return[new Gc(0)]}if(e.graveyardPosition&&(e.graveyardPosition=e.graveyardPosition._getTransformedBySplitOperation(t)),e.splitPosition.isEqual(t.insertionPosition)&&"splitBefore"==i.abRelation)return e.howMany++,[e];if(t.splitPosition.isEqual(e.insertionPosition)&&"splitBefore"==i.baRelation){const i=t.insertionPosition.path.slice();i.push(0);const n=new ul(t.insertionPosition.root,i);return[e,new $c(e.insertionPosition,1,n,0)]}return e.splitPosition.hasSameParentAs(t.splitPosition)&&e.splitPosition.offset{const i=t[0];i.isDocumentOperation&&md.call(this,i)}),{priority:"low"})}function md(e){const t=this.getTransformedByOperation(e);if(!this.isEqual(t)){const e=this.toPosition();this.path=t.path,this.root=t.root,this.fire("change",e)}}hd.prototype.is=function(e){return"livePosition"===e||"model:livePosition"===e||"position"==e||"model:position"===e};class gd{constructor(e={}){"string"==typeof e&&(e="transparent"===e?{isUndoable:!1}:{},v("batch-constructor-deprecated-string-type"));const{isUndoable:t=!0,isLocal:i=!0,isUndo:n=!1,isTyping:s=!1}=e;this.operations=[],this.isUndoable=t,this.isLocal=i,this.isUndo=n,this.isTyping=s}get type(){return v("batch-type-deprecated"),"default"}get baseVersion(){for(const e of this.operations)if(null!==e.baseVersion)return e.baseVersion;return null}addOperation(e){return e.batch=this,this.operations.push(e),e}}class fd{constructor(e){this._markerCollection=e,this._changesInElement=new Map,this._elementSnapshots=new Map,this._changedMarkers=new Map,this._changeCount=0,this._cachedChanges=null,this._cachedChangesWithGraveyard=null,this._refreshedItems=new Set}get isEmpty(){return 0==this._changesInElement.size&&0==this._changedMarkers.size}bufferOperation(e){const t=e;switch(t.type){case"insert":if(this._isInInsertedElement(t.position.parent))return;this._markInsert(t.position.parent,t.position.offset,t.nodes.maxOffset);break;case"addAttribute":case"removeAttribute":case"changeAttribute":for(const e of t.range.getItems({shallow:!0}))this._isInInsertedElement(e.parent)||this._markAttribute(e);break;case"remove":case"move":case"reinsert":{if(t.sourcePosition.isEqual(t.targetPosition)||t.sourcePosition.getShiftedBy(t.howMany).isEqual(t.targetPosition))return;const e=this._isInInsertedElement(t.sourcePosition.parent),i=this._isInInsertedElement(t.targetPosition.parent);e||this._markRemove(t.sourcePosition.parent,t.sourcePosition.offset,t.howMany),i||this._markInsert(t.targetPosition.parent,t.getMovedRangeStart().offset,t.howMany);break}case"rename":{if(this._isInInsertedElement(t.position.parent))return;this._markRemove(t.position.parent,t.position.offset,1),this._markInsert(t.position.parent,t.position.offset,1);const e=bl._createFromPositionAndShift(t.position,1);for(const t of this._markerCollection.getMarkersIntersectingRange(e)){const e=t.getData();this.bufferMarkerChange(t.name,e,e)}break}case"split":{const e=t.splitPosition.parent;this._isInInsertedElement(e)||this._markRemove(e,t.splitPosition.offset,t.howMany),this._isInInsertedElement(t.insertionPosition.parent)||this._markInsert(t.insertionPosition.parent,t.insertionPosition.offset,1),t.graveyardPosition&&this._markRemove(t.graveyardPosition.parent,t.graveyardPosition.offset,1);break}case"merge":{const e=t.sourcePosition.parent;this._isInInsertedElement(e.parent)||this._markRemove(e.parent,e.startOffset,1);const i=t.graveyardPosition.parent;this._markInsert(i,t.graveyardPosition.offset,1);const n=t.targetPosition.parent;this._isInInsertedElement(n)||this._markInsert(n,t.targetPosition.offset,e.maxOffset);break}}this._cachedChanges=null}bufferMarkerChange(e,t,i){const n=this._changedMarkers.get(e);n?(n.newMarkerData=i,null==n.oldMarkerData.range&&null==i.range&&this._changedMarkers.delete(e)):this._changedMarkers.set(e,{newMarkerData:i,oldMarkerData:t})}getMarkersToRemove(){const e=[];for(const[t,i]of this._changedMarkers)null!=i.oldMarkerData.range&&e.push({name:t,range:i.oldMarkerData.range});return e}getMarkersToAdd(){const e=[];for(const[t,i]of this._changedMarkers)null!=i.newMarkerData.range&&e.push({name:t,range:i.newMarkerData.range});return e}getChangedMarkers(){return Array.from(this._changedMarkers).map((([e,t])=>({name:e,data:{oldRange:t.oldMarkerData.range,newRange:t.newMarkerData.range}})))}hasDataChanges(){if(this._changesInElement.size>0)return!0;for(const{newMarkerData:e,oldMarkerData:t}of this._changedMarkers.values()){if(e.affectsData!==t.affectsData)return!0;if(e.affectsData){const i=e.range&&!t.range,n=!e.range&&t.range,s=e.range&&t.range&&!e.range.isEqual(t.range);if(i||n||s)return!0}}return!1}getChanges(e={}){if(this._cachedChanges)return e.includeChangesInGraveyard?this._cachedChangesWithGraveyard.slice():this._cachedChanges.slice();let t=[];for(const e of this._changesInElement.keys()){const i=this._changesInElement.get(e).sort(((e,t)=>e.offset===t.offset?e.type!=t.type?"remove"==e.type?-1:1:0:e.offsete.position.root!=t.position.root?e.position.root.rootNamee));for(const e of t)delete e.changeCount,"attribute"==e.type&&(delete e.position,delete e.length);return this._changeCount=0,this._cachedChangesWithGraveyard=t,this._cachedChanges=t.filter(bd),e.includeChangesInGraveyard?this._cachedChangesWithGraveyard.slice():this._cachedChanges.slice()}getRefreshedItems(){return new Set(this._refreshedItems)}reset(){this._changesInElement.clear(),this._elementSnapshots.clear(),this._changedMarkers.clear(),this._refreshedItems=new Set,this._cachedChanges=null}_refreshItem(e){if(this._isInInsertedElement(e.parent))return;this._markRemove(e.parent,e.startOffset,e.offsetSize),this._markInsert(e.parent,e.startOffset,e.offsetSize),this._refreshedItems.add(e);const t=bl._createOn(e);for(const e of this._markerCollection.getMarkersIntersectingRange(t)){const t=e.getData();this.bufferMarkerChange(e.name,t,t)}this._cachedChanges=null}_markInsert(e,t,i){const n={type:"insert",offset:t,howMany:i,count:this._changeCount++};this._markChange(e,n)}_markRemove(e,t,i){const n={type:"remove",offset:t,howMany:i,count:this._changeCount++};this._markChange(e,n),this._removeAllNestedChanges(e,t,i)}_markAttribute(e){const t={type:"attribute",offset:e.startOffset,howMany:e.offsetSize,count:this._changeCount++};this._markChange(e.parent,t)}_markChange(e,t){this._makeSnapshot(e);const i=this._getChangesForElement(e);this._handleChange(t,i),i.push(t);for(let e=0;ei.offset){if(n>s){const e={type:"attribute",offset:s,howMany:n-s,count:this._changeCount++};this._handleChange(e,t),t.push(e)}e.nodesToHandle=i.offset-e.offset,e.howMany=e.nodesToHandle}else e.offset>=i.offset&&e.offsets?(e.nodesToHandle=n-s,e.offset=s):e.nodesToHandle=0);if("remove"==i.type&&e.offseti.offset){const s={type:"attribute",offset:i.offset,howMany:n-i.offset,count:this._changeCount++};this._handleChange(s,t),t.push(s),e.nodesToHandle=i.offset-e.offset,e.howMany=e.nodesToHandle}"attribute"==i.type&&(e.offset>=i.offset&&n<=s?(e.nodesToHandle=0,e.howMany=0,e.offset=0):e.offset<=i.offset&&n>=s&&(i.howMany=0))}}e.howMany=e.nodesToHandle,delete e.nodesToHandle}_getInsertDiff(e,t,i){return{type:"insert",position:ul._createAt(e,t),name:i.name,attributes:new Map(i.attributes),length:1,changeCount:this._changeCount++}}_getRemoveDiff(e,t,i){return{type:"remove",position:ul._createAt(e,t),name:i.name,attributes:new Map(i.attributes),length:1,changeCount:this._changeCount++}}_getAttributesDiff(e,t,i){const n=[];i=new Map(i);for(const[s,o]of t){const t=i.has(s)?i.get(s):null;t!==o&&n.push({type:"attribute",position:e.start,range:e.clone(),length:1,attributeKey:s,attributeOldValue:o,attributeNewValue:t,changeCount:this._changeCount++}),i.delete(s)}for(const[t,s]of i)n.push({type:"attribute",position:e.start,range:e.clone(),length:1,attributeKey:t,attributeOldValue:null,attributeNewValue:s,changeCount:this._changeCount++});return n}_isInInsertedElement(e){const t=e.parent;if(!t)return!1;const i=this._changesInElement.get(t),n=e.startOffset;if(i)for(const e of i)if("insert"==e.type&&n>=e.offset&&nn){for(let t=0;tthis._version+1&&this._gaps.set(this._version,e),this._version=e}get lastOperation(){return this._operations[this._operations.length-1]}addOperation(e){if(e.baseVersion!==this.version)throw new b("model-document-history-addoperation-incorrect-version",this,{operation:e,historyVersion:this.version});this._operations.push(e),this._version++,this._baseVersionToOperationIndex.set(e.baseVersion,this._operations.length-1)}getOperations(e,t=this.version){if(!this._operations.length)return[];const i=this._operations[0];void 0===e&&(e=i.baseVersion);let n=t-1;for(const[t,i]of this._gaps)e>t&&et&&nthis.lastOperation.baseVersion)return[];let s=this._baseVersionToOperationIndex.get(e);void 0===s&&(s=0);let o=this._baseVersionToOperationIndex.get(n);return void 0===o&&(o=this._operations.length-1),this._operations.slice(s,o+1)}getOperation(e){const t=this._baseVersionToOperationIndex.get(e);if(void 0!==t)return this._operations[t]}setOperationAsUndone(e,t){this._undoPairs.set(t,e),this._undoneOperations.add(e)}isUndoingOperation(e){return this._undoPairs.has(e)}isUndoneOperation(e){return this._undoneOperations.has(e)}getUndoneOperation(e){return this._undoPairs.get(e)}reset(){this._version=0,this._undoPairs=new Map,this._operations=[],this._undoneOperations=new Set,this._gaps=new Map,this._baseVersionToOperationIndex=new Map}}class _d extends cl{constructor(e,t,i="main"){super(t),this._document=e,this.rootName=i}get document(){return this._document}toJSON(){return this.rootName}}_d.prototype.is=function(e,t){return t?t===this.name&&("rootElement"===e||"model:rootElement"===e||"element"===e||"model:element"===e):"rootElement"===e||"model:rootElement"===e||"element"===e||"model:element"===e||"node"===e||"model:node"===e};const yd="$graveyard";class kd extends(S()){constructor(e){super(),this.model=e,this.history=new vd,this.selection=new Ol(this),this.roots=new ys({idProperty:"rootName"}),this.differ=new fd(e.markers),this._postFixers=new Set,this._hasSelectionChangedFromTheLastChangeBlock=!1,this.createRoot("$root",yd),this.listenTo(e,"applyOperation",((e,t)=>{const i=t[0];i.isDocumentOperation&&this.differ.bufferOperation(i)}),{priority:"high"}),this.listenTo(e,"applyOperation",((e,t)=>{const i=t[0];i.isDocumentOperation&&this.history.addOperation(i)}),{priority:"low"}),this.listenTo(this.selection,"change",(()=>{this._hasSelectionChangedFromTheLastChangeBlock=!0})),this.listenTo(e.markers,"update",((e,t,i,n,s)=>{const o={...t.getData(),range:n};this.differ.bufferMarkerChange(t.name,s,o),null===i&&t.on("change",((e,i)=>{const n=t.getData();this.differ.bufferMarkerChange(t.name,{...n,range:i},n)}))}))}get version(){return this.history.version}set version(e){this.history.version=e}get graveyard(){return this.getRoot(yd)}createRoot(e="$root",t="main"){if(this.roots.get(t))throw new b("model-document-createroot-name-exists",this,{name:t});const i=new _d(this,e,t);return this.roots.add(i),i}destroy(){this.selection.destroy(),this.stopListening()}getRoot(e="main"){return this.roots.get(e)}getRootNames(){return Array.from(this.roots,(e=>e.rootName)).filter((e=>e!=yd))}registerPostFixer(e){this._postFixers.add(e)}toJSON(){const e=qs(this);return e.selection="[engine.model.DocumentSelection]",e.model="[engine.model.Model]",e}_handleChangeBlock(e){this._hasDocumentChangedFromTheLastChangeBlock()&&(this._callPostFixers(e),this.selection.refresh(),this.differ.hasDataChanges()?this.fire("change:data",e.batch):this.fire("change",e.batch),this.selection.refresh(),this.differ.reset()),this._hasSelectionChangedFromTheLastChangeBlock=!1}_hasDocumentChangedFromTheLastChangeBlock(){return!this.differ.isEmpty||this._hasSelectionChangedFromTheLastChangeBlock}_getDefaultRoot(){for(const e of this.roots)if(e!==this.graveyard)return e;return this.graveyard}_getDefaultRange(){const e=this._getDefaultRoot(),t=this.model,i=t.schema,n=t.createPositionFromPath(e,[0]);return i.getNearestSelectionRange(n)||t.createRange(n)}_validateSelectionRange(e){return Cd(e.start)&&Cd(e.end)}_callPostFixers(e){let t=!1;do{for(const i of this._postFixers)if(this.selection.refresh(),t=i(e),t)break}while(t)}}function Cd(e){const t=e.textNode;if(t){const i=t.data,n=e.offset-t.startOffset;return!Ts(i,n)&&!Es(i,n)}return!0}class Ad extends(S()){constructor(){super(),this._markers=new Map}[Symbol.iterator](){return this._markers.values()}has(e){const t=e instanceof xd?e.name:e;return this._markers.has(t)}get(e){return this._markers.get(e)||null}_set(e,t,i=!1,n=!1){const s=e instanceof xd?e.name:e;if(s.includes(","))throw new b("markercollection-incorrect-marker-name",this);const o=this._markers.get(s);if(o){const e=o.getData(),r=o.getRange();let a=!1;return r.isEqual(t)||(o._attachLiveRange(Il.fromRange(t)),a=!0),i!=o.managedUsingOperations&&(o._managedUsingOperations=i,a=!0),"boolean"==typeof n&&n!=o.affectsData&&(o._affectsData=n,a=!0),a&&this.fire(`update:${s}`,o,r,t,e),o}const r=Il.fromRange(t),a=new xd(s,r,i,n);return this._markers.set(s,a),this.fire(`update:${s}`,a,null,t,{...a.getData(),range:null}),a}_remove(e){const t=e instanceof xd?e.name:e,i=this._markers.get(t);return!!i&&(this._markers.delete(t),this.fire(`update:${t}`,i,i.getRange(),null,i.getData()),this._destroyMarker(i),!0)}_refresh(e){const t=e instanceof xd?e.name:e,i=this._markers.get(t);if(!i)throw new b("markercollection-refresh-marker-not-exists",this);const n=i.getRange();this.fire(`update:${t}`,i,n,n,i.getData())}*getMarkersAtPosition(e){for(const t of this)t.getRange().containsPosition(e)&&(yield t)}*getMarkersIntersectingRange(e){for(const t of this)null!==t.getRange().getIntersection(e)&&(yield t)}destroy(){for(const e of this._markers.values())this._destroyMarker(e);this._markers=null,this.stopListening()}*getMarkersGroup(e){for(const t of this._markers.values())t.name.startsWith(e+":")&&(yield t)}_destroyMarker(e){e.stopListening(),e._detachLiveRange()}}class xd extends(S(sl)){constructor(e,t,i,n){super(),this.name=e,this._liveRange=this._attachLiveRange(t),this._managedUsingOperations=i,this._affectsData=n}get managedUsingOperations(){if(!this._liveRange)throw new b("marker-destroyed",this);return this._managedUsingOperations}get affectsData(){if(!this._liveRange)throw new b("marker-destroyed",this);return this._affectsData}getData(){return{range:this.getRange(),affectsData:this.affectsData,managedUsingOperations:this.managedUsingOperations}}getStart(){if(!this._liveRange)throw new b("marker-destroyed",this);return this._liveRange.start.clone()}getEnd(){if(!this._liveRange)throw new b("marker-destroyed",this);return this._liveRange.end.clone()}getRange(){if(!this._liveRange)throw new b("marker-destroyed",this);return this._liveRange.toRange()}_attachLiveRange(e){return this._liveRange&&this._detachLiveRange(),e.delegate("change:range").to(this),e.delegate("change:content").to(this),this._liveRange=e,e}_detachLiveRange(){this._liveRange.stopDelegating("change:range",this),this._liveRange.stopDelegating("change:content",this),this._liveRange.detach(),this._liveRange=null}}xd.prototype.is=function(e){return"marker"===e||"model:marker"===e};class Td extends Oc{constructor(e,t){super(null),this.sourcePosition=e.clone(),this.howMany=t}get type(){return"detach"}toJSON(){const e=super.toJSON();return e.sourcePosition=this.sourcePosition.toJSON(),e}_validate(){if(this.sourcePosition.root.document)throw new b("detach-operation-on-document-node",this)}_execute(){Mc(bl._createFromPositionAndShift(this.sourcePosition,this.howMany))}static get className(){return"DetachOperation"}}class Ed extends sl{constructor(e){super(),this.markers=new Map,this._children=new rl,e&&this._insertChild(0,e)}[Symbol.iterator](){return this.getChildren()}get childCount(){return this._children.length}get maxOffset(){return this._children.maxOffset}get isEmpty(){return 0===this.childCount}get nextSibling(){return null}get previousSibling(){return null}get root(){return this}get parent(){return null}get document(){return null}getAncestors(){return[]}getChild(e){return this._children.getNode(e)}getChildren(){return this._children[Symbol.iterator]()}getChildIndex(e){return this._children.getNodeIndex(e)}getChildStartOffset(e){return this._children.getNodeStartOffset(e)}getPath(){return[]}getNodeByPath(e){let t=this;for(const i of e)t=t.getChild(t.offsetToIndex(i));return t}offsetToIndex(e){return this._children.offsetToIndex(e)}toJSON(){const e=[];for(const t of this._children)e.push(t.toJSON());return e}static fromJSON(e){const t=[];for(const i of e)i.name?t.push(cl.fromJSON(i)):t.push(al.fromJSON(i));return new Ed(t)}_appendChild(e){this._insertChild(this.childCount,e)}_insertChild(e,t){const i=function(e){if("string"==typeof e)return[new al(e)];X(e)||(e=[e]);return Array.from(e).map((e=>"string"==typeof e?new al(e):e instanceof ll?new al(e.data,e.getAttributes()):e))}(t);for(const e of i)null!==e.parent&&e._remove(),e.parent=this;this._children._insertNodes(e,i)}_removeChildren(e,t=1){const i=this._children._removeNodes(e,t);for(const e of i)e.parent=null;return i}}Ed.prototype.is=function(e){return"documentFragment"===e||"model:documentFragment"===e};class Sd{constructor(e,t){this.model=e,this.batch=t}createText(e,t){return new al(e,t)}createElement(e,t){return new cl(e,t)}createDocumentFragment(){return new Ed}cloneElement(e,t=!0){return e._clone(t)}insert(e,t,i=0){if(this._assertWriterUsedCorrectly(),e instanceof al&&""==e.data)return;const n=ul._createAt(t,i);if(e.parent){if(Ld(e.root,n.root))return void this.move(bl._createOn(e),n);if(e.root.document)throw new b("model-writer-insert-forbidden-move",this);this.remove(e)}const s=n.root.document?n.root.document.version:null,o=new Wc(n,e,s);if(e instanceof al&&(o.shouldReceiveAttributes=!0),this.batch.addOperation(o),this.model.applyOperation(o),e instanceof Ed)for(const[t,i]of e.markers){const e=ul._createAt(i.root,0),s={range:new bl(i.start._getCombined(e,n),i.end._getCombined(e,n)),usingOperation:!0,affectsData:!0};this.model.markers.has(t)?this.updateMarker(t,s):this.addMarker(t,s)}}insertText(e,t,i,n){t instanceof Ed||t instanceof cl||t instanceof ul?this.insert(this.createText(e),t,i):this.insert(this.createText(e,t),i,n)}insertElement(e,t,i,n){t instanceof Ed||t instanceof cl||t instanceof ul?this.insert(this.createElement(e),t,i):this.insert(this.createElement(e,t),i,n)}append(e,t){this.insert(e,t,"end")}appendText(e,t,i){t instanceof Ed||t instanceof cl?this.insert(this.createText(e),t,"end"):this.insert(this.createText(e,t),i,"end")}appendElement(e,t,i){t instanceof Ed||t instanceof cl?this.insert(this.createElement(e),t,"end"):this.insert(this.createElement(e,t),i,"end")}setAttribute(e,t,i){if(this._assertWriterUsedCorrectly(),i instanceof bl){const n=i.getMinimalFlatRanges();for(const i of n)Pd(this,e,t,i)}else Id(this,e,t,i)}setAttributes(e,t){for(const[i,n]of xs(e))this.setAttribute(i,n,t)}removeAttribute(e,t){if(this._assertWriterUsedCorrectly(),t instanceof bl){const i=t.getMinimalFlatRanges();for(const t of i)Pd(this,e,null,t)}else Id(this,e,null,t)}clearAttributes(e){this._assertWriterUsedCorrectly();const t=e=>{for(const t of e.getAttributeKeys())this.removeAttribute(t,e)};if(e instanceof bl)for(const i of e.getItems())t(i);else t(e)}move(e,t,i){if(this._assertWriterUsedCorrectly(),!(e instanceof bl))throw new b("writer-move-invalid-range",this);if(!e.isFlat)throw new b("writer-move-range-not-flat",this);const n=ul._createAt(t,i);if(n.isEqual(e.start))return;if(this._addOperationForAffectedMarkers("move",e),!Ld(e.root,n.root))throw new b("writer-move-different-document",this);const s=e.root.document?e.root.document.version:null,o=new $c(e.start,e.end.offset-e.start.offset,n,s);this.batch.addOperation(o),this.model.applyOperation(o)}remove(e){this._assertWriterUsedCorrectly();const t=(e instanceof bl?e:bl._createOn(e)).getMinimalFlatRanges().reverse();for(const e of t)this._addOperationForAffectedMarkers("move",e),Vd(e.start,e.end.offset-e.start.offset,this.batch,this.model)}merge(e){this._assertWriterUsedCorrectly();const t=e.nodeBefore,i=e.nodeAfter;if(this._addOperationForAffectedMarkers("merge",e),!(t instanceof cl))throw new b("writer-merge-no-element-before",this);if(!(i instanceof cl))throw new b("writer-merge-no-element-after",this);e.root.document?this._merge(e):this._mergeDetached(e)}createPositionFromPath(e,t,i){return this.model.createPositionFromPath(e,t,i)}createPositionAt(e,t){return this.model.createPositionAt(e,t)}createPositionAfter(e){return this.model.createPositionAfter(e)}createPositionBefore(e){return this.model.createPositionBefore(e)}createRange(e,t){return this.model.createRange(e,t)}createRangeIn(e){return this.model.createRangeIn(e)}createRangeOn(e){return this.model.createRangeOn(e)}createSelection(...e){return this.model.createSelection(...e)}_mergeDetached(e){const t=e.nodeBefore,i=e.nodeAfter;this.move(bl._createIn(i),ul._createAt(t,"end")),this.remove(i)}_merge(e){const t=ul._createAt(e.nodeBefore,"end"),i=ul._createAt(e.nodeAfter,0),n=e.root.document.graveyard,s=new ul(n,[0]),o=e.root.document.version,r=new Qc(i,e.nodeAfter.maxOffset,t,s,o);this.batch.addOperation(r),this.model.applyOperation(r)}rename(e,t){if(this._assertWriterUsedCorrectly(),!(e instanceof cl))throw new b("writer-rename-not-element-instance",this);const i=e.root.document?e.root.document.version:null,n=new Kc(ul._createBefore(e),e.name,t,i);this.batch.addOperation(n),this.model.applyOperation(n)}split(e,t){this._assertWriterUsedCorrectly();let i,n,s=e.parent;if(!s.parent)throw new b("writer-split-element-no-parent",this);if(t||(t=s.parent),!e.parent.getAncestors({includeSelf:!0}).includes(t))throw new b("writer-split-invalid-limit-element",this);do{const t=s.root.document?s.root.document.version:null,o=s.maxOffset-e.offset,r=Yc.getInsertionPosition(e),a=new Yc(e,o,r,null,t);this.batch.addOperation(a),this.model.applyOperation(a),i||n||(i=s,n=e.parent.nextSibling),s=(e=this.createPositionAfter(e.parent)).parent}while(s!==t);return{position:e,range:new bl(ul._createAt(i,"end"),ul._createAt(n,0))}}wrap(e,t){if(this._assertWriterUsedCorrectly(),!e.isFlat)throw new b("writer-wrap-range-not-flat",this);const i=t instanceof cl?t:new cl(t);if(i.childCount>0)throw new b("writer-wrap-element-not-empty",this);if(null!==i.parent)throw new b("writer-wrap-element-attached",this);this.insert(i,e.start);const n=new bl(e.start.getShiftedBy(1),e.end.getShiftedBy(1));this.move(n,ul._createAt(i,0))}unwrap(e){if(this._assertWriterUsedCorrectly(),null===e.parent)throw new b("writer-unwrap-element-no-parent",this);this.move(bl._createIn(e),this.createPositionAfter(e)),this.remove(e)}addMarker(e,t){if(this._assertWriterUsedCorrectly(),!t||"boolean"!=typeof t.usingOperation)throw new b("writer-addmarker-no-usingoperation",this);const i=t.usingOperation,n=t.range,s=void 0!==t.affectsData&&t.affectsData;if(this.model.markers.has(e))throw new b("writer-addmarker-marker-exists",this);if(!n)throw new b("writer-addmarker-no-range",this);return i?(Rd(this,e,null,n,s),this.model.markers.get(e)):this.model.markers._set(e,n,i,s)}updateMarker(e,t){this._assertWriterUsedCorrectly();const i="string"==typeof e?e:e.name,n=this.model.markers.get(i);if(!n)throw new b("writer-updatemarker-marker-not-exists",this);if(!t)return v("writer-updatemarker-reconvert-using-editingcontroller",{markerName:i}),void this.model.markers._refresh(n);const s="boolean"==typeof t.usingOperation,o="boolean"==typeof t.affectsData,r=o?t.affectsData:n.affectsData;if(!s&&!t.range&&!o)throw new b("writer-updatemarker-wrong-options",this);const a=n.getRange(),l=t.range?t.range:a;s&&t.usingOperation!==n.managedUsingOperations?t.usingOperation?Rd(this,i,null,l,r):(Rd(this,i,a,null,r),this.model.markers._set(i,l,void 0,r)):n.managedUsingOperations?Rd(this,i,a,l,r):this.model.markers._set(i,l,void 0,r)}removeMarker(e){this._assertWriterUsedCorrectly();const t="string"==typeof e?e:e.name;if(!this.model.markers.has(t))throw new b("writer-removemarker-no-marker",this);const i=this.model.markers.get(t);if(!i.managedUsingOperations)return void this.model.markers._remove(t);Rd(this,t,i.getRange(),null,i.affectsData)}setSelection(...e){this._assertWriterUsedCorrectly(),this.model.document.selection._setTo(...e)}setSelectionFocus(e,t){this._assertWriterUsedCorrectly(),this.model.document.selection._setFocus(e,t)}setSelectionAttribute(e,t){if(this._assertWriterUsedCorrectly(),"string"==typeof e)this._setSelectionAttribute(e,t);else for(const[t,i]of xs(e))this._setSelectionAttribute(t,i)}removeSelectionAttribute(e){if(this._assertWriterUsedCorrectly(),"string"==typeof e)this._removeSelectionAttribute(e);else for(const t of e)this._removeSelectionAttribute(t)}overrideSelectionGravity(){return this.model.document.selection._overrideGravity()}restoreSelectionGravity(e){this.model.document.selection._restoreGravity(e)}_setSelectionAttribute(e,t){const i=this.model.document.selection;if(i.isCollapsed&&i.anchor.parent.isEmpty){const n=Ol._getStoreAttributeKey(e);this.setAttribute(n,t,i.anchor.parent)}i._setAttribute(e,t)}_removeSelectionAttribute(e){const t=this.model.document.selection;if(t.isCollapsed&&t.anchor.parent.isEmpty){const i=Ol._getStoreAttributeKey(e);this.removeAttribute(i,t.anchor.parent)}t._removeAttribute(e)}_assertWriterUsedCorrectly(){if(this.model._currentWriter!==this)throw new b("writer-incorrect-use",this)}_addOperationForAffectedMarkers(e,t){for(const i of this.model.markers){if(!i.managedUsingOperations)continue;const n=i.getRange();let s=!1;if("move"===e){const e=t;s=e.containsPosition(n.start)||e.start.isEqual(n.start)||e.containsPosition(n.end)||e.end.isEqual(n.end)}else{const e=t,i=e.nodeBefore,o=e.nodeAfter,r=n.start.parent==i&&n.start.isAtEnd,a=n.end.parent==o&&0==n.end.offset,l=n.end.nodeAfter==o,c=n.start.nodeAfter==o;s=r||a||l||c}s&&this.updateMarker(i.name,{range:n})}}}function Pd(e,t,i,n){const s=e.model,o=s.document;let r,a,l,c=n.start;for(const e of n.getWalker({shallow:!0}))l=e.item.getAttribute(t),r&&a!=l&&(a!=i&&d(),c=r),r=e.nextPosition,a=l;function d(){const n=new bl(c,r),l=n.root.document?o.version:null,d=new Uc(n,t,a,i,l);e.batch.addOperation(d),s.applyOperation(d)}r instanceof ul&&r!=c&&a!=i&&d()}function Id(e,t,i,n){const s=e.model,o=s.document,r=n.getAttribute(t);let a,l;if(r!=i){if(n.root===n){const e=n.document?o.version:null;l=new Jc(n,t,r,i,e)}else{a=new bl(ul._createBefore(n),e.createPositionAfter(n));const s=a.root.document?o.version:null;l=new Uc(a,t,r,i,s)}e.batch.addOperation(l),s.applyOperation(l)}}function Rd(e,t,i,n,s){const o=e.model,r=o.document,a=new jc(t,i,n,o.markers,!!s,r.version);e.batch.addOperation(a),o.applyOperation(a)}function Vd(e,t,i,n){let s;if(e.root.document){const i=n.document,o=new ul(i.graveyard,[0]);s=new $c(e,t,o,i.version)}else s=new Td(e,t);i.addOperation(s),n.applyOperation(s)}function Ld(e,t){return e===t||e instanceof _d&&t instanceof _d}function Od(e){e.document.registerPostFixer((t=>function(e,t){const i=t.document.selection,n=t.schema,s=[];let o=!1;for(const e of i.getRanges()){const t=Bd(e,n);t&&!t.isEqual(e)?(s.push(t),o=!0):s.push(e)}o&&e.setSelection(function(e){const t=[...e],i=new Set;let n=1;for(;n!i.has(t)))}(s),{backward:i.isBackward});return!1}(t,e)))}function Bd(e,t){return e.isCollapsed?function(e,t){const i=e.start,n=t.getNearestSelectionRange(i);if(!n){const e=i.getAncestors().reverse().find((e=>t.isObject(e)));return e?bl._createOn(e):null}if(!n.isCollapsed)return n;const s=n.start;if(i.isEqual(s))return null;return new bl(s)}(e,t):function(e,t){const{start:i,end:n}=e,s=t.checkChild(i,"$text"),o=t.checkChild(n,"$text"),r=t.getLimitElement(i),a=t.getLimitElement(n);if(r===a){if(s&&o)return null;if(function(e,t,i){const n=e.nodeAfter&&!i.isLimit(e.nodeAfter)||i.checkChild(e,"$text"),s=t.nodeBefore&&!i.isLimit(t.nodeBefore)||i.checkChild(t,"$text");return n||s}(i,n,t)){const e=i.nodeAfter&&t.isSelectable(i.nodeAfter)?null:t.getNearestSelectionRange(i,"forward"),s=n.nodeBefore&&t.isSelectable(n.nodeBefore)?null:t.getNearestSelectionRange(n,"backward"),o=e?e.start:i,r=s?s.end:n;return new bl(o,r)}}const l=r&&!r.is("rootElement"),c=a&&!a.is("rootElement");if(l||c){const e=i.nodeAfter&&n.nodeBefore&&i.nodeAfter.parent===n.nodeBefore.parent,s=l&&(!e||!Nd(i.nodeAfter,t)),o=c&&(!e||!Nd(n.nodeBefore,t));let d=i,h=n;return s&&(d=ul._createBefore(Md(r,t))),o&&(h=ul._createAfter(Md(a,t))),new bl(d,h)}return null}(e,t)}function Md(e,t){let i=e,n=i;for(;t.isLimit(n)&&n.parent;)i=n,n=n.parent;return i}function Nd(e,t){return e&&t.isSelectable(e)}function Dd(e,t,i={}){if(t.isCollapsed)return;const n=t.getFirstRange();if("$graveyard"==n.root.rootName)return;const s=e.schema;e.change((e=>{if(!i.doNotResetEntireContent&&function(e,t){const i=e.getLimitElement(t);if(!t.containsEntireContent(i))return!1;const n=t.getFirstRange();if(n.start.parent==n.end.parent)return!1;return e.checkChild(i,"paragraph")}(s,t))return void function(e,t){const i=e.model.schema.getLimitElement(t);e.remove(e.createRangeIn(i)),$d(e,e.createPositionAt(i,0),t)}(e,t);const o={};if(!i.doNotAutoparagraph){const e=t.getSelectedElement();e&&Object.assign(o,s.getAttributesWithProperty(e,"copyOnReplace",!0))}const[r,a]=function(e){const t=e.root.document.model,i=e.start;let n=e.end;if(t.hasContent(e,{ignoreMarkers:!0})){const i=function(e){const t=e.parent,i=t.root.document.model.schema,n=t.getAncestors({parentFirst:!0,includeSelf:!0});for(const e of n){if(i.isLimit(e))return null;if(i.isBlock(e))return e}}(n);if(i&&n.isTouching(t.createPositionAt(i,0))){const i=t.createSelection(e);t.modifySelection(i,{direction:"backward"});const s=i.getLastPosition(),o=t.createRange(s,n);t.hasContent(o,{ignoreMarkers:!0})||(n=s)}}return[hd.fromPosition(i,"toPrevious"),hd.fromPosition(n,"toNext")]}(n);r.isTouching(a)||e.remove(e.createRange(r,a)),i.leaveUnmerged||(!function(e,t,i){const n=e.model;if(!Hd(e.model.schema,t,i))return;const[s,o]=function(e,t){const i=e.getAncestors(),n=t.getAncestors();let s=0;for(;i[s]&&i[s]==n[s];)s++;return[i[s],n[s]]}(t,i);if(!s||!o)return;!n.hasContent(s,{ignoreMarkers:!0})&&n.hasContent(o,{ignoreMarkers:!0})?zd(e,t,i,s.parent):Fd(e,t,i,s.parent)}(e,r,a),s.removeDisallowedAttributes(r.parent.getChildren(),e)),Wd(e,t,r),!i.doNotAutoparagraph&&function(e,t){const i=e.checkChild(t,"$text"),n=e.checkChild(t,"paragraph");return!i&&n}(s,r)&&$d(e,r,t,o),r.detach(),a.detach()}))}function Fd(e,t,i,n){const s=t.parent,o=i.parent;if(s!=n&&o!=n){for(t=e.createPositionAfter(s),(i=e.createPositionBefore(o)).isEqual(t)||e.insert(o,t),e.merge(t);i.parent.isEmpty;){const t=i.parent;i=e.createPositionBefore(t),e.remove(t)}Hd(e.model.schema,t,i)&&Fd(e,t,i,n)}}function zd(e,t,i,n){const s=t.parent,o=i.parent;if(s!=n&&o!=n){for(t=e.createPositionAfter(s),(i=e.createPositionBefore(o)).isEqual(t)||e.insert(s,i);t.parent.isEmpty;){const i=t.parent;t=e.createPositionBefore(i),e.remove(i)}i=e.createPositionBefore(o),function(e,t){const i=t.nodeBefore,n=t.nodeAfter;i.name!=n.name&&e.rename(i,n.name);e.clearAttributes(i),e.setAttributes(Object.fromEntries(n.getAttributes()),i),e.merge(t)}(e,i),Hd(e.model.schema,t,i)&&zd(e,t,i,n)}}function Hd(e,t,i){const n=t.parent,s=i.parent;return n!=s&&(!e.isLimit(n)&&!e.isLimit(s)&&function(e,t,i){const n=new bl(e,t);for(const e of n.getWalker())if(i.isLimit(e.item))return!1;return!0}(t,i,e))}function $d(e,t,i,n={}){const s=e.createElement("paragraph");e.model.schema.setAllowedAttributes(s,n,e),e.insert(s,t),Wd(e,i,e.createPositionAt(s,0))}function Wd(e,t,i){t instanceof Ol?e.setSelection(i):t.setTo(i)}function jd(e,t){const i=[];Array.from(e.getItems({direction:"backward"})).map((e=>t.createRangeOn(e))).filter((t=>(t.start.isAfter(e.start)||t.start.isEqual(e.start))&&(t.end.isBefore(e.end)||t.end.isEqual(e.end)))).forEach((e=>{i.push(e.start.parent),t.remove(e)})),i.forEach((e=>{let i=e;for(;i.parent&&i.isEmpty;){const e=t.createRangeOn(i);i=i.parent,t.remove(e)}}))}class qd{constructor(e,t,i){this.model=e,this.writer=t,this.position=i,this.canMergeWith=new Set([this.position.parent]),this.schema=e.schema,this._documentFragment=t.createDocumentFragment(),this._documentFragmentPosition=t.createPositionAt(this._documentFragment,0),this._firstNode=null,this._lastNode=null,this._lastAutoParagraph=null,this._filterAttributesOf=[],this._affectedStart=null,this._affectedEnd=null}handleNodes(e){for(const t of Array.from(e))this._handleNode(t);this._insertPartialFragment(),this._lastAutoParagraph&&this._updateLastNodeFromAutoParagraph(this._lastAutoParagraph),this._mergeOnRight(),this.schema.removeDisallowedAttributes(this._filterAttributesOf,this.writer),this._filterAttributesOf=[]}_updateLastNodeFromAutoParagraph(e){const t=this.writer.createPositionAfter(this._lastNode),i=this.writer.createPositionAfter(e);if(i.isAfter(t)){if(this._lastNode=e,this.position.parent!=e||!this.position.isAtEnd)throw new b("insertcontent-invalid-insertion-position",this);this.position=i,this._setAffectedBoundaries(this.position)}}getSelectionRange(){return this._nodeToSelect?bl._createOn(this._nodeToSelect):this.model.schema.getNearestSelectionRange(this.position)}getAffectedRange(){return this._affectedStart?new bl(this._affectedStart,this._affectedEnd):null}destroy(){this._affectedStart&&this._affectedStart.detach(),this._affectedEnd&&this._affectedEnd.detach()}_handleNode(e){if(this.schema.isObject(e))return void this._handleObject(e);let t=this._checkAndAutoParagraphToAllowedPosition(e);t||(t=this._checkAndSplitToAllowedPosition(e),t)?(this._appendToFragment(e),this._firstNode||(this._firstNode=e),this._lastNode=e):this._handleDisallowedNode(e)}_insertPartialFragment(){if(this._documentFragment.isEmpty)return;const e=hd.fromPosition(this.position,"toNext");this._setAffectedBoundaries(this.position),this._documentFragment.getChild(0)==this._firstNode&&(this.writer.insert(this._firstNode,this.position),this._mergeOnLeft(),this.position=e.toPosition()),this._documentFragment.isEmpty||this.writer.insert(this._documentFragment,this.position),this._documentFragmentPosition=this.writer.createPositionAt(this._documentFragment,0),this.position=e.toPosition(),e.detach()}_handleObject(e){this._checkAndSplitToAllowedPosition(e)?this._appendToFragment(e):this._tryAutoparagraphing(e)}_handleDisallowedNode(e){e.is("element")?this.handleNodes(e.getChildren()):this._tryAutoparagraphing(e)}_appendToFragment(e){if(!this.schema.checkChild(this.position,e))throw new b("insertcontent-wrong-position",this,{node:e,position:this.position});this.writer.insert(e,this._documentFragmentPosition),this._documentFragmentPosition=this._documentFragmentPosition.getShiftedBy(e.offsetSize),this.schema.isObject(e)&&!this.schema.checkChild(this.position,"$text")?this._nodeToSelect=e:this._nodeToSelect=null,this._filterAttributesOf.push(e)}_setAffectedBoundaries(e){this._affectedStart||(this._affectedStart=hd.fromPosition(e,"toPrevious")),this._affectedEnd&&!this._affectedEnd.isBefore(e)||(this._affectedEnd&&this._affectedEnd.detach(),this._affectedEnd=hd.fromPosition(e,"toNext"))}_mergeOnLeft(){const e=this._firstNode;if(!(e instanceof cl))return;if(!this._canMergeLeft(e))return;const t=hd._createBefore(e);t.stickiness="toNext";const i=hd.fromPosition(this.position,"toNext");this._affectedStart.isEqual(t)&&(this._affectedStart.detach(),this._affectedStart=hd._createAt(t.nodeBefore,"end","toPrevious")),this._firstNode===this._lastNode&&(this._firstNode=t.nodeBefore,this._lastNode=t.nodeBefore),this.writer.merge(t),t.isEqual(this._affectedEnd)&&this._firstNode===this._lastNode&&(this._affectedEnd.detach(),this._affectedEnd=hd._createAt(t.nodeBefore,"end","toNext")),this.position=i.toPosition(),i.detach(),this._filterAttributesOf.push(this.position.parent),t.detach()}_mergeOnRight(){const e=this._lastNode;if(!(e instanceof cl))return;if(!this._canMergeRight(e))return;const t=hd._createAfter(e);if(t.stickiness="toNext",!this.position.isEqual(t))throw new b("insertcontent-invalid-insertion-position",this);this.position=ul._createAt(t.nodeBefore,"end");const i=hd.fromPosition(this.position,"toPrevious");this._affectedEnd.isEqual(t)&&(this._affectedEnd.detach(),this._affectedEnd=hd._createAt(t.nodeBefore,"end","toNext")),this._firstNode===this._lastNode&&(this._firstNode=t.nodeBefore,this._lastNode=t.nodeBefore),this.writer.merge(t),t.getShiftedBy(-1).isEqual(this._affectedStart)&&this._firstNode===this._lastNode&&(this._affectedStart.detach(),this._affectedStart=hd._createAt(t.nodeBefore,0,"toPrevious")),this.position=i.toPosition(),i.detach(),this._filterAttributesOf.push(this.position.parent),t.detach()}_canMergeLeft(e){const t=e.previousSibling;return t instanceof cl&&this.canMergeWith.has(t)&&this.model.schema.checkMerge(t,e)}_canMergeRight(e){const t=e.nextSibling;return t instanceof cl&&this.canMergeWith.has(t)&&this.model.schema.checkMerge(e,t)}_tryAutoparagraphing(e){const t=this.writer.createElement("paragraph");this._getAllowedIn(this.position.parent,t)&&this.schema.checkChild(t,e)&&(t._appendChild(e),this._handleNode(t))}_checkAndAutoParagraphToAllowedPosition(e){if(this.schema.checkChild(this.position.parent,e))return!0;if(!this.schema.checkChild(this.position.parent,"paragraph")||!this.schema.checkChild("paragraph",e))return!1;this._insertPartialFragment();const t=this.writer.createElement("paragraph");return this.writer.insert(t,this.position),this._setAffectedBoundaries(this.position),this._lastAutoParagraph=t,this.position=this.writer.createPositionAt(t,0),!0}_checkAndSplitToAllowedPosition(e){const t=this._getAllowedIn(this.position.parent,e);if(!t)return!1;for(t!=this.position.parent&&this._insertPartialFragment();t!=this.position.parent;)if(this.position.isAtStart){const e=this.position.parent;this.position=this.writer.createPositionBefore(e),e.isEmpty&&e.parent===t&&this.writer.remove(e)}else if(this.position.isAtEnd)this.position=this.writer.createPositionAfter(this.position.parent);else{const e=this.writer.createPositionAfter(this.position.parent);this._setAffectedBoundaries(this.position),this.writer.split(this.position),this.position=e,this.canMergeWith.add(this.position.nodeAfter)}return!0}_getAllowedIn(e,t){return this.schema.checkChild(e,t)?e:this.schema.isLimit(e)?null:this._getAllowedIn(e.parent,t)}}function Ud(e,t,i="auto"){const n=e.getSelectedElement();if(n&&t.schema.isObject(n)&&!t.schema.isInline(n))return"before"==i||"after"==i?t.createRange(t.createPositionAt(n,i)):t.createRangeOn(n);const s=ks(e.getSelectedBlocks());if(!s)return t.createRange(e.focus);if(s.isEmpty)return t.createRange(t.createPositionAt(s,0));const o=t.createPositionAfter(s);return e.focus.isTouching(o)?t.createRange(o):t.createRange(t.createPositionBefore(s))}function Gd(e,t,i,n,s={}){if(!e.schema.isObject(t))throw new b("insertobject-element-not-an-object",e,{object:t});let o;o=i?i instanceof xl||i instanceof Ol?i:e.createSelection(i,n):e.document.selection;let r=o;s.findOptimalPosition&&e.schema.isBlock(t)&&(r=e.createSelection(Ud(o,e,s.findOptimalPosition)));const a=ks(o.getSelectedBlocks()),l={};return a&&Object.assign(l,e.schema.getAttributesWithProperty(a,"copyOnReplace",!0)),e.change((i=>{r.isCollapsed||e.deleteContent(r,{doNotAutoparagraph:!0});let n=t;const o=r.anchor.parent;!e.schema.checkChild(o,t)&&e.schema.checkChild(o,"paragraph")&&e.schema.checkChild("paragraph",t)&&(n=i.createElement("paragraph"),i.insert(t,n)),e.schema.setAllowedAttributes(n,l,i);const a=e.insertContent(n,r);return a.isCollapsed||s.setSelection&&function(e,t,i,n){const s=e.model;if("on"==i)return void e.setSelection(t,"on");if("after"!=i)throw new b("insertobject-invalid-place-parameter-value",s);let o=t.nextSibling;if(s.schema.isInline(t))return void e.setSelection(t,"after");const r=o&&s.schema.checkChild(o,"$text");!r&&s.schema.checkChild(t.parent,"paragraph")&&(o=e.createElement("paragraph"),s.schema.setAllowedAttributes(o,n,e),s.insertContent(o,e.createPositionAfter(t)));o&&e.setSelection(o,0)}(i,t,s.setSelection,l),a}))}const Kd=' ,.?!:;"-()';function Jd(e,t){const{isForward:i,walker:n,unit:s,schema:o,treatEmojiAsSingleUnit:r}=e,{type:a,item:l,nextPosition:c}=t;if("text"==a)return"word"===e.unit?function(e,t){let i=e.position.textNode;i||(i=t?e.position.nodeAfter:e.position.nodeBefore);for(;i&&i.is("$text");){const n=e.position.offset-i.startOffset;if(Xd(i,n,t))i=t?e.position.nodeAfter:e.position.nodeBefore;else{if(Yd(i.data,n,t))break;e.next()}}return e.position}(n,i):function(e,t,i){const n=e.position.textNode;if(n){const s=n.data;let o=e.position.offset-n.startOffset;for(;Ts(s,o)||"character"==t&&Es(s,o)||i&&Ps(s,o);)e.next(),o=e.position.offset-n.startOffset}return e.position}(n,s,r);if(a==(i?"elementStart":"elementEnd")){if(o.isSelectable(l))return ul._createAt(l,i?"after":"before");if(o.checkChild(c,"$text"))return c}else{if(o.isLimit(l))return void n.skip((()=>!0));if(o.checkChild(c,"$text"))return c}}function Qd(e,t){const i=e.root,n=ul._createAt(i,t?"end":0);return t?new bl(e,n):new bl(n,e)}function Yd(e,t,i){const n=t+(i?0:-1);return Kd.includes(e.charAt(n))}function Xd(e,t,i){return t===(i?e.offsetSize:0)}class Zd extends(W()){constructor(){super(),this.markers=new Ad,this.document=new kd(this),this.schema=new uc,this._pendingChanges=[],this._currentWriter=null,["insertContent","insertObject","deleteContent","modifySelection","getSelectedContent","applyOperation"].forEach((e=>this.decorate(e))),this.on("applyOperation",((e,t)=>{t[0]._validate()}),{priority:"highest"}),this.schema.register("$root",{isLimit:!0}),this.schema.register("$container",{allowIn:["$root","$container"]}),this.schema.register("$block",{allowIn:["$root","$container"],isBlock:!0}),this.schema.register("$blockObject",{allowWhere:"$block",isBlock:!0,isObject:!0}),this.schema.register("$inlineObject",{allowWhere:"$text",allowAttributesOf:"$text",isInline:!0,isObject:!0}),this.schema.register("$text",{allowIn:"$block",isInline:!0,isContent:!0}),this.schema.register("$clipboardHolder",{allowContentOf:"$root",allowChildren:"$text",isLimit:!0}),this.schema.register("$documentFragment",{allowContentOf:"$root",allowChildren:"$text",isLimit:!0}),this.schema.register("$marker"),this.schema.addChildCheck(((e,t)=>{if("$marker"===t.name)return!0})),Od(this),this.document.registerPostFixer(Xl)}change(e){try{return 0===this._pendingChanges.length?(this._pendingChanges.push({batch:new gd,callback:e}),this._runPendingChanges()[0]):e(this._currentWriter)}catch(e){b.rethrowUnexpectedError(e,this)}}enqueueChange(e,t){try{e?"function"==typeof e?(t=e,e=new gd):e instanceof gd||(e=new gd(e)):e=new gd,this._pendingChanges.push({batch:e,callback:t}),1==this._pendingChanges.length&&this._runPendingChanges()}catch(e){b.rethrowUnexpectedError(e,this)}}applyOperation(e){e._execute()}insertContent(e,t,i){return function(e,t,i,n){return e.change((s=>{let o;o=i?i instanceof xl||i instanceof Ol?i:s.createSelection(i,n):e.document.selection,o.isCollapsed||e.deleteContent(o,{doNotAutoparagraph:!0});const r=new qd(e,s,o.anchor),a=[];let l;if(t.is("documentFragment")){if(t.markers.size){const e=[];for(const[i,n]of t.markers){const{start:t,end:s}=n,o=t.isEqual(s);e.push({position:t,name:i,isCollapsed:o},{position:s,name:i,isCollapsed:o})}e.sort((({position:e},{position:t})=>e.isBefore(t)?1:-1));for(const{position:i,name:n,isCollapsed:o}of e){let e=null,r=null;const l=i.parent===t&&i.isAtStart,c=i.parent===t&&i.isAtEnd;l||c?o&&(r=l?"start":"end"):(e=s.createElement("$marker"),s.insert(e,i)),a.push({name:n,element:e,collapsed:r})}}l=t.getChildren()}else l=[t];r.handleNodes(l);let c=r.getSelectionRange();if(t.is("documentFragment")&&a.length){const e=c?Il.fromRange(c):null,t={};for(let e=a.length-1;e>=0;e--){const{name:i,element:n,collapsed:o}=a[e],l=!t[i];if(l&&(t[i]=[]),n){const e=s.createPositionAt(n,"before");t[i].push(e),s.remove(n)}else{const e=r.getAffectedRange();if(!e){o&&t[i].push(r.position);continue}o?t[i].push(e[o]):t[i].push(l?e.start:e.end)}}for(const[e,[i,n]]of Object.entries(t))i&&n&&i.root===n.root&&s.addMarker(e,{usingOperation:!0,affectsData:!0,range:new bl(i,n)});e&&(c=e.toRange(),e.detach())}c&&(o instanceof Ol?s.setSelection(c):o.setTo(c));const d=r.getAffectedRange()||e.createRange(o.anchor);return r.destroy(),d}))}(this,e,t,i)}insertObject(e,t,i,n){return Gd(this,e,t,i,n)}deleteContent(e,t){Dd(this,e,t)}modifySelection(e,t){!function(e,t,i={}){const n=e.schema,s="backward"!=i.direction,o=i.unit?i.unit:"character",r=!!i.treatEmojiAsSingleUnit,a=t.focus,l=new dl({boundaries:Qd(a,s),singleCharacters:!0,direction:s?"forward":"backward"}),c={walker:l,schema:n,isForward:s,unit:o,treatEmojiAsSingleUnit:r};let d;for(;d=l.next();){if(d.done)return;const i=Jd(c,d.value);if(i)return void(t instanceof Ol?e.change((e=>{e.setSelectionFocus(i)})):t.setFocus(i))}}(this,e,t)}getSelectedContent(e){return function(e,t){return e.change((e=>{const i=e.createDocumentFragment(),n=t.getFirstRange();if(!n||n.isCollapsed)return i;const s=n.start.root,o=n.start.getCommonPath(n.end),r=s.getNodeByPath(o);let a;a=n.start.parent==n.end.parent?n:e.createRange(e.createPositionAt(r,n.start.path[o.length]),e.createPositionAt(r,n.end.path[o.length]+1));const l=a.end.offset-a.start.offset;for(const t of a.getItems({shallow:!0}))t.is("$textProxy")?e.appendText(t.data,t.getAttributes(),i):e.append(e.cloneElement(t,!0),i);if(a!=n){const t=n._getTransformedByMove(a.start,e.createPositionAt(i,0),l)[0],s=e.createRange(e.createPositionAt(i,0),t.start);jd(e.createRange(t.end,e.createPositionAt(i,"end")),e),jd(s,e)}return i}))}(this,e)}hasContent(e,t={}){const i=e instanceof bl?e:bl._createIn(e);if(i.isCollapsed)return!1;const{ignoreWhitespaces:n=!1,ignoreMarkers:s=!1}=t;if(!s)for(const e of this.markers.getMarkersIntersectingRange(i))if(e.affectsData)return!0;for(const e of i.getItems())if(this.schema.isContent(e)){if(!e.is("$textProxy"))return!0;if(!n)return!0;if(-1!==e.data.search(/\S/))return!0}return!1}createPositionFromPath(e,t,i){return new ul(e,t,i)}createPositionAt(e,t){return ul._createAt(e,t)}createPositionAfter(e){return ul._createAfter(e)}createPositionBefore(e){return ul._createBefore(e)}createRange(e,t){return new bl(e,t)}createRangeIn(e){return bl._createIn(e)}createRangeOn(e){return bl._createOn(e)}createSelection(...e){return new xl(...e)}createBatch(e){return new gd(e)}createOperationFromJSON(e){return Zc.fromJSON(e,this.document)}destroy(){this.document.destroy(),this.stopListening()}_runPendingChanges(){const e=[];this.fire("_beforeChanges");try{for(;this._pendingChanges.length;){const t=this._pendingChanges[0].batch;this._currentWriter=new Sd(this,t);const i=this._pendingChanges[0].callback(this._currentWriter);e.push(i),this.document._handleChangeBlock(this._currentWriter),this._pendingChanges.shift(),this._currentWriter=null}}finally{this._pendingChanges.length=0,this._currentWriter=null,this.fire("_afterChanges")}return e}}class eh extends ha{constructor(e){super(e),this.domEventType="click"}onDomEvent(e){this.fire(e.type,e)}}class th extends ha{constructor(e){super(e),this.domEventType=["mousedown","mouseup","mouseover","mouseout"]}onDomEvent(e){this.fire(e.type,e)}}class ih{constructor(e){this.document=e}createDocumentFragment(e){return new Tr(this.document,e)}createElement(e,t,i){return new Jo(this.document,e,t,i)}createText(e){return new Gs(this.document,e)}clone(e,t=!1){return e._clone(t)}appendChild(e,t){return t._appendChild(e)}insertChild(e,t,i){return i._insertChild(e,t)}removeChildren(e,t,i){return i._removeChildren(e,t)}remove(e){const t=e.parent;return t?this.removeChildren(t.getChildIndex(e),1,t):[]}replace(e,t){const i=e.parent;if(i){const n=i.getChildIndex(e);return this.removeChildren(n,1,i),this.insertChild(n,t,i),!0}return!1}unwrapElement(e){const t=e.parent;if(t){const i=t.getChildIndex(e);this.remove(e),this.insertChild(i,e.getChildren(),t)}}rename(e,t){const i=new Jo(this.document,e,t.getAttributes(),t.getChildren());return this.replace(t,i)?i:null}setAttribute(e,t,i){i._setAttribute(e,t)}removeAttribute(e,t){t._removeAttribute(e)}addClass(e,t){t._addClass(e)}removeClass(e,t){t._removeClass(e)}setStyle(e,t,i){Ce(e)&&void 0===i?t._setStyle(e):i._setStyle(e,t)}removeStyle(e,t){t._removeStyle(e)}setCustomProperty(e,t,i){i._setCustomProperty(e,t)}removeCustomProperty(e,t){return t._removeCustomProperty(e)}createPositionAt(e,t){return nr._createAt(e,t)}createPositionAfter(e){return nr._createAfter(e)}createPositionBefore(e){return nr._createBefore(e)}createRange(e,t){return new sr(e,t)}createRangeOn(e){return sr._createOn(e)}createRangeIn(e){return sr._createIn(e)}createSelection(...e){return new rr(...e)}}const nh=/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,sh=/^rgb\([ ]?([0-9]{1,3}[ %]?,[ ]?){2,3}[0-9]{1,3}[ %]?\)$/i,oh=/^rgba\([ ]?([0-9]{1,3}[ %]?,[ ]?){3}(1|[0-9]+%|[0]?\.?[0-9]+)\)$/i,rh=/^hsl\([ ]?([0-9]{1,3}[ %]?[,]?[ ]*){3}(1|[0-9]+%|[0]?\.?[0-9]+)?\)$/i,ah=/^hsla\([ ]?([0-9]{1,3}[ %]?,[ ]?){2,3}(1|[0-9]+%|[0]?\.?[0-9]+)\)$/i,lh=new Set(["black","silver","gray","white","maroon","red","purple","fuchsia","green","lime","olive","yellow","navy","blue","teal","aqua","orange","aliceblue","antiquewhite","aquamarine","azure","beige","bisque","blanchedalmond","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","gainsboro","ghostwhite","gold","goldenrod","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","limegreen","linen","magenta","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","oldlace","olivedrab","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","thistle","tomato","turquoise","violet","wheat","whitesmoke","yellowgreen","activeborder","activecaption","appworkspace","background","buttonface","buttonhighlight","buttonshadow","buttontext","captiontext","graytext","highlight","highlighttext","inactiveborder","inactivecaption","inactivecaptiontext","infobackground","infotext","menu","menutext","scrollbar","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","window","windowframe","windowtext","rebeccapurple","currentcolor","transparent"]);function ch(e){return e.startsWith("#")?nh.test(e):e.startsWith("rgb")?sh.test(e)||oh.test(e):e.startsWith("hsl")?rh.test(e)||ah.test(e):lh.has(e.toLowerCase())}const dh=["none","hidden","dotted","dashed","solid","double","groove","ridge","inset","outset"];function hh(e){return dh.includes(e)}const uh=/^([+-]?[0-9]*([.][0-9]+)?(px|cm|mm|in|pc|pt|ch|em|ex|rem|vh|vw|vmin|vmax)|0)$/;function mh(e){return uh.test(e)}const gh=/^[+-]?[0-9]*([.][0-9]+)?%$/;function fh(e){return gh.test(e)}const ph=["repeat-x","repeat-y","repeat","space","round","no-repeat"];function wh(e){return ph.includes(e)}const bh=["center","top","bottom","left","right"];function vh(e){return bh.includes(e)}const _h=["fixed","scroll","local"];function yh(e){return _h.includes(e)}const kh=/^url\(/;function Ch(e){return kh.test(e)}function Ah(e=""){if(""===e)return{top:void 0,right:void 0,bottom:void 0,left:void 0};const t=Sh(e),i=t[0],n=t[2]||i,s=t[1]||i;return{top:i,bottom:n,right:s,left:t[3]||s}}function xh(e){return t=>{const{top:i,right:n,bottom:s,left:o}=t,r=[];return[i,n,o,s].every((e=>!!e))?r.push([e,Th(t)]):(i&&r.push([e+"-top",i]),n&&r.push([e+"-right",n]),s&&r.push([e+"-bottom",s]),o&&r.push([e+"-left",o])),r}}function Th({top:e,right:t,bottom:i,left:n}){const s=[];return n!==t?s.push(e,t,i,n):i!==e?s.push(e,t,i):t!==e?s.push(e,t):s.push(e),s.join(" ")}function Eh(e){return t=>({path:e,value:Ah(t)})}function Sh(e){return e.replace(/, /g,",").split(" ").map((e=>e.replace(/,/g,", ")))}function Ph(e){e.setNormalizer("background",(e=>{const t={},i=Sh(e);for(const e of i)wh(e)?(t.repeat=t.repeat||[],t.repeat.push(e)):vh(e)?(t.position=t.position||[],t.position.push(e)):yh(e)?t.attachment=e:ch(e)?t.color=e:Ch(e)&&(t.image=e);return{path:"background",value:t}})),e.setNormalizer("background-color",(e=>({path:"background.color",value:e}))),e.setReducer("background",(e=>{const t=[];return t.push(["background-color",e.color]),t})),e.setStyleRelation("background",["background-color"])}function Ih(e){e.setNormalizer("border",(e=>{const{color:t,style:i,width:n}=Nh(e);return{path:"border",value:{color:Ah(t),style:Ah(i),width:Ah(n)}}})),e.setNormalizer("border-top",Rh("top")),e.setNormalizer("border-right",Rh("right")),e.setNormalizer("border-bottom",Rh("bottom")),e.setNormalizer("border-left",Rh("left")),e.setNormalizer("border-color",Vh("color")),e.setNormalizer("border-width",Vh("width")),e.setNormalizer("border-style",Vh("style")),e.setNormalizer("border-top-color",Oh("color","top")),e.setNormalizer("border-top-style",Oh("style","top")),e.setNormalizer("border-top-width",Oh("width","top")),e.setNormalizer("border-right-color",Oh("color","right")),e.setNormalizer("border-right-style",Oh("style","right")),e.setNormalizer("border-right-width",Oh("width","right")),e.setNormalizer("border-bottom-color",Oh("color","bottom")),e.setNormalizer("border-bottom-style",Oh("style","bottom")),e.setNormalizer("border-bottom-width",Oh("width","bottom")),e.setNormalizer("border-left-color",Oh("color","left")),e.setNormalizer("border-left-style",Oh("style","left")),e.setNormalizer("border-left-width",Oh("width","left")),e.setExtractor("border-top",Bh("top")),e.setExtractor("border-right",Bh("right")),e.setExtractor("border-bottom",Bh("bottom")),e.setExtractor("border-left",Bh("left")),e.setExtractor("border-top-color","border.color.top"),e.setExtractor("border-right-color","border.color.right"),e.setExtractor("border-bottom-color","border.color.bottom"),e.setExtractor("border-left-color","border.color.left"),e.setExtractor("border-top-width","border.width.top"),e.setExtractor("border-right-width","border.width.right"),e.setExtractor("border-bottom-width","border.width.bottom"),e.setExtractor("border-left-width","border.width.left"),e.setExtractor("border-top-style","border.style.top"),e.setExtractor("border-right-style","border.style.right"),e.setExtractor("border-bottom-style","border.style.bottom"),e.setExtractor("border-left-style","border.style.left"),e.setReducer("border-color",xh("border-color")),e.setReducer("border-style",xh("border-style")),e.setReducer("border-width",xh("border-width")),e.setReducer("border-top",Dh("top")),e.setReducer("border-right",Dh("right")),e.setReducer("border-bottom",Dh("bottom")),e.setReducer("border-left",Dh("left")),e.setReducer("border",function(){return t=>{const i=Mh(t,"top"),n=Mh(t,"right"),s=Mh(t,"bottom"),o=Mh(t,"left"),r=[i,n,s,o],a={width:e(r,"width"),style:e(r,"style"),color:e(r,"color")},l=Fh(a,"all");if(l.length)return l;const c=Object.entries(a).reduce(((e,[t,i])=>(i&&(e.push([`border-${t}`,i]),r.forEach((e=>delete e[t]))),e)),[]);return[...c,...Fh(i,"top"),...Fh(n,"right"),...Fh(s,"bottom"),...Fh(o,"left")]};function e(e,t){return e.map((e=>e[t])).reduce(((e,t)=>e==t?e:null))}}()),e.setStyleRelation("border",["border-color","border-style","border-width","border-top","border-right","border-bottom","border-left","border-top-color","border-right-color","border-bottom-color","border-left-color","border-top-style","border-right-style","border-bottom-style","border-left-style","border-top-width","border-right-width","border-bottom-width","border-left-width"]),e.setStyleRelation("border-color",["border-top-color","border-right-color","border-bottom-color","border-left-color"]),e.setStyleRelation("border-style",["border-top-style","border-right-style","border-bottom-style","border-left-style"]),e.setStyleRelation("border-width",["border-top-width","border-right-width","border-bottom-width","border-left-width"]),e.setStyleRelation("border-top",["border-top-color","border-top-style","border-top-width"]),e.setStyleRelation("border-right",["border-right-color","border-right-style","border-right-width"]),e.setStyleRelation("border-bottom",["border-bottom-color","border-bottom-style","border-bottom-width"]),e.setStyleRelation("border-left",["border-left-color","border-left-style","border-left-width"])}function Rh(e){return t=>{const{color:i,style:n,width:s}=Nh(t),o={};return void 0!==i&&(o.color={[e]:i}),void 0!==n&&(o.style={[e]:n}),void 0!==s&&(o.width={[e]:s}),{path:"border",value:o}}}function Vh(e){return t=>({path:"border",value:Lh(t,e)})}function Lh(e,t){return{[t]:Ah(e)}}function Oh(e,t){return i=>({path:"border",value:{[e]:{[t]:i}}})}function Bh(e){return(t,i)=>{if(i.border)return Mh(i.border,e)}}function Mh(e,t){const i={};return e.width&&e.width[t]&&(i.width=e.width[t]),e.style&&e.style[t]&&(i.style=e.style[t]),e.color&&e.color[t]&&(i.color=e.color[t]),i}function Nh(e){const t={},i=Sh(e);for(const e of i)mh(e)||/thin|medium|thick/.test(e)?t.width=e:hh(e)?t.style=e:t.color=e;return t}function Dh(e){return t=>Fh(t,e)}function Fh(e,t){const i=[];if(e&&e.width&&i.push("width"),e&&e.style&&i.push("style"),e&&e.color&&i.push("color"),3==i.length){const n=i.map((t=>e[t])).join(" ");return["all"==t?["border",n]:[`border-${t}`,n]]}return"all"==t?[]:i.map((i=>[`border-${t}-${i}`,e[i]]))}function zh(e){e.setNormalizer("margin",Eh("margin")),e.setNormalizer("margin-top",(e=>({path:"margin.top",value:e}))),e.setNormalizer("margin-right",(e=>({path:"margin.right",value:e}))),e.setNormalizer("margin-bottom",(e=>({path:"margin.bottom",value:e}))),e.setNormalizer("margin-left",(e=>({path:"margin.left",value:e}))),e.setReducer("margin",xh("margin")),e.setStyleRelation("margin",["margin-top","margin-right","margin-bottom","margin-left"])}function Hh(e){e.setNormalizer("padding",Eh("padding")),e.setNormalizer("padding-top",(e=>({path:"padding.top",value:e}))),e.setNormalizer("padding-right",(e=>({path:"padding.right",value:e}))),e.setNormalizer("padding-bottom",(e=>({path:"padding.bottom",value:e}))),e.setNormalizer("padding-left",(e=>({path:"padding.left",value:e}))),e.setReducer("padding",xh("padding")),e.setStyleRelation("padding",["padding-top","padding-right","padding-bottom","padding-left"])}class $h{constructor(){this._commands=new Map}add(e,t){this._commands.set(e,t)}get(e){return this._commands.get(e)}execute(e,...t){const i=this.get(e);if(!i)throw new b("commandcollection-command-not-found",this,{commandName:e});return i.execute(...t)}*names(){yield*this._commands.keys()}*commands(){yield*this._commands.values()}[Symbol.iterator](){return this._commands[Symbol.iterator]()}destroy(){for(const e of this.commands())e.destroy()}}class Wh extends As{constructor(e){super(),this.editor=e}set(e,t,i={}){if("string"==typeof t){const e=t;t=(t,i)=>{this.editor.execute(e),i()}}super.set(e,t,i)}}class jh extends(W()){constructor(e={}){super();const t=this.constructor,i=e.language||t.defaultConfig&&t.defaultConfig.language;this._context=e.context||new Ms({language:i}),this._context._addEditor(this,!e.context);const n=Array.from(t.builtinPlugins||[]);this.config=new yn(e,t.defaultConfig),this.config.define("plugins",n),this.config.define(this._context._getEditorConfig()),this.plugins=new Bs(this,n,this._context.plugins),this.locale=this._context.locale,this.t=this.locale.t,this._readOnlyLocks=new Set,this.commands=new $h,this.set("state","initializing"),this.once("ready",(()=>this.state="ready"),{priority:"high"}),this.once("destroy",(()=>this.state="destroyed"),{priority:"high"}),this.model=new Zd;const s=new Uo;this.data=new Ic(this.model,s),this.editing=new lc(this.model,s),this.editing.view.document.bind("isReadOnly").to(this),this.conversion=new Rc([this.editing.downcastDispatcher,this.data.downcastDispatcher],this.data.upcastDispatcher),this.conversion.addAlias("dataDowncast",this.data.downcastDispatcher),this.conversion.addAlias("editingDowncast",this.editing.downcastDispatcher),this.keystrokes=new Wh(this),this.keystrokes.listenTo(this.editing.view.document)}get isReadOnly(){return this._readOnlyLocks.size>0}set isReadOnly(e){throw new b("editor-isreadonly-has-no-setter")}enableReadOnlyMode(e){if("string"!=typeof e&&"symbol"!=typeof e)throw new b("editor-read-only-lock-id-invalid",null,{lockId:e});this._readOnlyLocks.has(e)||(this._readOnlyLocks.add(e),1===this._readOnlyLocks.size&&this.fire("change:isReadOnly","isReadOnly",!0,!1))}disableReadOnlyMode(e){if("string"!=typeof e&&"symbol"!=typeof e)throw new b("editor-read-only-lock-id-invalid",null,{lockId:e});this._readOnlyLocks.has(e)&&(this._readOnlyLocks.delete(e),0===this._readOnlyLocks.size&&this.fire("change:isReadOnly","isReadOnly",!1,!0))}initPlugins(){const e=this.config,t=e.get("plugins"),i=e.get("removePlugins")||[],n=e.get("extraPlugins")||[],s=e.get("substitutePlugins")||[];return this.plugins.init(t.concat(n),i,s)}destroy(){let e=Promise.resolve();return"initializing"==this.state&&(e=new Promise((e=>this.once("ready",e)))),e.then((()=>{this.fire("destroy"),this.stopListening(),this.commands.destroy()})).then((()=>this.plugins.destroy())).then((()=>{this.model.destroy(),this.data.destroy(),this.editing.destroy(),this.keystrokes.destroy()})).then((()=>this._context._removeEditor(this)))}execute(e,...t){try{return this.commands.execute(e,...t)}catch(e){b.rethrowUnexpectedError(e,this)}}focus(){this.editing.view.focus()}}class qh{constructor(e){this.editor=e,this._components=new Map}*names(){for(const e of this._components.values())yield e.originalName}add(e,t){this._components.set(Uh(e),{callback:t,originalName:e})}create(e){if(!this.has(e))throw new b("componentfactory-item-missing",this,{name:e});return this._components.get(Uh(e)).callback(this.editor.locale)}has(e){return this._components.has(Uh(e))}}function Uh(e){return String(e).toLowerCase()}class Gh extends ys{constructor(e=[]){super(e,{idProperty:"viewUid"}),this.on("add",((e,t,i)=>{this._renderViewIntoCollectionParent(t,i)})),this.on("remove",((e,t)=>{t.element&&this._parentElement&&t.element.remove()})),this._parentElement=null}destroy(){this.map((e=>e.destroy()))}setParent(e){this._parentElement=e;for(const e of this)this._renderViewIntoCollectionParent(e)}delegate(...e){if(!e.length||!e.every((e=>"string"==typeof e)))throw new b("ui-viewcollection-delegate-wrong-events",this);return{to:t=>{for(const i of this)for(const n of e)i.delegate(n).to(t);this.on("add",((i,n)=>{for(const i of e)n.delegate(i).to(t)})),this.on("remove",((i,n)=>{for(const i of e)n.stopDelegating(i,t)}))}}}_renderViewIntoCollectionParent(e,t){e.isRendered||e.render(),e.element&&this._parentElement&&this._parentElement.insertBefore(e.element,this._parentElement.children[t])}}class Kh extends(S()){constructor(e){super(),Object.assign(this,su(nu(e))),this._isRendered=!1,this._revertData=null}render(){const e=this._renderNode({intoFragment:!0});return this._isRendered=!0,e}apply(e){return this._revertData={children:[],bindings:[],attributes:{}},this._renderNode({node:e,intoFragment:!1,isApplying:!0,revertData:this._revertData}),e}revert(e){if(!this._revertData)throw new b("ui-template-revert-not-applied",[this,e]);this._revertTemplateFromNode(e,this._revertData)}*getViews(){yield*function*e(t){if(t.children)for(const i of t.children)du(i)?yield i:hu(i)&&(yield*e(i))}(this)}static bind(e,t){return{to:(i,n)=>new Qh({eventNameOrFunction:i,attribute:i,observable:e,emitter:t,callback:n}),if:(i,n,s)=>new Yh({observable:e,emitter:t,attribute:i,valueIfTrue:n,callback:s})}}static extend(e,t){if(e._isRendered)throw new b("template-extend-render",[this,e]);lu(e,su(nu(t)))}_renderNode(e){let t;if(t=e.node?this.tag&&this.text:this.tag?this.text:!this.text,t)throw new b("ui-template-wrong-syntax",this);return this.text?this._renderText(e):this._renderElement(e)}_renderElement(e){let t=e.node;return t||(t=e.node=document.createElementNS(this.ns||"http://www.w3.org/1999/xhtml",this.tag)),this._renderAttributes(e),this._renderElementChildren(e),this._setUpListeners(e),t}_renderText(e){let t=e.node;return t?e.revertData.text=t.textContent:t=e.node=document.createTextNode(""),Xh(this.text)?this._bindToObservable({schema:this.text,updater:eu(t),data:e}):t.textContent=this.text.join(""),t}_renderAttributes(e){if(!this.attributes)return;const t=e.node,i=e.revertData;for(const n in this.attributes){const s=t.getAttribute(n),o=this.attributes[n];i&&(i.attributes[n]=s);const r=mu(o)?o[0].ns:null;if(Xh(o)){const a=mu(o)?o[0].value:o;i&&gu(n)&&a.unshift(s),this._bindToObservable({schema:a,updater:tu(t,n,r),data:e})}else if("style"==n&&"string"!=typeof o[0])this._renderStyleAttribute(o[0],e);else{i&&s&&gu(n)&&o.unshift(s);const e=o.map((e=>e&&e.value||e)).reduce(((e,t)=>e.concat(t)),[]).reduce(ru,"");cu(e)||t.setAttributeNS(r,n,e)}}}_renderStyleAttribute(e,t){const i=t.node;for(const n in e){const s=e[n];Xh(s)?this._bindToObservable({schema:[s],updater:iu(i,n),data:t}):i.style[n]=s}}_renderElementChildren(e){const t=e.node,i=e.intoFragment?document.createDocumentFragment():t,n=e.isApplying;let s=0;for(const o of this.children)if(uu(o)){if(!n){o.setParent(t);for(const e of o)i.appendChild(e.element)}}else if(du(o))n||(o.isRendered||o.render(),i.appendChild(o.element));else if(An(o))i.appendChild(o);else if(n){const t={children:[],bindings:[],attributes:{}};e.revertData.children.push(t),o._renderNode({intoFragment:!1,node:i.childNodes[s++],isApplying:!0,revertData:t})}else i.appendChild(o.render());e.intoFragment&&t.appendChild(i)}_setUpListeners(e){if(this.eventListeners)for(const t in this.eventListeners){const i=this.eventListeners[t].map((i=>{const[n,s]=t.split("@");return i.activateDomEventListener(n,s,e)}));e.revertData&&e.revertData.bindings.push(i)}}_bindToObservable({schema:e,updater:t,data:i}){const n=i.revertData;Zh(e,t,i);const s=e.filter((e=>!cu(e))).filter((e=>e.observable)).map((n=>n.activateAttributeListener(e,t,i)));n&&n.bindings.push(s)}_revertTemplateFromNode(e,t){for(const e of t.bindings)for(const t of e)t();if(t.text)return void(e.textContent=t.text);const i=e;for(const e in t.attributes){const n=t.attributes[e];null===n?i.removeAttribute(e):i.setAttribute(e,n)}for(let e=0;eZh(e,t,i);return this.emitter.listenTo(this.observable,`change:${this.attribute}`,n),()=>{this.emitter.stopListening(this.observable,`change:${this.attribute}`,n)}}}class Qh extends Jh{constructor(e){super(e),this.eventNameOrFunction=e.eventNameOrFunction}activateDomEventListener(e,t,i){const n=(e,i)=>{t&&!i.target.matches(t)||("function"==typeof this.eventNameOrFunction?this.eventNameOrFunction(i):this.observable.fire(this.eventNameOrFunction,i))};return this.emitter.listenTo(i.node,e,n),()=>{this.emitter.stopListening(i.node,e,n)}}}class Yh extends Jh{constructor(e){super(e),this.valueIfTrue=e.valueIfTrue}getValue(e){return!cu(super.getValue(e))&&(this.valueIfTrue||!0)}}function Xh(e){return!!e&&(e.value&&(e=e.value),Array.isArray(e)?e.some(Xh):e instanceof Jh)}function Zh(e,t,{node:i}){const n=function(e,t){return e.map((e=>e instanceof Jh?e.getValue(t):e))}(e,i);let s;s=1==e.length&&e[0]instanceof Yh?n[0]:n.reduce(ru,""),cu(s)?t.remove():t.set(s)}function eu(e){return{set(t){e.textContent=t},remove(){e.textContent=""}}}function tu(e,t,i){return{set(n){e.setAttributeNS(i,t,n)},remove(){e.removeAttributeNS(i,t)}}}function iu(e,t){return{set(i){e.style[t]=i},remove(){e.style[t]=null}}}function nu(e){return vn(e,(e=>{if(e&&(e instanceof Jh||hu(e)||du(e)||uu(e)))return e}))}function su(e){if("string"==typeof e?e=function(e){return{text:[e]}}(e):e.text&&function(e){e.text=ps(e.text)}(e),e.on&&(e.eventListeners=function(e){for(const t in e)ou(e,t);return e}(e.on),delete e.on),!e.text){e.attributes&&function(e){for(const t in e)e[t].value&&(e[t].value=ps(e[t].value)),ou(e,t)}(e.attributes);const t=[];if(e.children)if(uu(e.children))t.push(e.children);else for(const i of e.children)hu(i)||du(i)||An(i)?t.push(i):t.push(new Kh(i));e.children=t}return e}function ou(e,t){e[t]=ps(e[t])}function ru(e,t){return cu(t)?e:cu(e)?t:`${e} ${t}`}function au(e,t){for(const i in t)e[i]?e[i].push(...t[i]):e[i]=t[i]}function lu(e,t){if(t.attributes&&(e.attributes||(e.attributes={}),au(e.attributes,t.attributes)),t.eventListeners&&(e.eventListeners||(e.eventListeners={}),au(e.eventListeners,t.eventListeners)),t.text&&e.text.push(...t.text),t.children&&t.children.length){if(e.children.length!=t.children.length)throw new b("ui-template-extend-children-mismatch",e);let i=0;for(const n of t.children)lu(e.children[i++],n)}}function cu(e){return!e&&0!==e}function du(e){return e instanceof fu}function hu(e){return e instanceof Kh}function uu(e){return e instanceof Gh}function mu(e){return M(e[0])&&e[0].ns}function gu(e){return"class"==e||"style"==e}class fu extends(En(W())){constructor(e){super(),this.element=null,this.isRendered=!1,this.locale=e,this.t=e&&e.t,this._viewCollections=new ys,this._unboundChildren=this.createCollection(),this._viewCollections.on("add",((t,i)=>{i.locale=e,i.t=e&&e.t})),this.decorate("render")}get bindTemplate(){return this._bindTemplate?this._bindTemplate:this._bindTemplate=Kh.bind(this,this)}createCollection(e){const t=new Gh(e);return this._viewCollections.add(t),t}registerChild(e){X(e)||(e=[e]);for(const t of e)this._unboundChildren.add(t)}deregisterChild(e){X(e)||(e=[e]);for(const t of e)this._unboundChildren.remove(t)}setTemplate(e){this.template=new Kh(e)}extendTemplate(e){Kh.extend(this.template,e)}render(){if(this.isRendered)throw new b("ui-view-render-already-rendered",this);this.template&&(this.element=this.template.render(),this.registerChild(this.template.getViews())),this.isRendered=!0}destroy(){this.stopListening(),this._viewCollections.map((e=>e.destroy())),this.template&&this.template._revertData&&this.template.revert(this.element)}}const pu=Wn("px"),wu=Rn.document.body;class bu extends fu{constructor(e){super(e);const t=this.bindTemplate;this.set("top",0),this.set("left",0),this.set("position","arrow_nw"),this.set("isVisible",!1),this.set("withArrow",!0),this.set("class",void 0),this._pinWhenIsVisibleCallback=null,this.content=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-balloon-panel",t.to("position",(e=>`ck-balloon-panel_${e}`)),t.if("isVisible","ck-balloon-panel_visible"),t.if("withArrow","ck-balloon-panel_with-arrow"),t.to("class")],style:{top:t.to("top",pu),left:t.to("left",pu)}},children:this.content})}show(){this.isVisible=!0}hide(){this.isVisible=!1}attachTo(e){this.show();const t=bu.defaultPositions,i=Object.assign({},{element:this.element,positions:[t.southArrowNorth,t.southArrowNorthMiddleWest,t.southArrowNorthMiddleEast,t.southArrowNorthWest,t.southArrowNorthEast,t.northArrowSouth,t.northArrowSouthMiddleWest,t.northArrowSouthMiddleEast,t.northArrowSouthWest,t.northArrowSouthEast,t.viewportStickyNorth],limiter:wu,fitInViewport:!0},e),n=bu._getOptimalPosition(i),s=parseInt(n.left),o=parseInt(n.top),r=n.name,a=n.config||{},{withArrow:l=!0}=a;this.top=o,this.left=s,this.position=r,this.withArrow=l}pin(e){this.unpin(),this._pinWhenIsVisibleCallback=()=>{this.isVisible?this._startPinning(e):this._stopPinning()},this._startPinning(e),this.listenTo(this,"change:isVisible",this._pinWhenIsVisibleCallback)}unpin(){this._pinWhenIsVisibleCallback&&(this._stopPinning(),this.stopListening(this,"change:isVisible",this._pinWhenIsVisibleCallback),this._pinWhenIsVisibleCallback=null,this.hide())}_startPinning(e){this.attachTo(e);const t=vu(e.target),i=e.limiter?vu(e.limiter):wu;this.listenTo(Rn.document,"scroll",((n,s)=>{const o=s.target,r=t&&o.contains(t),a=i&&o.contains(i);!r&&!a&&t&&i||this.attachTo(e)}),{useCapture:!0}),this.listenTo(Rn.window,"resize",(()=>{this.attachTo(e)}))}_stopPinning(){this.stopListening(Rn.document,"scroll"),this.stopListening(Rn.window,"resize")}}function vu(e){return _n(e)?e:On(e)?e.commonAncestorContainer:"function"==typeof e?vu(e()):null}function _u(e={}){const{sideOffset:t=bu.arrowSideOffset,heightOffset:i=bu.arrowHeightOffset,stickyVerticalOffset:n=bu.stickyVerticalOffset,config:s}=e;return{northWestArrowSouthWest:(e,i)=>({top:o(e,i),left:e.left-t,name:"arrow_sw",...s&&{config:s}}),northWestArrowSouthMiddleWest:(e,i)=>({top:o(e,i),left:e.left-.25*i.width-t,name:"arrow_smw",...s&&{config:s}}),northWestArrowSouth:(e,t)=>({top:o(e,t),left:e.left-t.width/2,name:"arrow_s",...s&&{config:s}}),northWestArrowSouthMiddleEast:(e,i)=>({top:o(e,i),left:e.left-.75*i.width+t,name:"arrow_sme",...s&&{config:s}}),northWestArrowSouthEast:(e,i)=>({top:o(e,i),left:e.left-i.width+t,name:"arrow_se",...s&&{config:s}}),northArrowSouthWest:(e,i)=>({top:o(e,i),left:e.left+e.width/2-t,name:"arrow_sw",...s&&{config:s}}),northArrowSouthMiddleWest:(e,i)=>({top:o(e,i),left:e.left+e.width/2-.25*i.width-t,name:"arrow_smw",...s&&{config:s}}),northArrowSouth:(e,t)=>({top:o(e,t),left:e.left+e.width/2-t.width/2,name:"arrow_s",...s&&{config:s}}),northArrowSouthMiddleEast:(e,i)=>({top:o(e,i),left:e.left+e.width/2-.75*i.width+t,name:"arrow_sme",...s&&{config:s}}),northArrowSouthEast:(e,i)=>({top:o(e,i),left:e.left+e.width/2-i.width+t,name:"arrow_se",...s&&{config:s}}),northEastArrowSouthWest:(e,i)=>({top:o(e,i),left:e.right-t,name:"arrow_sw",...s&&{config:s}}),northEastArrowSouthMiddleWest:(e,i)=>({top:o(e,i),left:e.right-.25*i.width-t,name:"arrow_smw",...s&&{config:s}}),northEastArrowSouth:(e,t)=>({top:o(e,t),left:e.right-t.width/2,name:"arrow_s",...s&&{config:s}}),northEastArrowSouthMiddleEast:(e,i)=>({top:o(e,i),left:e.right-.75*i.width+t,name:"arrow_sme",...s&&{config:s}}),northEastArrowSouthEast:(e,i)=>({top:o(e,i),left:e.right-i.width+t,name:"arrow_se",...s&&{config:s}}),southWestArrowNorthWest:e=>({top:r(e),left:e.left-t,name:"arrow_nw",...s&&{config:s}}),southWestArrowNorthMiddleWest:(e,i)=>({top:r(e),left:e.left-.25*i.width-t,name:"arrow_nmw",...s&&{config:s}}),southWestArrowNorth:(e,t)=>({top:r(e),left:e.left-t.width/2,name:"arrow_n",...s&&{config:s}}),southWestArrowNorthMiddleEast:(e,i)=>({top:r(e),left:e.left-.75*i.width+t,name:"arrow_nme",...s&&{config:s}}),southWestArrowNorthEast:(e,i)=>({top:r(e),left:e.left-i.width+t,name:"arrow_ne",...s&&{config:s}}),southArrowNorthWest:e=>({top:r(e),left:e.left+e.width/2-t,name:"arrow_nw",...s&&{config:s}}),southArrowNorthMiddleWest:(e,i)=>({top:r(e),left:e.left+e.width/2-.25*i.width-t,name:"arrow_nmw",...s&&{config:s}}),southArrowNorth:(e,t)=>({top:r(e),left:e.left+e.width/2-t.width/2,name:"arrow_n",...s&&{config:s}}),southArrowNorthMiddleEast:(e,i)=>({top:r(e),left:e.left+e.width/2-.75*i.width+t,name:"arrow_nme",...s&&{config:s}}),southArrowNorthEast:(e,i)=>({top:r(e),left:e.left+e.width/2-i.width+t,name:"arrow_ne",...s&&{config:s}}),southEastArrowNorthWest:e=>({top:r(e),left:e.right-t,name:"arrow_nw",...s&&{config:s}}),southEastArrowNorthMiddleWest:(e,i)=>({top:r(e),left:e.right-.25*i.width-t,name:"arrow_nmw",...s&&{config:s}}),southEastArrowNorth:(e,t)=>({top:r(e),left:e.right-t.width/2,name:"arrow_n",...s&&{config:s}}),southEastArrowNorthMiddleEast:(e,i)=>({top:r(e),left:e.right-.75*i.width+t,name:"arrow_nme",...s&&{config:s}}),southEastArrowNorthEast:(e,i)=>({top:r(e),left:e.right-i.width+t,name:"arrow_ne",...s&&{config:s}}),westArrowEast:(e,t)=>({top:e.top+e.height/2-t.height/2,left:e.left-t.width-i,name:"arrow_e",...s&&{config:s}}),eastArrowWest:(e,t)=>({top:e.top+e.height/2-t.height/2,left:e.right+i,name:"arrow_w",...s&&{config:s}}),viewportStickyNorth:(e,t,i)=>e.getIntersection(i)?{top:i.top+n,left:e.left+e.width/2-t.width/2,name:"arrowless",config:{withArrow:!1,...s}}:null};function o(e,t){return e.top-t.height-i}function r(e){return e.bottom+i}}bu.arrowSideOffset=25,bu.arrowHeightOffset=10,bu.stickyVerticalOffset=20,bu._getOptimalPosition=Kn,bu.defaultPositions=_u();const yu="ck-tooltip";class ku extends(En()){constructor(e){if(super(),ku._editors.add(e),ku._instance)return ku._instance;ku._instance=this,this.tooltipTextView=new fu(e.locale),this.tooltipTextView.set("text",""),this.tooltipTextView.setTemplate({tag:"span",attributes:{class:["ck","ck-tooltip__text"]},children:[{text:this.tooltipTextView.bindTemplate.to("text")}]}),this.balloonPanelView=new bu(e.locale),this.balloonPanelView.class=yu,this.balloonPanelView.content.add(this.tooltipTextView),this._resizeObserver=null,this._currentElementWithTooltip=null,this._currentTooltipPosition=null,this._pinTooltipDebounced=xa(this._pinTooltip,600),this.listenTo(Rn.document,"mouseenter",this._onEnterOrFocus.bind(this),{useCapture:!0}),this.listenTo(Rn.document,"mouseleave",this._onLeaveOrBlur.bind(this),{useCapture:!0}),this.listenTo(Rn.document,"focus",this._onEnterOrFocus.bind(this),{useCapture:!0}),this.listenTo(Rn.document,"blur",this._onLeaveOrBlur.bind(this),{useCapture:!0}),this.listenTo(Rn.document,"scroll",this._onScroll.bind(this),{useCapture:!0}),this._watchdogExcluded=!0}destroy(e){const t=e.ui.view&&e.ui.view.body;ku._editors.delete(e),this.stopListening(e.ui),t&&t.has(this.balloonPanelView)&&t.remove(this.balloonPanelView),ku._editors.size||(this._unpinTooltip(),this.balloonPanelView.destroy(),this.stopListening(),ku._instance=null)}static getPositioningFunctions(e){const t=ku.defaultBalloonPositions;return{s:[t.southArrowNorth,t.southArrowNorthEast,t.southArrowNorthWest],n:[t.northArrowSouth],e:[t.eastArrowWest],w:[t.westArrowEast],sw:[t.southArrowNorthEast],se:[t.southArrowNorthWest]}[e]}_onEnterOrFocus(e,{target:t}){const i=Cu(t);var n;i&&(i!==this._currentElementWithTooltip&&(this._unpinTooltip(),this._pinTooltipDebounced(i,{text:(n=i).dataset.ckeTooltipText,position:n.dataset.ckeTooltipPosition||"s",cssClass:n.dataset.ckeTooltipClass||""})))}_onLeaveOrBlur(e,{target:t,relatedTarget:i}){if("mouseleave"===e.name){if(!_n(t))return;if(this._currentElementWithTooltip&&t!==this._currentElementWithTooltip)return;const e=Cu(t),n=Cu(i);e&&e!==n&&this._unpinTooltip()}else{if(this._currentElementWithTooltip&&t!==this._currentElementWithTooltip)return;this._unpinTooltip()}}_onScroll(e,{target:t}){this._currentElementWithTooltip&&(t.contains(this.balloonPanelView.element)&&t.contains(this._currentElementWithTooltip)||this._unpinTooltip())}_pinTooltip(e,{text:t,position:i,cssClass:n}){const s=ks(ku._editors.values()).ui.view.body;s.has(this.balloonPanelView)||s.add(this.balloonPanelView),this.tooltipTextView.text=t,this.balloonPanelView.pin({target:e,positions:ku.getPositioningFunctions(i)}),this._resizeObserver=new Hn(e,(()=>{Gn(e)||this._unpinTooltip()})),this.balloonPanelView.class=[yu,n].filter((e=>e)).join(" ");for(const e of ku._editors)this.listenTo(e.ui,"update",this._updateTooltipPosition.bind(this),{priority:"low"});this._currentElementWithTooltip=e,this._currentTooltipPosition=i}_unpinTooltip(){this._pinTooltipDebounced.cancel(),this.balloonPanelView.unpin();for(const e of ku._editors)this.stopListening(e.ui,"update");this._currentElementWithTooltip=null,this._currentTooltipPosition=null,this._resizeObserver&&this._resizeObserver.destroy()}_updateTooltipPosition(){Gn(this._currentElementWithTooltip)?this.balloonPanelView.pin({target:this._currentElementWithTooltip,positions:ku.getPositioningFunctions(this._currentTooltipPosition)}):this._unpinTooltip()}}function Cu(e){return _n(e)?e.closest("[data-cke-tooltip-text]:not([data-cke-tooltip-disabled])"):null}ku.defaultBalloonPositions=_u({heightOffset:5,sideOffset:13}),ku._editors=new Set,ku._instance=null;class Au extends(W()){constructor(e){super(),this.editor=e,this.componentFactory=new qh(e),this.focusTracker=new Cs,this.tooltipManager=new ku(e),this.set("viewportOffset",this._readViewportOffsetFromConfig()),this.isReady=!1,this.once("ready",(()=>{this.isReady=!0})),this._editableElementsMap=new Map,this._focusableToolbarDefinitions=[],this.listenTo(e.editing.view.document,"layoutChanged",(()=>this.update())),this._initFocusTracking()}get element(){return null}update(){this.fire("update")}destroy(){this.stopListening(),this.focusTracker.destroy(),this.tooltipManager.destroy(this.editor);for(const e of this._editableElementsMap.values())e.ckeditorInstance=null;this._editableElementsMap=new Map,this._focusableToolbarDefinitions=[]}setEditableElement(e,t){this._editableElementsMap.set(e,t),t.ckeditorInstance||(t.ckeditorInstance=this.editor),this.focusTracker.add(t);const i=()=>{this.editor.editing.view.getDomRoot(e)||this.editor.keystrokes.listenTo(t)};this.isReady?i():this.once("ready",i)}getEditableElement(e="main"){return this._editableElementsMap.get(e)}getEditableElementsNames(){return this._editableElementsMap.keys()}addToolbar(e,t={}){e.isRendered?(this.focusTracker.add(e.element),this.editor.keystrokes.listenTo(e.element)):e.once("render",(()=>{this.focusTracker.add(e.element),this.editor.keystrokes.listenTo(e.element)})),this._focusableToolbarDefinitions.push({toolbarView:e,options:t})}get _editableElements(){return console.warn("editor-ui-deprecated-editable-elements: The EditorUI#_editableElements property has been deprecated and will be removed in the near future.",{editorUI:this}),this._editableElementsMap}_readViewportOffsetFromConfig(){const e=this.editor,t=e.config.get("ui.viewportOffset");if(t)return t;const i=e.config.get("toolbar.viewportTopOffset");return i?(console.warn("editor-ui-deprecated-viewport-offset-config: The `toolbar.vieportTopOffset` configuration option is deprecated. It will be removed from future CKEditor versions. Use `ui.viewportOffset.top` instead."),{top:i}):{top:0}}_initFocusTracking(){const e=this.editor,t=e.editing.view;let i,n;e.keystrokes.set("Alt+F10",((e,s)=>{const o=this.focusTracker.focusedElement;Array.from(this._editableElementsMap.values()).includes(o)&&!Array.from(t.domRoots.values()).includes(o)&&(i=o);const r=this._getCurrentFocusedToolbarDefinition();r&&n||(n=this._getFocusableCandidateToolbarDefinitions());for(let e=0;e{const s=this._getCurrentFocusedToolbarDefinition();s&&(i?(i.focus(),i=null):e.editing.view.focus(),s.options.afterBlur&&s.options.afterBlur(),n())}))}_getFocusableCandidateToolbarDefinitions(){const e=[];for(const t of this._focusableToolbarDefinitions){const{toolbarView:i,options:n}=t;(Gn(i.element)||n.beforeFocus)&&e.push(t)}return e.sort(((e,t)=>xu(e)-xu(t))),e}_getCurrentFocusedToolbarDefinition(){for(const e of this._focusableToolbarDefinitions)if(e.toolbarView.element&&e.toolbarView.element.contains(this.focusTracker.focusedElement))return e;return null}_focusFocusableCandidateToolbar(e){const{toolbarView:t,options:{beforeFocus:i}}=e;return i&&i(),!!Gn(t.element)&&(t.focus(),!0)}}function xu(e){const{toolbarView:t,options:i}=e;let n=10;return Gn(t.element)&&n--,i.isContextual&&n--,n}function Tu(e){return class extends e{setData(e){this.data.set(e)}getData(e){return this.data.get(e)}}}{const e=Tu(Object);Tu.setData=e.prototype.setData,Tu.getData=e.prototype.getData}function Eu(e){return class extends e{updateSourceElement(e=this.data.get()){if(!this.sourceElement)throw new b("editor-missing-sourceelement",this);const t=this.config.get("updateSourceElementOnDestroy"),i=this.sourceElement instanceof HTMLTextAreaElement;$n(this.sourceElement,t||i?e:"")}}}Eu.updateSourceElement=Eu(Object).prototype.updateSourceElement;class Su extends Ns{static get pluginName(){return"PendingActions"}init(){this.set("hasAny",!1),this._actions=new ys({idProperty:"_id"}),this._actions.delegate("add","remove").to(this)}add(e){if("string"!=typeof e)throw new b("pendingactions-add-invalid-message",this);const t=new(W());return t.set("message",e),this._actions.add(t),this.hasAny=!0,t}remove(e){this._actions.remove(e),this.hasAny=!!this._actions.length}get first(){return this._actions.get(0)}[Symbol.iterator](){return this._actions[Symbol.iterator]()}}const Pu={bold:'',cancel:'',caption:'',check:'',cog:'',eraser:'',image:'',lowVision:'',importExport:'',paragraph:'',plus:'',text:'',alignBottom:'',alignMiddle:'',alignTop:'',alignLeft:'',alignCenter:'',alignRight:'',alignJustify:'',objectLeft:'',objectCenter:'',objectRight:'',objectFullWidth:'',objectInline:'',objectBlockLeft:'',objectBlockRight:'',objectSizeFull:'',objectSizeLarge:'',objectSizeSmall:'',objectSizeMedium:'',pencil:'',pilcrow:'',quote:'',threeVerticalDots:''};function Iu({emitter:e,activator:t,callback:i,contextElements:n}){e.listenTo(document,"mousedown",((e,s)=>{if(!t())return;const o="function"==typeof s.composedPath?s.composedPath():[];for(const e of n)if(e.contains(s.target)||o.includes(e))return;i()}))}function Ru(e){const t=e;t.set("_isCssTransitionsDisabled",!1),t.disableCssTransitions=()=>{t._isCssTransitionsDisabled=!0},t.enableCssTransitions=()=>{t._isCssTransitionsDisabled=!1},t.extendTemplate({attributes:{class:[t.bindTemplate.if("_isCssTransitionsDisabled","ck-transitions-disabled")]}})}function Vu({view:e}){e.listenTo(e.element,"submit",((t,i)=>{i.preventDefault(),e.fire("submit")}),{useCapture:!0})}function Lu({keystrokeHandler:e,focusTracker:t,gridItems:i,numberOfColumns:n,uiLanguageDirection:s}){const o="number"==typeof n?()=>n:n;function r(e){return n=>{const s=i.find((e=>e.element===t.focusedElement)),o=i.getIndex(s),r=e(o,i);i.get(r).focus(),n.stopPropagation(),n.preventDefault()}}function a(e,t){return e===t-1?0:e+1}function l(e,t){return 0===e?t-1:e-1}e.set("arrowright",r(((e,t)=>"rtl"===s?l(e,t.length):a(e,t.length)))),e.set("arrowleft",r(((e,t)=>"rtl"===s?a(e,t.length):l(e,t.length)))),e.set("arrowup",r(((e,t)=>{let i=e-o();return i<0&&(i=e+o()*Math.floor(t.length/o()),i>t.length-1&&(i-=o())),i}))),e.set("arrowdown",r(((e,t)=>{let i=e+o();return i>t.length-1&&(i=e%o()),i})))}class Ou extends Gh{constructor(e,t=[]){super(t),this.locale=e}attachToDom(){this._bodyCollectionContainer=new Kh({tag:"div",attributes:{class:["ck","ck-reset_all","ck-body","ck-rounded-corners"],dir:this.locale.uiLanguageDirection},children:this}).render();let e=document.querySelector(".ck-body-wrapper");e||(e=fe(document,"div",{class:"ck-body-wrapper"}),document.body.appendChild(e)),e.appendChild(this._bodyCollectionContainer)}detachFromDom(){super.destroy(),this._bodyCollectionContainer&&this._bodyCollectionContainer.remove();const e=document.querySelector(".ck-body-wrapper");e&&0==e.childElementCount&&e.remove()}}class Bu extends fu{constructor(){super();const e=this.bindTemplate;this.set("content",""),this.set("viewBox","0 0 20 20"),this.set("fillColor",""),this.set("isColorInherited",!0),this.setTemplate({tag:"svg",ns:"http://www.w3.org/2000/svg",attributes:{class:["ck","ck-icon","ck-reset_all-excluded",e.if("isColorInherited","ck-icon_inherit-color")],viewBox:e.to("viewBox")}})}render(){super.render(),this._updateXMLContent(),this._colorFillPaths(),this.on("change:content",(()=>{this._updateXMLContent(),this._colorFillPaths()})),this.on("change:fillColor",(()=>{this._colorFillPaths()}))}_updateXMLContent(){if(this.content){const e=(new DOMParser).parseFromString(this.content.trim(),"image/svg+xml").querySelector("svg"),t=e.getAttribute("viewBox");t&&(this.viewBox=t);for(const{name:t,value:i}of Array.from(e.attributes))Bu.presentationalAttributeNames.includes(t)&&this.element.setAttribute(t,i);for(;this.element.firstChild;)this.element.removeChild(this.element.firstChild);for(;e.childNodes.length>0;)this.element.appendChild(e.childNodes[0])}}_colorFillPaths(){this.fillColor&&this.element.querySelectorAll(".ck-icon__fill").forEach((e=>{e.style.fill=this.fillColor}))}}Bu.presentationalAttributeNames=["alignment-baseline","baseline-shift","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-rendering","cursor","direction","display","dominant-baseline","fill","fill-opacity","fill-rule","filter","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","image-rendering","letter-spacing","lighting-color","marker-end","marker-mid","marker-start","mask","opacity","overflow","paint-order","pointer-events","shape-rendering","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-anchor","text-decoration","text-overflow","text-rendering","transform","unicode-bidi","vector-effect","visibility","white-space","word-spacing","writing-mode"];class Mu extends fu{constructor(e){super(e);const t=this.bindTemplate,i=g();this.set("class",void 0),this.set("labelStyle",void 0),this.set("icon",void 0),this.set("isEnabled",!0),this.set("isOn",!1),this.set("isVisible",!0),this.set("isToggleable",!1),this.set("keystroke",void 0),this.set("label",void 0),this.set("tabindex",-1),this.set("tooltip",!1),this.set("tooltipPosition","s"),this.set("type","button"),this.set("withText",!1),this.set("withKeystroke",!1),this.children=this.createCollection(),this.labelView=this._createLabelView(i),this.iconView=new Bu,this.iconView.extendTemplate({attributes:{class:"ck-button__icon"}}),this.keystrokeView=this._createKeystrokeView(),this.bind("_tooltipString").to(this,"tooltip",this,"label",this,"keystroke",this._getTooltipString.bind(this));const n={tag:"button",attributes:{class:["ck","ck-button",t.to("class"),t.if("isEnabled","ck-disabled",(e=>!e)),t.if("isVisible","ck-hidden",(e=>!e)),t.to("isOn",(e=>e?"ck-on":"ck-off")),t.if("withText","ck-button_with-text"),t.if("withKeystroke","ck-button_with-keystroke")],type:t.to("type",(e=>e||"button")),tabindex:t.to("tabindex"),"aria-labelledby":`ck-editor__aria-label_${i}`,"aria-disabled":t.if("isEnabled",!0,(e=>!e)),"aria-pressed":t.to("isOn",(e=>!!this.isToggleable&&String(!!e))),"data-cke-tooltip-text":t.to("_tooltipString"),"data-cke-tooltip-position":t.to("tooltipPosition")},children:this.children,on:{click:t.to((e=>{this.isEnabled?this.fire("execute"):e.preventDefault()}))}};s.isSafari&&(n.on.mousedown=t.to((e=>{this.focus(),e.preventDefault()}))),this.setTemplate(n)}render(){super.render(),this.icon&&(this.iconView.bind("content").to(this,"icon"),this.children.add(this.iconView)),this.children.add(this.labelView),this.withKeystroke&&this.keystroke&&this.children.add(this.keystrokeView)}focus(){this.element.focus()}_createLabelView(e){const t=new fu,i=this.bindTemplate;return t.setTemplate({tag:"span",attributes:{class:["ck","ck-button__label"],style:i.to("labelStyle"),id:`ck-editor__aria-label_${e}`},children:[{text:this.bindTemplate.to("label")}]}),t}_createKeystrokeView(){const e=new fu;return e.setTemplate({tag:"span",attributes:{class:["ck","ck-button__keystroke"]},children:[{text:this.bindTemplate.to("keystroke",(e=>gs(e)))}]}),e}_getTooltipString(e,t,i){return e?"string"==typeof e?e:(i&&(i=gs(i)),e instanceof Function?e(t,i):`${t}${i?` (${i})`:""}`):""}}class Nu extends Mu{constructor(e){super(e),this.isToggleable=!0,this.toggleSwitchView=this._createToggleView(),this.extendTemplate({attributes:{class:"ck-switchbutton"}})}render(){super.render(),this.children.add(this.toggleSwitchView)}_createToggleView(){const e=new fu;return e.setTemplate({tag:"span",attributes:{class:["ck","ck-button__toggle"]},children:[{tag:"span",attributes:{class:["ck","ck-button__toggle__inner"]}}]}),e}}function Du(e,t){const i=e.t,n={Black:i("Black"),"Dim grey":i("Dim grey"),Grey:i("Grey"),"Light grey":i("Light grey"),White:i("White"),Red:i("Red"),Orange:i("Orange"),Yellow:i("Yellow"),"Light green":i("Light green"),Green:i("Green"),Aquamarine:i("Aquamarine"),Turquoise:i("Turquoise"),"Light blue":i("Light blue"),Blue:i("Blue"),Purple:i("Purple")};return t.map((e=>{const t=n[e.label];return t&&t!=e.label&&(e.label=t),e}))}function Fu(e){return e.map(zu).filter((e=>!!e))}function zu(e){return"string"==typeof e?{model:e,label:e,hasBorder:!1,view:{name:"span",styles:{color:e}}}:{model:e.color,label:e.label||e.color,hasBorder:void 0!==e.hasBorder&&e.hasBorder,view:{name:"span",styles:{color:`${e.color}`}}}}class Hu extends Mu{constructor(e){super(e);const t=this.bindTemplate;this.set("color",void 0),this.set("hasBorder",!1),this.icon='',this.extendTemplate({attributes:{style:{backgroundColor:t.to("color")},class:["ck","ck-color-grid__tile",t.if("hasBorder","ck-color-table__color-tile_bordered")]}})}render(){super.render(),this.iconView.fillColor="hsl(0, 0%, 100%)"}}class $u extends fu{constructor(e,t){super(e);const i=t&&t.colorDefinitions||[];this.columns=t&&t.columns?t.columns:5;const n={gridTemplateColumns:`repeat( ${this.columns}, 1fr)`};this.set("selectedColor",void 0),this.items=this.createCollection(),this.focusTracker=new Cs,this.keystrokes=new As,this.items.on("add",((e,t)=>{t.isOn=t.color===this.selectedColor})),i.forEach((e=>{const t=new Hu;t.set({color:e.color,label:e.label,tooltip:!0,hasBorder:e.options.hasBorder}),t.on("execute",(()=>{this.fire("execute",{value:e.color,hasBorder:e.options.hasBorder,label:e.label})})),this.items.add(t)})),this.setTemplate({tag:"div",children:this.items,attributes:{class:["ck","ck-color-grid"],style:n}}),this.on("change:selectedColor",((e,t,i)=>{for(const e of this.items)e.isOn=e.color===i}))}focus(){this.items.length&&this.items.first.focus()}focusLast(){this.items.length&&this.items.last.focus()}render(){super.render();for(const e of this.items)this.focusTracker.add(e.element);this.items.on("add",((e,t)=>{this.focusTracker.add(t.element)})),this.items.on("remove",((e,t)=>{this.focusTracker.remove(t.element)})),this.keystrokes.listenTo(this.element),Lu({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.items,numberOfColumns:this.columns,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection})}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}}const Wu='';class ju extends Mu{constructor(e){super(e),this.arrowView=this._createArrowView(),this.extendTemplate({attributes:{"aria-haspopup":!0,"aria-expanded":this.bindTemplate.to("isOn",(e=>String(e)))}}),this.delegate("execute").to(this,"open")}render(){super.render(),this.children.add(this.arrowView)}_createArrowView(){const e=new Bu;return e.content=Wu,e.extendTemplate({attributes:{class:"ck-dropdown__arrow"}}),e}}class qu extends fu{constructor(e){super(e);const t=this.bindTemplate;this.set("class",void 0),this.set("labelStyle",void 0),this.set("icon",void 0),this.set("isEnabled",!0),this.set("isOn",!1),this.set("isToggleable",!1),this.set("isVisible",!0),this.set("keystroke",void 0),this.set("withKeystroke",!1),this.set("label",void 0),this.set("tabindex",-1),this.set("tooltip",!1),this.set("tooltipPosition","s"),this.set("type","button"),this.set("withText",!1),this.children=this.createCollection(),this.actionView=this._createActionView(),this.arrowView=this._createArrowView(),this.keystrokes=new As,this.focusTracker=new Cs,this.setTemplate({tag:"div",attributes:{class:["ck","ck-splitbutton",t.to("class"),t.if("isVisible","ck-hidden",(e=>!e)),this.arrowView.bindTemplate.if("isOn","ck-splitbutton_open")]},children:this.children})}render(){super.render(),this.children.add(this.actionView),this.children.add(this.arrowView),this.focusTracker.add(this.actionView.element),this.focusTracker.add(this.arrowView.element),this.keystrokes.listenTo(this.element),this.keystrokes.set("arrowright",((e,t)=>{this.focusTracker.focusedElement===this.actionView.element&&(this.arrowView.focus(),t())})),this.keystrokes.set("arrowleft",((e,t)=>{this.focusTracker.focusedElement===this.arrowView.element&&(this.actionView.focus(),t())}))}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.actionView.focus()}_createActionView(){const e=new Mu;return e.bind("icon","isEnabled","isOn","isToggleable","keystroke","label","tabindex","tooltip","tooltipPosition","type","withText").to(this),e.extendTemplate({attributes:{class:"ck-splitbutton__action"}}),e.delegate("execute").to(this),e}_createArrowView(){const e=new Mu,t=e.bindTemplate;return e.icon=Wu,e.extendTemplate({attributes:{class:["ck-splitbutton__arrow"],"data-cke-tooltip-disabled":t.to("isOn"),"aria-haspopup":!0,"aria-expanded":t.to("isOn",(e=>String(e)))}}),e.bind("isEnabled").to(this),e.bind("label").to(this),e.bind("tooltip").to(this),e.delegate("execute").to(this,"open"),e}}class Uu extends fu{constructor(e){super(e);const t=this.bindTemplate;this.set("isVisible",!1),this.set("position","se"),this.children=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-reset","ck-dropdown__panel",t.to("position",(e=>`ck-dropdown__panel_${e}`)),t.if("isVisible","ck-dropdown__panel-visible")]},children:this.children,on:{selectstart:t.to((e=>e.preventDefault()))}})}focus(){if(this.children.length){const e=this.children.first;"function"==typeof e.focus?e.focus():v("ui-dropdown-panel-focus-child-missing-focus",{childView:this.children.first,dropdownPanel:this})}}focusLast(){if(this.children.length){const e=this.children.last;"function"==typeof e.focusLast?e.focusLast():e.focus()}}}class Gu extends fu{constructor(e,t,i){super(e);const n=this.bindTemplate;this.buttonView=t,this.panelView=i,this.set("isOpen",!1),this.set("isEnabled",!0),this.set("class",void 0),this.set("id",void 0),this.set("panelPosition","auto"),this.keystrokes=new As,this.focusTracker=new Cs,this.setTemplate({tag:"div",attributes:{class:["ck","ck-dropdown",n.to("class"),n.if("isEnabled","ck-disabled",(e=>!e))],id:n.to("id"),"aria-describedby":n.to("ariaDescribedById")},children:[t,i]}),t.extendTemplate({attributes:{class:["ck-dropdown__button"],"data-cke-tooltip-disabled":n.to("isOpen")}})}render(){super.render(),this.focusTracker.add(this.buttonView.element),this.focusTracker.add(this.panelView.element),this.listenTo(this.buttonView,"open",(()=>{this.isOpen=!this.isOpen})),this.panelView.bind("isVisible").to(this,"isOpen"),this.on("change:isOpen",((e,t,i)=>{i&&("auto"===this.panelPosition?this.panelView.position=Gu._getOptimalPosition({element:this.panelView.element,target:this.buttonView.element,fitInViewport:!0,positions:this._panelPositions}).name:this.panelView.position=this.panelPosition)})),this.keystrokes.listenTo(this.element);const e=(e,t)=>{this.isOpen&&(this.isOpen=!1,t())};this.keystrokes.set("arrowdown",((e,t)=>{this.buttonView.isEnabled&&!this.isOpen&&(this.isOpen=!0,t())})),this.keystrokes.set("arrowright",((e,t)=>{this.isOpen&&t()})),this.keystrokes.set("arrowleft",e),this.keystrokes.set("esc",e)}focus(){this.buttonView.focus()}get _panelPositions(){const{south:e,north:t,southEast:i,southWest:n,northEast:s,northWest:o,southMiddleEast:r,southMiddleWest:a,northMiddleEast:l,northMiddleWest:c}=Gu.defaultPanelPositions;return"rtl"!==this.locale.uiLanguageDirection?[i,n,r,a,e,s,o,l,c,t]:[n,i,a,r,e,o,s,c,l,t]}}Gu.defaultPanelPositions={south:(e,t)=>({top:e.bottom,left:e.left-(t.width-e.width)/2,name:"s"}),southEast:e=>({top:e.bottom,left:e.left,name:"se"}),southWest:(e,t)=>({top:e.bottom,left:e.left-t.width+e.width,name:"sw"}),southMiddleEast:(e,t)=>({top:e.bottom,left:e.left-(t.width-e.width)/4,name:"sme"}),southMiddleWest:(e,t)=>({top:e.bottom,left:e.left-3*(t.width-e.width)/4,name:"smw"}),north:(e,t)=>({top:e.top-t.height,left:e.left-(t.width-e.width)/2,name:"n"}),northEast:(e,t)=>({top:e.top-t.height,left:e.left,name:"ne"}),northWest:(e,t)=>({top:e.top-t.height,left:e.left-t.width+e.width,name:"nw"}),northMiddleEast:(e,t)=>({top:e.top-t.height,left:e.left-(t.width-e.width)/4,name:"nme"}),northMiddleWest:(e,t)=>({top:e.top-t.height,left:e.left-3*(t.width-e.width)/4,name:"nmw"})},Gu._getOptimalPosition=Kn;class Ku{constructor(e){if(this.focusables=e.focusables,this.focusTracker=e.focusTracker,this.keystrokeHandler=e.keystrokeHandler,this.actions=e.actions,e.actions&&e.keystrokeHandler)for(const t in e.actions){let i=e.actions[t];"string"==typeof i&&(i=[i]);for(const n of i)e.keystrokeHandler.set(n,((e,i)=>{this[t](),i()}))}}get first(){return this.focusables.find(Ju)||null}get last(){return this.focusables.filter(Ju).slice(-1)[0]||null}get next(){return this._getFocusableItem(1)}get previous(){return this._getFocusableItem(-1)}get current(){let e=null;return null===this.focusTracker.focusedElement?null:(this.focusables.find(((t,i)=>{const n=t.element===this.focusTracker.focusedElement;return n&&(e=i),n})),e)}focusFirst(){this._focus(this.first)}focusLast(){this._focus(this.last)}focusNext(){this._focus(this.next)}focusPrevious(){this._focus(this.previous)}_focus(e){e&&e.focus()}_getFocusableItem(e){const t=this.current,i=this.focusables.length;if(!i)return null;if(null===t)return this[1===e?"first":"last"];let n=(t+i+e)%i;do{const t=this.focusables.get(n);if(Ju(t))return t;n=(n+i+e)%i}while(n!==t);return null}}function Ju(e){return!(!e.focus||!Gn(e.element))}class Qu extends fu{constructor(e){super(e),this.setTemplate({tag:"span",attributes:{class:["ck","ck-toolbar__separator"]}})}}class Yu extends fu{constructor(e){super(e),this.setTemplate({tag:"span",attributes:{class:["ck","ck-toolbar__line-break"]}})}}function Xu(e){return Array.isArray(e)?{items:e,removeItems:[]}:e?Object.assign({items:[],removeItems:[]},e):{items:[],removeItems:[]}}const{threeVerticalDots:Zu}=Pu,em={alignLeft:Pu.alignLeft,bold:Pu.bold,importExport:Pu.importExport,paragraph:Pu.paragraph,plus:Pu.plus,text:Pu.text,threeVerticalDots:Pu.threeVerticalDots};class tm extends fu{constructor(e,t){super(e);const i=this.bindTemplate,n=this.t;this.options=t||{},this.set("ariaLabel",n("Editor toolbar")),this.set("maxWidth","auto"),this.items=this.createCollection(),this.focusTracker=new Cs,this.keystrokes=new As,this.set("class",void 0),this.set("isCompact",!1),this.itemsView=new im(e),this.children=this.createCollection(),this.children.add(this.itemsView),this.focusables=this.createCollection();const s="rtl"===e.uiLanguageDirection;this._focusCycler=new Ku({focusables:this.focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:[s?"arrowright":"arrowleft","arrowup"],focusNext:[s?"arrowleft":"arrowright","arrowdown"]}});const o=["ck","ck-toolbar",i.to("class"),i.if("isCompact","ck-toolbar_compact")];var r;this.options.shouldGroupWhenFull&&this.options.isFloating&&o.push("ck-toolbar_floating"),this.setTemplate({tag:"div",attributes:{class:o,role:"toolbar","aria-label":i.to("ariaLabel"),style:{maxWidth:i.to("maxWidth")}},children:this.children,on:{mousedown:(r=this,r.bindTemplate.to((e=>{e.target===r.element&&e.preventDefault()})))}}),this._behavior=this.options.shouldGroupWhenFull?new sm(this):new nm(this)}render(){super.render();for(const e of this.items)this.focusTracker.add(e.element);this.items.on("add",((e,t)=>{this.focusTracker.add(t.element)})),this.items.on("remove",((e,t)=>{this.focusTracker.remove(t.element)})),this.keystrokes.listenTo(this.element),this._behavior.render(this)}destroy(){return this._behavior.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy(),super.destroy()}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}fillFromConfig(e,t,i){const n=Xu(e),s=i||n.removeItems,o=this._cleanItemsConfiguration(n.items,t,s).map((e=>M(e)?this._createNestedToolbarDropdown(e,t,s):"|"===e?new Qu:"-"===e?new Yu:t.create(e))).filter((e=>!!e));this.items.addMany(o)}_cleanItemsConfiguration(e,t,i){const n=e.filter(((e,n,s)=>"|"===e||-1===i.indexOf(e)&&("-"===e?!this.options.shouldGroupWhenFull||(v("toolbarview-line-break-ignored-when-grouping-items",s),!1):!(!M(e)&&!t.has(e))||(v("toolbarview-item-unavailable",{item:e}),!1))));return this._cleanSeparatorsAndLineBreaks(n)}_cleanSeparatorsAndLineBreaks(e){const t=e=>"-"!==e&&"|"!==e,i=e.length,n=e.findIndex(t);if(-1===n)return[];const s=i-e.slice().reverse().findIndex(t);return e.slice(n,s).filter(((e,i,n)=>{if(t(e))return!0;return!(i>0&&n[i-1]===e)}))}_createNestedToolbarDropdown(e,t,i){let{label:n,icon:s,items:o,tooltip:r=!0,withText:a=!1}=e;if(o=this._cleanItemsConfiguration(o,t,i),!o.length)return null;const l=lm(this.locale);return n||v("toolbarview-nested-toolbar-dropdown-missing-label",e),l.class="ck-toolbar__nested-toolbar-dropdown",l.buttonView.set({label:n,tooltip:r,withText:!!a}),!1!==s?l.buttonView.icon=em[s]||s||Zu:l.buttonView.withText=!0,cm(l,[]),l.toolbarView.fillFromConfig(o,t,i),l}}class im extends fu{constructor(e){super(e),this.children=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-toolbar__items"]},children:this.children})}}class nm{constructor(e){const t=e.bindTemplate;e.set("isVertical",!1),e.itemsView.children.bindTo(e.items).using((e=>e)),e.focusables.bindTo(e.items).using((e=>e)),e.extendTemplate({attributes:{class:[t.if("isVertical","ck-toolbar_vertical")]}})}render(){}destroy(){}}class sm{constructor(e){this.view=e,this.viewChildren=e.children,this.viewFocusables=e.focusables,this.viewItemsView=e.itemsView,this.viewFocusTracker=e.focusTracker,this.viewLocale=e.locale,this.ungroupedItems=e.createCollection(),this.groupedItems=e.createCollection(),this.groupedItemsDropdown=this._createGroupedItemsDropdown(),this.resizeObserver=null,this.cachedPadding=null,this.shouldUpdateGroupingOnNextResize=!1,e.itemsView.children.bindTo(this.ungroupedItems).using((e=>e)),this.ungroupedItems.on("change",this._updateFocusCycleableItems.bind(this)),e.children.on("change",this._updateFocusCycleableItems.bind(this)),e.items.on("change",((e,t)=>{const i=t.index,n=Array.from(t.added);for(const e of t.removed)i>=this.ungroupedItems.length?this.groupedItems.remove(e):this.ungroupedItems.remove(e);for(let e=i;ethis.ungroupedItems.length?this.groupedItems.add(t,e-this.ungroupedItems.length):this.ungroupedItems.add(t,e)}this._updateGrouping()})),e.extendTemplate({attributes:{class:["ck-toolbar_grouping"]}})}render(e){this.viewElement=e.element,this._enableGroupingOnResize(),this._enableGroupingOnMaxWidthChange(e)}destroy(){this.groupedItemsDropdown.destroy(),this.resizeObserver.destroy()}_updateGrouping(){if(!this.viewElement.ownerDocument.body.contains(this.viewElement))return;if(!Gn(this.viewElement))return void(this.shouldUpdateGroupingOnNextResize=!0);const e=this.groupedItems.length;let t;for(;this._areItemsOverflowing;)this._groupLastItem(),t=!0;if(!t&&this.groupedItems.length){for(;this.groupedItems.length&&!this._areItemsOverflowing;)this._ungroupFirstItem();this._areItemsOverflowing&&this._groupLastItem()}this.groupedItems.length!==e&&this.view.fire("groupedItemsUpdate")}get _areItemsOverflowing(){if(!this.ungroupedItems.length)return!1;const e=this.viewElement,t=this.viewLocale.uiLanguageDirection,i=new Nn(e.lastChild),n=new Nn(e);if(!this.cachedPadding){const i=Rn.window.getComputedStyle(e),n="ltr"===t?"paddingRight":"paddingLeft";this.cachedPadding=Number.parseInt(i[n])}return"ltr"===t?i.right>n.right-this.cachedPadding:i.left{e&&e===t.contentRect.width&&!this.shouldUpdateGroupingOnNextResize||(this.shouldUpdateGroupingOnNextResize=!1,this._updateGrouping(),e=t.contentRect.width)})),this._updateGrouping()}_enableGroupingOnMaxWidthChange(e){e.on("change:maxWidth",(()=>{this._updateGrouping()}))}_groupLastItem(){this.groupedItems.length||(this.viewChildren.add(new Qu),this.viewChildren.add(this.groupedItemsDropdown),this.viewFocusTracker.add(this.groupedItemsDropdown.element)),this.groupedItems.add(this.ungroupedItems.remove(this.ungroupedItems.last),0)}_ungroupFirstItem(){this.ungroupedItems.add(this.groupedItems.remove(this.groupedItems.first)),this.groupedItems.length||(this.viewChildren.remove(this.groupedItemsDropdown),this.viewChildren.remove(this.viewChildren.last),this.viewFocusTracker.remove(this.groupedItemsDropdown.element))}_createGroupedItemsDropdown(){const e=this.viewLocale,t=e.t,i=lm(e);return i.class="ck-toolbar__grouped-dropdown",i.panelPosition="ltr"===e.uiLanguageDirection?"sw":"se",cm(i,[]),i.buttonView.set({label:t("Show more items"),tooltip:!0,tooltipPosition:"rtl"===e.uiLanguageDirection?"se":"sw",icon:Zu}),i.toolbarView.items.bindTo(this.groupedItems).using((e=>e)),i}_updateFocusCycleableItems(){this.viewFocusables.clear(),this.ungroupedItems.map((e=>{this.viewFocusables.add(e)})),this.groupedItems.length&&this.viewFocusables.add(this.groupedItemsDropdown)}}class om extends fu{constructor(e){super(e),this.items=this.createCollection(),this.focusTracker=new Cs,this.keystrokes=new As,this._focusCycler=new Ku({focusables:this.items,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"arrowup",focusNext:"arrowdown"}}),this.setTemplate({tag:"ul",attributes:{class:["ck","ck-reset","ck-list"]},children:this.items})}render(){super.render();for(const e of this.items)this.focusTracker.add(e.element);this.items.on("add",((e,t)=>{this.focusTracker.add(t.element)})),this.items.on("remove",((e,t)=>{this.focusTracker.remove(t.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}}class rm extends fu{constructor(e){super(e);const t=this.bindTemplate;this.set("isVisible",!0),this.children=this.createCollection(),this.setTemplate({tag:"li",attributes:{class:["ck","ck-list__item",t.if("isVisible","ck-hidden",(e=>!e))]},children:this.children})}focus(){this.children.first.focus()}}class am extends fu{constructor(e){super(e),this.setTemplate({tag:"li",attributes:{class:["ck","ck-list__separator"]}})}}function lm(e,t=ju){const i=new t(e),n=new Uu(e),s=new Gu(e,i,n);return i.bind("isEnabled").to(s),i instanceof qu?i.arrowView.bind("isOn").to(s,"isOpen"):i.bind("isOn").to(s,"isOpen"),function(e){(function(e){e.on("render",(()=>{Iu({emitter:e,activator:()=>e.isOpen,callback:()=>{e.isOpen=!1},contextElements:[e.element]})}))})(e),function(e){e.on("execute",(t=>{t.source instanceof Nu||(e.isOpen=!1)}))}(e),function(e){e.focusTracker.on("change:isFocused",((t,i,n)=>{e.isOpen&&!n&&(e.isOpen=!1)}))}(e),function(e){e.keystrokes.set("arrowdown",((t,i)=>{e.isOpen&&(e.panelView.focus(),i())})),e.keystrokes.set("arrowup",((t,i)=>{e.isOpen&&(e.panelView.focusLast(),i())}))}(e),function(e){e.on("change:isOpen",((t,i,n)=>{n||e.panelView.element.contains(Rn.document.activeElement)&&e.buttonView.focus()}))}(e),function(e){e.on("change:isOpen",((t,i,n)=>{n&&e.panelView.focus()}),{priority:"low"})}(e)}(s),s}function cm(e,t,i={}){const n=e.locale,s=n.t,o=e.toolbarView=new tm(n);o.set("ariaLabel",s("Dropdown toolbar")),e.extendTemplate({attributes:{class:["ck-toolbar-dropdown"]}}),t.map((e=>o.items.add(e))),i.enableActiveItemFocusOnDropdownOpen&&hm(e,(()=>o.items.find((e=>e.isOn)))),e.panelView.children.add(o),o.items.delegate("execute").to(e)}function dm(e,t){const i=e.locale,n=e.listView=new om(i);n.items.bindTo(t).using((e=>{if("separator"===e.type)return new am(i);if("button"===e.type||"switchbutton"===e.type){const t=new rm(i);let n;return n="button"===e.type?new Mu(i):new Nu(i),n.bind(...Object.keys(e.model)).to(e.model),n.delegate("execute").to(t),t.children.add(n),t}return null})),e.panelView.children.add(n),n.items.delegate("execute").to(e),hm(e,(()=>n.items.find((e=>e instanceof rm&&e.children.first.isOn))))}function hm(e,t){e.on("change:isOpen",(()=>{if(!e.isOpen)return;const i=t();i&&("function"==typeof i.focus?i.focus():v("ui-dropdown-focus-child-on-open-child-missing-focus",{view:i}))}),{priority:f.low-10})}class um extends fu{constructor(e){super(e),this.body=new Ou(e)}render(){super.render(),this.body.attachToDom()}destroy(){return this.body.detachFromDom(),super.destroy()}}class mm extends fu{constructor(e){super(e),this.set("text",void 0),this.set("for",void 0),this.id=`ck-editor__label_${g()}`;const t=this.bindTemplate;this.setTemplate({tag:"label",attributes:{class:["ck","ck-label"],id:this.id,for:t.to("for")},children:[{text:t.to("text")}]})}}class gm extends um{constructor(e){super(e),this.top=this.createCollection(),this.main=this.createCollection(),this._voiceLabelView=this._createVoiceLabel(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-reset","ck-editor","ck-rounded-corners"],role:"application",dir:e.uiLanguageDirection,lang:e.uiLanguage,"aria-labelledby":this._voiceLabelView.id},children:[this._voiceLabelView,{tag:"div",attributes:{class:["ck","ck-editor__top","ck-reset_all"],role:"presentation"},children:this.top},{tag:"div",attributes:{class:["ck","ck-editor__main"],role:"presentation"},children:this.main}]})}_createVoiceLabel(){const e=this.t,t=new mm;return t.text=e("Rich Text Editor"),t.extendTemplate({attributes:{class:"ck-voice-label"}}),t}}class fm extends fu{constructor(e,t,i){super(e),this.setTemplate({tag:"div",attributes:{class:["ck","ck-content","ck-editor__editable","ck-rounded-corners"],lang:e.contentLanguage,dir:e.contentLanguageDirection}}),this.name=null,this.set("isFocused",!1),this._editableElement=i,this._hasExternalElement=!!this._editableElement,this._editingView=t}render(){super.render(),this._hasExternalElement?this.template.apply(this.element=this._editableElement):this._editableElement=this.element,this.on("change:isFocused",(()=>this._updateIsFocusedClasses())),this._updateIsFocusedClasses()}destroy(){this._hasExternalElement&&this.template.revert(this._editableElement),super.destroy()}_updateIsFocusedClasses(){const e=this._editingView;function t(t){e.change((i=>{const n=e.document.getRoot(t.name);i.addClass(t.isFocused?"ck-focused":"ck-blurred",n),i.removeClass(t.isFocused?"ck-blurred":"ck-focused",n)}))}e.isRenderingInProgress?function i(n){e.once("change:isRenderingInProgress",((e,s,o)=>{o?i(n):t(n)}))}(this):t(this)}}class pm extends fm{constructor(e,t,i,n={}){super(e,t,i);const s=e.t;this.extendTemplate({attributes:{role:"textbox",class:"ck-editor__editable_inline"}}),this._generateLabel=n.label||(()=>s("Editor editing area: %0",this.name))}render(){super.render();const e=this._editingView;e.change((t=>{const i=e.document.getRoot(this.name);t.setAttribute("aria-label",this._generateLabel(this),i)}))}}class wm extends fu{constructor(e,t={}){super(e);const i=this.bindTemplate;this.set("label",t.label||""),this.set("class",t.class||null),this.children=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-form__header",i.to("class")]},children:this.children});const n=new fu(e);n.setTemplate({tag:"h2",attributes:{class:["ck","ck-form__header__label"]},children:[{text:i.to("label")}]}),this.children.add(n)}}class bm extends fu{constructor(e){super(e),this.set("value",void 0),this.set("id",void 0),this.set("placeholder",void 0),this.set("isReadOnly",!1),this.set("hasError",!1),this.set("ariaDescribedById",void 0),this.focusTracker=new Cs,this.bind("isFocused").to(this.focusTracker),this.set("isEmpty",!0),this.set("inputMode","text");const t=this.bindTemplate;this.setTemplate({tag:"input",attributes:{class:["ck","ck-input",t.if("isFocused","ck-input_focused"),t.if("isEmpty","ck-input-text_empty"),t.if("hasError","ck-error")],id:t.to("id"),placeholder:t.to("placeholder"),readonly:t.to("isReadOnly"),inputmode:t.to("inputMode"),"aria-invalid":t.if("hasError",!0),"aria-describedby":t.to("ariaDescribedById")},on:{input:t.to(((...e)=>{this.fire("input",...e),this._updateIsEmpty()})),change:t.to(this._updateIsEmpty.bind(this))}})}render(){super.render(),this.focusTracker.add(this.element),this._setDomElementValue(this.value),this._updateIsEmpty(),this.on("change:value",((e,t,i)=>{this._setDomElementValue(i),this._updateIsEmpty()}))}destroy(){super.destroy(),this.focusTracker.destroy()}select(){this.element.select()}focus(){this.element.focus()}_updateIsEmpty(){this.isEmpty=!this.element.value}_setDomElementValue(e){this.element.value=e||0===e?e:""}}class vm extends bm{constructor(e){super(e),this.extendTemplate({attributes:{type:"text",class:["ck-input-text"]}})}}class _m extends bm{constructor(e,{min:t,max:i,step:n}={}){super(e);const s=this.bindTemplate;this.set("min",t),this.set("max",i),this.set("step",n),this.extendTemplate({attributes:{type:"number",class:["ck-input-number"],min:s.to("min"),max:s.to("max"),step:s.to("step")}})}}class ym extends fu{constructor(e,t){super(e);const i=`ck-labeled-field-view-${g()}`,n=`ck-labeled-field-view-status-${g()}`;this.fieldView=t(this,i,n),this.set("label",void 0),this.set("isEnabled",!0),this.set("isEmpty",!0),this.set("isFocused",!1),this.set("errorText",null),this.set("infoText",null),this.set("class",void 0),this.set("placeholder",void 0),this.labelView=this._createLabelView(i),this.statusView=this._createStatusView(n),this.fieldWrapperChildren=this.createCollection([this.fieldView,this.labelView]),this.bind("_statusText").to(this,"errorText",this,"infoText",((e,t)=>e||t));const s=this.bindTemplate;this.setTemplate({tag:"div",attributes:{class:["ck","ck-labeled-field-view",s.to("class"),s.if("isEnabled","ck-disabled",(e=>!e)),s.if("isEmpty","ck-labeled-field-view_empty"),s.if("isFocused","ck-labeled-field-view_focused"),s.if("placeholder","ck-labeled-field-view_placeholder"),s.if("errorText","ck-error")]},children:[{tag:"div",attributes:{class:["ck","ck-labeled-field-view__input-wrapper"]},children:this.fieldWrapperChildren},this.statusView]})}_createLabelView(e){const t=new mm(this.locale);return t.for=e,t.bind("text").to(this,"label"),t}_createStatusView(e){const t=new fu(this.locale),i=this.bindTemplate;return t.setTemplate({tag:"div",attributes:{class:["ck","ck-labeled-field-view__status",i.if("errorText","ck-labeled-field-view__status_error"),i.if("_statusText","ck-hidden",(e=>!e))],id:e,role:i.if("errorText","alert")},children:[{text:i.to("_statusText")}]}),t}focus(){this.fieldView.focus()}}function km(e,t,i){const n=new vm(e.locale);return n.set({id:t,ariaDescribedById:i}),n.bind("isReadOnly").to(e,"isEnabled",(e=>!e)),n.bind("hasError").to(e,"errorText",(e=>!!e)),n.on("input",(()=>{e.errorText=null})),e.bind("isEmpty","isFocused","placeholder").to(n),n}function Cm(e,t,i){const n=new _m(e.locale);return n.set({id:t,ariaDescribedById:i,inputMode:"numeric"}),n.bind("isReadOnly").to(e,"isEnabled",(e=>!e)),n.bind("hasError").to(e,"errorText",(e=>!!e)),n.on("input",(()=>{e.errorText=null})),e.bind("isEmpty","isFocused","placeholder").to(n),n}function Am(e,t,i){const n=lm(e.locale);return n.set({id:t,ariaDescribedById:i}),n.bind("isEnabled").to(e),n}class xm extends Ns{static get pluginName(){return"Notification"}init(){this.on("show:warning",((e,t)=>{window.alert(t.message)}),{priority:"lowest"})}showSuccess(e,t={}){this._showNotification({message:e,type:"success",namespace:t.namespace,title:t.title})}showInfo(e,t={}){this._showNotification({message:e,type:"info",namespace:t.namespace,title:t.title})}showWarning(e,t={}){this._showNotification({message:e,type:"warning",namespace:t.namespace,title:t.title})}_showNotification(e){const t=e.namespace?`show:${e.type}:${e.namespace}`:`show:${e.type}`;this.fire(t,{message:e.message,type:e.type,title:e.title||""})}}class Tm extends(W()){constructor(e,t){super(),t&&ca(this,t),e&&this.set(e)}}const Em='',Sm=Wn("px");class Pm extends Is{static get pluginName(){return"ContextualBalloon"}constructor(e){super(e),this.positionLimiter=()=>{const e=this.editor.editing.view,t=e.document.selection.editableElement;return t?e.domConverter.mapViewToDom(t.root):null},this.set("visibleView",null),this.view=new bu(e.locale),e.ui.view.body.add(this.view),e.ui.focusTracker.add(this.view.element),this._viewToStack=new Map,this._idToStack=new Map,this.set("_numberOfStacks",0),this.set("_singleViewMode",!1),this._rotatorView=this._createRotatorView(),this._fakePanelsView=this._createFakePanelsView()}destroy(){super.destroy(),this.view.destroy(),this._rotatorView.destroy(),this._fakePanelsView.destroy()}hasView(e){return Array.from(this._viewToStack.keys()).includes(e)}add(e){if(this.hasView(e.view))throw new b("contextualballoon-add-view-exist",[this,e]);const t=e.stackId||"main";if(!this._idToStack.has(t))return this._idToStack.set(t,new Map([[e.view,e]])),this._viewToStack.set(e.view,this._idToStack.get(t)),this._numberOfStacks=this._idToStack.size,void(this._visibleStack&&!e.singleViewMode||this.showStack(t));const i=this._idToStack.get(t);e.singleViewMode&&this.showStack(t),i.set(e.view,e),this._viewToStack.set(e.view,i),i===this._visibleStack&&this._showView(e)}remove(e){if(!this.hasView(e))throw new b("contextualballoon-remove-view-not-exist",[this,e]);const t=this._viewToStack.get(e);this._singleViewMode&&this.visibleView===e&&(this._singleViewMode=!1),this.visibleView===e&&(1===t.size?this._idToStack.size>1?this._showNextStack():(this.view.hide(),this.visibleView=null,this._rotatorView.hideView()):this._showView(Array.from(t.values())[t.size-2])),1===t.size?(this._idToStack.delete(this._getStackId(t)),this._numberOfStacks=this._idToStack.size):t.delete(e),this._viewToStack.delete(e)}updatePosition(e){e&&(this._visibleStack.get(this.visibleView).position=e),this.view.pin(this._getBalloonPosition()),this._fakePanelsView.updatePosition()}showStack(e){this.visibleStack=e;const t=this._idToStack.get(e);if(!t)throw new b("contextualballoon-showstack-stack-not-exist",this);this._visibleStack!==t&&this._showView(Array.from(t.values()).pop())}get _visibleStack(){return this._viewToStack.get(this.visibleView)}_getStackId(e){return Array.from(this._idToStack.entries()).find((t=>t[1]===e))[0]}_showNextStack(){const e=Array.from(this._idToStack.values());let t=e.indexOf(this._visibleStack)+1;e[t]||(t=0),this.showStack(this._getStackId(e[t]))}_showPrevStack(){const e=Array.from(this._idToStack.values());let t=e.indexOf(this._visibleStack)-1;e[t]||(t=e.length-1),this.showStack(this._getStackId(e[t]))}_createRotatorView(){const e=new Im(this.editor.locale),t=this.editor.locale.t;return this.view.content.add(e),e.bind("isNavigationVisible").to(this,"_numberOfStacks",this,"_singleViewMode",((e,t)=>!t&&e>1)),e.on("change:isNavigationVisible",(()=>this.updatePosition()),{priority:"low"}),e.bind("counter").to(this,"visibleView",this,"_numberOfStacks",((e,i)=>{if(i<2)return"";const n=Array.from(this._idToStack.values()).indexOf(this._visibleStack)+1;return t("%0 of %1",[n,i])})),e.buttonNextView.on("execute",(()=>{e.focusTracker.isFocused&&this.editor.editing.view.focus(),this._showNextStack()})),e.buttonPrevView.on("execute",(()=>{e.focusTracker.isFocused&&this.editor.editing.view.focus(),this._showPrevStack()})),e}_createFakePanelsView(){const e=new Rm(this.editor.locale,this.view);return e.bind("numberOfPanels").to(this,"_numberOfStacks",this,"_singleViewMode",((e,t)=>!t&&e>=2?Math.min(e-1,2):0)),e.listenTo(this.view,"change:top",(()=>e.updatePosition())),e.listenTo(this.view,"change:left",(()=>e.updatePosition())),this.editor.ui.view.body.add(e),e}_showView({view:e,balloonClassName:t="",withArrow:i=!0,singleViewMode:n=!1}){this.view.class=t,this.view.withArrow=i,this._rotatorView.showView(e),this.visibleView=e,this.view.pin(this._getBalloonPosition()),this._fakePanelsView.updatePosition(),n&&(this._singleViewMode=!0)}_getBalloonPosition(){let e=Array.from(this._visibleStack.values()).pop().position;return e&&(e.limiter||(e=Object.assign({},e,{limiter:this.positionLimiter})),e=Object.assign({},e,{viewportOffsetConfig:this.editor.ui.viewportOffset})),e}}class Im extends fu{constructor(e){super(e);const t=e.t,i=this.bindTemplate;this.set("isNavigationVisible",!0),this.focusTracker=new Cs,this.buttonPrevView=this._createButtonView(t("Previous"),Em),this.buttonNextView=this._createButtonView(t("Next"),''),this.content=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-balloon-rotator"],"z-index":"-1"},children:[{tag:"div",attributes:{class:["ck-balloon-rotator__navigation",i.to("isNavigationVisible",(e=>e?"":"ck-hidden"))]},children:[this.buttonPrevView,{tag:"span",attributes:{class:["ck-balloon-rotator__counter"]},children:[{text:i.to("counter")}]},this.buttonNextView]},{tag:"div",attributes:{class:"ck-balloon-rotator__content"},children:this.content}]})}render(){super.render(),this.focusTracker.add(this.element)}destroy(){super.destroy(),this.focusTracker.destroy()}showView(e){this.hideView(),this.content.add(e)}hideView(){this.content.clear()}_createButtonView(e,t){const i=new Mu(this.locale);return i.set({label:e,icon:t,tooltip:!0}),i}}class Rm extends fu{constructor(e,t){super(e);const i=this.bindTemplate;this.set("top",0),this.set("left",0),this.set("height",0),this.set("width",0),this.set("numberOfPanels",0),this.content=this.createCollection(),this._balloonPanelView=t,this.setTemplate({tag:"div",attributes:{class:["ck-fake-panel",i.to("numberOfPanels",(e=>e?"":"ck-hidden"))],style:{top:i.to("top",Sm),left:i.to("left",Sm),width:i.to("width",Sm),height:i.to("height",Sm)}},children:this.content}),this.on("change:numberOfPanels",((e,t,i,n)=>{i>n?this._addPanels(i-n):this._removePanels(n-i),this.updatePosition()}))}_addPanels(e){for(;e--;){const e=new fu;e.setTemplate({tag:"div"}),this.content.add(e),this.registerChild(e)}}_removePanels(e){for(;e--;){const e=this.content.last;this.content.remove(e),this.deregisterChild(e),e.destroy()}}updatePosition(){if(this.numberOfPanels){const{top:e,left:t}=this._balloonPanelView,{width:i,height:n}=new Nn(this._balloonPanelView.element);Object.assign(this,{top:e,left:t,width:i,height:n})}}}const Vm=Wn("px");class Lm extends fu{constructor(e){super(e);const t=this.bindTemplate;this.set("isActive",!1),this.set("isSticky",!1),this.set("limiterElement",null),this.set("limiterBottomOffset",50),this.set("viewportTopOffset",0),this.set("_marginLeft",null),this.set("_isStickyToTheLimiter",!1),this.set("_hasViewportTopOffset",!1),this.content=this.createCollection(),this._contentPanelPlaceholder=new Kh({tag:"div",attributes:{class:["ck","ck-sticky-panel__placeholder"],style:{display:t.to("isSticky",(e=>e?"block":"none")),height:t.to("isSticky",(e=>e?Vm(this._panelRect.height):null))}}}).render(),this._contentPanel=new Kh({tag:"div",attributes:{class:["ck","ck-sticky-panel__content",t.if("isSticky","ck-sticky-panel__content_sticky"),t.if("_isStickyToTheLimiter","ck-sticky-panel__content_sticky_bottom-limit")],style:{width:t.to("isSticky",(e=>e?Vm(this._contentPanelPlaceholder.getBoundingClientRect().width):null)),top:t.to("_hasViewportTopOffset",(e=>e?Vm(this.viewportTopOffset):null)),bottom:t.to("_isStickyToTheLimiter",(e=>e?Vm(this.limiterBottomOffset):null)),marginLeft:t.to("_marginLeft")}},children:this.content}).render(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-sticky-panel"]},children:[this._contentPanelPlaceholder,this._contentPanel]})}render(){super.render(),this._checkIfShouldBeSticky(),this.listenTo(Rn.window,"scroll",(()=>{this._checkIfShouldBeSticky()})),this.listenTo(this,"change:isActive",(()=>{this._checkIfShouldBeSticky()}))}_checkIfShouldBeSticky(){const e=this._panelRect=this._contentPanel.getBoundingClientRect();let t;this.limiterElement?(t=this._limiterRect=this.limiterElement.getBoundingClientRect(),this.isSticky=this.isActive&&t.tope||0)),e.toolbar.fillFromConfig(this._toolbarConfig,this.componentFactory),this.addToolbar(e.toolbar)}_initPlaceholder(){const e=this.editor,t=e.editing.view,i=t.document.getRoot(),n=e.sourceElement,s=e.config.get("placeholder")||n&&"textarea"===n.tagName.toLowerCase()&&n.getAttribute("placeholder");s&&Fs({view:t,element:i,text:s,isDirectHost:!1,keepOnFocus:!0})}}class Mm extends gm{constructor(e,t,i={}){super(e),this.stickyPanel=new Lm(e),this.toolbar=new tm(e,{shouldGroupWhenFull:i.shouldToolbarGroupWhenFull}),this.editable=new pm(e,t)}render(){super.render(),this.stickyPanel.content.add(this.toolbar),this.top.add(this.stickyPanel),this.main.add(this.editable)}}class Nm extends(Tu(Eu(jh))){constructor(e,t={}){if(!Dm(e)&&void 0!==t.initialData)throw new b("editor-create-initial-data",null);super(t),void 0===this.config.get("initialData")&&this.config.set("initialData",function(e){return Dm(e)?(t=e,t instanceof HTMLTextAreaElement?t.value:t.innerHTML):e;var t}(e)),Dm(e)&&(this.sourceElement=e),this.model.document.createRoot();const i=!this.config.get("toolbar.shouldNotGroupWhenFull"),n=new Mm(this.locale,this.editing.view,{shouldToolbarGroupWhenFull:i});this.ui=new Bm(this,n),function(e){if(!De(e.updateSourceElement))throw new b("attachtoform-missing-elementapi-interface",e);const t=e.sourceElement;if(function(e){return!!e&&"textarea"===e.tagName.toLowerCase()}(t)&&t.form){let i;const n=t.form,s=()=>e.updateSourceElement();De(n.submit)&&(i=n.submit,n.submit=()=>{s(),i.apply(n)}),n.addEventListener("submit",s),e.on("destroy",(()=>{n.removeEventListener("submit",s),i&&(n.submit=i)}))}}(this)}destroy(){return this.sourceElement&&this.updateSourceElement(),this.ui.destroy(),super.destroy()}static create(e,t={}){return new Promise((i=>{const n=new this(e,t);i(n.initPlugins().then((()=>n.ui.init(Dm(e)?e:null))).then((()=>n.data.init(n.config.get("initialData")))).then((()=>n.fire("ready"))).then((()=>n)))}))}}function Dm(e){return _n(e)}const Fm=["left","right","center","justify"];function zm(e){return Fm.includes(e)}function Hm(e,t){return"rtl"==t.contentLanguageDirection?"right"===e:"left"===e}function $m(e){const t=e.map((e=>{let t;return t="string"==typeof e?{name:e}:e,t})).filter((e=>{const t=!!Fm.includes(e.name);return t||v("alignment-config-name-not-recognized",{option:e}),t})),i=t.filter((e=>!!e.className)).length;if(i&&i{const s=n.slice(i+1);if(s.some((e=>e.name==t.name)))throw new b("alignment-config-name-already-defined",{option:t,configuredOptions:e});if(t.className){if(s.some((e=>e.className==t.className)))throw new b("alignment-config-classname-already-defined",{option:t,configuredOptions:e})}})),t}const Wm="alignment";class jm extends Vs{refresh(){const e=this.editor.locale,t=ks(this.editor.model.document.selection.getSelectedBlocks());this.isEnabled=!!t&&this._canBeAligned(t),this.isEnabled&&t.hasAttribute("alignment")?this.value=t.getAttribute("alignment"):this.value="rtl"===e.contentLanguageDirection?"right":"left"}execute(e={}){const t=this.editor,i=t.locale,n=t.model,s=n.document,o=e.value;n.change((e=>{const t=Array.from(s.selection.getSelectedBlocks()).filter((e=>this._canBeAligned(e))),n=t[0].getAttribute("alignment");Hm(o,i)||n===o||!o?function(e,t){for(const i of e)t.removeAttribute(Wm,i)}(t,e):function(e,t,i){for(const n of e)t.setAttribute(Wm,i,n)}(t,e,o)}))}_canBeAligned(e){return this.editor.model.schema.checkAttribute(e,Wm)}}class qm extends Is{static get pluginName(){return"AlignmentEditing"}constructor(e){super(e),e.config.define("alignment",{options:[...Fm.map((e=>({name:e})))]})}init(){const e=this.editor,t=e.locale,i=e.model.schema,n=$m(e.config.get("alignment.options")).filter((e=>zm(e.name)&&!Hm(e.name,t))),s=n.some((e=>!!e.className));i.extend("$block",{allowAttributes:"alignment"}),e.model.schema.setAttributeProperties("alignment",{isFormatting:!0}),s?e.conversion.attributeToAttribute(function(e){const t={model:{key:"alignment",values:e.map((e=>e.name))},view:{}};for(const i of e)t.view[i.name]={key:"class",value:i.className};return t}(n)):e.conversion.for("downcast").attributeToAttribute(function(e){const t={model:{key:"alignment",values:e.map((e=>e.name))},view:{}};for(const{name:i}of e)t.view[i]={key:"style",value:{"text-align":i}};return t}(n));const o=function(e){const t=[];for(const{name:i}of e)t.push({view:{key:"style",value:{"text-align":i}},model:{key:"alignment",value:i}});return t}(n);for(const t of o)e.conversion.for("upcast").attributeToAttribute(t);const r=function(e){const t=[];for(const{name:i}of e)t.push({view:{key:"align",value:i},model:{key:"alignment",value:i}});return t}(n);for(const t of r)e.conversion.for("upcast").attributeToAttribute(t);e.commands.add("alignment",new jm(e))}}const Um=new Map([["left",Pu.alignLeft],["right",Pu.alignRight],["center",Pu.alignCenter],["justify",Pu.alignJustify]]);class Gm extends Is{get localizedOptionTitles(){const e=this.editor.t;return{left:e("Align left"),right:e("Align right"),center:e("Align center"),justify:e("Justify")}}static get pluginName(){return"AlignmentUI"}init(){const e=this.editor,t=e.ui.componentFactory,i=e.t,n=$m(e.config.get("alignment.options"));n.map((e=>e.name)).filter(zm).forEach((e=>this._addButton(e))),t.add("alignment",(s=>{const o=lm(s),r=n.map((e=>t.create(`alignment:${e.name}`)));cm(o,r,{enableActiveItemFocusOnDropdownOpen:!0}),o.buttonView.set({label:i("Text alignment"),tooltip:!0}),o.toolbarView.isVertical=!0,o.toolbarView.ariaLabel=i("Text alignment toolbar"),o.extendTemplate({attributes:{class:"ck-alignment-dropdown"}});const a="rtl"===s.contentLanguageDirection?Um.get("right"):Um.get("left");return o.buttonView.bind("icon").toMany(r,"isOn",((...e)=>{const t=e.findIndex((e=>e));return t<0?a:r[t].icon})),o.bind("isEnabled").toMany(r,"isEnabled",((...e)=>e.some((e=>e)))),this.listenTo(o,"execute",(()=>{e.editing.view.focus()})),o}))}_addButton(e){const t=this.editor;t.ui.componentFactory.add(`alignment:${e}`,(i=>{const n=t.commands.get("alignment"),s=new Mu(i);return s.set({label:this.localizedOptionTitles[e],icon:Um.get(e),tooltip:!0,isToggleable:!0}),s.bind("isEnabled").to(n),s.bind("isOn").to(n,"value",(t=>t===e)),this.listenTo(s,"execute",(()=>{t.execute("alignment",{value:e}),t.editing.view.focus()})),s}))}}class Km{constructor(e,t=20){this._batch=null,this.model=e,this._size=0,this.limit=t,this._isLocked=!1,this._changeCallback=(e,t)=>{t.isLocal&&t.isUndoable&&t!==this._batch&&this._reset(!0)},this._selectionChangeCallback=()=>{this._reset()},this.model.document.on("change",this._changeCallback),this.model.document.selection.on("change:range",this._selectionChangeCallback),this.model.document.selection.on("change:attribute",this._selectionChangeCallback)}get batch(){return this._batch||(this._batch=this.model.createBatch({isTyping:!0})),this._batch}get size(){return this._size}input(e){this._size+=e,this._size>=this.limit&&this._reset(!0)}get isLocked(){return this._isLocked}lock(){this._isLocked=!0}unlock(){this._isLocked=!1}destroy(){this.model.document.off("change",this._changeCallback),this.model.document.selection.off("change:range",this._selectionChangeCallback),this.model.document.selection.off("change:attribute",this._selectionChangeCallback)}_reset(e=!1){this.isLocked&&!e||(this._batch=null,this._size=0)}}class Jm extends Vs{constructor(e,t){super(e),this._buffer=new Km(e.model,t)}get buffer(){return this._buffer}destroy(){super.destroy(),this._buffer.destroy()}execute(e={}){const t=this.editor.model,i=t.document,n=e.text||"",s=n.length;let o=i.selection;e.selection?o=e.selection:e.range&&(o=t.createSelection(e.range));const r=e.resultRange;t.enqueueChange(this._buffer.batch,(e=>{this._buffer.lock(),t.deleteContent(o),n&&t.insertContent(e.createText(n,i.selection.getAttributes()),o),r?e.setSelection(r):o.is("documentSelection")||e.setSelection(o),this._buffer.unlock(),this._buffer.input(s)}))}}const Qm=["insertText","insertReplacementText"];class Ym extends la{constructor(e){super(e),s.isAndroid&&Qm.push("insertCompositionText");const t=e.document;t.on("beforeinput",((i,n)=>{if(!this.isEnabled)return;const{data:s,targetRanges:o,inputType:r,domEvent:a}=n;if(!Qm.includes(r))return;const l=new u(t,"insertText");t.fire(l,new da(e,a,{text:s,selection:e.createSelection(o)})),l.stop.called&&i.stop()})),t.on("compositionend",((i,{data:n,domEvent:o})=>{this.isEnabled&&!s.isAndroid&&n&&t.fire("insertText",new da(e,o,{text:n,selection:t.selection}))}),{priority:"lowest"})}observe(){}}class Xm extends Is{static get pluginName(){return"Input"}init(){const e=this.editor,t=e.model,i=e.editing.view,n=t.document.selection;i.addObserver(Ym);const o=new Jm(e,e.config.get("typing.undoStep")||20);e.commands.add("insertText",o),e.commands.add("input",o),this.listenTo(i.document,"insertText",((n,o)=>{i.document.isComposing||o.preventDefault();const{text:r,selection:a,resultRange:l}=o,c=Array.from(a.getRanges()).map((t=>e.editing.mapper.toModelRange(t)));let d=r;if(s.isAndroid){const e=Array.from(c[0].getItems()).reduce(((e,t)=>e+(t.is("$textProxy")?t.data:"")),"");e&&(e.length<=d.length?d.startsWith(e)&&(d=d.substring(e.length),c[0].start=c[0].start.getShiftedBy(e.length)):e.startsWith(d)&&(c[0].start=c[0].start.getShiftedBy(d.length),d=""))}const h={text:d,selection:t.createSelection(c)};l&&(h.resultRange=e.editing.mapper.toModelRange(l)),e.execute("insertText",h)})),s.isAndroid?this.listenTo(i.document,"keydown",((e,s)=>{!n.isCollapsed&&229==s.keyCode&&i.document.isComposing&&Zm(t,o)})):this.listenTo(i.document,"compositionstart",(()=>{n.isCollapsed||Zm(t,o)}))}}function Zm(e,t){if(!t.isEnabled)return;const i=t.buffer;i.lock(),e.enqueueChange(i.batch,(()=>{e.deleteContent(e.document.selection)})),i.unlock()}class eg extends Vs{constructor(e,t){super(e),this.direction=t,this._buffer=new Km(e.model,e.config.get("typing.undoStep"))}get buffer(){return this._buffer}execute(e={}){const t=this.editor.model,i=t.document;t.enqueueChange(this._buffer.batch,(n=>{this._buffer.lock();const s=n.createSelection(e.selection||i.selection),o=e.sequence||1,r=s.isCollapsed;if(s.isCollapsed&&t.modifySelection(s,{direction:this.direction,unit:e.unit,treatEmojiAsSingleUnit:!0}),this._shouldEntireContentBeReplacedWithParagraph(o))return void this._replaceEntireContentWithParagraph(n);if(this._shouldReplaceFirstBlockWithParagraph(s,o))return void this.editor.execute("paragraph",{selection:s});if(s.isCollapsed)return;let a=0;s.getFirstRange().getMinimalFlatRanges().forEach((e=>{a+=Q(e.getWalker({singleCharacters:!0,ignoreElementEnd:!0,shallow:!0}))})),t.deleteContent(s,{doNotResetEntireContent:r,direction:this.direction}),this._buffer.input(a),n.setSelection(s),this._buffer.unlock()}))}_shouldEntireContentBeReplacedWithParagraph(e){if(e>1)return!1;const t=this.editor.model,i=t.document.selection,n=t.schema.getLimitElement(i);if(!(i.isCollapsed&&i.containsEntireContent(n)))return!1;if(!t.schema.checkChild(n,"paragraph"))return!1;const s=n.getChild(0);return!s||!s.is("element","paragraph")}_replaceEntireContentWithParagraph(e){const t=this.editor.model,i=t.document.selection,n=t.schema.getLimitElement(i),s=e.createElement("paragraph");e.remove(e.createRangeIn(n)),e.insert(s,n),e.setSelection(s,0)}_shouldReplaceFirstBlockWithParagraph(e,t){const i=this.editor.model;if(t>1||"backward"!=this.direction)return!1;if(!e.isCollapsed)return!1;const n=e.getFirstPosition(),s=i.schema.getLimitElement(n),o=s.getChild(0);return n.parent==o&&(!!e.containsEntireContent(o)&&(!!i.schema.checkChild(s,"paragraph")&&"paragraph"!=o.name))}}const tg="word",ig="selection",ng="backward",sg="forward",og={deleteContent:{unit:ig,direction:ng},deleteContentBackward:{unit:"codePoint",direction:ng},deleteWordBackward:{unit:tg,direction:ng},deleteHardLineBackward:{unit:ig,direction:ng},deleteSoftLineBackward:{unit:ig,direction:ng},deleteContentForward:{unit:"character",direction:sg},deleteWordForward:{unit:tg,direction:sg},deleteHardLineForward:{unit:ig,direction:sg},deleteSoftLineForward:{unit:ig,direction:sg}};class rg extends la{constructor(e){super(e);const t=e.document;let i=0;t.on("keydown",(()=>{i++})),t.on("keyup",(()=>{i=0})),t.on("beforeinput",((n,o)=>{if(!this.isEnabled)return;const{targetRanges:r,domEvent:a,inputType:l}=o,c=og[l];if(!c)return;const d={direction:c.direction,unit:c.unit,sequence:i};d.unit==ig&&(d.selectionToRemove=e.createSelection(r[0])),s.isAndroid&&"deleteContentBackward"===l&&(d.sequence=1,1!=r.length||r[0].start.parent==r[0].end.parent&&r[0].start.offset+1==r[0].end.offset||(d.unit=ig,d.selectionToRemove=e.createSelection(r)));const h=new lr(t,"delete",r[0]);t.fire(h,new da(e,a,d)),h.stop.called&&n.stop()})),s.isBlink&&function(e){const t=e.view,i=t.document;let n=null,s=!1;function o(e){return e==ds.backspace||e==ds.delete}function r(e){return e==ds.backspace?ng:sg}i.on("keydown",((e,{keyCode:t})=>{n=t,s=!1})),i.on("keyup",((a,{keyCode:l,domEvent:c})=>{const d=i.selection,h=e.isEnabled&&l==n&&o(l)&&!d.isCollapsed&&!s;if(n=null,h){const e=d.getFirstRange(),n=new lr(i,"delete",e),s={unit:ig,direction:r(l),selectionToRemove:d};i.fire(n,new da(t,c,s))}})),i.on("beforeinput",((e,{inputType:t})=>{const i=og[t];o(n)&&i&&i.direction==r(n)&&(s=!0)}),{priority:"high"}),i.on("beforeinput",((e,{inputType:t,data:i})=>{n==ds.delete&&"insertText"==t&&""==i&&e.stop()}),{priority:"high"})}(this)}observe(){}}class ag extends Is{static get pluginName(){return"Delete"}init(){const e=this.editor,t=e.editing.view,i=t.document,n=e.model.document;t.addObserver(rg),this._undoOnBackspace=!1;const s=new eg(e,"forward");e.commands.add("deleteForward",s),e.commands.add("forwardDelete",s),e.commands.add("delete",new eg(e,"backward")),this.listenTo(i,"delete",((n,s)=>{i.isComposing||s.preventDefault();const{direction:o,sequence:r,selectionToRemove:a,unit:l}=s,c="forward"===o?"deleteForward":"delete",d={sequence:r};if("selection"==l){const t=Array.from(a.getRanges()).map((t=>e.editing.mapper.toModelRange(t)));d.selection=e.model.createSelection(t)}else d.unit=l;e.execute(c,d),t.scrollToTheSelection()}),{priority:"low"}),this.editor.plugins.has("UndoEditing")&&(this.listenTo(i,"delete",((t,i)=>{this._undoOnBackspace&&"backward"==i.direction&&1==i.sequence&&"codePoint"==i.unit&&(this._undoOnBackspace=!1,e.execute("undo"),i.preventDefault(),t.stop())}),{context:"$capture"}),this.listenTo(n,"change",(()=>{this._undoOnBackspace=!1})))}requestUndoOnBackspace(){this.editor.plugins.has("UndoEditing")&&(this._undoOnBackspace=!0)}}class lg extends Is{static get requires(){return[Xm,ag]}static get pluginName(){return"Typing"}}function cg(e,t){let i=e.start;return{text:Array.from(e.getItems()).reduce(((e,n)=>n.is("$text")||n.is("$textProxy")?e+n.data:(i=t.createPositionAfter(n),"")),""),range:t.createRange(i,e.end)}}class dg extends(W()){constructor(e,t){super(),this.model=e,this.testCallback=t,this._hasMatch=!1,this.set("isEnabled",!0),this.on("change:isEnabled",(()=>{this.isEnabled?this._startListening():(this.stopListening(e.document.selection),this.stopListening(e.document))})),this._startListening()}get hasMatch(){return this._hasMatch}_startListening(){const e=this.model.document;this.listenTo(e.selection,"change:range",((t,{directChange:i})=>{i&&(e.selection.isCollapsed?this._evaluateTextBeforeSelection("selection"):this.hasMatch&&(this.fire("unmatched"),this._hasMatch=!1))})),this.listenTo(e,"change:data",((e,t)=>{!t.isUndo&&t.isLocal&&this._evaluateTextBeforeSelection("data",{batch:t})}))}_evaluateTextBeforeSelection(e,t={}){const i=this.model,n=i.document.selection,s=i.createRange(i.createPositionAt(n.focus.parent,0),n.focus),{text:o,range:r}=cg(s,i),a=this.testCallback(o);if(!a&&this.hasMatch&&this.fire("unmatched"),this._hasMatch=!!a,a){const i=Object.assign(t,{text:o,range:r});"object"==typeof a&&Object.assign(i,a),this.fire(`matched:${e}`,i)}}}class hg extends Is{static get pluginName(){return"TwoStepCaretMovement"}constructor(e){super(e),this.attributes=new Set,this._overrideUid=null}init(){const e=this.editor,t=e.model,i=e.editing.view,n=e.locale,s=t.document.selection;this.listenTo(i.document,"arrowKey",((e,t)=>{if(!s.isCollapsed)return;if(t.shiftKey||t.altKey||t.ctrlKey)return;const i=t.keyCode==ds.arrowright,o=t.keyCode==ds.arrowleft;if(!i&&!o)return;const r=n.contentLanguageDirection;let a=!1;a="ltr"===r&&i||"rtl"===r&&o?this._handleForwardMovement(t):this._handleBackwardMovement(t),!0===a&&e.stop()}),{context:"$text",priority:"highest"}),this._isNextGravityRestorationSkipped=!1,this.listenTo(s,"change:range",((e,t)=>{this._isNextGravityRestorationSkipped?this._isNextGravityRestorationSkipped=!1:this._isGravityOverridden&&(!t.directChange&&fg(s.getFirstPosition(),this.attributes)||this._restoreGravity())}))}registerAttribute(e){this.attributes.add(e)}_handleForwardMovement(e){const t=this.attributes,i=this.editor.model.document.selection,n=i.getFirstPosition();return!this._isGravityOverridden&&((!n.isAtStart||!ug(i,t))&&(!!fg(n,t)&&(gg(e),this._overrideGravity(),!0)))}_handleBackwardMovement(e){const t=this.attributes,i=this.editor.model,n=i.document.selection,s=n.getFirstPosition();return this._isGravityOverridden?(gg(e),this._restoreGravity(),mg(i,t,s),!0):s.isAtStart?!!ug(n,t)&&(gg(e),mg(i,t,s),!0):!!function(e,t){const i=e.getShiftedBy(-1);return fg(i,t)}(s,t)&&(s.isAtEnd&&!ug(n,t)&&fg(s,t)?(gg(e),mg(i,t,s),!0):(this._isNextGravityRestorationSkipped=!0,this._overrideGravity(),!1))}get _isGravityOverridden(){return!!this._overrideUid}_overrideGravity(){this._overrideUid=this.editor.model.change((e=>e.overrideSelectionGravity()))}_restoreGravity(){this.editor.model.change((e=>{e.restoreSelectionGravity(this._overrideUid),this._overrideUid=null}))}}function ug(e,t){for(const i of t)if(e.hasAttribute(i))return!0;return!1}function mg(e,t,i){const n=i.nodeBefore;e.change((e=>{n?e.setSelectionAttribute(n.getAttributes()):e.removeSelectionAttribute(t)}))}function gg(e){e.preventDefault()}function fg(e,t){const{nodeBefore:i,nodeAfter:n}=e;for(const e of t){const t=i?i.getAttribute(e):void 0;if((n?n.getAttribute(e):void 0)!==t)return!0}return!1}var pg=/[\\^$.*+?()[\]{}|]/g,wg=RegExp(pg.source);const bg=function(e){return(e=mo(e))&&wg.test(e)?e.replace(pg,"\\$&"):e},vg={copyright:{from:"(c)",to:"©"},registeredTrademark:{from:"(r)",to:"®"},trademark:{from:"(tm)",to:"™"},oneHalf:{from:/(^|[^/a-z0-9])(1\/2)([^/a-z0-9])$/i,to:[null,"½",null]},oneThird:{from:/(^|[^/a-z0-9])(1\/3)([^/a-z0-9])$/i,to:[null,"⅓",null]},twoThirds:{from:/(^|[^/a-z0-9])(2\/3)([^/a-z0-9])$/i,to:[null,"⅔",null]},oneForth:{from:/(^|[^/a-z0-9])(1\/4)([^/a-z0-9])$/i,to:[null,"¼",null]},threeQuarters:{from:/(^|[^/a-z0-9])(3\/4)([^/a-z0-9])$/i,to:[null,"¾",null]},lessThanOrEqual:{from:"<=",to:"≤"},greaterThanOrEqual:{from:">=",to:"≥"},notEqual:{from:"!=",to:"≠"},arrowLeft:{from:"<-",to:"←"},arrowRight:{from:"->",to:"→"},horizontalEllipsis:{from:"...",to:"…"},enDash:{from:/(^| )(--)( )$/,to:[null,"–",null]},emDash:{from:/(^| )(---)( )$/,to:[null,"—",null]},quotesPrimary:{from:xg('"'),to:[null,"“",null,"”"]},quotesSecondary:{from:xg("'"),to:[null,"‘",null,"’"]},quotesPrimaryEnGb:{from:xg("'"),to:[null,"‘",null,"’"]},quotesSecondaryEnGb:{from:xg('"'),to:[null,"“",null,"”"]},quotesPrimaryPl:{from:xg('"'),to:[null,"„",null,"”"]},quotesSecondaryPl:{from:xg("'"),to:[null,"‚",null,"’"]}},_g={symbols:["copyright","registeredTrademark","trademark"],mathematical:["oneHalf","oneThird","twoThirds","oneForth","threeQuarters","lessThanOrEqual","greaterThanOrEqual","notEqual","arrowLeft","arrowRight"],typography:["horizontalEllipsis","enDash","emDash"],quotes:["quotesPrimary","quotesSecondary"]},yg=["symbols","mathematical","typography","quotes"];function kg(e){return"string"==typeof e?new RegExp(`(${bg(e)})$`):e}function Cg(e){return"string"==typeof e?()=>[e]:e instanceof Array?()=>e:e}function Ag(e){return(e.textNode?e.textNode:e.nodeAfter).getAttributes()}function xg(e){return new RegExp(`(^|\\s)(${e})([^${e}]*)(${e})$`)}function Tg(e,t,i,n){return n.createRange(Eg(e,t,i,!0,n),Eg(e,t,i,!1,n))}function Eg(e,t,i,n,s){let o=e.textNode||(n?e.nodeBefore:e.nodeAfter),r=null;for(;o&&o.getAttribute(t)==i;)r=o,o=n?o.previousSibling:o.nextSibling;return r?s.createPositionAt(r,n?"before":"after"):e}function Sg(e,t,i,n){const s=e.editing.view,o=new Set;s.document.registerPostFixer((s=>{const r=e.model.document.selection;let a=!1;if(r.hasAttribute(t)){const l=Tg(r.getFirstPosition(),t,r.getAttribute(t),e.model),c=e.editing.mapper.toViewRange(l);for(const e of c.getItems())e.is("element",i)&&!e.hasClass(n)&&(s.addClass(n,e),o.add(e),a=!0)}return a})),e.conversion.for("editingDowncast").add((e=>{function t(){s.change((e=>{for(const t of o.values())e.removeClass(n,t),o.delete(t)}))}e.on("insert",t,{priority:"highest"}),e.on("remove",t,{priority:"highest"}),e.on("attribute",t,{priority:"highest"}),e.on("selection",t,{priority:"highest"})}))}function Pg(e,t,i,n){let s,o=null;"function"==typeof n?s=n:(o=e.commands.get(n),s=()=>{e.execute(n)}),e.model.document.on("change:data",((r,a)=>{if(o&&!o.isEnabled||!t.isEnabled)return;const l=ks(e.model.document.selection.getRanges());if(!l.isCollapsed)return;if(a.isUndo||!a.isLocal)return;const c=Array.from(e.model.document.differ.getChanges()),d=c[0];if(1!=c.length||"insert"!==d.type||"$text"!=d.name||1!=d.length)return;const h=d.position.parent;if(h.is("element","codeBlock"))return;if(h.is("element","listItem")&&"function"!=typeof n&&!["numberedList","bulletedList","todoList"].includes(n))return;if(o&&!0===o.value)return;const u=h.getChild(0),m=e.model.createRangeOn(u);if(!m.containsRange(l)&&!l.end.isEqual(m.end))return;const g=i.exec(u.data.substr(0,l.end.offset));g&&e.model.enqueueChange((t=>{const i=t.createPositionAt(h,0),n=t.createPositionAt(h,g[0].length),o=new Il(i,n);if(!1!==s({match:g})){t.remove(o);const i=e.model.document.selection.getFirstRange(),n=t.createRangeIn(h);!h.isEmpty||n.isEqual(i)||n.containsRange(i,!0)||t.remove(h)}o.detach(),e.model.enqueueChange((()=>{e.plugins.get("Delete").requestUndoOnBackspace()}))}))}))}function Ig(e,t,i,n){let s,o;i instanceof RegExp?s=i:o=i,o=o||(e=>{let t;const i=[],n=[];for(;null!==(t=s.exec(e))&&!(t&&t.length<4);){let{index:e,1:s,2:o,3:r}=t;const a=s+o+r;e+=t[0].length-a.length;const l=[e,e+s.length],c=[e+s.length+o.length,e+s.length+o.length+r.length];i.push(l),i.push(c),n.push([e+s.length,e+s.length+o.length])}return{remove:i,format:n}}),e.model.document.on("change:data",((i,s)=>{if(s.isUndo||!s.isLocal||!t.isEnabled)return;const r=e.model,a=r.document.selection;if(!a.isCollapsed)return;const l=Array.from(r.document.differ.getChanges()),c=l[0];if(1!=l.length||"insert"!==c.type||"$text"!=c.name||1!=c.length)return;const d=a.focus,h=d.parent,{text:u,range:m}=function(e,t){let i=e.start;const n=Array.from(e.getItems()).reduce(((e,n)=>!n.is("$text")&&!n.is("$textProxy")||n.getAttribute("code")?(i=t.createPositionAfter(n),""):e+n.data),"");return{text:n,range:t.createRange(i,e.end)}}(r.createRange(r.createPositionAt(h,0),d),r),g=o(u),f=Rg(m.start,g.format,r),p=Rg(m.start,g.remove,r);f.length&&p.length&&r.enqueueChange((t=>{if(!1!==n(t,f)){for(const e of p.reverse())t.remove(e);r.enqueueChange((()=>{e.plugins.get("Delete").requestUndoOnBackspace()}))}}))}))}function Rg(e,t,i){return t.filter((e=>void 0!==e[0]&&void 0!==e[1])).map((t=>i.createRange(e.getShiftedBy(t[0]),e.getShiftedBy(t[1]))))}function Vg(e,t){return(i,n)=>{if(!e.commands.get(t).isEnabled)return!1;const s=e.model.schema.getValidRanges(n,t);for(const e of s)i.setAttribute(t,!0,e);i.removeSelectionAttribute(t)}}class Lg extends ha{constructor(e){super(e);const t=this.document;function i(e){return(i,n)=>{n.preventDefault();const s=n.dropRange?[n.dropRange]:null,o=new u(t,e);t.fire(o,{dataTransfer:n.dataTransfer,method:i.name,targetRanges:s,target:n.target}),o.stop.called&&n.stopPropagation()}}this.domEventType=["paste","copy","cut","drop","dragover","dragstart","dragend","dragenter","dragleave"],this.listenTo(t,"paste",i("clipboardInput"),{priority:"low"}),this.listenTo(t,"drop",i("clipboardInput"),{priority:"low"}),this.listenTo(t,"dragover",i("dragging"),{priority:"low"})}onDomEvent(e){const t={dataTransfer:new Za("clipboardData"in e?e.clipboardData:e.dataTransfer)};"drop"!=e.type&&"dragover"!=e.type||(t.dropRange=function(e,t){const i=t.target.ownerDocument,n=t.clientX,s=t.clientY;let o;i.caretRangeFromPoint&&i.caretRangeFromPoint(n,s)?o=i.caretRangeFromPoint(n,s):t.rangeParent&&(o=i.createRange(),o.setStart(t.rangeParent,t.rangeOffset),o.collapse(!0));if(o)return e.domConverter.domRangeToView(o);return null}(this.view,e)),this.fire(e.type,e,t)}}const Og=["figcaption","li"];function Bg(e){let t="";if(e.is("$text")||e.is("$textProxy"))t=e.data;else if(e.is("element","img")&&e.hasAttribute("alt"))t=e.getAttribute("alt");else if(e.is("element","br"))t="\n";else{let i=null;for(const n of e.getChildren()){const e=Bg(n);i&&(i.is("containerElement")||n.is("containerElement"))&&(Og.includes(i.name)||Og.includes(n.name)?t+="\n":t+="\n\n"),t+=e,i=n}}return t}class Mg extends Is{static get pluginName(){return"ClipboardPipeline"}init(){this.editor.editing.view.addObserver(Lg),this._setupPasteDrop(),this._setupCopyCut()}_setupPasteDrop(){const e=this.editor,t=e.model,i=e.editing.view,n=i.document;this.listenTo(n,"clipboardInput",(t=>{e.isReadOnly&&t.stop()}),{priority:"highest"}),this.listenTo(n,"clipboardInput",((e,t)=>{const n=t.dataTransfer;let s;if(t.content)s=t.content;else{let e="";n.getData("text/html")?e=function(e){return e.replace(/(\s+)<\/span>/g,((e,t)=>1==t.length?" ":t)).replace(//g,"")}(n.getData("text/html")):n.getData("text/plain")&&(((o=(o=n.getData("text/plain")).replace(//g,">").replace(/\r?\n\r?\n/g,"

    ").replace(/\r?\n/g,"
    ").replace(/\t/g,"    ").replace(/^\s/," ").replace(/\s$/," ").replace(/\s\s/g,"  ")).includes("

    ")||o.includes("
    "))&&(o=`

    ${o}

    `),e=o),s=this.editor.data.htmlProcessor.toView(e)}var o;const r=new u(this,"inputTransformation");this.fire(r,{content:s,dataTransfer:n,targetRanges:t.targetRanges,method:t.method}),r.stop.called&&e.stop(),i.scrollToTheSelection()}),{priority:"low"}),this.listenTo(this,"inputTransformation",((e,i)=>{if(i.content.isEmpty)return;const n=this.editor.data.toModel(i.content,"$clipboardHolder");0!=n.childCount&&(e.stop(),t.change((()=>{this.fire("contentInsertion",{content:n,method:i.method,dataTransfer:i.dataTransfer,targetRanges:i.targetRanges})})))}),{priority:"low"}),this.listenTo(this,"contentInsertion",((e,i)=>{i.resultRange=t.insertContent(i.content)}),{priority:"low"})}_setupCopyCut(){const e=this.editor,t=e.model.document,i=e.editing.view.document,n=(n,s)=>{const o=s.dataTransfer;s.preventDefault();const r=e.data.toView(e.model.getSelectedContent(t.selection));i.fire("clipboardOutput",{dataTransfer:o,content:r,method:n.name})};this.listenTo(i,"copy",n,{priority:"low"}),this.listenTo(i,"cut",((t,i)=>{e.isReadOnly?i.preventDefault():n(t,i)}),{priority:"low"}),this.listenTo(i,"clipboardOutput",((i,n)=>{n.content.isEmpty||(n.dataTransfer.setData("text/html",this.editor.data.htmlProcessor.toData(n.content)),n.dataTransfer.setData("text/plain",Bg(n.content))),"cut"==n.method&&e.model.deleteContent(t.selection)}),{priority:"low"})}}function*Ng(e,t){for(const i of t)i&&e.getAttributeProperties(i[0]).copyOnEnter&&(yield i)}class Dg extends Vs{execute(){this.editor.model.change((e=>{this.enterBlock(e),this.fire("afterExecute",{writer:e})}))}enterBlock(e){const t=this.editor.model,i=t.document.selection,n=t.schema,s=i.isCollapsed,o=i.getFirstRange(),r=o.start.parent,a=o.end.parent;if(n.isLimit(r)||n.isLimit(a))return s||r!=a||t.deleteContent(i),!1;if(s){const t=Ng(e.model.schema,i.getAttributes());return Fg(e,o.start),e.setSelectionAttribute(t),!0}{const n=!(o.start.isAtStart&&o.end.isAtEnd),s=r==a;if(t.deleteContent(i,{leaveUnmerged:n}),n){if(s)return Fg(e,i.focus),!0;e.setSelection(a,0)}}return!1}}function Fg(e,t){e.split(t),e.setSelection(t.parent.nextSibling,0)}const zg={insertParagraph:{isSoft:!1},insertLineBreak:{isSoft:!0}};class Hg extends la{constructor(e){super(e);const t=this.document;t.on("beforeinput",((i,n)=>{if(!this.isEnabled)return;const s=n.domEvent,o=zg[n.inputType];if(!o)return;const r=new lr(t,"enter",n.targetRanges[0]);t.fire(r,new da(e,s,{isSoft:o.isSoft})),r.stop.called&&i.stop()}))}observe(){}}class $g extends Is{static get pluginName(){return"Enter"}init(){const e=this.editor,t=e.editing.view,i=t.document;t.addObserver(Hg),e.commands.add("enter",new Dg(e)),this.listenTo(i,"enter",((n,s)=>{i.isComposing||s.preventDefault(),s.isSoft||(e.execute("enter"),t.scrollToTheSelection())}),{priority:"low"})}}class Wg extends Vs{execute(){const e=this.editor.model,t=e.document;e.change((i=>{!function(e,t,i){const n=i.isCollapsed,s=i.getFirstRange(),o=s.start.parent,r=s.end.parent,a=o==r;if(n){const n=Ng(e.schema,i.getAttributes());jg(e,t,s.end),t.removeSelectionAttribute(i.getAttributeKeys()),t.setSelectionAttribute(n)}else{const n=!(s.start.isAtStart&&s.end.isAtEnd);e.deleteContent(i,{leaveUnmerged:n}),a?jg(e,t,i.focus):n&&t.setSelection(r,0)}}(e,i,t.selection),this.fire("afterExecute",{writer:i})}))}refresh(){const e=this.editor.model,t=e.document;this.isEnabled=function(e,t){if(t.rangeCount>1)return!1;const i=t.anchor;if(!i||!e.checkChild(i,"softBreak"))return!1;const n=t.getFirstRange(),s=n.start.parent,o=n.end.parent;if((qg(s,e)||qg(o,e))&&s!==o)return!1;return!0}(e.schema,t.selection)}}function jg(e,t,i){const n=t.createElement("softBreak");e.insertContent(n,i),t.setSelection(n,"after")}function qg(e,t){return!e.is("rootElement")&&(t.isLimit(e)||qg(e.parent,t))}class Ug extends Is{static get pluginName(){return"ShiftEnter"}init(){const e=this.editor,t=e.model.schema,i=e.conversion,n=e.editing.view,s=n.document;t.register("softBreak",{allowWhere:"$text",isInline:!0}),i.for("upcast").elementToElement({model:"softBreak",view:"br"}),i.for("downcast").elementToElement({model:"softBreak",view:(e,{writer:t})=>t.createEmptyElement("br")}),n.addObserver(Hg),e.commands.add("shiftEnter",new Wg(e)),this.listenTo(s,"enter",((t,i)=>{s.isComposing||i.preventDefault(),i.isSoft&&(e.execute("shiftEnter"),n.scrollToTheSelection())}),{priority:"low"})}}class Gg extends(S()){constructor(){super(),this._stack=[]}add(e,t){const i=this._stack,n=i[0];this._insertDescriptor(e);const s=i[0];n===s||Kg(n,s)||this.fire("change:top",{oldDescriptor:n,newDescriptor:s,writer:t})}remove(e,t){const i=this._stack,n=i[0];this._removeDescriptor(e);const s=i[0];n===s||Kg(n,s)||this.fire("change:top",{oldDescriptor:n,newDescriptor:s,writer:t})}_insertDescriptor(e){const t=this._stack,i=t.findIndex((t=>t.id===e.id));if(Kg(e,t[i]))return;i>-1&&t.splice(i,1);let n=0;for(;t[n]&&Jg(t[n],e);)n++;t.splice(n,0,e)}_removeDescriptor(e){const t=this._stack,i=t.findIndex((t=>t.id===e));i>-1&&t.splice(i,1)}}function Kg(e,t){return e&&t&&e.priority==t.priority&&Qg(e.classes)==Qg(t.classes)}function Jg(e,t){return e.priority>t.priority||!(e.priorityQg(t.classes)}function Qg(e){return Array.isArray(e)?e.sort().join(","):e}const Yg='',Xg="ck-widget",Zg="ck-widget_selected";function ef(e){return!!e.is("element")&&!!e.getCustomProperty("widget")}function tf(e,t,i={}){if(!e.is("containerElement"))throw new b("widget-to-widget-wrong-element-type",null,{element:e});return t.setAttribute("contenteditable","false",e),t.addClass(Xg,e),t.setCustomProperty("widget",!0,e),e.getFillerOffset=lf,t.setCustomProperty("widgetLabel",[],e),i.label&&function(e,t){const i=e.getCustomProperty("widgetLabel");i.push(t)}(e,i.label),i.hasSelectionHandle&&function(e,t){const i=t.createUIElement("div",{class:"ck ck-widget__selection-handle"},(function(e){const t=this.toDomElement(e),i=new Bu;return i.set("content",Yg),i.render(),t.appendChild(i.element),t}));t.insert(t.createPositionAt(e,0),i),t.addClass(["ck-widget_with-selection-handle"],e)}(e,t),of(e,t),e}function nf(e,t,i){if(t.classes&&i.addClass(ps(t.classes),e),t.attributes)for(const n in t.attributes)i.setAttribute(n,t.attributes[n],e)}function sf(e,t,i){if(t.classes&&i.removeClass(ps(t.classes),e),t.attributes)for(const n in t.attributes)i.removeAttribute(n,e)}function of(e,t,i=nf,n=sf){const s=new Gg;s.on("change:top",((t,s)=>{s.oldDescriptor&&n(e,s.oldDescriptor,s.writer),s.newDescriptor&&i(e,s.newDescriptor,s.writer)}));t.setCustomProperty("addHighlight",((e,t,i)=>s.add(t,i)),e),t.setCustomProperty("removeHighlight",((e,t,i)=>s.remove(t,i)),e)}function rf(e,t,i={}){return t.addClass(["ck-editor__editable","ck-editor__nested-editable"],e),t.setAttribute("role","textbox",e),i.label&&t.setAttribute("aria-label",i.label,e),t.setAttribute("contenteditable",e.isReadOnly?"false":"true",e),e.on("change:isReadOnly",((i,n,s)=>{t.setAttribute("contenteditable",s?"false":"true",e)})),e.on("change:isFocused",((i,n,s)=>{s?t.addClass("ck-editor__nested-editable_focused",e):t.removeClass("ck-editor__nested-editable_focused",e)})),of(e,t),e}function af(e,t){const i=e.getSelectedElement();if(i){const n=hf(e);if(n)return t.createRange(t.createPositionAt(i,n))}return Ud(e,t)}function lf(){return null}const cf="widget-type-around";function df(e,t,i){return!!e&&ef(e)&&!i.isInline(t)}function hf(e){return e.getAttribute(cf)}const uf=["before","after"],mf=(new DOMParser).parseFromString('',"image/svg+xml").firstChild,gf="ck-widget__type-around_disabled";class ff extends Is{static get pluginName(){return"WidgetTypeAround"}static get requires(){return[$g,ag]}constructor(e){super(e),this._currentFakeCaretModelElement=null}init(){const e=this.editor,t=e.editing.view;this.on("change:isEnabled",((i,n,s)=>{t.change((e=>{for(const i of t.document.roots)s?e.removeClass(gf,i):e.addClass(gf,i)})),s||e.model.change((e=>{e.removeSelectionAttribute(cf)}))})),this._enableTypeAroundUIInjection(),this._enableInsertingParagraphsOnButtonClick(),this._enableInsertingParagraphsOnEnterKeypress(),this._enableInsertingParagraphsOnTypingKeystroke(),this._enableTypeAroundFakeCaretActivationUsingKeyboardArrows(),this._enableDeleteIntegration(),this._enableInsertContentIntegration(),this._enableInsertObjectIntegration(),this._enableDeleteContentIntegration()}destroy(){super.destroy(),this._currentFakeCaretModelElement=null}_insertParagraph(e,t){const i=this.editor,n=i.editing.view,s=i.model.schema.getAttributesWithProperty(e,"copyOnReplace",!0);i.execute("insertParagraph",{position:i.model.createPositionAt(e,t),attributes:s}),n.focus(),n.scrollToTheSelection()}_listenToIfEnabled(e,t,i,n){this.listenTo(e,t,((...e)=>{this.isEnabled&&i(...e)}),n)}_insertParagraphAccordingToFakeCaretPosition(){const e=this.editor.model.document.selection,t=hf(e);if(!t)return!1;const i=e.getSelectedElement();return this._insertParagraph(i,t),!0}_enableTypeAroundUIInjection(){const e=this.editor,t=e.model.schema,i=e.locale.t,n={before:i("Insert paragraph before block"),after:i("Insert paragraph after block")};e.editing.downcastDispatcher.on("insert",((e,s,o)=>{const r=o.mapper.toViewElement(s.item);if(r&&df(r,s.item,t)){!function(e,t,i){const n=e.createUIElement("div",{class:"ck ck-reset_all ck-widget__type-around"},(function(e){const i=this.toDomElement(e);return function(e,t){for(const i of uf){const n=new Kh({tag:"div",attributes:{class:["ck","ck-widget__type-around__button",`ck-widget__type-around__button_${i}`],title:t[i],"aria-hidden":"true"},children:[e.ownerDocument.importNode(mf,!0)]});e.appendChild(n.render())}}(i,t),function(e){const t=new Kh({tag:"div",attributes:{class:["ck","ck-widget__type-around__fake-caret"]}});e.appendChild(t.render())}(i),i}));e.insert(e.createPositionAt(i,"end"),n)}(o.writer,n,r);r.getCustomProperty("widgetLabel").push((()=>this.isEnabled?i("Press Enter to type after or press Shift + Enter to type before the widget"):""))}}),{priority:"low"})}_enableTypeAroundFakeCaretActivationUsingKeyboardArrows(){const e=this.editor,t=e.model,i=t.document.selection,n=t.schema,s=e.editing.view;function o(e){return`ck-widget_type-around_show-fake-caret_${e}`}this._listenToIfEnabled(s.document,"arrowKey",((e,t)=>{this._handleArrowKeyPress(e,t)}),{context:[ef,"$text"],priority:"high"}),this._listenToIfEnabled(i,"change:range",((t,i)=>{i.directChange&&e.model.change((e=>{e.removeSelectionAttribute(cf)}))})),this._listenToIfEnabled(t.document,"change:data",(()=>{const t=i.getSelectedElement();if(t){if(df(e.editing.mapper.toViewElement(t),t,n))return}e.model.change((e=>{e.removeSelectionAttribute(cf)}))})),this._listenToIfEnabled(e.editing.downcastDispatcher,"selection",((e,t,i)=>{const s=i.writer;if(this._currentFakeCaretModelElement){const e=i.mapper.toViewElement(this._currentFakeCaretModelElement);e&&(s.removeClass(uf.map(o),e),this._currentFakeCaretModelElement=null)}const r=t.selection.getSelectedElement();if(!r)return;const a=i.mapper.toViewElement(r);if(!df(a,r,n))return;const l=hf(t.selection);l&&(s.addClass(o(l),a),this._currentFakeCaretModelElement=r)})),this._listenToIfEnabled(e.ui.focusTracker,"change:isFocused",((t,i,n)=>{n||e.model.change((e=>{e.removeSelectionAttribute(cf)}))}))}_handleArrowKeyPress(e,t){const i=this.editor,n=i.model,s=n.document.selection,o=n.schema,r=i.editing.view,a=function(e,t){const i=fs(e,t);return"down"===i||"right"===i}(t.keyCode,i.locale.contentLanguageDirection),l=r.document.selection.getSelectedElement();let c;df(l,i.editing.mapper.toModelElement(l),o)?c=this._handleArrowKeyPressOnSelectedWidget(a):s.isCollapsed?c=this._handleArrowKeyPressWhenSelectionNextToAWidget(a):t.shiftKey||(c=this._handleArrowKeyPressWhenNonCollapsedSelection(a)),c&&(t.preventDefault(),e.stop())}_handleArrowKeyPressOnSelectedWidget(e){const t=this.editor.model,i=hf(t.document.selection);return t.change((t=>{if(!i)return t.setSelectionAttribute(cf,e?"after":"before"),!0;if(!(i===(e?"after":"before")))return t.removeSelectionAttribute(cf),!0;return!1}))}_handleArrowKeyPressWhenSelectionNextToAWidget(e){const t=this.editor,i=t.model,n=i.schema,s=t.plugins.get("Widget"),o=s._getObjectElementNextToSelection(e);return!!df(t.editing.mapper.toViewElement(o),o,n)&&(i.change((t=>{s._setSelectionOverElement(o),t.setSelectionAttribute(cf,e?"before":"after")})),!0)}_handleArrowKeyPressWhenNonCollapsedSelection(e){const t=this.editor,i=t.model,n=i.schema,s=t.editing.mapper,o=i.document.selection,r=e?o.getLastPosition().nodeBefore:o.getFirstPosition().nodeAfter;return!!df(s.toViewElement(r),r,n)&&(i.change((t=>{t.setSelection(r,"on"),t.setSelectionAttribute(cf,e?"after":"before")})),!0)}_enableInsertingParagraphsOnButtonClick(){const e=this.editor,t=e.editing.view;this._listenToIfEnabled(t.document,"mousedown",((i,n)=>{const s=n.domTarget.closest(".ck-widget__type-around__button");if(!s)return;const o=function(e){return e.classList.contains("ck-widget__type-around__button_before")?"before":"after"}(s),r=function(e,t){const i=e.closest(".ck-widget");return t.mapDomToView(i)}(s,t.domConverter),a=e.editing.mapper.toModelElement(r);this._insertParagraph(a,o),n.preventDefault(),i.stop()}))}_enableInsertingParagraphsOnEnterKeypress(){const e=this.editor,t=e.model.document.selection,i=e.editing.view;this._listenToIfEnabled(i.document,"enter",((i,n)=>{if("atTarget"!=i.eventPhase)return;const s=t.getSelectedElement(),o=e.editing.mapper.toViewElement(s),r=e.model.schema;let a;this._insertParagraphAccordingToFakeCaretPosition()?a=!0:df(o,s,r)&&(this._insertParagraph(s,n.isSoft?"before":"after"),a=!0),a&&(n.preventDefault(),i.stop())}),{context:ef})}_enableInsertingParagraphsOnTypingKeystroke(){const e=this.editor.editing.view.document;this._listenToIfEnabled(e,"insertText",((t,i)=>{this._insertParagraphAccordingToFakeCaretPosition()&&(i.selection=e.selection)}),{priority:"high"}),s.isAndroid?this._listenToIfEnabled(e,"keydown",((e,t)=>{229==t.keyCode&&this._insertParagraphAccordingToFakeCaretPosition()})):this._listenToIfEnabled(e,"compositionstart",(()=>{this._insertParagraphAccordingToFakeCaretPosition()}),{priority:"high"})}_enableDeleteIntegration(){const e=this.editor,t=e.editing.view,i=e.model,n=i.schema;this._listenToIfEnabled(t.document,"delete",((t,s)=>{if("atTarget"!=t.eventPhase)return;const o=hf(i.document.selection);if(!o)return;const r=s.direction,a=i.document.selection.getSelectedElement(),l="forward"==r;if("before"===o===l)e.execute("delete",{selection:i.createSelection(a,"on")});else{const t=n.getNearestSelectionRange(i.createPositionAt(a,o),r);if(t)if(t.isCollapsed){const s=i.createSelection(t.start);if(i.modifySelection(s,{direction:r}),s.focus.isEqual(t.start)){const e=function(e,t){let i=t;for(const n of t.getAncestors({parentFirst:!0})){if(n.childCount>1||e.isLimit(n))break;i=n}return i}(n,t.start.parent);i.deleteContent(i.createSelection(e,"on"),{doNotAutoparagraph:!0})}else i.change((i=>{i.setSelection(t),e.execute(l?"deleteForward":"delete")}))}else i.change((i=>{i.setSelection(t),e.execute(l?"deleteForward":"delete")}))}s.preventDefault(),t.stop()}),{context:ef})}_enableInsertContentIntegration(){const e=this.editor,t=this.editor.model,i=t.document.selection;this._listenToIfEnabled(e.model,"insertContent",((e,[n,s])=>{if(s&&!s.is("documentSelection"))return;const o=hf(i);return o?(e.stop(),t.change((e=>{const s=i.getSelectedElement(),r=t.createPositionAt(s,o),a=e.createSelection(r),l=t.insertContent(n,a);return e.setSelection(a),l}))):void 0}),{priority:"high"})}_enableInsertObjectIntegration(){const e=this.editor,t=this.editor.model.document.selection;this._listenToIfEnabled(e.model,"insertObject",((e,i)=>{const[,n,,s={}]=i;if(n&&!n.is("documentSelection"))return;const o=hf(t);o&&(s.findOptimalPosition=o,i[3]=s)}),{priority:"high"})}_enableDeleteContentIntegration(){const e=this.editor,t=this.editor.model.document.selection;this._listenToIfEnabled(e.model,"deleteContent",((e,[i])=>{if(i&&!i.is("documentSelection"))return;hf(t)&&e.stop()}),{priority:"high"})}}function pf(e){const t=e.model;return(i,n)=>{const s=n.keyCode==ds.arrowup,o=n.keyCode==ds.arrowdown,r=n.shiftKey,a=t.document.selection;if(!s&&!o)return;const l=o;if(r&&function(e,t){return!e.isCollapsed&&e.isBackward==t}(a,l))return;const c=function(e,t,i){const n=e.model;if(i){const e=t.isCollapsed?t.focus:t.getLastPosition(),i=wf(n,e,"forward");if(!i)return null;const s=n.createRange(e,i),o=bf(n.schema,s,"backward");return o?n.createRange(e,o):null}{const e=t.isCollapsed?t.focus:t.getFirstPosition(),i=wf(n,e,"backward");if(!i)return null;const s=n.createRange(i,e),o=bf(n.schema,s,"forward");return o?n.createRange(o,e):null}}(e,a,l);if(c){if(c.isCollapsed){if(a.isCollapsed)return;if(r)return}(c.isCollapsed||function(e,t,i){const n=e.model,s=e.view.domConverter;if(i){const e=n.createSelection(t.start);n.modifySelection(e),e.focus.isAtEnd||t.start.isEqual(e.focus)||(t=n.createRange(e.focus,t.end))}const o=e.mapper.toViewRange(t),r=s.viewRangeToDom(o),a=Nn.getDomRangeRects(r);let l;for(const e of a)if(void 0!==l){if(Math.round(e.top)>=l)return!1;l=Math.max(l,Math.round(e.bottom))}else l=Math.round(e.bottom);return!0}(e,c,l))&&(t.change((e=>{const i=l?c.end:c.start;if(r){const n=t.createSelection(a.anchor);n.setFocus(i),e.setSelection(n)}else e.setSelection(i)})),i.stop(),n.preventDefault(),n.stopPropagation())}}}function wf(e,t,i){const n=e.schema,s=e.createRangeIn(t.root),o="forward"==i?"elementStart":"elementEnd";for(const{previousPosition:e,item:r,type:a}of s.getWalker({startPosition:t,direction:i})){if(n.isLimit(r)&&!n.isInline(r))return e;if(a==o&&n.isBlock(r))return null}return null}function bf(e,t,i){const n="backward"==i?t.end:t.start;if(e.checkChild(n,"$text"))return n;for(const{nextPosition:n}of t.getWalker({direction:i}))if(e.checkChild(n,"$text"))return n;return null}class vf extends Is{static get pluginName(){return"Widget"}static get requires(){return[ff,ag]}init(){const e=this.editor,t=e.editing.view,i=t.document;this._previouslySelected=new Set,this.editor.editing.downcastDispatcher.on("selection",((t,i,n)=>{const s=n.writer,o=i.selection;if(o.isCollapsed)return;const r=o.getSelectedElement();if(!r)return;const a=e.editing.mapper.toViewElement(r);var l;ef(a)&&(n.consumable.consume(o,"selection")&&s.setSelection(s.createRangeOn(a),{fake:!0,label:(l=a,l.getCustomProperty("widgetLabel").reduce(((e,t)=>"function"==typeof t?e?e+". "+t():t():e?e+". "+t:t),""))}))})),this.editor.editing.downcastDispatcher.on("selection",((e,t,i)=>{this._clearPreviouslySelectedWidgets(i.writer);const n=i.writer,s=n.document.selection;let o=null;for(const e of s.getRanges())for(const t of e){const e=t.item;ef(e)&&!_f(e,o)&&(n.addClass(Zg,e),this._previouslySelected.add(e),o=e)}}),{priority:"low"}),t.addObserver(th),this.listenTo(i,"mousedown",((...e)=>this._onMousedown(...e))),this.listenTo(i,"arrowKey",((...e)=>{this._handleSelectionChangeOnArrowKeyPress(...e)}),{context:[ef,"$text"]}),this.listenTo(i,"arrowKey",((...e)=>{this._preventDefaultOnArrowKeyPress(...e)}),{context:"$root"}),this.listenTo(i,"arrowKey",pf(this.editor.editing),{context:"$text"}),this.listenTo(i,"delete",((e,t)=>{this._handleDelete("forward"==t.direction)&&(t.preventDefault(),e.stop())}),{context:"$root"})}_onMousedown(e,t){const i=this.editor,n=i.editing.view,o=n.document;let r=t.target;if(function(e){let t=e;for(;t;){if(t.is("editableElement")&&!t.is("rootElement"))return!0;if(ef(t))return!1;t=t.parent}return!1}(r)){if((s.isSafari||s.isGecko)&&t.domEvent.detail>=3){const e=i.editing.mapper,n=r.is("attributeElement")?r.findAncestor((e=>!e.is("attributeElement"))):r,s=e.toModelElement(n);t.preventDefault(),this.editor.model.change((e=>{e.setSelection(s,"in")}))}return}if(!ef(r)&&(r=r.findAncestor(ef),!r))return;s.isAndroid&&t.preventDefault(),o.isFocused||n.focus();const a=i.editing.mapper.toModelElement(r);this._setSelectionOverElement(a)}_handleSelectionChangeOnArrowKeyPress(e,t){const i=t.keyCode,n=this.editor.model,s=n.schema,o=n.document.selection,r=o.getSelectedElement(),a=fs(i,this.editor.locale.contentLanguageDirection),l="down"==a||"right"==a,c="up"==a||"down"==a;if(r&&s.isObject(r)){const i=l?o.getLastPosition():o.getFirstPosition(),r=s.getNearestSelectionRange(i,l?"forward":"backward");return void(r&&(n.change((e=>{e.setSelection(r)})),t.preventDefault(),e.stop()))}if(!o.isCollapsed&&!t.shiftKey){const i=o.getFirstPosition(),r=o.getLastPosition(),a=i.nodeAfter,c=r.nodeBefore;return void((a&&s.isObject(a)||c&&s.isObject(c))&&(n.change((e=>{e.setSelection(l?r:i)})),t.preventDefault(),e.stop()))}if(!o.isCollapsed)return;const d=this._getObjectElementNextToSelection(l);if(d&&s.isObject(d)){if(s.isInline(d)&&c)return;this._setSelectionOverElement(d),t.preventDefault(),e.stop()}}_preventDefaultOnArrowKeyPress(e,t){const i=this.editor.model,n=i.schema,s=i.document.selection.getSelectedElement();s&&n.isObject(s)&&(t.preventDefault(),e.stop())}_handleDelete(e){if(this.editor.isReadOnly)return;const t=this.editor.model.document.selection;if(!t.isCollapsed)return;const i=this._getObjectElementNextToSelection(e);return i?(this.editor.model.change((e=>{let n=t.anchor.parent;for(;n.isEmpty;){const t=n;n=t.parent,e.remove(t)}this._setSelectionOverElement(i)})),!0):void 0}_setSelectionOverElement(e){this.editor.model.change((t=>{t.setSelection(t.createRangeOn(e))}))}_getObjectElementNextToSelection(e){const t=this.editor.model,i=t.schema,n=t.document.selection,s=t.createSelection(n);if(t.modifySelection(s,{direction:e?"forward":"backward"}),s.isEqual(n))return null;const o=e?s.focus.nodeBefore:s.focus.nodeAfter;return o&&i.isObject(o)?o:null}_clearPreviouslySelectedWidgets(e){for(const t of this._previouslySelected)e.removeClass(Zg,t);this._previouslySelected.clear()}}function _f(e,t){return!!t&&Array.from(e.getAncestors()).includes(t)}class yf extends Is{static get requires(){return[Pm]}static get pluginName(){return"WidgetToolbarRepository"}init(){const e=this.editor;if(e.plugins.has("BalloonToolbar")){const t=e.plugins.get("BalloonToolbar");this.listenTo(t,"show",(t=>{(function(e){const t=e.getSelectedElement();return!(!t||!ef(t))})(e.editing.view.document.selection)&&t.stop()}),{priority:"high"})}this._toolbarDefinitions=new Map,this._balloon=this.editor.plugins.get("ContextualBalloon"),this.on("change:isEnabled",(()=>{this._updateToolbarsVisibility()})),this.listenTo(e.ui,"update",(()=>{this._updateToolbarsVisibility()})),this.listenTo(e.ui.focusTracker,"change:isFocused",(()=>{this._updateToolbarsVisibility()}),{priority:"low"})}destroy(){super.destroy();for(const e of this._toolbarDefinitions.values())e.view.destroy()}register(e,{ariaLabel:t,items:i,getRelatedElement:n,balloonClassName:s="ck-toolbar-container"}){if(!i.length)return void v("widget-toolbar-no-items",{toolbarId:e});const o=this.editor,r=o.t,a=new tm(o.locale);if(a.ariaLabel=t||r("Widget toolbar"),this._toolbarDefinitions.has(e))throw new b("widget-toolbar-duplicated",this,{toolbarId:e});a.fillFromConfig(i,o.ui.componentFactory);const l={view:a,getRelatedElement:n,balloonClassName:s};o.ui.addToolbar(a,{isContextual:!0,beforeFocus:()=>{const e=n(o.editing.view.document.selection);e&&this._showToolbar(l,e)},afterBlur:()=>{this._hideToolbar(l)}}),this._toolbarDefinitions.set(e,l)}_updateToolbarsVisibility(){let e=0,t=null,i=null;for(const n of this._toolbarDefinitions.values()){const s=n.getRelatedElement(this.editor.editing.view.document.selection);if(this.isEnabled&&s)if(this.editor.ui.focusTracker.isFocused){const o=s.getAncestors().length;o>e&&(e=o,t=s,i=n)}else this._isToolbarVisible(n)&&this._hideToolbar(n);else this._isToolbarInBalloon(n)&&this._hideToolbar(n)}i&&this._showToolbar(i,t)}_hideToolbar(e){this._balloon.remove(e.view),this.stopListening(this._balloon,"change:visibleView")}_showToolbar(e,t){this._isToolbarVisible(e)?kf(this.editor,t):this._isToolbarInBalloon(e)||(this._balloon.add({view:e.view,position:Cf(this.editor,t),balloonClassName:e.balloonClassName}),this.listenTo(this._balloon,"change:visibleView",(()=>{for(const e of this._toolbarDefinitions.values())if(this._isToolbarVisible(e)){const t=e.getRelatedElement(this.editor.editing.view.document.selection);kf(this.editor,t)}})))}_isToolbarVisible(e){return this._balloon.visibleView===e.view}_isToolbarInBalloon(e){return this._balloon.hasView(e.view)}}function kf(e,t){const i=e.plugins.get("ContextualBalloon"),n=Cf(e,t);i.updatePosition(n)}function Cf(e,t){const i=e.editing.view,n=bu.defaultPositions;return{target:i.domConverter.mapViewToDom(t),positions:[n.northArrowSouth,n.northArrowSouthWest,n.northArrowSouthEast,n.southArrowNorth,n.southArrowNorthWest,n.southArrowNorthEast,n.viewportStickyNorth]}}class Af extends(W()){constructor(e){super(),this.set("activeHandlePosition",null),this.set("proposedWidthPercents",null),this.set("proposedWidth",null),this.set("proposedHeight",null),this.set("proposedHandleHostWidth",null),this.set("proposedHandleHostHeight",null),this._options=e,this._referenceCoordinates=null}get originalWidth(){return this._originalWidth}get originalHeight(){return this._originalHeight}get originalWidthPercents(){return this._originalWidthPercents}get aspectRatio(){return this._aspectRatio}begin(e,t,i){const n=new Nn(t);this.activeHandlePosition=function(e){const t=["top-left","top-right","bottom-right","bottom-left"];for(const i of t)if(e.classList.contains(xf(i)))return i}(e),this._referenceCoordinates=function(e,t){const i=new Nn(e),n=t.split("-"),s={x:"right"==n[1]?i.right:i.left,y:"bottom"==n[0]?i.bottom:i.top};return s.x+=e.ownerDocument.defaultView.scrollX,s.y+=e.ownerDocument.defaultView.scrollY,s}(t,function(e){const t=e.split("-"),i={top:"bottom",bottom:"top",left:"right",right:"left"};return`${i[t[0]]}-${i[t[1]]}`}(this.activeHandlePosition)),this._originalWidth=n.width,this._originalHeight=n.height,this._aspectRatio=n.width/n.height;const s=i.style.width;s&&s.match(/^\d+(\.\d*)?%$/)?this._originalWidthPercents=parseFloat(s):this._originalWidthPercents=function(e,t){const i=e.parentElement,n=parseFloat(i.ownerDocument.defaultView.getComputedStyle(i).width);return t.width/n*100}(i,n)}update(e){this.proposedWidth=e.width,this.proposedHeight=e.height,this.proposedWidthPercents=e.widthPercents,this.proposedHandleHostWidth=e.handleHostWidth,this.proposedHandleHostHeight=e.handleHostHeight}}function xf(e){return`ck-widget__resizer__handle-${e}`}class Tf extends fu{constructor(){super();const e=this.bindTemplate;this.setTemplate({tag:"div",attributes:{class:["ck","ck-size-view",e.to("_viewPosition",(e=>e?`ck-orientation-${e}`:""))],style:{display:e.if("_isVisible","none",(e=>!e))}},children:[{text:e.to("_label")}]})}_bindToState(e,t){this.bind("_isVisible").to(t,"proposedWidth",t,"proposedHeight",((e,t)=>null!==e&&null!==t)),this.bind("_label").to(t,"proposedHandleHostWidth",t,"proposedHandleHostHeight",t,"proposedWidthPercents",((t,i,n)=>"px"===e.unit?`${t}×${i}`:`${n}%`)),this.bind("_viewPosition").to(t,"activeHandlePosition",t,"proposedHandleHostWidth",t,"proposedHandleHostHeight",((e,t,i)=>t<50||i<50?"above-center":e))}_dismiss(){this.unbind(),this._isVisible=!1}}class Ef extends(W()){constructor(e){super(),this._options=e,this._viewResizerWrapper=null,this.set("isEnabled",!0),this.set("isSelected",!1),this.bind("isVisible").to(this,"isEnabled",this,"isSelected",((e,t)=>e&&t)),this.decorate("begin"),this.decorate("cancel"),this.decorate("commit"),this.decorate("updateSize"),this.on("commit",(e=>{this.state.proposedWidth||this.state.proposedWidthPercents||(this._cleanup(),e.stop())}),{priority:"high"})}get state(){return this._state}show(){this._options.editor.editing.view.change((e=>{e.removeClass("ck-hidden",this._viewResizerWrapper)}))}hide(){this._options.editor.editing.view.change((e=>{e.addClass("ck-hidden",this._viewResizerWrapper)}))}attach(){const e=this,t=this._options.viewElement;this._options.editor.editing.view.change((i=>{const n=i.createUIElement("div",{class:"ck ck-reset_all ck-widget__resizer"},(function(t){const i=this.toDomElement(t);return e._appendHandles(i),e._appendSizeUI(i),i}));i.insert(i.createPositionAt(t,"end"),n),i.addClass("ck-widget_with-resizer",t),this._viewResizerWrapper=n,this.isVisible||this.hide()})),this.on("change:isVisible",(()=>{this.isVisible?(this.show(),this.redraw()):this.hide()}))}begin(e){this._state=new Af(this._options),this._sizeView._bindToState(this._options,this.state),this._initialViewWidth=this._options.viewElement.getStyle("width"),this.state.begin(e,this._getHandleHost(),this._getResizeHost())}updateSize(e){const t=this._proposeNewSize(e);this._options.editor.editing.view.change((e=>{const i=this._options.unit||"%",n=("%"===i?t.widthPercents:t.width)+i;e.setStyle("width",n,this._options.viewElement)}));const i=this._getHandleHost(),n=new Nn(i),s=Math.round(n.width),o=Math.round(n.height),r=new Nn(i);t.width=Math.round(r.width),t.height=Math.round(r.height),this.redraw(n),this.state.update({...t,handleHostWidth:s,handleHostHeight:o})}commit(){const e=this._options.unit||"%",t=("%"===e?this.state.proposedWidthPercents:this.state.proposedWidth)+e;this._options.editor.editing.view.change((()=>{this._cleanup(),this._options.onCommit(t)}))}cancel(){this._cleanup()}destroy(){this.cancel()}redraw(e){const t=this._domResizerWrapper;if(!((i=t)&&i.ownerDocument&&i.ownerDocument.contains(i)))return;var i;const n=t.parentElement,s=this._getHandleHost(),o=this._viewResizerWrapper,r=[o.getStyle("width"),o.getStyle("height"),o.getStyle("left"),o.getStyle("top")];let a;if(n.isSameNode(s)){const t=e||new Nn(s);a=[t.width+"px",t.height+"px",void 0,void 0]}else a=[s.offsetWidth+"px",s.offsetHeight+"px",s.offsetLeft+"px",s.offsetTop+"px"];"same"!==Y(r,a)&&this._options.editor.editing.view.change((e=>{e.setStyle({width:a[0],height:a[1],left:a[2],top:a[3]},o)}))}containsHandle(e){return this._domResizerWrapper.contains(e)}static isResizeHandle(e){return e.classList.contains("ck-widget__resizer__handle")}_cleanup(){this._sizeView._dismiss();this._options.editor.editing.view.change((e=>{e.setStyle("width",this._initialViewWidth,this._options.viewElement)}))}_proposeNewSize(e){const t=this.state,i={x:(n=e).pageX,y:n.pageY};var n;const s=!this._options.isCentered||this._options.isCentered(this),o={x:t._referenceCoordinates.x-(i.x+t.originalWidth),y:i.y-t.originalHeight-t._referenceCoordinates.y};s&&t.activeHandlePosition.endsWith("-right")&&(o.x=i.x-(t._referenceCoordinates.x+t.originalWidth)),s&&(o.x*=2);let r=Math.abs(t.originalWidth+o.x),a=Math.abs(t.originalHeight+o.y);return"width"==(r/t.aspectRatio>a?"width":"height")?a=r/t.aspectRatio:r=a*t.aspectRatio,{width:Math.round(r),height:Math.round(a),widthPercents:Math.min(Math.round(t.originalWidthPercents/t.originalWidth*r*100)/100,100)}}_getResizeHost(){const e=this._domResizerWrapper.parentElement;return this._options.getResizeHost(e)}_getHandleHost(){const e=this._domResizerWrapper.parentElement;return this._options.getHandleHost(e)}get _domResizerWrapper(){return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper)}_appendHandles(e){const t=["top-left","top-right","bottom-right","bottom-left"];for(const n of t)e.appendChild(new Kh({tag:"div",attributes:{class:"ck-widget__resizer__handle "+(i=n,`ck-widget__resizer__handle-${i}`)}}).render());var i}_appendSizeUI(e){this._sizeView=new Tf,this._sizeView.render(),e.appendChild(this._sizeView.element)}}const Sf=function(e,t,i){var n=!0,s=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return M(i)&&(n="leading"in i?!!i.leading:n,s="trailing"in i?!!i.trailing:s),xa(e,t,{leading:n,maxWait:t,trailing:s})};class Pf extends Is{static get pluginName(){return"WidgetResize"}init(){const e=this.editor.editing,t=Rn.window.document;this.set("selectedResizer",null),this.set("_activeResizer",null),this._resizers=new Map,e.view.addObserver(th),this._observer=new(En()),this.listenTo(e.view.document,"mousedown",this._mouseDownListener.bind(this),{priority:"high"}),this._observer.listenTo(t,"mousemove",this._mouseMoveListener.bind(this)),this._observer.listenTo(t,"mouseup",this._mouseUpListener.bind(this)),this._redrawSelectedResizerThrottled=Sf((()=>this.redrawSelectedResizer()),200),this.editor.ui.on("update",this._redrawSelectedResizerThrottled),this.editor.model.document.on("change",(()=>{for(const[e,t]of this._resizers)e.isAttached()||(this._resizers.delete(e),t.destroy())}),{priority:"lowest"}),this._observer.listenTo(Rn.window,"resize",this._redrawSelectedResizerThrottled);const i=this.editor.editing.view.document.selection;i.on("change",(()=>{const e=i.getSelectedElement(),t=this.getResizerByViewElement(e)||null;t?this.select(t):this.deselect()}))}redrawSelectedResizer(){this.selectedResizer&&this.selectedResizer.isVisible&&this.selectedResizer.redraw()}destroy(){super.destroy(),this._observer.stopListening();for(const e of this._resizers.values())e.destroy();this._redrawSelectedResizerThrottled.cancel()}select(e){this.deselect(),this.selectedResizer=e,this.selectedResizer.isSelected=!0}deselect(){this.selectedResizer&&(this.selectedResizer.isSelected=!1),this.selectedResizer=null}attachTo(e){const t=new Ef(e),i=this.editor.plugins;if(t.attach(),i.has("WidgetToolbarRepository")){const e=i.get("WidgetToolbarRepository");t.on("begin",(()=>{e.forceDisabled("resize")}),{priority:"lowest"}),t.on("cancel",(()=>{e.clearForceDisabled("resize")}),{priority:"highest"}),t.on("commit",(()=>{e.clearForceDisabled("resize")}),{priority:"highest"})}this._resizers.set(e.viewElement,t);const n=this.editor.editing.view.document.selection.getSelectedElement();return this.getResizerByViewElement(n)==t&&this.select(t),t}getResizerByViewElement(e){return this._resizers.get(e)}_getResizerByHandle(e){for(const t of this._resizers.values())if(t.containsHandle(e))return t}_mouseDownListener(e,t){const i=t.domTarget;Ef.isResizeHandle(i)&&(this._activeResizer=this._getResizerByHandle(i)||null,this._activeResizer&&(this._activeResizer.begin(i),e.stop(),t.preventDefault()))}_mouseMoveListener(e,t){this._activeResizer&&this._activeResizer.updateSize(t)}_mouseUpListener(){this._activeResizer&&(this._activeResizer.commit(),this._activeResizer=null)}}class If extends Is{static get pluginName(){return"DragDrop"}static get requires(){return[Mg,vf]}init(){const e=this.editor,t=e.editing.view;this._draggedRange=null,this._draggingUid="",this._draggableElement=null,this._updateDropMarkerThrottled=Sf((e=>this._updateDropMarker(e)),40),this._removeDropMarkerDelayed=Lf((()=>this._removeDropMarker()),40),this._clearDraggableAttributesDelayed=Lf((()=>this._clearDraggableAttributes()),40),t.addObserver(Lg),t.addObserver(th),this._setupDragging(),this._setupContentInsertionIntegration(),this._setupClipboardInputIntegration(),this._setupDropMarker(),this._setupDraggableAttributeHandling(),this.listenTo(e,"change:isReadOnly",((e,t,i)=>{i?this.forceDisabled("readOnlyMode"):this.clearForceDisabled("readOnlyMode")})),this.on("change:isEnabled",((e,t,i)=>{i||this._finalizeDragging(!1)})),s.isAndroid&&this.forceDisabled("noAndroidSupport")}destroy(){return this._draggedRange&&(this._draggedRange.detach(),this._draggedRange=null),this._updateDropMarkerThrottled.cancel(),this._removeDropMarkerDelayed.cancel(),this._clearDraggableAttributesDelayed.cancel(),super.destroy()}_setupDragging(){const e=this.editor,t=e.model,i=t.document,n=e.editing.view,o=n.document;this.listenTo(o,"dragstart",((n,s)=>{const r=i.selection;if(s.target&&s.target.is("editableElement"))return void s.preventDefault();const a=s.target?Of(s.target):null;if(a){const i=e.editing.mapper.toModelElement(a);this._draggedRange=Il.fromRange(t.createRangeOn(i)),e.plugins.has("WidgetToolbarRepository")&&e.plugins.get("WidgetToolbarRepository").forceDisabled("dragDrop")}else if(!o.selection.isCollapsed){const e=o.selection.getSelectedElement();e&&ef(e)||(this._draggedRange=Il.fromRange(r.getFirstRange()))}if(!this._draggedRange)return void s.preventDefault();this._draggingUid=g(),s.dataTransfer.effectAllowed=this.isEnabled?"copyMove":"copy",s.dataTransfer.setData("application/ckeditor5-dragging-uid",this._draggingUid);const l=t.createSelection(this._draggedRange.toRange()),c=e.data.toView(t.getSelectedContent(l));o.fire("clipboardOutput",{dataTransfer:s.dataTransfer,content:c,method:"dragstart"}),this.isEnabled||(this._draggedRange.detach(),this._draggedRange=null,this._draggingUid="")}),{priority:"low"}),this.listenTo(o,"dragend",((e,t)=>{this._finalizeDragging(!t.dataTransfer.isCanceled&&"move"==t.dataTransfer.dropEffect)}),{priority:"low"}),this.listenTo(o,"dragenter",(()=>{this.isEnabled&&n.focus()})),this.listenTo(o,"dragleave",(()=>{this._removeDropMarkerDelayed()})),this.listenTo(o,"dragging",((t,i)=>{if(!this.isEnabled)return void(i.dataTransfer.dropEffect="none");this._removeDropMarkerDelayed.cancel();const n=Rf(e,i.targetRanges,i.target);this._draggedRange||(i.dataTransfer.dropEffect="copy"),s.isGecko||("copy"==i.dataTransfer.effectAllowed?i.dataTransfer.dropEffect="copy":["all","copyMove"].includes(i.dataTransfer.effectAllowed)&&(i.dataTransfer.dropEffect="move")),n&&this._updateDropMarkerThrottled(n)}),{priority:"low"})}_setupClipboardInputIntegration(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"clipboardInput",((t,i)=>{if("drop"!=i.method)return;const n=Rf(e,i.targetRanges,i.target);if(this._removeDropMarker(),!n)return this._finalizeDragging(!1),void t.stop();this._draggedRange&&this._draggingUid!=i.dataTransfer.getData("application/ckeditor5-dragging-uid")&&(this._draggedRange.detach(),this._draggedRange=null,this._draggingUid="");if("move"==Vf(i.dataTransfer)&&this._draggedRange&&this._draggedRange.containsRange(n,!0))return this._finalizeDragging(!1),void t.stop();i.targetRanges=[e.editing.mapper.toViewRange(n)]}),{priority:"high"})}_setupContentInsertionIntegration(){const e=this.editor.plugins.get(Mg);e.on("contentInsertion",((e,t)=>{if(!this.isEnabled||"drop"!==t.method)return;const i=t.targetRanges.map((e=>this.editor.editing.mapper.toModelRange(e)));this.editor.model.change((e=>e.setSelection(i)))}),{priority:"high"}),e.on("contentInsertion",((e,t)=>{if(!this.isEnabled||"drop"!==t.method)return;const i="move"==Vf(t.dataTransfer),n=!t.resultRange||!t.resultRange.isCollapsed;this._finalizeDragging(n&&i)}),{priority:"lowest"})}_setupDraggableAttributeHandling(){const e=this.editor,t=e.editing.view,i=t.document;this.listenTo(i,"mousedown",((n,o)=>{if(s.isAndroid||!o)return;this._clearDraggableAttributesDelayed.cancel();let r=Of(o.target);if(s.isBlink&&!e.isReadOnly&&!r&&!i.selection.isCollapsed){const e=i.selection.getSelectedElement();e&&ef(e)||(r=i.selection.editableElement)}r&&(t.change((e=>{e.setAttribute("draggable","true",r)})),this._draggableElement=e.editing.mapper.toModelElement(r))})),this.listenTo(i,"mouseup",(()=>{s.isAndroid||this._clearDraggableAttributesDelayed()}))}_clearDraggableAttributes(){const e=this.editor.editing;e.view.change((t=>{this._draggableElement&&"$graveyard"!=this._draggableElement.root.rootName&&t.removeAttribute("draggable",e.mapper.toViewElement(this._draggableElement)),this._draggableElement=null}))}_setupDropMarker(){const e=this.editor;e.conversion.for("editingDowncast").markerToHighlight({model:"drop-target",view:{classes:["ck-clipboard-drop-target-range"]}}),e.conversion.for("editingDowncast").markerToElement({model:"drop-target",view:(t,{writer:i})=>{if(e.model.schema.checkChild(t.markerRange.start,"$text"))return i.createUIElement("span",{class:"ck ck-clipboard-drop-target-position"},(function(e){const t=this.toDomElement(e);return t.append("⁠",e.createElement("span"),"⁠"),t}))}})}_updateDropMarker(e){const t=this.editor,i=t.model.markers;t.model.change((t=>{i.has("drop-target")?i.get("drop-target").getRange().isEqual(e)||t.updateMarker("drop-target",{range:e}):t.addMarker("drop-target",{range:e,usingOperation:!1,affectsData:!1})}))}_removeDropMarker(){const e=this.editor.model;this._removeDropMarkerDelayed.cancel(),this._updateDropMarkerThrottled.cancel(),e.markers.has("drop-target")&&e.change((e=>{e.removeMarker("drop-target")}))}_finalizeDragging(e){const t=this.editor,i=t.model;this._removeDropMarker(),this._clearDraggableAttributes(),t.plugins.has("WidgetToolbarRepository")&&t.plugins.get("WidgetToolbarRepository").clearForceDisabled("dragDrop"),this._draggingUid="",this._draggedRange&&(e&&this.isEnabled&&i.deleteContent(i.createSelection(this._draggedRange),{doNotAutoparagraph:!0}),this._draggedRange.detach(),this._draggedRange=null)}}function Rf(e,t,i){const n=e.model,o=e.editing.mapper;let r=null;const a=t?t[0].start:null;if(i.is("uiElement")&&(i=i.parent),r=function(e,t){const i=e.model,n=e.editing.mapper;if(ef(t))return i.createRangeOn(n.toModelElement(t));if(!t.is("editableElement")){const e=t.findAncestor((e=>ef(e)||e.is("editableElement")));if(ef(e))return i.createRangeOn(n.toModelElement(e))}return null}(e,i),r)return r;const l=function(e,t){const i=e.editing.mapper,n=e.editing.view,s=i.toModelElement(t);if(s)return s;const o=n.createPositionBefore(t),r=i.findMappedViewAncestor(o);return i.toModelElement(r)}(e,i),c=a?o.toModelPosition(a):null;return c?(r=function(e,t,i){const n=e.model;if(!n.schema.checkChild(i,"$block"))return null;const s=n.createPositionAt(i,0),o=t.path.slice(0,s.path.length),r=n.createPositionFromPath(t.root,o),a=r.nodeAfter;if(a&&n.schema.isObject(a))return n.createRangeOn(a);return null}(e,c,l),r||(r=n.schema.getNearestSelectionRange(c,s.isGecko?"forward":"backward"),r||function(e,t){const i=e.model;let n=t;for(;n;){if(i.schema.isObject(n))return i.createRangeOn(n);n=n.parent}return null}(e,c.parent))):function(e,t){const i=e.model,n=i.schema,s=i.createPositionAt(t,0);return n.getNearestSelectionRange(s,"forward")}(e,l)}function Vf(e){return s.isGecko?e.dropEffect:["all","copyMove"].includes(e.effectAllowed)?"move":"copy"}function Lf(e,t){let i;function n(...s){n.cancel(),i=setTimeout((()=>e(...s)),t)}return n.cancel=()=>{clearTimeout(i)},n}function Of(e){if(e.is("editableElement"))return null;if(e.hasClass("ck-widget__selection-handle"))return e.findAncestor(ef);if(ef(e))return e;const t=e.findAncestor((e=>ef(e)||e.is("editableElement")));return ef(t)?t:null}class Bf extends Is{static get pluginName(){return"PastePlainText"}static get requires(){return[Mg]}init(){const e=this.editor,t=e.model,i=e.editing.view,n=i.document,s=t.document.selection;let o=!1;i.addObserver(Lg),this.listenTo(n,"keydown",((e,t)=>{o=t.shiftKey})),e.plugins.get(Mg).on("contentInsertion",((e,i)=>{(o||function(e,t){if(e.childCount>1)return!1;const i=e.getChild(0);if(t.isObject(i))return!1;return 0==Array.from(i.getAttributeKeys()).length}(i.content,t.schema))&&t.change((e=>{const n=Array.from(s.getAttributes()).filter((([e])=>t.schema.getAttributeProperties(e).isFormatting));s.isCollapsed||t.deleteContent(s,{doNotAutoparagraph:!0}),n.push(...s.getAttributes());const o=e.createRangeIn(i.content);for(const t of o.getItems())t.is("$textProxy")&&e.setAttributes(n,t)}))}))}}class Mf extends Is{static get pluginName(){return"Clipboard"}static get requires(){return[Mg,If,Bf]}}class Nf extends Vs{constructor(e){super(e),this._stack=[],this._createdBatches=new WeakSet,this.refresh(),this.listenTo(e.data,"set",((e,t)=>{t[1]={...t[1]};const i=t[1];i.batchType||(i.batchType={isUndoable:!1})}),{priority:"high"}),this.listenTo(e.data,"set",((e,t)=>{t[1].batchType.isUndoable||this.clearStack()}))}refresh(){this.isEnabled=this._stack.length>0}addBatch(e){const t=this.editor.model.document.selection,i={ranges:t.hasOwnRange?Array.from(t.getRanges()):[],isBackward:t.isBackward};this._stack.push({batch:e,selection:i}),this.refresh()}clearStack(){this._stack=[],this.refresh()}_restoreSelection(e,t,i){const n=this.editor.model,s=n.document,o=[],r=e.map((e=>e.getTransformedByOperations(i))),a=r.flat();for(const e of r){const t=e.filter((e=>e.root!=s.graveyard)).filter((e=>!Ff(e,a)));t.length&&(Df(t),o.push(t[0]))}o.length&&n.change((e=>{e.setSelection(o,{backward:t})}))}_undo(e,t){const i=this.editor.model,n=i.document;this._createdBatches.add(t);const s=e.operations.slice().filter((e=>e.isDocumentOperation));s.reverse();for(const e of s){const s=e.baseVersion+1,o=Array.from(n.history.getOperations(s)),r=sd([e.getReversed()],o,{useRelations:!0,document:this.editor.model.document,padWithNoOps:!1,forceWeakRemove:!0}).operationsA;for(const s of r)t.addOperation(s),i.applyOperation(s),n.history.setOperationAsUndone(e,s)}}}function Df(e){e.sort(((e,t)=>e.start.isBefore(t.start)?-1:1));for(let t=1;tt!==e&&t.containsRange(e,!0)))}class zf extends Nf{execute(e=null){const t=e?this._stack.findIndex((t=>t.batch==e)):this._stack.length-1,i=this._stack.splice(t,1)[0],n=this.editor.model.createBatch({isUndo:!0});this.editor.model.enqueueChange(n,(()=>{this._undo(i.batch,n);const e=this.editor.model.document.history.getOperations(i.batch.baseVersion);this._restoreSelection(i.selection.ranges,i.selection.isBackward,e),this.fire("revert",i.batch,n)})),this.refresh()}}class Hf extends Nf{execute(){const e=this._stack.pop(),t=this.editor.model.createBatch({isUndo:!0});this.editor.model.enqueueChange(t,(()=>{const i=e.batch.operations[e.batch.operations.length-1].baseVersion+1,n=this.editor.model.document.history.getOperations(i);this._restoreSelection(e.selection.ranges,e.selection.isBackward,n),this._undo(e.batch,t)})),this.refresh()}}class $f extends Is{static get pluginName(){return"UndoEditing"}constructor(e){super(e),this._batchRegistry=new WeakSet}init(){const e=this.editor;this._undoCommand=new zf(e),this._redoCommand=new Hf(e),e.commands.add("undo",this._undoCommand),e.commands.add("redo",this._redoCommand),this.listenTo(e.model,"applyOperation",((e,t)=>{const i=t[0];if(!i.isDocumentOperation)return;const n=i.batch,s=this._redoCommand._createdBatches.has(n),o=this._undoCommand._createdBatches.has(n);this._batchRegistry.has(n)||(this._batchRegistry.add(n),n.isUndoable&&(s?this._undoCommand.addBatch(n):o||(this._undoCommand.addBatch(n),this._redoCommand.clearStack())))}),{priority:"highest"}),this.listenTo(this._undoCommand,"revert",((e,t,i)=>{this._redoCommand.addBatch(i)})),e.keystrokes.set("CTRL+Z","undo"),e.keystrokes.set("CTRL+Y","redo"),e.keystrokes.set("CTRL+SHIFT+Z","redo")}}const Wf='',jf='';class qf extends Is{static get pluginName(){return"UndoUI"}init(){const e=this.editor,t=e.locale,i=e.t,n="ltr"==t.uiLanguageDirection?Wf:jf,s="ltr"==t.uiLanguageDirection?jf:Wf;this._addButton("undo",i("Undo"),"CTRL+Z",n),this._addButton("redo",i("Redo"),"CTRL+Y",s)}_addButton(e,t,i,n){const s=this.editor;s.ui.componentFactory.add(e,(o=>{const r=s.commands.get(e),a=new Mu(o);return a.set({label:t,icon:n,keystroke:i,tooltip:!0}),a.bind("isEnabled").to(r,"isEnabled"),this.listenTo(a,"execute",(()=>{s.execute(e),s.editing.view.focus()})),a}))}}class Uf extends Is{static get requires(){return[$f,qf]}static get pluginName(){return"Undo"}}function Gf(e){return e.createContainerElement("figure",{class:"image"},[e.createEmptyElement("img"),e.createSlot()])}function Kf(e,t){const i=e.plugins.get("ImageUtils"),n=e.plugins.has("ImageInlineEditing")&&e.plugins.has("ImageBlockEditing");return e=>{if(!i.isInlineImageView(e))return null;if(!n)return s(e);return("block"==e.getStyle("display")||e.findAncestor(i.isBlockImageView)?"imageBlock":"imageInline")!==t?null:s(e)};function s(e){const t={name:!0};return e.hasAttribute("src")&&(t.attributes=["src"]),t}}function Jf(e,t){const i=ks(t.getSelectedBlocks());return!i||e.isObject(i)||i.isEmpty&&"listItem"!=i.name?"imageBlock":"imageInline"}class Qf extends Is{static get pluginName(){return"ImageUtils"}isImage(e){return this.isInlineImage(e)||this.isBlockImage(e)}isInlineImageView(e){return!!e&&e.is("element","img")}isBlockImageView(e){return!!e&&e.is("element","figure")&&e.hasClass("image")}insertImage(e={},t=null,i=null){const n=this.editor,s=n.model,o=s.document.selection;i=Yf(n,t||o,i),e={...Object.fromEntries(o.getAttributes()),...e};for(const t in e)s.schema.checkAttribute(i,t)||delete e[t];return s.change((n=>{const o=n.createElement(i,e);return s.insertObject(o,t,null,{setSelection:"on",findOptimalPosition:!t&&"imageInline"!=i}),o.parent?o:null}))}getClosestSelectedImageWidget(e){const t=e.getFirstPosition();if(!t)return null;const i=e.getSelectedElement();if(i&&this.isImageWidget(i))return i;let n=t.parent;for(;n;){if(n.is("element")&&this.isImageWidget(n))return n;n=n.parent}return null}getClosestSelectedImageElement(e){const t=e.getSelectedElement();return this.isImage(t)?t:e.getFirstPosition().findAncestor("imageBlock")}isImageAllowed(){const e=this.editor.model.document.selection;return function(e,t){const i=Yf(e,t);if("imageBlock"==i){const i=function(e,t){const i=af(e,t),n=i.start.parent;if(n.isEmpty&&!n.is("element","$root"))return n.parent;return n}(t,e.model);if(e.model.schema.checkChild(i,"imageBlock"))return!0}else if(e.model.schema.checkChild(t.focus,"imageInline"))return!0;return!1}(this.editor,e)&&function(e){return[...e.focus.getAncestors()].every((e=>!e.is("element","imageBlock")))}(e)}toImageWidget(e,t,i){t.setCustomProperty("image",!0,e);return tf(e,t,{label:()=>{const t=this.findViewImgElement(e).getAttribute("alt");return t?`${t} ${i}`:i}})}isImageWidget(e){return!!e.getCustomProperty("image")&&ef(e)}isBlockImage(e){return!!e&&e.is("element","imageBlock")}isInlineImage(e){return!!e&&e.is("element","imageInline")}findViewImgElement(e){if(this.isInlineImageView(e))return e;const t=this.editor.editing.view;for(const{item:i}of t.createRangeIn(e))if(this.isInlineImageView(i))return i}}function Yf(e,t,i){const n=e.model.schema,s=e.config.get("image.insert.type");return e.plugins.has("ImageBlockEditing")?e.plugins.has("ImageInlineEditing")?i||("inline"===s?"imageInline":"block"===s?"imageBlock":t.is("selection")?Jf(n,t):n.checkChild(t,"imageInline")?"imageInline":"imageBlock"):"imageBlock":"imageInline"}const Xf=new RegExp(String(/^(http(s)?:\/\/)?[\w-]+\.[\w.~:/[\]@!$&'()*+,;=%-]+/.source+/\.(jpg|jpeg|png|gif|ico|webp|JPG|JPEG|PNG|GIF|ICO|WEBP)/.source+/(\?[\w.~:/[\]@!$&'()*+,;=%-]*)?/.source+/(#[\w.~:/[\]@!$&'()*+,;=%-]*)?$/.source));const Zf=function(e,t,i){var n=e.length;return i=void 0===i?n:i,!t&&i>=n?e:bo(e,t,i)};var ep=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");const tp=function(e){return ep.test(e)};const ip=function(e){return e.split("")};var np="\\ud800-\\udfff",sp="["+np+"]",op="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",rp="\\ud83c[\\udffb-\\udfff]",ap="[^"+np+"]",lp="(?:\\ud83c[\\udde6-\\uddff]){2}",cp="[\\ud800-\\udbff][\\udc00-\\udfff]",dp="(?:"+op+"|"+rp+")"+"?",hp="[\\ufe0e\\ufe0f]?",up=hp+dp+("(?:\\u200d(?:"+[ap,lp,cp].join("|")+")"+hp+dp+")*"),mp="(?:"+[ap+op+"?",op,lp,cp,sp].join("|")+")",gp=RegExp(rp+"(?="+rp+")|"+mp+up,"g");const fp=function(e){return e.match(gp)||[]};const pp=function(e){return tp(e)?fp(e):ip(e)};const wp=function(e){return function(t){t=mo(t);var i=tp(t)?pp(t):void 0,n=i?i[0]:t.charAt(0),s=i?Zf(i,1).join(""):t.slice(1);return n[e]()+s}}("toUpperCase"),bp=/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g,vp=/^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i,_p=/^[\S]+@((?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.))+(?:[a-z\u00a1-\uffff]{2,})$/i,yp=/^((\w+:(\/{2,})?)|(\W))/i,kp="Ctrl+K";function Cp(e,{writer:t}){const i=t.createAttributeElement("a",{href:e},{priority:5});return t.setCustomProperty("link",!0,i),i}function Ap(e){return function(e){const t=e.replace(bp,"");return t.match(vp)}(e=String(e))?e:"#"}function xp(e,t){return!!e&&t.checkAttribute(e.name,"linkHref")}function Tp(e,t){const i=(n=e,_p.test(n)?"mailto:":t);var n;const s=!!i&&!Ep(e);return e&&s?i+e:e}function Ep(e){return yp.test(e)}function Sp(e){window.open(e,"_blank","noopener")}const Pp=new RegExp("(^|\\s)(((?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(((?!www\\.)|(www\\.))(?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.)+(?:[a-z\\u00a1-\\uffff]{2,63})))(?::\\d{2,5})?(?:[/?#]\\S*)?)|((www.|(\\S+@))((?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.))+(?:[a-z\\u00a1-\\uffff]{2,63})))$","i");class Ip extends Is{static get requires(){return[ag]}static get pluginName(){return"AutoLink"}init(){const e=this.editor.model.document.selection;e.on("change:range",(()=>{this.isEnabled=!e.anchor.parent.is("element","codeBlock")})),this._enableTypingHandling()}afterInit(){this._enableEnterHandling(),this._enableShiftEnterHandling()}_enableTypingHandling(){const e=this.editor,t=new dg(e.model,(e=>{if(!function(e){return e.length>4&&" "===e[e.length-1]&&" "!==e[e.length-2]}(e))return;const t=Rp(e.substr(0,e.length-1));return t?{url:t}:void 0}));t.on("matched:data",((t,i)=>{const{batch:n,range:s,url:o}=i;if(!n.isTyping)return;const r=s.end.getShiftedBy(-1),a=r.getShiftedBy(-o.length),l=e.model.createRange(a,r);this._applyAutoLink(o,l)})),t.bind("isEnabled").to(this)}_enableEnterHandling(){const e=this.editor,t=e.model,i=e.commands.get("enter");i&&i.on("execute",(()=>{const e=t.document.selection.getFirstPosition();if(!e.parent.previousSibling)return;const i=t.createRangeIn(e.parent.previousSibling);this._checkAndApplyAutoLinkOnRange(i)}))}_enableShiftEnterHandling(){const e=this.editor,t=e.model,i=e.commands.get("shiftEnter");i&&i.on("execute",(()=>{const e=t.document.selection.getFirstPosition(),i=t.createRange(t.createPositionAt(e.parent,0),e.getShiftedBy(-1));this._checkAndApplyAutoLinkOnRange(i)}))}_checkAndApplyAutoLinkOnRange(e){const t=this.editor.model,{text:i,range:n}=cg(e,t),s=Rp(i);if(s){const e=t.createRange(n.end.getShiftedBy(-s.length),n.end);this._applyAutoLink(s,e)}}_applyAutoLink(e,t){const i=this.editor.model,n=Tp(e,this.editor.config.get("link.defaultProtocol"));this.isEnabled&&function(e,t){return t.schema.checkAttributeInSelection(t.createSelection(e),"linkHref")}(t,i)&&Ep(n)&&!function(e){const t=e.start.nodeAfter;return t&&t.hasAttribute("linkHref")}(t)&&this._persistAutoLink(n,t)}_persistAutoLink(e,t){const i=this.editor.model,n=this.editor.plugins.get("Delete");i.enqueueChange((s=>{s.setAttribute("linkHref",e,t),i.enqueueChange((()=>{n.requestUndoOnBackspace()}))}))}}function Rp(e){const t=Pp.exec(e);return t?t[2]:null}class Vp extends Vs{refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor.model,i=t.schema,n=t.document.selection,s=Array.from(n.getSelectedBlocks()),o=void 0===e.forceValue?!this.value:e.forceValue;t.change((e=>{if(o){const t=s.filter((e=>Lp(e)||Bp(i,e)));this._applyQuote(e,t)}else this._removeQuote(e,s.filter(Lp))}))}_getValue(){const e=ks(this.editor.model.document.selection.getSelectedBlocks());return!(!e||!Lp(e))}_checkEnabled(){if(this.value)return!0;const e=this.editor.model.document.selection,t=this.editor.model.schema,i=ks(e.getSelectedBlocks());return!!i&&Bp(t,i)}_removeQuote(e,t){Op(e,t).reverse().forEach((t=>{if(t.start.isAtStart&&t.end.isAtEnd)return void e.unwrap(t.start.parent);if(t.start.isAtStart){const i=e.createPositionBefore(t.start.parent);return void e.move(t,i)}t.end.isAtEnd||e.split(t.end);const i=e.createPositionAfter(t.end.parent);e.move(t,i)}))}_applyQuote(e,t){const i=[];Op(e,t).reverse().forEach((t=>{let n=Lp(t.start);n||(n=e.createElement("blockQuote"),e.wrap(t,n)),i.push(n)})),i.reverse().reduce(((t,i)=>t.nextSibling==i?(e.merge(e.createPositionAfter(t)),t):i))}}function Lp(e){return"blockQuote"==e.parent.name?e.parent:null}function Op(e,t){let i,n=0;const s=[];for(;n{const n=e.model.document.differ.getChanges();for(const e of n)if("insert"==e.type){const n=e.position.nodeAfter;if(!n)continue;if(n.is("element","blockQuote")&&n.isEmpty)return i.remove(n),!0;if(n.is("element","blockQuote")&&!t.checkChild(e.position,n))return i.unwrap(n),!0;if(n.is("element")){const e=i.createRangeIn(n);for(const n of e.getItems())if(n.is("element","blockQuote")&&!t.checkChild(i.createPositionBefore(n),n))return i.unwrap(n),!0}}else if("remove"==e.type){const t=e.position.parent;if(t.is("element","blockQuote")&&t.isEmpty)return i.remove(t),!0}return!1}));const i=this.editor.editing.view.document,n=e.model.document.selection,s=e.commands.get("blockQuote");this.listenTo(i,"enter",((t,i)=>{if(!n.isCollapsed||!s.value)return;n.getLastPosition().parent.isEmpty&&(e.execute("blockQuote"),e.editing.view.scrollToTheSelection(),i.preventDefault(),t.stop())}),{context:"blockquote"}),this.listenTo(i,"delete",((t,i)=>{if("backward"!=i.direction||!n.isCollapsed||!s.value)return;const o=n.getLastPosition().parent;o.isEmpty&&!o.previousSibling&&(e.execute("blockQuote"),e.editing.view.scrollToTheSelection(),i.preventDefault(),t.stop())}),{context:"blockquote"})}}class Np extends Is{static get pluginName(){return"BlockQuoteUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("blockQuote",(i=>{const n=e.commands.get("blockQuote"),s=new Mu(i);return s.set({label:t("Block quote"),icon:Pu.quote,tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("blockQuote"),e.editing.view.focus()})),s}))}}class Dp extends Vs{constructor(e,t){super(e),this.attributeKey=t}refresh(){const e=this.editor.model,t=e.document;this.value=this._getValueFromFirstAllowedNode(),this.isEnabled=e.schema.checkAttributeInSelection(t.selection,this.attributeKey)}execute(e={}){const t=this.editor.model,i=t.document.selection,n=void 0===e.forceValue?!this.value:e.forceValue;t.change((e=>{if(i.isCollapsed)n?e.setSelectionAttribute(this.attributeKey,!0):e.removeSelectionAttribute(this.attributeKey);else{const s=t.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const t of s)n?e.setAttribute(this.attributeKey,n,t):e.removeAttribute(this.attributeKey,t)}}))}_getValueFromFirstAllowedNode(){const e=this.editor.model,t=e.schema,i=e.document.selection;if(i.isCollapsed)return i.hasAttribute(this.attributeKey);for(const e of i.getRanges())for(const i of e.getItems())if(t.checkAttribute(i,this.attributeKey))return i.hasAttribute(this.attributeKey);return!1}}const Fp="bold";class zp extends Is{static get pluginName(){return"BoldEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:Fp}),e.model.schema.setAttributeProperties(Fp,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:Fp,view:"strong",upcastAlso:["b",e=>{const t=e.getStyle("font-weight");return t?"bold"==t||Number(t)>=600?{name:!0,styles:["font-weight"]}:void 0:null}]}),e.commands.add(Fp,new Dp(e,Fp)),e.keystrokes.set("CTRL+B",Fp)}}const Hp="bold";class $p extends Is{static get pluginName(){return"BoldUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(Hp,(i=>{const n=e.commands.get(Hp),s=new Mu(i);return s.set({label:t("Bold"),icon:Pu.bold,keystroke:"CTRL+B",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(Hp),e.editing.view.focus()})),s}))}}const Wp="code";class jp extends Is{static get pluginName(){return"CodeEditing"}static get requires(){return[hg]}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:Wp}),e.model.schema.setAttributeProperties(Wp,{isFormatting:!0,copyOnEnter:!1}),e.conversion.attributeToElement({model:Wp,view:"code",upcastAlso:{styles:{"word-wrap":"break-word"}}}),e.commands.add(Wp,new Dp(e,Wp)),e.plugins.get(hg).registerAttribute(Wp),Sg(e,Wp,"code","ck-code_selected")}}const qp="code";class Up extends Is{static get pluginName(){return"CodeUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(qp,(i=>{const n=e.commands.get(qp),s=new Mu(i);return s.set({label:t("Code"),icon:'',tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(qp),e.editing.view.focus()})),s}))}}function Gp(e){const t=e.t,i=e.config.get("codeBlock.languages");for(const e of i)"Plain text"===e.label&&(e.label=t("Plain text")),void 0===e.class&&(e.class=`language-${e.language}`);return i}function Kp(e,t,i){const n={};for(const s of e)"class"===t?n[s[t].split(" ").shift()]=s[i]:n[s[t]]=s[i];return n}function Jp(e){return e.data.match(/^(\s*)/)[0]}function Qp(e){const t=e.document.selection,i=[];if(t.isCollapsed)i.push(t.anchor);else{const n=t.getFirstRange().getWalker({ignoreElementEnd:!0,direction:"backward"});for(const{item:t}of n)if(t.is("$textProxy")&&t.parent.is("element","codeBlock")){const n=Jp(t.textNode),{parent:s,startOffset:o}=t.textNode,r=e.createPositionAt(s,o+n.length);i.push(r)}}return i}function Yp(e){const t=ks(e.getSelectedBlocks());return t&&t.is("element","codeBlock")}function Xp(e,t){return!t.is("rootElement")&&!e.isLimit(t)&&e.checkChild(t.parent,"codeBlock")}class Zp extends Vs{constructor(e){super(e),this._lastLanguage=null}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor,i=t.model,n=i.document.selection,s=Gp(t)[0],o=Array.from(n.getSelectedBlocks()),r=void 0===e.forceValue?!this.value:e.forceValue,a=function(e,t,i){if(e.language)return e.language;if(e.usePreviousLanguageChoice&&t)return t;return i}(e,this._lastLanguage,s.language);i.change((e=>{r?this._applyCodeBlock(e,o,a):this._removeCodeBlock(e,o)}))}_getValue(){const e=ks(this.editor.model.document.selection.getSelectedBlocks());return!!!(!e||!e.is("element","codeBlock"))&&e.getAttribute("language")}_checkEnabled(){if(this.value)return!0;const e=this.editor.model.document.selection,t=this.editor.model.schema,i=ks(e.getSelectedBlocks());return!!i&&Xp(t,i)}_applyCodeBlock(e,t,i){this._lastLanguage=i;const n=this.editor.model.schema,s=t.filter((e=>Xp(n,e)));for(const t of s)e.rename(t,"codeBlock"),e.setAttribute("language",i,t),n.removeDisallowedAttributes([t],e),Array.from(t.getChildren()).filter((e=>!n.checkChild(t,e))).forEach((t=>e.remove(t)));s.reverse().forEach(((t,i)=>{const n=s[i+1];t.previousSibling===n&&(e.appendElement("softBreak",n),e.merge(e.createPositionBefore(t)))}))}_removeCodeBlock(e,t){const i=t.filter((e=>e.is("element","codeBlock")));for(const t of i){const i=e.createRangeOn(t);for(const t of Array.from(i.getItems()).reverse())if(t.is("element","softBreak")&&t.parent.is("element","codeBlock")){const{position:i}=e.split(e.createPositionBefore(t));e.rename(i.nodeAfter,"paragraph"),e.removeAttribute("language",i.nodeAfter),e.remove(t)}e.rename(t,"paragraph"),e.removeAttribute("language",t)}}}class ew extends Vs{constructor(e){super(e),this._indentSequence=e.config.get("codeBlock.indentSequence")}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model;e.change((t=>{const i=Qp(e);for(const n of i){const i=t.createText(this._indentSequence);e.insertContent(i,n)}}))}_checkEnabled(){return!!this._indentSequence&&Yp(this.editor.model.document.selection)}}class tw extends Vs{constructor(e){super(e),this._indentSequence=e.config.get("codeBlock.indentSequence")}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model;e.change((()=>{const t=Qp(e);for(const i of t){const t=iw(e,i,this._indentSequence);t&&e.deleteContent(e.createSelection(t))}}))}_checkEnabled(){if(!this._indentSequence)return!1;const e=this.editor.model;return!!Yp(e.document.selection)&&Qp(e).some((t=>iw(e,t,this._indentSequence)))}}function iw(e,t,i){const n=function(e){let t=e.parent.getChild(e.index);t&&!t.is("element","softBreak")||(t=e.nodeBefore);if(!t||t.is("element","softBreak"))return null;return t}(t);if(!n)return null;const s=Jp(n),o=s.lastIndexOf(i);if(o+i.length!==s.length)return null;if(-1===o)return null;const{parent:r,startOffset:a}=n;return e.createRange(e.createPositionAt(r,a+o),e.createPositionAt(r,a+o+i.length))}function nw(e,t,i=!1){const n=Kp(t,"language","class"),s=Kp(t,"language","label");return(t,o,r)=>{const{writer:a,mapper:l,consumable:c}=r;if(!c.consume(o.item,"insert"))return;const d=o.item.getAttribute("language"),h=l.toViewPosition(e.createPositionBefore(o.item)),u={};i&&(u["data-language"]=s[d],u.spellcheck="false");const m=a.createContainerElement("code",{class:n[d]||null}),g=a.createContainerElement("pre",u,m);a.insert(h,g),l.bindElements(o.item,m)}}const sw="paragraph";class ow extends Is{static get pluginName(){return"CodeBlockEditing"}static get requires(){return[Ug]}constructor(e){super(e),e.config.define("codeBlock",{languages:[{language:"plaintext",label:"Plain text"},{language:"c",label:"C"},{language:"cs",label:"C#"},{language:"cpp",label:"C++"},{language:"css",label:"CSS"},{language:"diff",label:"Diff"},{language:"html",label:"HTML"},{language:"java",label:"Java"},{language:"javascript",label:"JavaScript"},{language:"php",label:"PHP"},{language:"python",label:"Python"},{language:"ruby",label:"Ruby"},{language:"typescript",label:"TypeScript"},{language:"xml",label:"XML"}],indentSequence:"\t"})}init(){const e=this.editor,t=e.model.schema,i=e.model,n=e.editing.view,s=e.plugins.has("DocumentListEditing"),o=Gp(e);e.commands.add("codeBlock",new Zp(e)),e.commands.add("indentCodeBlock",new ew(e)),e.commands.add("outdentCodeBlock",new tw(e)),this.listenTo(n.document,"tab",((t,i)=>{const n=i.shiftKey?"outdentCodeBlock":"indentCodeBlock";e.commands.get(n).isEnabled&&(e.execute(n),i.stopPropagation(),i.preventDefault(),t.stop())}),{context:"pre"}),t.register("codeBlock",{allowWhere:"$block",allowChildren:"$text",isBlock:!0,allowAttributes:["language"]}),t.addAttributeCheck(((e,t)=>{const i=e.endsWith("codeBlock")&&t.startsWith("list")&&"list"!==t;return!(!s||!i)||!e.endsWith("codeBlock $text")&&void 0})),e.model.schema.addChildCheck(((e,t)=>{if(e.endsWith("codeBlock")&&t.isObject)return!1})),e.editing.downcastDispatcher.on("insert:codeBlock",nw(i,o,!0)),e.data.downcastDispatcher.on("insert:codeBlock",nw(i,o)),e.data.downcastDispatcher.on("insert:softBreak",function(e){return(t,i,n)=>{if("codeBlock"!==i.item.parent.name)return;const{writer:s,mapper:o,consumable:r}=n;if(!r.consume(i.item,"insert"))return;const a=o.toViewPosition(e.createPositionBefore(i.item));s.insert(a,s.createText("\n"))}}(i),{priority:"high"}),e.data.upcastDispatcher.on("element:code",function(e,t){const i=Kp(t,"class","language"),n=t[0].language;return(e,t,s)=>{const o=t.viewItem,r=o.parent;if(!r||!r.is("element","pre"))return;if(t.modelCursor.findAncestor("codeBlock"))return;const{consumable:a,writer:l}=s;if(!a.test(o,{name:!0}))return;const c=l.createElement("codeBlock"),d=[...o.getClassNames()];d.length||d.push("");for(const e of d){const t=i[e];if(t){l.setAttribute("language",t,c);break}}c.hasAttribute("language")||l.setAttribute("language",n,c),s.convertChildren(o,c),s.safeInsert(c,t.modelCursor)&&(a.consume(o,{name:!0}),s.updateConversionResult(c,t))}}(0,o)),e.data.upcastDispatcher.on("text",((e,t,{consumable:i,writer:n})=>{let s=t.modelCursor;if(!i.test(t.viewItem))return;if(!s.findAncestor("codeBlock"))return;i.consume(t.viewItem);const o=t.viewItem.data.split("\n").map((e=>n.createText(e))),r=o[o.length-1];for(const e of o)if(n.insert(e,s),s=s.getShiftedBy(e.offsetSize),e!==r){const e=n.createElement("softBreak");n.insert(e,s),s=n.createPositionAfter(e)}t.modelRange=n.createRange(t.modelCursor,s),t.modelCursor=s})),e.data.upcastDispatcher.on("element:pre",((e,t,{consumable:i})=>{const n=t.viewItem;if(n.findAncestor("pre"))return;const s=Array.from(n.getChildren()),o=s.find((e=>e.is("element","code")));if(o)for(const e of s)e!==o&&e.is("$text")&&i.consume(e,{name:!0})}),{priority:"high"}),this.listenTo(e.editing.view.document,"clipboardInput",((t,n)=>{let s=i.createRange(i.document.selection.anchor);if(n.targetRanges&&(s=e.editing.mapper.toModelRange(n.targetRanges[0])),!s.start.parent.is("element","codeBlock"))return;const o=n.dataTransfer.getData("text/plain"),r=new ih(e.editing.view.document);n.content=function(e,t){const i=e.createDocumentFragment(),n=t.split("\n"),s=n.reduce(((t,i,s)=>(t.push(i),s{const s=n.anchor;!n.isCollapsed&&s.parent.is("element","codeBlock")&&s.hasSameParentAs(n.focus)&&i.change((i=>{const o=e.return;if(o.childCount>1||n.containsEntireContent(s.parent)){const t=i.createElement("codeBlock",s.parent.getAttributes());i.append(o,t);const n=i.createDocumentFragment();i.append(t,n),e.return=n}else{const e=o.getChild(0);t.checkAttribute(e,"code")&&i.setAttribute("code",!0,e)}}))}))}afterInit(){const e=this.editor,t=e.commands,i=t.get("indent"),n=t.get("outdent");i&&i.registerChildCommand(t.get("indentCodeBlock"),{priority:"highest"}),n&&n.registerChildCommand(t.get("outdentCodeBlock")),this.listenTo(e.editing.view.document,"enter",((t,i)=>{e.model.document.selection.getLastPosition().parent.is("element","codeBlock")&&(function(e,t){const i=e.model,n=i.document,s=e.editing.view,o=n.selection.getLastPosition(),r=o.nodeAfter;if(t||!n.selection.isCollapsed||!o.isAtStart)return!1;if(!aw(r))return!1;return e.model.change((t=>{e.execute("enter");const i=n.selection.anchor.parent.previousSibling;t.rename(i,sw),t.setSelection(i,"in"),e.model.schema.removeDisallowedAttributes([i],t),t.remove(r)})),s.scrollToTheSelection(),!0}(e,i.isSoft)||function(e,t){const i=e.model,n=i.document,s=e.editing.view,o=n.selection.getLastPosition(),r=o.nodeBefore;let a;if(t||!n.selection.isCollapsed||!o.isAtEnd||!r||!r.previousSibling)return!1;if(aw(r)&&aw(r.previousSibling))a=i.createRange(i.createPositionBefore(r.previousSibling),i.createPositionAfter(r));else if(rw(r)&&aw(r.previousSibling)&&aw(r.previousSibling.previousSibling))a=i.createRange(i.createPositionBefore(r.previousSibling.previousSibling),i.createPositionAfter(r));else{if(!(rw(r)&&aw(r.previousSibling)&&rw(r.previousSibling.previousSibling)&&aw(r.previousSibling.previousSibling.previousSibling)))return!1;a=i.createRange(i.createPositionBefore(r.previousSibling.previousSibling.previousSibling),i.createPositionAfter(r))}return e.model.change((t=>{t.remove(a),e.execute("enter");const i=n.selection.anchor.parent;t.rename(i,sw),e.model.schema.removeDisallowedAttributes([i],t)})),s.scrollToTheSelection(),!0}(e,i.isSoft)||function(e){const t=e.model,i=t.document,n=i.selection.getLastPosition(),s=n.nodeBefore||n.textNode;let o;s&&s.is("$text")&&(o=Jp(s));e.model.change((t=>{e.execute("shiftEnter"),o&&t.insertText(o,i.selection.anchor)}))}(e),i.preventDefault(),t.stop())}),{context:"pre"})}}function rw(e){return e&&e.is("$text")&&!e.data.match(/\S/)}function aw(e){return e&&e.is("element","softBreak")}class lw extends Is{static get pluginName(){return"CodeBlockUI"}init(){const e=this.editor,t=e.t,i=e.ui.componentFactory,n=Gp(e);i.add("codeBlock",(i=>{const s=e.commands.get("codeBlock"),o=lm(i,qu),r=o.buttonView;return r.set({label:t("Insert code block"),tooltip:!0,icon:'',isToggleable:!0}),r.bind("isOn").to(s,"value",(e=>!!e)),r.on("execute",(()=>{e.execute("codeBlock",{usePreviousLanguageChoice:!0}),e.editing.view.focus()})),o.on("execute",(t=>{e.execute("codeBlock",{language:t.source._codeBlockLanguage,forceValue:!0}),e.editing.view.focus()})),o.class="ck-code-block-dropdown",o.bind("isEnabled").to(s),dm(o,this._getLanguageListItemDefinitions(n)),o}))}_getLanguageListItemDefinitions(e){const t=this.editor.commands.get("codeBlock"),i=new ys;for(const n of e){const e={type:"button",model:new Tm({_codeBlockLanguage:n.language,label:n.label,withText:!0})};e.model.bind("isOn").to(t,"value",(t=>t===e.model._codeBlockLanguage)),i.add(e)}return i}}const cw=[{model:"codeBlock",view:"pre"},{model:"paragraph",view:"p"},{model:"blockQuote",view:"blockquote"},{model:"listItem",view:"li"},{model:"pageBreak",view:"div"},{model:"rawHtml",view:"div"},{model:"table",view:"table"},{model:"tableRow",view:"tr"},{model:"tableCell",view:"td"},{model:"tableCell",view:"th"},{model:"caption",view:"caption"},{model:"caption",view:"figcaption"},{model:"imageBlock",view:"img"},{model:"imageInline",view:"img"},{model:"htmlP",view:"p",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlBlockquote",view:"blockquote",modelSchema:{inheritAllFrom:"$container"}},{model:"htmlTable",view:"table",modelSchema:{allowWhere:"$block",isBlock:!0}},{model:"htmlTbody",view:"tbody",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlThead",view:"thead",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlTfoot",view:"tfoot",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlCaption",view:"caption",modelSchema:{allowIn:"htmlTable",allowChildren:"$text",isBlock:!1}},{model:"htmlColgroup",view:"colgroup",modelSchema:{allowIn:"htmlTable",allowChildren:"col",isBlock:!1}},{model:"htmlCol",view:"col",modelSchema:{allowIn:"htmlColgroup",isBlock:!1}},{model:"htmlTr",view:"tr",modelSchema:{allowIn:["htmlTable","htmlThead","htmlTbody"],isLimit:!0}},{model:"htmlTd",view:"td",modelSchema:{allowIn:"htmlTr",allowContentOf:"$container",isLimit:!0,isBlock:!1}},{model:"htmlTh",view:"th",modelSchema:{allowIn:"htmlTr",allowContentOf:"$container",isLimit:!0,isBlock:!1}},{model:"htmlFigure",view:"figure",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlFigcaption",view:"figcaption",modelSchema:{allowIn:"htmlFigure",allowChildren:"$text",isBlock:!1}},{model:"htmlAddress",view:"address",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlAside",view:"aside",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlMain",view:"main",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlDetails",view:"details",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlSummary",view:"summary",modelSchema:{allowChildren:"$text",allowIn:"htmlDetails",isBlock:!1}},{model:"htmlDiv",view:"div",paragraphLikeModel:"htmlDivParagraph",modelSchema:{inheritAllFrom:"$container"}},{model:"htmlFieldset",view:"fieldset",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlLegend",view:"legend",modelSchema:{allowIn:"htmlFieldset",allowChildren:"$text"}},{model:"htmlHeader",view:"header",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlFooter",view:"footer",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlForm",view:"form",modelSchema:{inheritAllFrom:"$container",isBlock:!0}},{model:"htmlHgroup",view:"hgroup",modelSchema:{allowChildren:["htmlH1","htmlH2","htmlH3","htmlH4","htmlH5","htmlH6"],isBlock:!1}},{model:"htmlH1",view:"h1",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH2",view:"h2",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH3",view:"h3",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH4",view:"h4",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH5",view:"h5",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH6",view:"h6",modelSchema:{inheritAllFrom:"$block"}},{model:"$htmlList",modelSchema:{allowWhere:"$container",allowChildren:["$htmlList","htmlLi"],isBlock:!1}},{model:"htmlDir",view:"dir",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlMenu",view:"menu",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlUl",view:"ul",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlOl",view:"ol",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlLi",view:"li",modelSchema:{allowIn:"$htmlList",allowChildren:"$text",isBlock:!1}},{model:"htmlPre",view:"pre",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlArticle",view:"article",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlSection",view:"section",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlNav",view:"nav",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlDl",view:"dl",modelSchema:{allowWhere:"$container",allowChildren:["htmlDt","htmlDd"],isBlock:!1}},{model:"htmlDt",view:"dt",modelSchema:{allowChildren:"$block",isBlock:!1}},{model:"htmlDd",view:"dd",modelSchema:{allowChildren:"$block",isBlock:!1}},{model:"htmlCenter",view:"center",modelSchema:{inheritAllFrom:"$container",isBlock:!1}}],dw=[{model:"htmlAcronym",view:"acronym",attributeProperties:{copyOnEnter:!0}},{model:"htmlTt",view:"tt",attributeProperties:{copyOnEnter:!0}},{model:"htmlFont",view:"font",attributeProperties:{copyOnEnter:!0}},{model:"htmlTime",view:"time",attributeProperties:{copyOnEnter:!0}},{model:"htmlVar",view:"var",attributeProperties:{copyOnEnter:!0}},{model:"htmlBig",view:"big",attributeProperties:{copyOnEnter:!0}},{model:"htmlSmall",view:"small",attributeProperties:{copyOnEnter:!0}},{model:"htmlSamp",view:"samp",attributeProperties:{copyOnEnter:!0}},{model:"htmlQ",view:"q",attributeProperties:{copyOnEnter:!0}},{model:"htmlOutput",view:"output",attributeProperties:{copyOnEnter:!0}},{model:"htmlKbd",view:"kbd",attributeProperties:{copyOnEnter:!0}},{model:"htmlBdi",view:"bdi",attributeProperties:{copyOnEnter:!0}},{model:"htmlBdo",view:"bdo",attributeProperties:{copyOnEnter:!0}},{model:"htmlAbbr",view:"abbr",attributeProperties:{copyOnEnter:!0}},{model:"htmlA",view:"a",priority:5,coupledAttribute:"linkHref",attributeProperties:{copyOnEnter:!0}},{model:"htmlStrong",view:"strong",coupledAttribute:"bold",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlB",view:"b",coupledAttribute:"bold",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlI",view:"i",coupledAttribute:"italic",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlEm",view:"em",coupledAttribute:"italic",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlS",view:"s",coupledAttribute:"strikethrough",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlDel",view:"del",coupledAttribute:"strikethrough",attributeProperties:{copyOnEnter:!0}},{model:"htmlIns",view:"ins",attributeProperties:{copyOnEnter:!0}},{model:"htmlU",view:"u",coupledAttribute:"underline",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSub",view:"sub",coupledAttribute:"subscript",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSup",view:"sup",coupledAttribute:"superscript",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlCode",view:"code",coupledAttribute:"code",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlMark",view:"mark",attributeProperties:{copyOnEnter:!0}},{model:"htmlSpan",view:"span",attributeProperties:{copyOnEnter:!0}},{model:"htmlCite",view:"cite",attributeProperties:{copyOnEnter:!0}},{model:"htmlLabel",view:"label",attributeProperties:{copyOnEnter:!0}},{model:"htmlDfn",view:"dfn",attributeProperties:{copyOnEnter:!0}},{model:"htmlObject",view:"object",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlIframe",view:"iframe",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlInput",view:"input",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlButton",view:"button",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlTextarea",view:"textarea",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlSelect",view:"select",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlVideo",view:"video",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlEmbed",view:"embed",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlOembed",view:"oembed",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlAudio",view:"audio",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlImg",view:"img",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlCanvas",view:"canvas",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlMeter",view:"meter",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlProgress",view:"progress",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlScript",view:"script",modelSchema:{allowWhere:["$text","$block"],isInline:!0}},{model:"htmlStyle",view:"style",modelSchema:{allowWhere:["$text","$block"],isInline:!0}},{model:"htmlCustomElement",view:"$customElement",modelSchema:{allowWhere:["$text","$block"],isInline:!0}}];const hw=Ho((function(e,t,i,n){Po(e,t,i,n)}));class uw extends Is{constructor(e){super(e),this._definitions=new Map}static get pluginName(){return"DataSchema"}init(){for(const e of cw)this.registerBlockElement(e);for(const e of dw)this.registerInlineElement(e)}registerBlockElement(e){this._definitions.set(e.model,{...e,isBlock:!0})}registerInlineElement(e){this._definitions.set(e.model,{...e,isInline:!0})}extendBlockElement(e){this._extendDefinition({...e,isBlock:!0})}extendInlineElement(e){this._extendDefinition({...e,isInline:!0})}getDefinitionsForView(e,t){const i=new Set;for(const n of this._getMatchingViewDefinitions(e)){if(t)for(const e of this._getReferences(n.model))i.add(e);i.add(n)}return i}_getMatchingViewDefinitions(e){return Array.from(this._definitions.values()).filter((t=>t.view&&function(e,t){if("string"==typeof e)return e===t;if(e instanceof RegExp)return e.test(t);return!1}(e,t.view)))}*_getReferences(e){const{modelSchema:t}=this._definitions.get(e);if(!t)return;const i=["inheritAllFrom","inheritTypesFrom","allowWhere","allowContentOf","allowAttributesOf"];for(const n of i)for(const i of ps(t[n]||[])){const t=this._definitions.get(i);i!==e&&t&&(yield*this._getReferences(t.model),yield t)}}_extendDefinition(e){const t=this._definitions.get(e.model),i=hw({},t,e,((e,t)=>Array.isArray(e)?e.concat(t):void 0));this._definitions.set(e.model,i)}}function mw(e,t,i,n){t&&function(e,t,i){if(t.attributes)for(const[n]of Object.entries(t.attributes))e.removeAttribute(n,i);if(t.styles)for(const n of Object.keys(t.styles))e.removeStyle(n,i);t.classes&&e.removeClass(t.classes,i)}(e,t,n),i&&gw(e,i,n)}function gw(e,t,i){if(t.attributes)for(const[n,s]of Object.entries(t.attributes))e.setAttribute(n,s,i);t.styles&&e.setStyle(t.styles,i),t.classes&&e.addClass(t.classes,i)}function fw(e,t){const i=Dl(e);for(const n in t)Array.isArray(t[n])?i[n]=Array.from(new Set([...e[n]||[],...t[n]])):i[n]={...e[n],...t[n]};return i}function pw({model:e}){return(t,i)=>i.writer.createElement(e,{htmlContent:t.getCustomProperty("$rawContent")})}function ww(e,{view:t,isInline:i}){const n=e.t;return(e,{writer:s})=>{const o=n("HTML object"),r=bw(t,e,s),a=e.getAttribute("htmlAttributes");s.addClass("html-object-embed__content",r),a&&gw(s,a,r);return tf(s.createContainerElement(i?"span":"div",{class:"html-object-embed","data-html-object-embed-label":o},r),s,{widgetLabel:o})}}function bw(e,t,i){return i.createRawElement(e,null,((e,i)=>{i.setContentOf(e,t.getAttribute("htmlContent"))}))}function vw({priority:e,view:t}){return(i,n)=>{if(!i)return;const{writer:s}=n,o=s.createAttributeElement(t,null,{priority:e});return gw(s,i,o),o}}function _w({view:e},t){return i=>{i.on(`element:${e}`,((e,i,n)=>{if(!i.modelRange||i.modelRange.isCollapsed)return;const s=t.processViewAttributes(i.viewItem,n);s&&n.writer.setAttribute("htmlAttributes",s,i.modelRange)}),{priority:"low"})}}function yw({model:e}){return t=>{t.on(`attribute:htmlAttributes:${e}`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t;mw(i.writer,n,s,i.mapper.toViewElement(t.item))}))}}const kw=function(e,t,i,n){for(var s=e.length,o=i+(n?1:-1);n?o--:++o-1;)a!==e&&Ew.call(a,l,1),Ew.call(e,l,1);return e};const Pw=Fo((function(e,t){return e&&e.length&&t&&t.length?Sw(e,t):e}));class Iw extends Is{constructor(e){super(e),this._dataSchema=e.plugins.get("DataSchema"),this._allowedAttributes=new Js,this._disallowedAttributes=new Js,this._allowedElements=new Set,this._disallowedElements=new Set,this._dataInitialized=!1,this._coupledAttributes=null,this._registerElementsAfterInit(),this._registerElementHandlers(),this._registerModelPostFixer()}static get pluginName(){return"DataFilter"}static get requires(){return[uw,vf]}loadAllowedConfig(e){for(const t of e){const e=t.name||/[\s\S]+/,i=Bw(t);this.allowElement(e),i.forEach((e=>this.allowAttributes(e)))}}loadDisallowedConfig(e){for(const t of e){const e=t.name||/[\s\S]+/,i=Bw(t);0==i.length?this.disallowElement(e):i.forEach((e=>this.disallowAttributes(e)))}}allowElement(e){for(const t of this._dataSchema.getDefinitionsForView(e,!0))this._allowedElements.has(t)||(this._allowedElements.add(t),this._dataInitialized&&this.editor.data.once("set",(()=>{this._fireRegisterEvent(t)}),{priority:f.get("highest")+1}),this._coupledAttributes=null)}disallowElement(e){for(const t of this._dataSchema.getDefinitionsForView(e,!1))this._disallowedElements.add(t.view)}allowAttributes(e){this._allowedAttributes.add(e)}disallowAttributes(e){this._disallowedAttributes.add(e)}processViewAttributes(e,t){return Rw(e,t,this._disallowedAttributes),Rw(e,t,this._allowedAttributes)}_registerElementsAfterInit(){this.editor.data.on("init",(()=>{this._dataInitialized=!0;for(const e of this._allowedElements)this._fireRegisterEvent(e)}),{priority:f.get("highest")+1})}_registerElementHandlers(){this.on("register",((e,t)=>{const i=this.editor.model.schema;if(t.isObject&&!i.isRegistered(t.model))this._registerObjectElement(t);else if(t.isBlock)this._registerBlockElement(t);else{if(!t.isInline)throw new b("data-filter-invalid-definition",null,t);this._registerInlineElement(t)}e.stop()}),{priority:"lowest"})}_registerModelPostFixer(){const e=this.editor.model;e.document.registerPostFixer((t=>{const i=e.document.differ.getChanges();let n=!1;const s=this._getCoupledAttributesMap();for(const e of i){if("attribute"!=e.type||null!==e.attributeNewValue)continue;const i=s.get(e.attributeKey);if(i)for(const{item:s}of e.range.getWalker({shallow:!0}))for(const e of i)s.hasAttribute(e)&&(t.removeAttribute(e,s),n=!0)}return n}))}_getCoupledAttributesMap(){if(this._coupledAttributes)return this._coupledAttributes;this._coupledAttributes=new Map;for(const e of this._allowedElements)if(e.coupledAttribute&&e.model){const t=this._coupledAttributes.get(e.coupledAttribute);t?t.push(e.model):this._coupledAttributes.set(e.coupledAttribute,[e.model])}}_fireRegisterEvent(e){e.view&&this._disallowedElements.has(e.view)||this.fire(e.view?`register:${e.view}`:"register",e)}_registerObjectElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,{view:s,model:o}=e;i.register(o,e.modelSchema),s&&(i.extend(e.model,{allowAttributes:["htmlAttributes","htmlContent"]}),t.data.registerRawContentMatcher({name:s}),n.for("upcast").elementToElement({view:s,model:pw(e),converterPriority:f.get("low")+1}),n.for("upcast").add(_w(e,this)),n.for("editingDowncast").elementToStructure({model:{name:o,attributes:["htmlAttributes"]},view:ww(t,e)}),n.for("dataDowncast").elementToElement({model:o,view:(e,{writer:t})=>bw(s,e,t)}),n.for("dataDowncast").add(yw(e)))}_registerBlockElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,{view:s,model:o}=e;if(!i.isRegistered(e.model)){if(i.register(e.model,e.modelSchema),!s)return;n.for("upcast").elementToElement({model:o,view:s,converterPriority:f.get("low")+1}),n.for("downcast").elementToElement({model:o,view:s})}s&&(i.extend(e.model,{allowAttributes:"htmlAttributes"}),n.for("upcast").add(_w(e,this)),n.for("downcast").add(yw(e)))}_registerInlineElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,s=e.model;i.extend("$text",{allowAttributes:s}),e.attributeProperties&&i.setAttributeProperties(s,e.attributeProperties),n.for("upcast").add(function({view:e,model:t},i){return n=>{n.on(`element:${e}`,((e,n,s)=>{let o=i.processViewAttributes(n.viewItem,s);if(o||s.consumable.test(n.viewItem,{name:!0})){o=o||{},s.consumable.consume(n.viewItem,{name:!0}),n.modelRange||(n=Object.assign(n,s.convertChildren(n.viewItem,n.modelCursor)));for(const e of n.modelRange.getItems())if(s.schema.checkAttribute(e,t)){const i=fw(o,e.getAttribute(t)||{});s.writer.setAttribute(t,i,e)}}}),{priority:"low"})}}(e,this)),n.for("downcast").attributeToElement({model:s,view:vw(e)})}}function Rw(e,t,i){const n=function(e,{consumable:t},i){const n=i.matchAll(e)||[],s=[];for(const i of n)Vw(t,e,i),delete i.match.name,t.consume(e,i.match),s.push(i);return s}(e,t,i),{attributes:s,styles:o,classes:r}=function(e){const t={attributes:new Set,classes:new Set,styles:new Set};for(const i of e)for(const e in t){(i.match[e]||[]).forEach((i=>t[e].add(i)))}return t}(n),a={};if(s.size)for(const e of s)Mw(e)||s.delete(e);return s.size&&(a.attributes=Lw(s,(t=>e.getAttribute(t)))),o.size&&(a.styles=Lw(o,(t=>e.getStyle(t)))),r.size&&(a.classes=Array.from(r)),Object.keys(a).length?a:null}function Vw(e,t,i){for(const n of["attributes","classes","styles"]){const s=i.match[n];if(s)for(const i of Array.from(s))e.test(t,{[n]:[i]})||Pw(s,i)}}function Lw(e,t){const i={};for(const n of e){void 0!==t(n)&&(i[n]=t(n))}return i}function Ow(e,t){const{name:i}=e;return Ce(e[t])?Object.entries(e[t]).map((([e,n])=>({name:i,[t]:{[e]:n}}))):Array.isArray(e[t])?e[t].map((e=>({name:i,[t]:[e]}))):[e]}function Bw(e){const{name:t,attributes:i,classes:n,styles:s}=e,o=[];return i&&o.push(...Ow({name:t,attributes:i},"attributes")),n&&o.push(...Ow({name:t,classes:n},"classes")),s&&o.push(...Ow({name:t,styles:s},"styles")),o}function Mw(e){try{document.createAttribute(e)}catch(e){return!1}return!0}class Nw extends Vs{constructor(e){super(e),this.affectsData=!1}execute(){const e=this.editor.model,t=e.document.selection;let i=e.schema.getLimitElement(t);if(t.containsEntireContent(i)||!Dw(e.schema,i))do{if(i=i.parent,!i)return}while(!Dw(e.schema,i));e.change((e=>{e.setSelection(i,"in")}))}}function Dw(e,t){return e.isLimit(t)&&(e.checkChild(t,"$text")||e.checkChild(t,"paragraph"))}const Fw=ms("Ctrl+A");class zw extends Is{static get pluginName(){return"SelectAllEditing"}init(){const e=this.editor,t=e.editing.view.document;e.commands.add("selectAll",new Nw(e)),this.listenTo(t,"keydown",((t,i)=>{us(i)===Fw&&(e.execute("selectAll"),i.preventDefault())}))}}class Hw extends Is{static get pluginName(){return"SelectAllUI"}init(){const e=this.editor;e.ui.componentFactory.add("selectAll",(t=>{const i=e.commands.get("selectAll"),n=new Mu(t),s=t.t;return n.set({label:s("Select all"),icon:'',keystroke:"Ctrl+A",tooltip:!0}),n.bind("isEnabled").to(i,"isEnabled"),this.listenTo(n,"execute",(()=>{e.execute("selectAll"),e.editing.view.focus()})),n}))}}class $w extends Is{static get requires(){return[zw,Hw]}static get pluginName(){return"SelectAll"}}class Ww extends fu{constructor(e){super(e);const t=e.t;this.set("matchCount",0),this.set("highlightOffset",0),this.set("isDirty",!1),this.set("_areCommandsEnabled",{}),this.set("_resultsCounterText",""),this.set("_matchCase",!1),this.set("_wholeWordsOnly",!1),this.bind("_searchResultsFound").to(this,"matchCount",this,"isDirty",((e,t)=>e>0&&!t)),this._findInputView=this._createInputField(t("Find in text…")),this._replaceInputView=this._createInputField(t("Replace with…")),this._findButtonView=this._createButton({label:t("Find"),class:"ck-button-find ck-button-action",withText:!0}),this._findPrevButtonView=this._createButton({label:t("Previous result"),class:"ck-button-prev",icon:Em,keystroke:"Shift+F3",tooltip:!0}),this._findNextButtonView=this._createButton({label:t("Next result"),class:"ck-button-next",icon:Em,keystroke:"F3",tooltip:!0}),this._optionsDropdown=this._createOptionsDropdown(),this._replaceButtonView=this._createButton({label:t("Replace"),class:"ck-button-replace",withText:!0}),this._replaceAllButtonView=this._createButton({label:t("Replace all"),class:"ck-button-replaceall",withText:!0}),this._findFieldsetView=this._createFindFieldset(),this._replaceFieldsetView=this._createReplaceFieldset(),this._focusTracker=new Cs,this._keystrokes=new As,this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this._focusTracker,keystrokeHandler:this._keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-find-and-replace-form"],tabindex:"-1"},children:[new wm(e,{label:t("Find and replace")}),this._findFieldsetView,this._replaceFieldsetView]}),Ru(this)}render(){super.render(),Vu({view:this}),this._initFocusCycling(),this._initKeystrokeHandling()}destroy(){super.destroy(),this._focusTracker.destroy(),this._keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}reset(){this._findInputView.errorText=null,this.isDirty=!0}get _textToFind(){return this._findInputView.fieldView.element.value}get _textToReplace(){return this._replaceInputView.fieldView.element.value}_createFindFieldset(){const e=this.locale,t=new fu(e);return this._findInputView.fieldView.on("input",(()=>{this.isDirty=!0})),this._findButtonView.on("execute",this._onFindButtonExecute.bind(this)),this._findPrevButtonView.delegate("execute").to(this,"findPrevious"),this._findNextButtonView.delegate("execute").to(this,"findNext"),this._findPrevButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",(({findPrevious:e})=>e)),this._findNextButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",(({findNext:e})=>e)),this._injectFindResultsCounter(),t.setTemplate({tag:"fieldset",attributes:{class:["ck","ck-find-and-replace-form__find"]},children:[this._findInputView,this._findButtonView,this._findPrevButtonView,this._findNextButtonView]}),t}_onFindButtonExecute(){if(this._textToFind)this.isDirty=!1,this.fire("findNext",{searchText:this._textToFind,matchCase:this._matchCase,wholeWords:this._wholeWordsOnly});else{const e=this.t;this._findInputView.errorText=e("Text to find must not be empty.")}}_injectFindResultsCounter(){const e=this.locale,t=e.t,i=this.bindTemplate,n=new fu(e);this.bind("_resultsCounterText").to(this,"highlightOffset",this,"matchCount",((e,i)=>t("%0 of %1",[e,i]))),n.setTemplate({tag:"span",attributes:{class:["ck","ck-results-counter",i.if("isDirty","ck-hidden")]},children:[{text:i.to("_resultsCounterText")}]});const s=()=>{const t=this._findInputView.fieldView.element;if(!t||!Gn(t))return;const i=new Nn(n.element).width,s="ltr"===e.uiLanguageDirection?"paddingRight":"paddingLeft";t.style[s]=i?`calc( 2 * var(--ck-spacing-standard) + ${i}px )`:null};this.on("change:_resultsCounterText",s,{priority:"low"}),this.on("change:isDirty",s,{priority:"low"}),this._findInputView.template.children[0].children.push(n)}_createReplaceFieldset(){const e=this.locale,t=e.t,i=new fu(e);return this._replaceButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replace:e},t)=>e&&t)),this._replaceAllButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replaceAll:e},t)=>e&&t)),this._replaceInputView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replace:e},t)=>e&&t)),this._replaceInputView.bind("infoText").to(this._replaceInputView,"isEnabled",this._replaceInputView,"isFocused",((e,i)=>e||!i?"":t("Tip: Find some text first in order to replace it."))),this._replaceButtonView.on("execute",(()=>{this.fire("replace",{searchText:this._textToFind,replaceText:this._textToReplace})})),this._replaceAllButtonView.on("execute",(()=>{this.fire("replaceAll",{searchText:this._textToFind,replaceText:this._textToReplace}),this.focus()})),i.setTemplate({tag:"fieldset",attributes:{class:["ck","ck-find-and-replace-form__replace"]},children:[this._replaceInputView,this._optionsDropdown,this._replaceButtonView,this._replaceAllButtonView]}),i}_createOptionsDropdown(){const e=this.locale,t=e.t,i=lm(e);i.class="ck-options-dropdown",i.buttonView.set({withText:!1,label:t("Show options"),icon:Pu.cog,tooltip:!0});const n=new Tm({withText:!0,label:t("Match case"),_isMatchCaseSwitch:!0}),s=new Tm({withText:!0,label:t("Whole words only")});return n.bind("isOn").to(this,"_matchCase"),s.bind("isOn").to(this,"_wholeWordsOnly"),i.on("execute",(e=>{e.source._isMatchCaseSwitch?this._matchCase=!this._matchCase:this._wholeWordsOnly=!this._wholeWordsOnly,this.isDirty=!0})),dm(i,new ys([{type:"switchbutton",model:n},{type:"switchbutton",model:s}])),i}_initFocusCycling(){[this._findInputView,this._findButtonView,this._findPrevButtonView,this._findNextButtonView,this._replaceInputView,this._optionsDropdown,this._replaceButtonView,this._replaceAllButtonView].forEach((e=>{this._focusables.add(e),this._focusTracker.add(e.element)}))}_initKeystrokeHandling(){const e=e=>e.stopPropagation(),t=e=>{e.stopPropagation(),e.preventDefault()};this._keystrokes.listenTo(this.element),this._keystrokes.set("f3",(e=>{t(e),this._findNextButtonView.fire("execute")})),this._keystrokes.set("shift+f3",(e=>{t(e),this._findPrevButtonView.fire("execute")})),this._keystrokes.set("enter",(e=>{const i=e.target;i===this._findInputView.fieldView.element?(this._areCommandsEnabled.findNext?this._findNextButtonView.fire("execute"):this._findButtonView.fire("execute"),t(e)):i!==this._replaceInputView.fieldView.element||this.isDirty||(this._replaceButtonView.fire("execute"),t(e))})),this._keystrokes.set("shift+enter",(e=>{e.target===this._findInputView.fieldView.element&&(this._areCommandsEnabled.findPrevious?this._findPrevButtonView.fire("execute"):this._findButtonView.fire("execute"),t(e))})),this._keystrokes.set("arrowright",e),this._keystrokes.set("arrowleft",e),this._keystrokes.set("arrowup",e),this._keystrokes.set("arrowdown",e),this.listenTo(this._findInputView.element,"selectstart",((e,t)=>{t.stopPropagation()}),{priority:"high"}),this.listenTo(this._replaceInputView.element,"selectstart",((e,t)=>{t.stopPropagation()}),{priority:"high"})}_createButton(e){const t=new Mu(this.locale);return t.set(e),t}_createInputField(e){const t=new ym(this.locale,km);return t.label=e,t}}class jw extends Is{static get pluginName(){return"FindAndReplaceUI"}constructor(e){super(e),this.formView=null}init(){const e=this.editor;e.ui.componentFactory.add("findAndReplace",(t=>{const i=lm(t),n=this.formView=new Ww(e.locale);return i.bind("isEnabled").to(e.commands.get("find")),i.panelView.children.add(n),i.on("change:isOpen",((e,t,i)=>{i?(n.disableCssTransitions(),n.reset(),n._findInputView.fieldView.select(),n.enableCssTransitions()):this.fire("searchReseted")}),{priority:"low"}),this._setupDropdownButton(i),this._setupFormView(n),i}))}_setupDropdownButton(e){const t=this.editor,i=t.locale.t;e.buttonView.set({icon:'',label:i("Find and replace"),keystroke:"CTRL+F",tooltip:!0}),t.keystrokes.set("Ctrl+F",((t,i)=>{e.isOpen=!0,i()}))}_setupFormView(e){const t=this.editor.commands,i=this.editor.plugins.get("FindAndReplaceEditing").state,n={before:-1,same:0,after:1};e.bind("highlightOffset").to(i,"highlightedResult",(e=>e?Array.from(i.results).sort(((e,t)=>n[e.marker.getStart().compareWith(t.marker.getStart())])).indexOf(e)+1:0)),e.listenTo(i.results,"change",(()=>{e.matchCount=i.results.length})),e.bind("_areCommandsEnabled").to(t.get("findNext"),"isEnabled",t.get("findPrevious"),"isEnabled",t.get("replace"),"isEnabled",t.get("replaceAll"),"isEnabled",((e,t,i,n)=>({findNext:e,findPrevious:t,replace:i,replaceAll:n}))),e.delegate("findNext","findPrevious","replace","replaceAll").to(this),e.on("change:isDirty",((e,t,i)=>{i&&this.fire("searchReseted")}))}}function qw(e,t,i,n){const s=n||new ys;return t.change((n=>{[...e].forEach((({type:e,item:o})=>{if("elementStart"===e&&t.schema.checkChild(o,"$text")){const e=i({item:o,text:Uw(t.createRangeIn(o))});if(!e)return;e.forEach((e=>{const t=`findResult:${g()}`,i=n.addMarker(t,{usingOperation:!1,affectsData:!1,range:n.createRange(n.createPositionAt(o,e.start),n.createPositionAt(o,e.end))}),r=function(e,t){const i=e.find((({marker:e})=>t.getStart().isBefore(e.getStart())));return i?e.getIndex(i):e.length}(s,i);s.add({id:t,label:e.label,marker:i},r)}))}}))})),s}function Uw(e){return Array.from(e.getItems()).reduce(((e,t)=>t.is("text")||t.is("textProxy")?e+t.data:`${e}\n`),"")}function Gw(e){const t=e.length-1;let i=e.index;return 3===e.length&&(i+=e[1].length),{label:e[t],start:i,end:i+e[t].length}}function Kw(e,t){let i="gu";t.matchCase||(i+="i");let n=`(${bg(e)})`;if(t.wholeWords){const t="[^a-zA-ZÀ-ɏḀ-ỿ]";new RegExp("^"+t).test(e)||(n=`(^|${t}|_)${n}`),new RegExp(t+"$").test(e)||(n=`${n}(?=_|${t}|$)`)}const s=new RegExp(n,i);return function({text:e}){return[...e.matchAll(s)].map(Gw)}}class Jw extends Vs{constructor(e,t){super(e),this.isEnabled=!0,this.affectsData=!1,this._state=t}execute(e,{matchCase:t,wholeWords:i}={}){const{editor:n}=this,{model:s}=n;let o;"string"==typeof e?(o=Kw(e,{matchCase:t,wholeWords:i}),this._state.searchText=e):o=e;const r=s.document.getRootNames().reduce(((e,t)=>qw(s.createRangeIn(s.document.getRoot(t)),s,o,e)),null);return this._state.clear(s),this._state.results.addMany(Array.from(r)),this._state.highlightedResult=r.get(0),"string"==typeof e&&(this._state.searchText=e),this._state.matchCase=!!t,this._state.matchWholeWords=!!i,{results:r,findCallback:o}}}class Qw extends Vs{constructor(e,t){super(e),this.isEnabled=!0,this._state=t}execute(e,t){const{model:i}=this.editor;i.change((n=>{const s=t.marker.getRange();if("$graveyard"===s.root.rootName)return void this._state.results.remove(t);let o={};for(const e of s.getItems())if(e.is("$text")||e.is("$textProxy")){o=e.getAttributes();break}i.insertContent(n.createText(e,o),s),this._state.results.has(t)&&this._state.results.remove(t)}))}}class Yw extends Qw{execute(e,t){const{editor:i}=this,{model:n}=i,s=t instanceof ys?t:n.document.getRootNames().reduce(((e,i)=>qw(n.createRangeIn(n.document.getRoot(i)),n,Kw(t,this._state),e)),null);s.length&&n.change((()=>{[...s].forEach((t=>{super.execute(e,t)}))}))}}class Xw extends Vs{constructor(e,t){super(e),this.affectsData=!1,this._state=t,this.isEnabled=!1,this.listenTo(this._state.results,"change",(()=>{this.isEnabled=this._state.results.length>1}))}refresh(){this.isEnabled=this._state.results.length>1}execute(){const e=this._state.results,t=e.getIndex(this._state.highlightedResult),i=t+1>=e.length?0:t+1;this._state.highlightedResult=this._state.results.get(i)}}class Zw extends Xw{execute(){const e=this._state.results.getIndex(this._state.highlightedResult),t=e-1<0?this._state.results.length-1:e-1;this._state.highlightedResult=this._state.results.get(t)}}class eb{constructor(e){this.set("results",new ys),this.set("highlightedResult",null),this.set("searchText",""),this.set("replaceText",""),this.set("matchCase",!1),this.set("matchWholeWords",!1),this.results.on("change",((t,{removed:i,index:n})=>{if((i=Array.from(i)).length){let t=!1;if(e.change((n=>{for(const s of i)this.highlightedResult===s&&(t=!0),e.markers.has(s.marker.name)&&n.removeMarker(s.marker)})),t){const e=n>=this.results.length?0:n;this.highlightedResult=this.results.get(e)}}}))}clear(e){this.searchText="",e.change((t=>{if(this.highlightedResult){const i=this.highlightedResult.marker.name.split(":")[1],n=e.markers.get(`findResultHighlighted:${i}`);n&&t.removeMarker(n)}[...this.results].forEach((({marker:e})=>{t.removeMarker(e)}))})),this.results.clear()}}d(eb,W);class tb extends Is{static get pluginName(){return"FindAndReplaceEditing"}init(){this._activeResults=null,this.state=new eb(this.editor.model),this._defineConverters(),this._defineCommands(),this.listenTo(this.state,"change:highlightedResult",((e,t,i,n)=>{const{model:s}=this.editor;s.change((e=>{if(n){const t=n.marker.name.split(":")[1],i=s.markers.get(`findResultHighlighted:${t}`);i&&e.removeMarker(i)}if(i){const t=i.marker.name.split(":")[1];e.addMarker(`findResultHighlighted:${t}`,{usingOperation:!1,affectsData:!1,range:i.marker.getRange()})}}))}));const e=xa(function(e,t,i){if(i){const e=this.editor.editing.view.domConverter,t=this.editor.editing.mapper.toViewRange(i.marker.getRange());Xn({target:e.viewRangeToDom(t),viewportOffset:40})}}.bind(this),32);this.listenTo(this.state,"change:highlightedResult",e,{priority:"low"}),this.listenTo(this.editor,"destroy",e.cancel)}find(e){const{editor:t}=this,{model:i}=t,{findCallback:n,results:s}=t.execute("find",e);return this._activeResults=s,this.listenTo(i.document,"change:data",(()=>function(e,t,i){const n=new Set,s=new Set;t.document.differ.getChanges().forEach((e=>{"$text"===e.name||t.schema.isInline(e.position.nodeAfter)?(n.add(e.position.parent),[...t.markers.getMarkersAtPosition(e.position)].forEach((e=>{s.add(e.name)}))):"insert"===e.type&&n.add(e.position.nodeAfter)})),t.document.differ.getChangedMarkers().forEach((({name:e,data:{newRange:t}})=>{t&&"$graveyard"===t.start.root.rootName&&s.add(e)})),n.forEach((e=>{[...t.markers.getMarkersIntersectingRange(t.createRangeIn(e))].forEach((e=>s.add(e.name)))})),t.change((t=>{s.forEach((i=>{e.has(i)&&e.remove(i),t.removeMarker(i)}))})),n.forEach((n=>{qw(t.createRangeOn(n),t,i,e)}))}(this._activeResults,i,n))),this._activeResults}stop(){this._activeResults&&(this.stopListening(this.editor.model.document),this.state.clear(this.editor.model),this._activeResults=null)}_defineCommands(){this.editor.commands.add("find",new Jw(this.editor,this.state)),this.editor.commands.add("findNext",new Xw(this.editor,this.state)),this.editor.commands.add("findPrevious",new Zw(this.editor,this.state)),this.editor.commands.add("replace",new Qw(this.editor,this.state)),this.editor.commands.add("replaceAll",new Yw(this.editor,this.state))}_defineConverters(){const{editor:e}=this;e.conversion.for("editingDowncast").markerToHighlight({model:"findResult",view:({markerName:e})=>{const[,t]=e.split(":");return{name:"span",classes:["ck-find-result"],attributes:{"data-find-result":t}}}}),e.conversion.for("editingDowncast").markerToHighlight({model:"findResultHighlighted",view:({markerName:e})=>{const[,t]=e.split(":");return{name:"span",classes:["ck-find-result_selected"],attributes:{"data-find-result":t}}}})}}class ib extends Vs{constructor(e,t){super(e),this.attributeKey=t}refresh(){const e=this.editor.model,t=e.document;this.value=t.selection.getAttribute(this.attributeKey),this.isEnabled=e.schema.checkAttributeInSelection(t.selection,this.attributeKey)}execute(e={}){const t=this.editor.model,i=t.document.selection,n=e.value;t.change((e=>{if(i.isCollapsed)n?e.setSelectionAttribute(this.attributeKey,n):e.removeSelectionAttribute(this.attributeKey);else{const s=t.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const t of s)n?e.setAttribute(this.attributeKey,n,t):e.removeAttribute(this.attributeKey,t)}}))}}d(class extends ys{constructor(e){super(e),this.set("isEmpty",!0),this.on("change",(()=>{this.set("isEmpty",0===this.length)}))}add(e,t){this.find((t=>t.color===e.color))||super.add(e,t)}hasColor(e){return!!this.find((t=>t.color===e))}},W);const nb="fontSize";class sb extends ib{constructor(e){super(e,nb)}}function ob(e){return e.map((e=>function(e){if(t=e,"object"==typeof t&&t.title&&t.model&&t.view)return ab(e);var t;const i=function(e){return rb[e]||rb[e.model]}(e);if(i)return ab(i);if("default"===e)return{model:void 0,title:"Default"};if(function(e){let t;if("object"==typeof e){if(!e.model)throw new b("font-size-invalid-definition",null,e);t=parseFloat(e.model)}else t=parseFloat(e);return isNaN(t)}(e))return;return function(e){"number"!=typeof e&&"string"!=typeof e||(e={title:String(e),model:`${parseFloat(e)}px`});return e.view={name:"span",styles:{"font-size":e.model}},ab(e)}(e)}(e))).filter((e=>!!e))}const rb={get tiny(){return{title:"Tiny",model:"tiny",view:{name:"span",classes:"text-tiny",priority:7}}},get small(){return{title:"Small",model:"small",view:{name:"span",classes:"text-small",priority:7}}},get big(){return{title:"Big",model:"big",view:{name:"span",classes:"text-big",priority:7}}},get huge(){return{title:"Huge",model:"huge",view:{name:"span",classes:"text-huge",priority:7}}}};function ab(e){return e.view.priority||(e.view.priority=7),e}const lb=["x-small","x-small","small","medium","large","x-large","xx-large","xxx-large"];class cb extends Is{static get pluginName(){return"FontSizeEditing"}constructor(e){super(e),e.config.define(nb,{options:["tiny","small","default","big","huge"],supportAllValues:!1})}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:nb}),e.model.schema.setAttributeProperties(nb,{isFormatting:!0,copyOnEnter:!0});const t=e.config.get("fontSize.supportAllValues"),i=ob(this.editor.config.get("fontSize.options")).filter((e=>e.model)),n=function(e,t){const i={model:{key:e,values:[]},view:{},upcastAlso:{}};for(const e of t)i.model.values.push(e.model),i.view[e.model]=e.view,e.upcastAlso&&(i.upcastAlso[e.model]=e.upcastAlso);return i}(nb,i);t?(this._prepareAnyValueConverters(n),this._prepareCompatibilityConverter()):e.conversion.attributeToElement(n),e.commands.add(nb,new sb(e))}_prepareAnyValueConverters(e){const t=this.editor,i=e.model.values.filter((e=>!mh(String(e))&&!fh(String(e))));if(i.length)throw new b("font-size-invalid-use-of-named-presets",null,{presets:i});t.conversion.for("downcast").attributeToElement({model:nb,view:(e,{writer:t})=>{if(e)return t.createAttributeElement("span",{style:"font-size:"+e},{priority:7})}}),t.conversion.for("upcast").elementToAttribute({model:{key:nb,value:e=>e.getStyle("font-size")},view:{name:"span",styles:{"font-size":/.*/}}})}_prepareCompatibilityConverter(){this.editor.conversion.for("upcast").elementToAttribute({view:{name:"font",attributes:{size:/^[+-]?\d{1,3}$/}},model:{key:nb,value:e=>{const t=e.getAttribute("size"),i="-"===t[0]||"+"===t[0];let n=parseInt(t,10);i&&(n=3+n);const s=lb.length-1,o=Math.min(Math.max(n,0),s);return lb[o]}}})}}class db extends Is{static get pluginName(){return"FontSizeUI"}init(){const e=this.editor,t=e.t,i=this._getLocalizedOptions(),n=e.commands.get(nb);e.ui.componentFactory.add(nb,(s=>{const o=lm(s);return dm(o,function(e,t){const i=new ys;for(const n of e){const e={type:"button",model:new Tm({commandName:nb,commandParam:n.model,label:n.title,class:"ck-fontsize-option",withText:!0})};n.view&&n.view.styles&&e.model.set("labelStyle",`font-size:${n.view.styles["font-size"]}`),n.view&&n.view.classes&&e.model.set("class",`${e.model.class} ${n.view.classes}`),e.model.bind("isOn").to(t,"value",(e=>e===n.model)),i.add(e)}return i}(i,n)),o.buttonView.set({label:t("Font Size"),icon:'',tooltip:!0}),o.extendTemplate({attributes:{class:["ck-font-size-dropdown"]}}),o.bind("isEnabled").to(n),this.listenTo(o,"execute",(t=>{e.execute(t.source.commandName,{value:t.source.commandParam}),e.editing.view.focus()})),o}))}_getLocalizedOptions(){const e=this.editor,t=e.t,i={Default:t("Default"),Tiny:t("Tiny"),Small:t("Small"),Big:t("Big"),Huge:t("Huge")};return ob(e.config.get(nb).options).map((e=>{const t=i[e.title];return t&&t!=e.title&&(e=Object.assign({},e,{title:t})),e}))}}class hb extends Is{static get requires(){return[Iw]}static get pluginName(){return"CodeBlockElementSupport"}init(){if(!this.editor.plugins.has("CodeBlockEditing"))return;const e=this.editor.plugins.get(Iw);e.on("register:pre",((t,i)=>{if("codeBlock"!==i.model)return;const n=this.editor,s=n.model.schema,o=n.conversion;s.extend("codeBlock",{allowAttributes:["htmlAttributes","htmlContentAttributes"]}),o.for("upcast").add(function(e){return t=>{t.on("element:code",((t,i,n)=>{const s=i.viewItem,o=s.parent;function r(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}o&&o.is("element","pre")&&(r(o,"htmlAttributes"),r(s,"htmlContentAttributes"))}),{priority:"low"})}}(e)),o.for("downcast").add((e=>{e.on("attribute:htmlAttributes:codeBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item).parent;mw(i.writer,n,s,o)})),e.on("attribute:htmlContentAttributes:codeBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item);mw(i.writer,n,s,o)}))})),t.stop()}))}}class ub extends Is{static get requires(){return[Iw]}static get pluginName(){return"DualContentModelElementSupport"}init(){this.editor.plugins.get(Iw).on("register",((e,t)=>{const i=this.editor,n=i.model.schema,s=i.conversion;if(!t.paragraphLikeModel)return;if(n.isRegistered(t.model)||n.isRegistered(t.paragraphLikeModel))return;const o={model:t.paragraphLikeModel,view:t.view};n.register(t.model,t.modelSchema),n.register(o.model,{inheritAllFrom:"$block"}),s.for("upcast").elementToElement({view:t.view,model:(e,{writer:i})=>this._hasBlockContent(e)?i.createElement(t.model):i.createElement(o.model),converterPriority:f.get("low")+1}),s.for("downcast").elementToElement({view:t.view,model:t.model}),this._addAttributeConversion(t),s.for("downcast").elementToElement({view:o.view,model:o.model}),this._addAttributeConversion(o),e.stop()}))}_hasBlockContent(e){const t=this.editor.editing.view,i=t.domConverter.blockElements;for(const n of t.createRangeIn(e).getItems())if(n.is("element")&&i.includes(n.name))return!0;return!1}_addAttributeConversion(e){const t=this.editor,i=t.conversion,n=t.plugins.get(Iw);t.model.schema.extend(e.model,{allowAttributes:"htmlAttributes"}),i.for("upcast").add(_w(e,n)),i.for("downcast").add(yw(e))}}class mb extends Is{static get requires(){return[uw]}static get pluginName(){return"HeadingElementSupport"}init(){const e=this.editor;if(!e.plugins.has("HeadingEditing"))return;const t=e.plugins.get(uw),i=e.config.get("heading.options"),n=[];for(const e of i)"model"in e&&"view"in e&&(t.registerBlockElement({view:e.view,model:e.model}),n.push(e.model));t.extendBlockElement({model:"htmlHgroup",modelSchema:{allowChildren:n}})}}class gb extends Is{static get requires(){return[Iw]}static get pluginName(){return"ImageElementSupport"}init(){const e=this.editor;if(!e.plugins.has("ImageInlineEditing")&&!e.plugins.has("ImageBlockEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(Iw);n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("image"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on("register:img",((e,s)=>{"imageBlock"!==s.model&&"imageInline"!==s.model||(t.isRegistered("imageBlock")&&t.extend("imageBlock",{allowAttributes:["htmlAttributes","htmlFigureAttributes","htmlLinkAttributes"]}),t.isRegistered("imageInline")&&t.extend("imageInline",{allowAttributes:["htmlA","htmlAttributes"]}),i.for("upcast").add(function(e){return t=>{t.on("element:img",((t,i,n)=>{if(!i.modelRange)return;const s=i.viewItem,o=s.parent;function r(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}function a(e){i.modelRange&&i.modelRange.getContainedElement().is("element","imageBlock")&&r(e,"htmlLinkAttributes")}r(s,"htmlAttributes"),o.is("element","a")&&a(o)}),{priority:"low"})}}(n)),i.for("downcast").add((e=>{function t(t){e.on(`attribute:${t}:imageInline`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item);mw(i.writer,n,s,o)}),{priority:"low"})}function i(t,i){e.on(`attribute:${i}:imageBlock`,((e,i,n)=>{if(!n.consumable.test(i.item,e.name))return;const{attributeOldValue:s,attributeNewValue:o}=i,r=n.mapper.toViewElement(i.item),a=fb(n.writer,r,t);a&&(mw(n.writer,s,o,a),n.consumable.consume(i.item,e.name))}),{priority:"low"}),"a"===t&&e.on("attribute:linkHref:imageBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,"attribute:htmlLinkAttributes:imageBlock"))return;const n=i.mapper.toViewElement(t.item),s=fb(i.writer,n,"a");gw(i.writer,t.item.getAttribute("htmlLinkAttributes"),s)}),{priority:"low"})}t("htmlAttributes"),i("img","htmlAttributes"),i("figure","htmlFigureAttributes"),i("a","htmlLinkAttributes")})),e.stop())}))}}function fb(e,t,i){const n=e.createRangeOn(t);for(const{item:e}of n.getWalker())if(e.is("element",i))return e}class pb extends Is{static get requires(){return[Iw]}static get pluginName(){return"MediaEmbedElementSupport"}init(){const e=this.editor;if(!e.plugins.has("MediaEmbed")||e.config.get("mediaEmbed.previewsInData"))return;const t=e.model.schema,i=e.conversion,n=this.editor.plugins.get(Iw),s=this.editor.plugins.get(uw),o=e.config.get("mediaEmbed.elementName");s.registerBlockElement({model:"media",view:o}),n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("media"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on(`register:${o}`,((e,s)=>{"media"===s.model&&(t.extend("media",{allowAttributes:["htmlAttributes","htmlFigureAttributes"]}),i.for("upcast").add(function(e,t){return e=>{e.on(`element:${t}`,i,{priority:"low"})};function i(t,i,n){function s(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}s(i.viewItem,"htmlAttributes")}}(n,o)),i.for("dataDowncast").add(function(e){return t=>{function i(e,i){t.on(`attribute:${i}:media`,((t,i,n)=>{if(!n.consumable.consume(i.item,t.name))return;const{attributeOldValue:s,attributeNewValue:o}=i,r=n.mapper.toViewElement(i.item),a=function(e,t,i){const n=e.createRangeOn(t);for(const{item:e}of n.getWalker())if(e.is("element",i))return e}(n.writer,r,e);mw(n.writer,s,o,a)}))}i(e,"htmlAttributes"),i("figure","htmlFigureAttributes")}}(o)),e.stop())}))}}class wb extends Is{static get requires(){return[Iw]}static get pluginName(){return"ScriptElementSupport"}init(){const e=this.editor.plugins.get(Iw);e.on("register:script",((t,i)=>{const n=this.editor,s=n.model.schema,o=n.conversion;s.register("htmlScript",i.modelSchema),s.extend("htmlScript",{allowAttributes:["htmlAttributes","htmlContent"],isContent:!0}),n.data.registerRawContentMatcher({name:"script"}),o.for("upcast").elementToElement({view:"script",model:pw(i)}),o.for("upcast").add(_w(i,e)),o.for("downcast").elementToElement({model:"htmlScript",view:(e,{writer:t})=>bw("script",e,t)}),o.for("downcast").add(yw(i)),t.stop()}))}}class bb extends Is{static get requires(){return[Iw]}static get pluginName(){return"TableElementSupport"}init(){const e=this.editor;if(!e.plugins.has("TableEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(Iw);n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("table"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on("register:table",((e,s)=>{"table"===s.model&&(t.extend("table",{allowAttributes:["htmlAttributes","htmlFigureAttributes","htmlTheadAttributes","htmlTbodyAttributes"]}),i.for("upcast").add(function(e){return t=>{t.on("element:table",((t,i,n)=>{const s=i.viewItem;o(s,"htmlAttributes");for(const e of s.getChildren())e.is("element","thead")&&o(e,"htmlTheadAttributes"),e.is("element","tbody")&&o(e,"htmlTbodyAttributes");function o(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}}),{priority:"low"})}}(n)),i.for("downcast").add((e=>{function t(t,i){e.on(`attribute:${i}:table`,((e,i,n)=>{if(!n.consumable.consume(i.item,e.name))return;const s=n.mapper.toViewElement(i.item),o=function(e,t,i){const n=e.createRangeOn(t);for(const{item:e}of n.getWalker())if(e.is("element",i))return e}(n.writer,s,t);gw(n.writer,i.attributeNewValue,o)}))}t("table","htmlAttributes"),t("figure","htmlFigureAttributes"),t("thead","htmlTheadAttributes"),t("tbody","htmlTbodyAttributes")})),e.stop())}))}}class vb extends Is{static get requires(){return[Iw]}static get pluginName(){return"StyleElementSupport"}init(){const e=this.editor.plugins.get(Iw);e.on("register:style",((t,i)=>{const n=this.editor,s=n.model.schema,o=n.conversion;s.register("htmlStyle",i.modelSchema),s.extend("htmlStyle",{allowAttributes:["htmlAttributes","htmlContent"],isContent:!0}),n.data.registerRawContentMatcher({name:"style"}),o.for("upcast").elementToElement({view:"style",model:pw(i)}),o.for("upcast").add(_w(i,e)),o.for("downcast").elementToElement({model:"htmlStyle",view:(e,{writer:t})=>bw("style",e,t)}),o.for("downcast").add(yw(i)),t.stop()}))}}class _b extends Is{static get requires(){return[Iw]}static get pluginName(){return"DocumentListElementSupport"}init(){const e=this.editor;if(!e.plugins.has("DocumentListEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(Iw),s=e.plugins.get("DocumentListEditing");s.registerDowncastStrategy({scope:"item",attributeName:"htmlLiAttributes",setAttributeOnDowncast(e,t,i){gw(e,t,i)}}),s.registerDowncastStrategy({scope:"list",attributeName:"htmlListAttributes",setAttributeOnDowncast(e,t,i){gw(e,t,i)}}),n.on("register",((e,s)=>{["ul","ol","li"].includes(s.view)&&(e.stop(),t.checkAttribute("$block","htmlListAttributes")||(t.extend("$block",{allowAttributes:["htmlListAttributes","htmlLiAttributes"]}),t.extend("$blockObject",{allowAttributes:["htmlListAttributes","htmlLiAttributes"]}),t.extend("$container",{allowAttributes:["htmlListAttributes","htmlLiAttributes"]}),i.for("upcast").add((e=>{e.on("element:ul",yb("htmlListAttributes",n),{priority:"low"}),e.on("element:ol",yb("htmlListAttributes",n),{priority:"low"}),e.on("element:li",yb("htmlLiAttributes",n),{priority:"low"})}))))})),s.on("postFixer",((e,{listNodes:t,writer:i})=>{const n=[];for(const{node:s,previous:o}of t){if(!o)continue;const t=s.getAttribute("listIndent"),r=o.getAttribute("listIndent");let a=null;if(t>r?n[r]=o:t{e.model.change((e=>{for(const t of i)e.setAttribute("htmlListAttributes",{},t)}))}))}}function yb(e,t){return(i,n,s)=>{const o=n.viewItem;n.modelRange||Object.assign(n,s.convertChildren(n.viewItem,n.modelCursor));const r=t.processViewAttributes(o,s);for(const t of n.modelRange.getItems({shallow:!0}))t.hasAttribute("listItemId")&&(t.hasAttribute(e)||s.writer.setAttribute(e,r||{},t))}}class kb extends Is{static get requires(){return[Iw,uw]}static get pluginName(){return"CustomElementSupport"}init(){const e=this.editor.plugins.get(Iw),t=this.editor.plugins.get(uw);e.on("register:$customElement",((i,n)=>{i.stop();const s=this.editor,o=s.model.schema,r=s.conversion,a=s.editing.view.domConverter.unsafeElements,l=s.data.htmlProcessor.domConverter.preElements;o.register(n.model,n.modelSchema),o.extend(n.model,{allowAttributes:["htmlElementName","htmlAttributes","htmlContent"],isContent:!0}),r.for("upcast").elementToElement({view:/.*/,model:(i,o)=>{if("$comment"==i.name)return;if(!function(e){try{document.createElement(e)}catch(e){return!1}return!0}(i.name))return;if(t.getDefinitionsForView(i.name).size)return;a.includes(i.name)||a.push(i.name),l.includes(i.name)||l.push(i.name);const r=o.writer.createElement(n.model,{htmlElementName:i.name}),c=e.processViewAttributes(i,o);c&&o.writer.setAttribute("htmlAttributes",c,r);const d=new ih(i.document).createDocumentFragment(i),h=s.data.processor.toData(d);o.writer.setAttribute("htmlContent",h,r);for(const{item:e}of s.editing.view.createRangeIn(i))o.consumable.consume(e,{name:!0});return r},converterPriority:"low"}),r.for("editingDowncast").elementToElement({model:{name:n.model,attributes:["htmlElementName","htmlAttributes","htmlContent"]},view:(e,{writer:t})=>{const i=e.getAttribute("htmlElementName"),n=t.createRawElement(i);return e.hasAttribute("htmlAttributes")&&gw(t,e.getAttribute("htmlAttributes"),n),n}}),r.for("dataDowncast").elementToElement({model:{name:n.model,attributes:["htmlElementName","htmlAttributes","htmlContent"]},view:(e,{writer:t})=>{const i=e.getAttribute("htmlElementName"),n=e.getAttribute("htmlContent"),s=t.createRawElement(i,null,((e,t)=>{t.setContentOf(e,n);const i=e.firstChild;for(i.remove();i.firstChild;)e.appendChild(i.firstChild)}));return e.hasAttribute("htmlAttributes")&&gw(t,e.getAttribute("htmlAttributes"),s),s}})}))}}function*Cb(e,t,i){if(t.is("documentSelection")&&t.isCollapsed)e.schema.checkAttributeInSelection(t,i)&&(yield t);else for(const n of function(e,t,i){return t.is("node")||t.is("$text")||t.is("$textProxy")?e.schema.checkAttribute(t,i)?[e.createRangeOn(t)]:[]:e.schema.getValidRanges(e.createSelection(t).getRanges(),i)}(e,t,i))yield*n.getItems({shallow:!0})}function Ab(e,t,i,n,s){const o=t.getAttribute(i),r={};for(const e of["attributes","styles","classes"])if(e!=n)o&&o[e]&&(r[e]=o[e]);else{const t="classes"==e?new Set(o&&o[e]||[]):new Map(Object.entries(o&&o[e]||{}));s(t),t.size&&(r[e]="classes"==e?Array.from(t):Object.fromEntries(t))}Object.keys(r).length?t.is("documentSelection")?e.setSelectionAttribute(i,r):e.setAttribute(i,r,t):o&&(t.is("documentSelection")?e.removeSelectionAttribute(i):e.removeAttribute(i,t))}class xb extends Vs{refresh(){const e=this.editor.model,t=ks(e.document.selection.getSelectedBlocks());this.value=!!t&&t.is("element","paragraph"),this.isEnabled=!!t&&Tb(t,e.schema)}execute(e={}){const t=this.editor.model,i=t.document;t.change((n=>{const s=(e.selection||i.selection).getSelectedBlocks();for(const e of s)!e.is("element","paragraph")&&Tb(e,t.schema)&&n.rename(e,"paragraph")}))}}function Tb(e,t){return t.checkChild(e.parent,"paragraph")&&!t.isObject(e)}class Eb extends Vs{execute(e){const t=this.editor.model,i=e.attributes;let n=e.position;t.change((e=>{const s=e.createElement("paragraph");if(i&&t.schema.setAllowedAttributes(s,i,e),!t.schema.checkChild(n.parent,s)){const i=t.schema.findAllowedParent(n,s);if(!i)return;n=e.split(n,i).position}t.insertContent(s,n),e.setSelection(s,"in")}))}}class Sb extends Is{static get pluginName(){return"Paragraph"}init(){const e=this.editor,t=e.model;e.commands.add("paragraph",new xb(e)),e.commands.add("insertParagraph",new Eb(e)),t.schema.register("paragraph",{inheritAllFrom:"$block"}),e.conversion.elementToElement({model:"paragraph",view:"p"}),e.conversion.for("upcast").elementToElement({model:(e,{writer:t})=>Sb.paragraphLikeElements.has(e.name)?e.isEmpty?null:t.createElement("paragraph"):null,view:/.+/,converterPriority:"low"})}}Sb.paragraphLikeElements=new Set(["blockquote","dd","div","dt","h1","h2","h3","h4","h5","h6","li","p","td","th"]);Pu.paragraph;class Pb extends Vs{constructor(e,t){super(e),this.modelElements=t}refresh(){const e=ks(this.editor.model.document.selection.getSelectedBlocks());this.value=!!e&&this.modelElements.includes(e.name)&&e.name,this.isEnabled=!!e&&this.modelElements.some((t=>Ib(e,t,this.editor.model.schema)))}execute(e){const t=this.editor.model,i=t.document,n=e.value;t.change((e=>{const s=Array.from(i.selection.getSelectedBlocks()).filter((e=>Ib(e,n,t.schema)));for(const t of s)t.is("element",n)||e.rename(t,n)}))}}function Ib(e,t,i){return i.checkChild(e.parent,t)&&!i.isObject(e)}const Rb="paragraph";class Vb extends Is{static get pluginName(){return"HeadingEditing"}constructor(e){super(e),e.config.define("heading",{options:[{model:"paragraph",title:"Paragraph",class:"ck-heading_paragraph"},{model:"heading1",view:"h2",title:"Heading 1",class:"ck-heading_heading1"},{model:"heading2",view:"h3",title:"Heading 2",class:"ck-heading_heading2"},{model:"heading3",view:"h4",title:"Heading 3",class:"ck-heading_heading3"}]})}static get requires(){return[Sb]}init(){const e=this.editor,t=e.config.get("heading.options"),i=[];for(const n of t)n.model!==Rb&&(e.model.schema.register(n.model,{inheritAllFrom:"$block"}),e.conversion.elementToElement(n),i.push(n.model));this._addDefaultH1Conversion(e),e.commands.add("heading",new Pb(e,i))}afterInit(){const e=this.editor,t=e.commands.get("enter"),i=e.config.get("heading.options");t&&this.listenTo(t,"afterExecute",((t,n)=>{const s=e.model.document.selection.getFirstPosition().parent;i.some((e=>s.is("element",e.model)))&&!s.is("element",Rb)&&0===s.childCount&&n.writer.rename(s,Rb)}))}_addDefaultH1Conversion(e){e.conversion.for("upcast").elementToElement({model:"heading1",view:"h1",converterPriority:f.get("low")+1})}}class Lb extends Is{static get pluginName(){return"HeadingUI"}init(){const e=this.editor,t=e.t,i=function(e){const t=e.t,i={Paragraph:t("Paragraph"),"Heading 1":t("Heading 1"),"Heading 2":t("Heading 2"),"Heading 3":t("Heading 3"),"Heading 4":t("Heading 4"),"Heading 5":t("Heading 5"),"Heading 6":t("Heading 6")};return e.config.get("heading.options").map((e=>{const t=i[e.title];return t&&t!=e.title&&(e.title=t),e}))}(e),n=t("Choose heading"),s=t("Heading");e.ui.componentFactory.add("heading",(t=>{const o={},r=new ys,a=e.commands.get("heading"),l=e.commands.get("paragraph"),c=[a];for(const e of i){const t={type:"button",model:new Tm({label:e.title,class:e.class,withText:!0})};"paragraph"===e.model?(t.model.bind("isOn").to(l,"value"),t.model.set("commandName","paragraph"),c.push(l)):(t.model.bind("isOn").to(a,"value",(t=>t===e.model)),t.model.set({commandName:"heading",commandValue:e.model})),r.add(t),o[e.model]=e.title}const d=lm(t);return dm(d,r),d.buttonView.set({isOn:!1,withText:!0,tooltip:s}),d.extendTemplate({attributes:{class:["ck-heading-dropdown"]}}),d.bind("isEnabled").toMany(c,"isEnabled",((...e)=>e.some((e=>e)))),d.buttonView.bind("label").to(a,"value",l,"value",((e,t)=>{const i=e||t&&"paragraph";return o[i]?o[i]:n})),this.listenTo(d,"execute",(t=>{e.execute(t.source.commandName,t.source.commandValue?{value:t.source.commandValue}:void 0),e.editing.view.focus()})),d}))}}class Ob extends Vs{refresh(){const e=this.editor.model,t=e.schema,i=e.document.selection;this.isEnabled=function(e,t,i){const n=function(e,t){const i=af(e,t),n=i.start.parent;if(n.isEmpty&&!n.is("element","$root"))return n.parent;return n}(e,i);return t.checkChild(n,"horizontalLine")}(i,t,e)}execute(){const e=this.editor.model;e.change((t=>{const i=t.createElement("horizontalLine");e.insertObject(i,null,null,{setSelection:"after"})}))}}class Bb extends Is{static get pluginName(){return"HorizontalLineEditing"}init(){const e=this.editor,t=e.model.schema,i=e.t,n=e.conversion;t.register("horizontalLine",{inheritAllFrom:"$blockObject"}),n.for("dataDowncast").elementToElement({model:"horizontalLine",view:(e,{writer:t})=>t.createEmptyElement("hr")}),n.for("editingDowncast").elementToStructure({model:"horizontalLine",view:(e,{writer:t})=>{const n=i("Horizontal line"),s=t.createContainerElement("div",null,t.createEmptyElement("hr"));return t.addClass("ck-horizontal-line",s),t.setCustomProperty("hr",!0,s),function(e,t,i){return t.setCustomProperty("horizontalLine",!0,e),tf(e,t,{label:i})}(s,t,n)}}),n.for("upcast").elementToElement({view:"hr",model:"horizontalLine"}),e.commands.add("horizontalLine",new Ob(e))}}class Mb extends Is{static get pluginName(){return"HorizontalLineUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("horizontalLine",(i=>{const n=e.commands.get("horizontalLine"),s=new Mu(i);return s.set({label:t("Horizontal line"),icon:'',tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("horizontalLine"),e.editing.view.focus()})),s}))}}class Nb extends Vs{refresh(){const e=this.editor.model,t=e.schema,i=e.document.selection,n=Db(i);this.isEnabled=function(e,t,i){const n=function(e,t){const i=af(e,t),n=i.start.parent;if(n.isEmpty&&!n.is("element","$root"))return n.parent;return n}(e,i);return t.checkChild(n,"rawHtml")}(i,t,e),this.value=n?n.getAttribute("value")||"":null}execute(e){const t=this.editor.model,i=t.document.selection;t.change((n=>{let s;null!==this.value?s=Db(i):(s=n.createElement("rawHtml"),t.insertObject(s,null,null,{setSelection:"on"})),n.setAttribute("value",e,s)}))}}function Db(e){const t=e.getSelectedElement();return t&&t.is("element","rawHtml")?t:null}class Fb extends Is{static get pluginName(){return"HtmlEmbedEditing"}constructor(e){super(e),e.config.define("htmlEmbed",{showPreviews:!1,sanitizeHtml:e=>(v("html-embed-provide-sanitize-function"),{html:e,hasChanged:!1})}),this._widgetButtonViewReferences=new Set}init(){const e=this.editor;e.model.schema.register("rawHtml",{inheritAllFrom:"$blockObject",allowAttributes:["value"]}),e.commands.add("htmlEmbed",new Nb(e)),this._setupConversion()}_setupConversion(){const e=this.editor,t=e.t,i=e.editing.view,n=this._widgetButtonViewReferences,s=e.config.get("htmlEmbed");function o({domElement:e,editor:i,state:s,props:o}){e.textContent="";const a=e.ownerDocument;let l;if(s.isEditable){const t={isDisabled:!1,placeholder:o.textareaPlaceholder};l=r({domDocument:a,state:s,props:t}),e.append(l)}else if(s.showPreviews){const n={sanitizeHtml:o.sanitizeHtml};e.append(function({domDocument:e,state:i,props:n,editor:s}){const o=n.sanitizeHtml(i.getRawHtmlValue()),r=i.getRawHtmlValue().length>0?t("No preview available"):t("Empty snippet content"),a=fe(e,"div",{class:"ck ck-reset_all raw-html-embed__preview-placeholder"},r),l=fe(e,"div",{class:"raw-html-embed__preview-content",dir:s.locale.contentLanguageDirection}),c=e.createRange(),d=c.createContextualFragment(o.html);l.appendChild(d);const h=fe(e,"div",{class:"raw-html-embed__preview"},[a,l]);return h}({domDocument:a,state:s,props:n,editor:i}))}else{const t={isDisabled:!0,placeholder:o.textareaPlaceholder};e.append(r({domDocument:a,state:s,props:t}))}const c={onEditClick:o.onEditClick,onSaveClick:()=>{o.onSaveClick(l.value)},onCancelClick:o.onCancelClick};e.prepend(function({editor:e,domDocument:t,state:i,props:s}){const o=fe(t,"div",{class:"raw-html-embed__buttons-wrapper"});if(i.isEditable){const t=zb(e,"save",s.onSaveClick),i=zb(e,"cancel",s.onCancelClick);o.append(t.element,i.element),n.add(t).add(i)}else{const t=zb(e,"edit",s.onEditClick);o.append(t.element),n.add(t)}return o}({editor:i,domDocument:a,state:s,props:c}))}function r({domDocument:e,state:t,props:i}){const n=fe(e,"textarea",{placeholder:i.placeholder,class:"ck ck-reset ck-input ck-input-text raw-html-embed__source"});return n.disabled=i.isDisabled,n.value=t.getRawHtmlValue(),n}this.editor.editing.view.on("render",(()=>{for(const e of n){if(e.element.isConnected)return;e.destroy(),n.delete(e)}}),{priority:"lowest"}),e.data.registerRawContentMatcher({name:"div",classes:"raw-html-embed"}),e.conversion.for("upcast").elementToElement({view:{name:"div",classes:"raw-html-embed"},model:(e,{writer:t})=>t.createElement("rawHtml",{value:e.getCustomProperty("$rawContent")})}),e.conversion.for("dataDowncast").elementToElement({model:"rawHtml",view:(e,{writer:t})=>t.createRawElement("div",{class:"raw-html-embed"},(function(t){t.innerHTML=e.getAttribute("value")||""}))}),e.conversion.for("editingDowncast").elementToStructure({model:{name:"rawHtml",attributes:["value"]},view:(n,{writer:r})=>{let a,l,c;const d=r.createRawElement("div",{class:"raw-html-embed__content-wrapper"},(function(t){a=t,o({domElement:t,editor:e,state:l,props:c}),a.addEventListener("mousedown",(()=>{if(l.isEditable){const t=e.model;t.document.selection.getSelectedElement()!==n&&t.change((e=>e.setSelection(n,"on")))}}),!0)})),h={makeEditable(){l=Object.assign({},l,{isEditable:!0}),o({domElement:a,editor:e,state:l,props:c}),i.change((e=>{e.setAttribute("data-cke-ignore-events","true",d)})),a.querySelector("textarea").focus()},save(t){t!==l.getRawHtmlValue()?(e.execute("htmlEmbed",t),e.editing.view.focus()):this.cancel()},cancel(){l=Object.assign({},l,{isEditable:!1}),o({domElement:a,editor:e,state:l,props:c}),e.editing.view.focus(),i.change((e=>{e.removeAttribute("data-cke-ignore-events",d)}))}};l={showPreviews:s.showPreviews,isEditable:!1,getRawHtmlValue:()=>n.getAttribute("value")||""},c={sanitizeHtml:s.sanitizeHtml,textareaPlaceholder:t("Paste raw HTML here..."),onEditClick(){h.makeEditable()},onSaveClick(e){h.save(e)},onCancelClick(){h.cancel()}};const u=r.createContainerElement("div",{class:"raw-html-embed","data-html-embed-label":t("HTML snippet"),dir:e.locale.uiLanguageDirection},d);return r.setCustomProperty("rawHtmlApi",h,u),r.setCustomProperty("rawHtml",!0,u),tf(u,r,{widgetLabel:t("HTML snippet"),hasSelectionHandle:!0})}})}}function zb(e,t,i){const n=e.locale.t,s=new Mu(e.locale),o=e.commands.get("htmlEmbed");return s.set({class:`raw-html-embed__${t}-button`,icon:Pu.pencil,tooltip:!0,tooltipPosition:"rtl"===e.locale.uiLanguageDirection?"e":"w"}),s.render(),"edit"===t?(s.set({icon:Pu.pencil,label:n("Edit source")}),s.bind("isEnabled").to(o)):"save"===t?(s.set({icon:Pu.check,label:n("Save changes")}),s.bind("isEnabled").to(o)):s.set({icon:Pu.cancel,label:n("Cancel")}),s.on("execute",i),s}class Hb extends Is{static get pluginName(){return"HtmlEmbedUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("htmlEmbed",(i=>{const n=e.commands.get("htmlEmbed"),s=new Mu(i);return s.set({label:t("Insert HTML"),icon:'',tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("htmlEmbed"),e.editing.view.focus();e.editing.view.document.selection.getSelectedElement().getCustomProperty("rawHtmlApi").makeEditable()})),s}))}}class $b extends Vs{refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled&&e.hasAttribute("alt")?this.value=e.getAttribute("alt"):this.value=!1}execute(e){const t=this.editor,i=t.plugins.get("ImageUtils"),n=t.model,s=i.getClosestSelectedImageElement(n.document.selection);n.change((t=>{t.setAttribute("alt",e.newValue,s)}))}}class Wb extends Is{static get requires(){return[Qf]}static get pluginName(){return"ImageTextAlternativeEditing"}init(){this.editor.commands.add("imageTextAlternative",new $b(this.editor))}}class jb extends fu{constructor(e){super(e);const t=this.locale.t;this.focusTracker=new Cs,this.keystrokes=new As,this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(t("Save"),Pu.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(t("Cancel"),Pu.cancel,"ck-button-cancel","cancel"),this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-text-alternative-form","ck-responsive-form"],tabindex:"-1"},children:[this.labeledInput,this.saveButtonView,this.cancelButtonView]}),Ru(this)}render(){super.render(),this.keystrokes.listenTo(this.element),Vu({view:this}),[this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)}))}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createButton(e,t,i,n){const s=new Mu(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}_createLabeledInputView(){const e=this.locale.t,t=new ym(this.locale,km);return t.label=e("Text alternative"),t}}function qb(e){const t=e.editing.view,i=bu.defaultPositions,n=e.plugins.get("ImageUtils");return{target:t.domConverter.mapViewToDom(n.getClosestSelectedImageWidget(t.document.selection)),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast,i.viewportStickyNorth]}}class Ub extends Is{static get requires(){return[Pm]}static get pluginName(){return"ImageTextAlternativeUI"}init(){this._createButton(),this._createForm()}destroy(){super.destroy(),this._form.destroy()}_createButton(){const e=this.editor,t=e.t;e.ui.componentFactory.add("imageTextAlternative",(i=>{const n=e.commands.get("imageTextAlternative"),s=new Mu(i);return s.set({label:t("Change image text alternative"),icon:Pu.lowVision,tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),s.bind("isOn").to(n,"value",(e=>!!e)),this.listenTo(s,"execute",(()=>{this._showForm()})),s}))}_createForm(){const e=this.editor,t=e.editing.view.document,i=e.plugins.get("ImageUtils");this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new jb(e.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{e.execute("imageTextAlternative",{newValue:this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this._form.keystrokes.set("Esc",((e,t)=>{this._hideForm(!0),t()})),this.listenTo(e.ui,"update",(()=>{i.getClosestSelectedImageWidget(t.selection)?this._isVisible&&function(e){const t=e.plugins.get("ContextualBalloon");if(e.plugins.get("ImageUtils").getClosestSelectedImageWidget(e.editing.view.document.selection)){const i=qb(e);t.updatePosition(i)}}(e):this._hideForm(!0)})),Iu({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const e=this.editor,t=e.commands.get("imageTextAlternative"),i=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:qb(e)}),i.fieldView.value=i.fieldView.element.value=t.value||"",this._form.labeledInput.fieldView.select(),this._form.enableCssTransitions()}_hideForm(e){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),e&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class Gb extends Is{static get requires(){return[Wb,Ub]}static get pluginName(){return"ImageTextAlternative"}}function Kb(e,t){return e=>{e.on(`attribute:srcset:${t}`,i)};function i(t,i,n){if(!n.consumable.consume(i.item,t.name))return;const s=n.writer,o=n.mapper.toViewElement(i.item),r=e.findViewImgElement(o);if(null===i.attributeNewValue){const e=i.attributeOldValue;e.data&&(s.removeAttribute("srcset",r),s.removeAttribute("sizes",r),e.width&&s.removeAttribute("width",r))}else{const e=i.attributeNewValue;e.data&&(s.setAttribute("srcset",e.data,r),s.setAttribute("sizes","100vw",r),e.width&&s.setAttribute("width",e.width,r))}}}function Jb(e,t,i){return e=>{e.on(`attribute:${i}:${t}`,n)};function n(t,i,n){if(!n.consumable.consume(i.item,t.name))return;const s=n.writer,o=n.mapper.toViewElement(i.item),r=e.findViewImgElement(o);s.setAttribute(i.attributeKey,i.attributeNewValue||"",r)}}class Qb extends la{observe(e){this.listenTo(e,"load",((e,t)=>{const i=t.target;this.checkShouldIgnoreEventFromTarget(i)||"IMG"==i.tagName&&this._fireEvents(t)}),{useCapture:!0})}_fireEvents(e){this.isEnabled&&(this.document.fire("layoutChanged"),this.document.fire("imageLoaded",e))}}class Yb extends Vs{constructor(e){super(e);const t=e.config.get("image.insert.type");e.plugins.has("ImageBlockEditing")||"block"===t&&v("image-block-plugin-required"),e.plugins.has("ImageInlineEditing")||"inline"===t&&v("image-inline-plugin-required")}refresh(){this.isEnabled=this.editor.plugins.get("ImageUtils").isImageAllowed()}execute(e){const t=ps(e.source),i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageUtils"),s=Object.fromEntries(i.getAttributes());t.forEach(((e,t)=>{const o=i.getSelectedElement();if("string"==typeof e&&(e={src:e}),t&&o&&n.isImage(o)){const t=this.editor.model.createPositionAfter(o);n.insertImage({...e,...s},t)}else n.insertImage({...e,...s})}))}}class Xb extends Is{static get requires(){return[Qf]}static get pluginName(){return"ImageEditing"}init(){const e=this.editor,t=e.conversion;e.editing.view.addObserver(Qb),t.for("upcast").attributeToAttribute({view:{name:"img",key:"alt"},model:"alt"}).attributeToAttribute({view:{name:"img",key:"srcset"},model:{key:"srcset",value:e=>{const t={data:e.getAttribute("srcset")};return e.hasAttribute("width")&&(t.width=e.getAttribute("width")),t}}});const i=new Yb(e);e.commands.add("insertImage",i),e.commands.add("imageInsert",i)}}class Zb extends Vs{constructor(e,t){super(e),this._modelElementName=t}refresh(){const e=this.editor.plugins.get("ImageUtils"),t=e.getClosestSelectedImageElement(this.editor.model.document.selection);"imageBlock"===this._modelElementName?this.isEnabled=e.isInlineImage(t):this.isEnabled=e.isBlockImage(t)}execute(){const e=this.editor,t=this.editor.model,i=e.plugins.get("ImageUtils"),n=i.getClosestSelectedImageElement(t.document.selection),s=Object.fromEntries(n.getAttributes());return s.src||s.uploadId?t.change((e=>{const o=Array.from(t.markers).filter((e=>e.getRange().containsItem(n))),r=i.insertImage(s,t.createSelection(n,"on"),this._modelElementName);if(!r)return null;const a=e.createRangeOn(r);for(const t of o){const i=t.getRange(),n="$graveyard"!=i.root.rootName?i.getJoined(a,!0):a;e.updateMarker(t,{range:n})}return{oldElement:n,newElement:r}})):null}}class ev extends Is{static get requires(){return[Xb,Qf,Mg]}static get pluginName(){return"ImageBlockEditing"}init(){const e=this.editor;e.model.schema.register("imageBlock",{inheritAllFrom:"$blockObject",allowAttributes:["alt","src","srcset"]}),this._setupConversion(),e.plugins.has("ImageInlineEditing")&&(e.commands.add("imageTypeBlock",new Zb(this.editor,"imageBlock")),this._setupClipboardIntegration())}_setupConversion(){const e=this.editor,t=e.t,i=e.conversion,n=e.plugins.get("ImageUtils");i.for("dataDowncast").elementToStructure({model:"imageBlock",view:(e,{writer:t})=>Gf(t)}),i.for("editingDowncast").elementToStructure({model:"imageBlock",view:(e,{writer:i})=>n.toImageWidget(Gf(i),i,t("image widget"))}),i.for("downcast").add(Jb(n,"imageBlock","src")).add(Jb(n,"imageBlock","alt")).add(Kb(n,"imageBlock")),i.for("upcast").elementToElement({view:Kf(e,"imageBlock"),model:(e,{writer:t})=>t.createElement("imageBlock",e.hasAttribute("src")?{src:e.getAttribute("src")}:null)}).add(function(e){return e=>{e.on("element:figure",t)};function t(t,i,n){if(!n.consumable.test(i.viewItem,{name:!0,classes:"image"}))return;const s=e.findViewImgElement(i.viewItem);if(!s||!n.consumable.test(s,{name:!0}))return;n.consumable.consume(i.viewItem,{name:!0,classes:"image"});const o=ks(n.convertItem(s,i.modelCursor).modelRange.getItems());o?(n.convertChildren(i.viewItem,o),n.updateConversionResult(o,i)):n.consumable.revert(i.viewItem,{name:!0,classes:"image"})}}(n))}_setupClipboardIntegration(){const e=this.editor,t=e.model,i=e.editing.view,n=e.plugins.get("ImageUtils");this.listenTo(e.plugins.get("ClipboardPipeline"),"inputTransformation",((s,o)=>{const r=Array.from(o.content.getChildren());let a;if(!r.every(n.isInlineImageView))return;a=o.targetRanges?e.editing.mapper.toModelRange(o.targetRanges[0]):t.document.selection.getFirstRange();const l=t.createSelection(a);if("imageBlock"===Jf(t.schema,l)){const e=new ih(i.document),t=r.map((t=>e.createElement("figure",{class:"image"},t)));o.content=e.createDocumentFragment(t)}}))}}class tv extends Is{static get requires(){return[ev,vf,Gb]}static get pluginName(){return"ImageBlock"}}class iv extends Is{static get requires(){return[Xb,Qf,Mg]}static get pluginName(){return"ImageInlineEditing"}init(){const e=this.editor,t=e.model.schema;t.register("imageInline",{inheritAllFrom:"$inlineObject",allowAttributes:["alt","src","srcset"]}),t.addChildCheck(((e,t)=>{if(e.endsWith("caption")&&"imageInline"===t.name)return!1})),this._setupConversion(),e.plugins.has("ImageBlockEditing")&&(e.commands.add("imageTypeInline",new Zb(this.editor,"imageInline")),this._setupClipboardIntegration())}_setupConversion(){const e=this.editor,t=e.t,i=e.conversion,n=e.plugins.get("ImageUtils");i.for("dataDowncast").elementToElement({model:"imageInline",view:(e,{writer:t})=>t.createEmptyElement("img")}),i.for("editingDowncast").elementToStructure({model:"imageInline",view:(e,{writer:i})=>n.toImageWidget(function(e){return e.createContainerElement("span",{class:"image-inline"},e.createEmptyElement("img"))}(i),i,t("image widget"))}),i.for("downcast").add(Jb(n,"imageInline","src")).add(Jb(n,"imageInline","alt")).add(Kb(n,"imageInline")),i.for("upcast").elementToElement({view:Kf(e,"imageInline"),model:(e,{writer:t})=>t.createElement("imageInline",e.hasAttribute("src")?{src:e.getAttribute("src")}:null)})}_setupClipboardIntegration(){const e=this.editor,t=e.model,i=e.editing.view,n=e.plugins.get("ImageUtils");this.listenTo(e.plugins.get("ClipboardPipeline"),"inputTransformation",((s,o)=>{const r=Array.from(o.content.getChildren());let a;if(!r.every(n.isBlockImageView))return;a=o.targetRanges?e.editing.mapper.toModelRange(o.targetRanges[0]):t.document.selection.getFirstRange();const l=t.createSelection(a);if("imageInline"===Jf(t.schema,l)){const e=new ih(i.document),t=r.map((t=>1===t.childCount?(Array.from(t.getAttributes()).forEach((i=>e.setAttribute(...i,n.findViewImgElement(t)))),t.getChild(0)):t));o.content=e.createDocumentFragment(t)}}))}}class nv extends Is{static get requires(){return[iv,vf,Gb]}static get pluginName(){return"ImageInline"}}class sv extends Vs{refresh(){const e=this.editor,t=e.plugins.get("ImageCaptionUtils");if(!e.plugins.has(ev))return this.isEnabled=!1,void(this.value=!1);const i=e.model.document.selection,n=i.getSelectedElement();if(!n){const e=t.getCaptionFromModelSelection(i);return this.isEnabled=!!e,void(this.value=!!e)}this.isEnabled=this.editor.plugins.get("ImageUtils").isImage(n),this.isEnabled?this.value=!!t.getCaptionFromImageModelElement(n):this.value=!1}execute(e={}){const{focusCaptionOnShow:t}=e;this.editor.model.change((e=>{this.value?this._hideImageCaption(e):this._showImageCaption(e,t)}))}_showImageCaption(e,t){const i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageCaptionEditing");let s=i.getSelectedElement();const o=n._getSavedCaption(s);this.editor.plugins.get("ImageUtils").isInlineImage(s)&&(this.editor.execute("imageTypeBlock"),s=i.getSelectedElement());const r=o||e.createElement("caption");e.append(r,s),t&&e.setSelection(r,"in")}_hideImageCaption(e){const t=this.editor,i=t.model.document.selection,n=t.plugins.get("ImageCaptionEditing"),s=t.plugins.get("ImageCaptionUtils");let o,r=i.getSelectedElement();r?o=s.getCaptionFromImageModelElement(r):(o=s.getCaptionFromModelSelection(i),r=o.parent),n._saveCaption(r,o),e.setSelection(r,"on"),e.remove(o)}}class ov extends Is{static get pluginName(){return"ImageCaptionUtils"}static get requires(){return[Qf]}getCaptionFromImageModelElement(e){for(const t of e.getChildren())if(t&&t.is("element","caption"))return t;return null}getCaptionFromModelSelection(e){const t=this.editor.plugins.get("ImageUtils"),i=e.getFirstPosition().findAncestor("caption");return i&&t.isBlockImage(i.parent)?i:null}matchImageCaptionViewElement(e){const t=this.editor.plugins.get("ImageUtils");return"figcaption"==e.name&&t.isBlockImageView(e.parent)?{name:!0}:null}}class rv extends Is{static get requires(){return[Qf,ov]}static get pluginName(){return"ImageCaptionEditing"}constructor(e){super(e),this._savedCaptionsMap=new WeakMap}init(){const e=this.editor,t=e.model.schema;t.isRegistered("caption")?t.extend("caption",{allowIn:"imageBlock"}):t.register("caption",{allowIn:"imageBlock",allowContentOf:"$block",isLimit:!0}),e.commands.add("toggleImageCaption",new sv(this.editor)),this._setupConversion(),this._setupImageTypeCommandsIntegration(),this._registerCaptionReconversion()}_setupConversion(){const e=this.editor,t=e.editing.view,i=e.plugins.get("ImageUtils"),n=e.plugins.get("ImageCaptionUtils"),s=e.t;e.conversion.for("upcast").elementToElement({view:e=>n.matchImageCaptionViewElement(e),model:"caption"}),e.conversion.for("dataDowncast").elementToElement({model:"caption",view:(e,{writer:t})=>i.isBlockImage(e.parent)?t.createContainerElement("figcaption"):null}),e.conversion.for("editingDowncast").elementToElement({model:"caption",view:(e,{writer:n})=>{if(!i.isBlockImage(e.parent))return null;const o=n.createEditableElement("figcaption");n.setCustomProperty("imageCaption",!0,o),Fs({view:t,element:o,text:s("Enter image caption"),keepOnFocus:!0});const r=e.parent.getAttribute("alt");return rf(o,n,{label:r?s("Caption for image: %0",[r]):s("Caption for the image")})}})}_setupImageTypeCommandsIntegration(){const e=this.editor,t=e.plugins.get("ImageUtils"),i=e.plugins.get("ImageCaptionUtils"),n=e.commands.get("imageTypeInline"),s=e.commands.get("imageTypeBlock"),o=e=>{if(!e.return)return;const{oldElement:n,newElement:s}=e.return;if(!n)return;if(t.isBlockImage(n)){const e=i.getCaptionFromImageModelElement(n);if(e)return void this._saveCaption(s,e)}const o=this._getSavedCaption(n);o&&this._saveCaption(s,o)};n&&this.listenTo(n,"execute",o,{priority:"low"}),s&&this.listenTo(s,"execute",o,{priority:"low"})}_getSavedCaption(e){const t=this._savedCaptionsMap.get(e);return t?cl.fromJSON(t):null}_saveCaption(e,t){this._savedCaptionsMap.set(e,t.toJSON())}_registerCaptionReconversion(){const e=this.editor,t=e.model,i=e.plugins.get("ImageUtils"),n=e.plugins.get("ImageCaptionUtils");t.document.on("change:data",(()=>{const s=t.document.differ.getChanges();for(const t of s){if("alt"!==t.attributeKey)continue;const s=t.range.start.nodeAfter;if(i.isBlockImage(s)){const t=n.getCaptionFromImageModelElement(s);if(!t)return;e.editing.reconvertItem(t)}}}))}}class av extends Is{static get requires(){return[ov]}static get pluginName(){return"ImageCaptionUI"}init(){const e=this.editor,t=e.editing.view,i=e.plugins.get("ImageCaptionUtils"),n=e.t;e.ui.componentFactory.add("toggleImageCaption",(s=>{const o=e.commands.get("toggleImageCaption"),r=new Mu(s);return r.set({icon:Pu.caption,tooltip:!0,isToggleable:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),r.bind("label").to(o,"value",(e=>n(e?"Toggle caption off":"Toggle caption on"))),this.listenTo(r,"execute",(()=>{e.execute("toggleImageCaption",{focusCaptionOnShow:!0});const n=i.getCaptionFromModelSelection(e.model.document.selection);if(n){const i=e.editing.mapper.toViewElement(n);t.scrollToTheSelection(),t.change((e=>{e.addClass("image__caption_highlighted",i)}))}e.editing.view.focus()})),r}))}}class lv extends(W()){constructor(){super();const e=new window.FileReader;this._reader=e,this._data=void 0,this.set("loaded",0),e.onprogress=e=>{this.loaded=e.loaded}}get error(){return this._reader.error}get data(){return this._data}read(e){const t=this._reader;return this.total=e.size,new Promise(((i,n)=>{t.onload=()=>{const e=t.result;this._data=e,i(e)},t.onerror=()=>{n("error")},t.onabort=()=>{n("aborted")},this._reader.readAsDataURL(e)}))}abort(){this._reader.abort()}}class cv extends Is{static get pluginName(){return"FileRepository"}static get requires(){return[Su]}init(){this.loaders=new ys,this.loaders.on("change",(()=>this._updatePendingAction())),this._loadersMap=new Map,this._pendingAction=null,this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",((e,t)=>t?e/t*100:0))}getLoader(e){return this._loadersMap.get(e)||null}createLoader(e){if(!this.createUploadAdapter)return v("filerepository-no-upload-adapter"),null;const t=new dv(Promise.resolve(e),this.createUploadAdapter);return this.loaders.add(t),this._loadersMap.set(e,t),e instanceof Promise&&t.file.then((e=>{this._loadersMap.set(e,t)})).catch((()=>{})),t.on("change:uploaded",(()=>{let e=0;for(const t of this.loaders)e+=t.uploaded;this.uploaded=e})),t.on("change:uploadTotal",(()=>{let e=0;for(const t of this.loaders)t.uploadTotal&&(e+=t.uploadTotal);this.uploadTotal=e})),t}destroyLoader(e){const t=e instanceof dv?e:this.getLoader(e);t._destroy(),this.loaders.remove(t),this._loadersMap.forEach(((e,i)=>{e===t&&this._loadersMap.delete(i)}))}_updatePendingAction(){const e=this.editor.plugins.get(Su);if(this.loaders.length){if(!this._pendingAction){const t=this.editor.t,i=e=>`${t("Upload in progress")} ${parseInt(e)}%.`;this._pendingAction=e.add(i(this.uploadedPercent)),this._pendingAction.bind("message").to(this,"uploadedPercent",i)}}else e.remove(this._pendingAction),this._pendingAction=null}}class dv extends(W()){constructor(e,t){super(),this.id=g(),this._filePromiseWrapper=this._createFilePromiseWrapper(e),this._adapter=t(this),this._reader=new lv,this.set("status","idle"),this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",((e,t)=>t?e/t*100:0)),this.set("uploadResponse",null)}get file(){return this._filePromiseWrapper?this._filePromiseWrapper.promise.then((e=>this._filePromiseWrapper?e:null)):Promise.resolve(null)}get data(){return this._reader.data}read(){if("idle"!=this.status)throw new b("filerepository-read-wrong-status",this);return this.status="reading",this.file.then((e=>this._reader.read(e))).then((e=>{if("reading"!==this.status)throw this.status;return this.status="idle",e})).catch((e=>{if("aborted"===e)throw this.status="aborted","aborted";throw this.status="error",this._reader.error?this._reader.error:e}))}upload(){if("idle"!=this.status)throw new b("filerepository-upload-wrong-status",this);return this.status="uploading",this.file.then((()=>this._adapter.upload())).then((e=>(this.uploadResponse=e,this.status="idle",e))).catch((e=>{if("aborted"===this.status)throw"aborted";throw this.status="error",e}))}abort(){const e=this.status;this.status="aborted",this._filePromiseWrapper.isFulfilled?"reading"==e?this._reader.abort():"uploading"==e&&this._adapter.abort&&this._adapter.abort():(this._filePromiseWrapper.promise.catch((()=>{})),this._filePromiseWrapper.rejecter("aborted")),this._destroy()}_destroy(){this._filePromiseWrapper=void 0,this._reader=void 0,this._adapter=void 0,this.uploadResponse=void 0}_createFilePromiseWrapper(e){const t={};return t.promise=new Promise(((i,n)=>{t.rejecter=n,t.isFulfilled=!1,e.then((e=>{t.isFulfilled=!0,i(e)})).catch((e=>{t.isFulfilled=!0,n(e)}))})),t}}class hv extends fu{constructor(e){super(e),this.buttonView=new Mu(e),this._fileInputView=new uv(e),this._fileInputView.bind("acceptedType").to(this),this._fileInputView.bind("allowMultipleFiles").to(this),this._fileInputView.delegate("done").to(this),this.setTemplate({tag:"span",attributes:{class:"ck-file-dialog-button"},children:[this.buttonView,this._fileInputView]}),this.buttonView.on("execute",(()=>{this._fileInputView.open()}))}focus(){this.buttonView.focus()}}class uv extends fu{constructor(e){super(e),this.set("acceptedType",void 0),this.set("allowMultipleFiles",!1);const t=this.bindTemplate;this.setTemplate({tag:"input",attributes:{class:["ck-hidden"],type:"file",tabindex:"-1",accept:t.to("acceptedType"),multiple:t.to("allowMultipleFiles")},on:{change:t.to((()=>{this.element&&this.element.files&&this.element.files.length&&this.fire("done",this.element.files),this.element.value=""}))}})}open(){this.element.click()}}class mv{constructor(e,t){this.loader=e,this.options=t}upload(){return this.loader.file.then((e=>new Promise(((t,i)=>{this._initRequest(),this._initListeners(t,i,e),this._sendRequest(e)}))))}abort(){this.xhr&&this.xhr.abort()}_initRequest(){const e=this.xhr=new XMLHttpRequest;e.open("POST",this.options.uploadUrl,!0),e.responseType="json"}_initListeners(e,t,i){const n=this.xhr,s=this.loader,o=`Couldn't upload file: ${i.name}.`;n.addEventListener("error",(()=>t(o))),n.addEventListener("abort",(()=>t())),n.addEventListener("load",(()=>{const i=n.response;if(!i||i.error)return t(i&&i.error&&i.error.message?i.error.message:o);const s=i.url?{default:i.url}:i.urls;e({...i,urls:s})})),n.upload&&n.upload.addEventListener("progress",(e=>{e.lengthComputable&&(s.uploadTotal=e.total,s.uploaded=e.loaded)}))}_sendRequest(e){const t=this.options.headers||{},i=this.options.withCredentials||!1;for(const e of Object.keys(t))this.xhr.setRequestHeader(e,t[e]);this.xhr.withCredentials=i;const n=new FormData;n.append("upload",e),this.xhr.send(n)}}function gv(e){const t=e.map((e=>e.replace("+","\\+")));return new RegExp(`^image\\/(${t.join("|")})$`)}function fv(e){return new Promise(((t,i)=>{const n=e.getAttribute("src");fetch(n).then((e=>e.blob())).then((e=>{const i=pv(e,n),s=i.replace("image/",""),o=new File([e],`image.${s}`,{type:i});t(o)})).catch((e=>e&&"TypeError"===e.name?function(e){return function(e){return new Promise(((t,i)=>{const n=Rn.document.createElement("img");n.addEventListener("load",(()=>{const e=Rn.document.createElement("canvas");e.width=n.width,e.height=n.height;e.getContext("2d").drawImage(n,0,0),e.toBlob((e=>e?t(e):i()))})),n.addEventListener("error",(()=>i())),n.src=e}))}(e).then((t=>{const i=pv(t,e),n=i.replace("image/","");return new File([t],`image.${n}`,{type:i})}))}(n).then(t).catch(i):i(e)))}))}function pv(e,t){return e.type?e.type:t.match(/data:(image\/\w+);base64/)?t.match(/data:(image\/\w+);base64/)[1].toLowerCase():"image/jpeg"}class wv extends Is{static get pluginName(){return"ImageUploadUI"}init(){const e=this.editor,t=e.t,i=i=>{const n=new hv(i),s=e.commands.get("uploadImage"),o=e.config.get("image.upload.types"),r=gv(o);return n.set({acceptedType:o.map((e=>`image/${e}`)).join(","),allowMultipleFiles:!0}),n.buttonView.set({label:t("Insert image"),icon:Pu.image,tooltip:!0}),n.buttonView.bind("isEnabled").to(s),n.on("done",((t,i)=>{const n=Array.from(i).filter((e=>r.test(e.type)));n.length&&(e.execute("uploadImage",{file:n}),e.editing.view.focus())})),n};e.ui.componentFactory.add("uploadImage",i),e.ui.componentFactory.add("imageUpload",i)}}class bv extends Is{static get pluginName(){return"ImageUploadProgress"}constructor(e){super(e),this.placeholder="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="}init(){const e=this.editor;e.plugins.has("ImageBlockEditing")&&e.editing.downcastDispatcher.on("attribute:uploadStatus:imageBlock",((...e)=>this.uploadStatusChange(...e))),e.plugins.has("ImageInlineEditing")&&e.editing.downcastDispatcher.on("attribute:uploadStatus:imageInline",((...e)=>this.uploadStatusChange(...e)))}uploadStatusChange(e,t,i){const n=this.editor,s=t.item,o=s.getAttribute("uploadId");if(!i.consumable.consume(t.item,e.name))return;const r=n.plugins.get("ImageUtils"),a=n.plugins.get(cv),l=o?t.attributeNewValue:null,c=this.placeholder,d=n.editing.mapper.toViewElement(s),h=i.writer;if("reading"==l)return vv(d,h),void _v(r,c,d,h);if("uploading"==l){const e=a.loaders.get(o);return vv(d,h),void(e?(yv(d,h),function(e,t,i,n){const s=function(e){const t=e.createUIElement("div",{class:"ck-progress-bar"});return e.setCustomProperty("progressBar",!0,t),t}(t);t.insert(t.createPositionAt(e,"end"),s),i.on("change:uploadedPercent",((e,t,i)=>{n.change((e=>{e.setStyle("width",i+"%",s)}))}))}(d,h,e,n.editing.view),function(e,t,i,n){if(n.data){const s=e.findViewImgElement(t);i.setAttribute("src",n.data,s)}}(r,d,h,e)):_v(r,c,d,h))}"complete"==l&&a.loaders.get(o)&&function(e,t,i){const n=t.createUIElement("div",{class:"ck-image-upload-complete-icon"});t.insert(t.createPositionAt(e,"end"),n),setTimeout((()=>{i.change((e=>e.remove(e.createRangeOn(n))))}),3e3)}(d,h,n.editing.view),function(e,t){Cv(e,t,"progressBar")}(d,h),yv(d,h),function(e,t){t.removeClass("ck-appear",e)}(d,h)}}function vv(e,t){e.hasClass("ck-appear")||t.addClass("ck-appear",e)}function _v(e,t,i,n){i.hasClass("ck-image-upload-placeholder")||n.addClass("ck-image-upload-placeholder",i);const s=e.findViewImgElement(i);s.getAttribute("src")!==t&&n.setAttribute("src",t,s),kv(i,"placeholder")||n.insert(n.createPositionAfter(s),function(e){const t=e.createUIElement("div",{class:"ck-upload-placeholder-loader"});return e.setCustomProperty("placeholder",!0,t),t}(n))}function yv(e,t){e.hasClass("ck-image-upload-placeholder")&&t.removeClass("ck-image-upload-placeholder",e),Cv(e,t,"placeholder")}function kv(e,t){for(const i of e.getChildren())if(i.getCustomProperty(t))return i}function Cv(e,t,i){const n=kv(e,i);n&&t.remove(t.createRangeOn(n))}class Av extends Vs{refresh(){const e=this.editor,t=e.plugins.get("ImageUtils"),i=e.model.document.selection.getSelectedElement();this.isEnabled=t.isImageAllowed()||t.isImage(i)}execute(e){const t=ps(e.file),i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageUtils"),s=Object.fromEntries(i.getAttributes());t.forEach(((e,t)=>{const o=i.getSelectedElement();if(t&&o&&n.isImage(o)){const t=this.editor.model.createPositionAfter(o);this._uploadImage(e,s,t)}else this._uploadImage(e,s)}))}_uploadImage(e,t,i){const n=this.editor,s=n.plugins.get(cv).createLoader(e),o=n.plugins.get("ImageUtils");s&&o.insertImage({...t,uploadId:s.id},i)}}class xv extends Is{static get requires(){return[cv,xm,Mg,Qf]}static get pluginName(){return"ImageUploadEditing"}constructor(e){super(e),e.config.define("image",{upload:{types:["jpeg","png","gif","bmp","webp","tiff"]}}),this._uploadImageElements=new Map}init(){const e=this.editor,t=e.model.document,i=e.conversion,n=e.plugins.get(cv),s=e.plugins.get("ImageUtils"),o=gv(e.config.get("image.upload.types")),r=new Av(e);e.commands.add("uploadImage",r),e.commands.add("imageUpload",r),i.for("upcast").attributeToAttribute({view:{name:"img",key:"uploadId"},model:"uploadId"}),this.listenTo(e.editing.view.document,"clipboardInput",((t,i)=>{if(n=i.dataTransfer,Array.from(n.types).includes("text/html")&&""!==n.getData("text/html"))return;var n;const s=Array.from(i.dataTransfer.files).filter((e=>!!e&&o.test(e.type)));s.length&&(t.stop(),e.model.change((t=>{i.targetRanges&&t.setSelection(i.targetRanges.map((t=>e.editing.mapper.toModelRange(t)))),e.model.enqueueChange((()=>{e.execute("uploadImage",{file:s})}))})))})),this.listenTo(e.plugins.get("ClipboardPipeline"),"inputTransformation",((t,i)=>{const o=Array.from(e.editing.view.createRangeIn(i.content)).filter((e=>function(e,t){return!(!e.isInlineImageView(t)||!t.getAttribute("src"))&&(t.getAttribute("src").match(/^data:image\/\w+;base64,/g)||t.getAttribute("src").match(/^blob:/g))}(s,e.item)&&!e.item.getAttribute("uploadProcessed"))).map((e=>({promise:fv(e.item),imageElement:e.item})));if(!o.length)return;const r=new ih(e.editing.view.document);for(const e of o){r.setAttribute("uploadProcessed",!0,e.imageElement);const t=n.createLoader(e.promise);t&&(r.setAttribute("src","",e.imageElement),r.setAttribute("uploadId",t.id,e.imageElement))}})),e.editing.view.document.on("dragover",((e,t)=>{t.preventDefault()})),t.on("change",(()=>{const i=t.differ.getChanges({includeChangesInGraveyard:!0}).reverse(),s=new Set;for(const t of i)if("insert"==t.type&&"$text"!=t.name){const i=t.position.nodeAfter,o="$graveyard"==t.position.root.rootName;for(const t of Tv(e,i)){const e=t.getAttribute("uploadId");if(!e)continue;const i=n.loaders.get(e);i&&(o?s.has(e)||i.abort():(s.add(e),this._uploadImageElements.set(e,t),"idle"==i.status&&this._readAndUpload(i)))}}})),this.on("uploadComplete",((e,{imageElement:t,data:i})=>{const n=i.urls?i.urls:i;this.editor.model.change((e=>{e.setAttribute("src",n.default,t),this._parseAndSetSrcsetAttributeOnImage(n,t,e)}))}),{priority:"low"})}afterInit(){const e=this.editor.model.schema;this.editor.plugins.has("ImageBlockEditing")&&e.extend("imageBlock",{allowAttributes:["uploadId","uploadStatus"]}),this.editor.plugins.has("ImageInlineEditing")&&e.extend("imageInline",{allowAttributes:["uploadId","uploadStatus"]})}_readAndUpload(e){const t=this.editor,i=t.model,n=t.locale.t,o=t.plugins.get(cv),r=t.plugins.get(xm),a=t.plugins.get("ImageUtils"),l=this._uploadImageElements;return i.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("uploadStatus","reading",l.get(e.id))})),e.read().then((()=>{const n=e.upload(),o=l.get(e.id);if(s.isSafari){const e=t.editing.mapper.toViewElement(o),i=a.findViewImgElement(e);t.editing.view.once("render",(()=>{if(!i.parent)return;const e=t.editing.view.domConverter.mapViewToDom(i.parent);if(!e)return;const n=e.style.display;e.style.display="none",e._ckHack=e.offsetHeight,e.style.display=n}))}return i.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("uploadStatus","uploading",o)})),n})).then((t=>{i.enqueueChange({isUndoable:!1},(i=>{const n=l.get(e.id);i.setAttribute("uploadStatus","complete",n),this.fire("uploadComplete",{data:t,imageElement:n})})),c()})).catch((t=>{if("error"!==e.status&&"aborted"!==e.status)throw t;"error"==e.status&&t&&r.showWarning(t,{title:n("Upload failed"),namespace:"upload"}),i.enqueueChange({isUndoable:!1},(t=>{t.remove(l.get(e.id))})),c()}));function c(){i.enqueueChange({isUndoable:!1},(t=>{const i=l.get(e.id);t.removeAttribute("uploadId",i),t.removeAttribute("uploadStatus",i),l.delete(e.id)})),o.destroyLoader(e)}}_parseAndSetSrcsetAttributeOnImage(e,t,i){let n=0;const s=Object.keys(e).filter((e=>{const t=parseInt(e,10);if(!isNaN(t))return n=Math.max(n,t),!0})).map((t=>`${e[t]} ${t}w`)).join(", ");""!=s&&i.setAttribute("srcset",{data:s,width:n},t)}}function Tv(e,t){const i=e.plugins.get("ImageUtils");return Array.from(e.model.createRangeOn(t)).filter((e=>i.isImage(e.item))).map((e=>e.item))}class Ev extends Is{static get pluginName(){return"ImageUpload"}static get requires(){return[xv,wv,bv]}}class Sv extends fu{constructor(e,t={}){super(e);const i=this.bindTemplate;this.set("class",t.class||null),this.children=this.createCollection(),t.children&&t.children.forEach((e=>this.children.add(e))),this.set("_role",null),this.set("_ariaLabelledBy",null),t.labelView&&this.set({_role:"group",_ariaLabelledBy:t.labelView.id}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-form__row",i.to("class")],role:i.to("_role"),"aria-labelledby":i.to("_ariaLabelledBy")},children:this.children})}}class Pv extends fu{constructor(e,t){super(e);const{insertButtonView:i,cancelButtonView:n}=this._createActionButtons(e);if(this.insertButtonView=i,this.cancelButtonView=n,this.set("imageURLInputValue",""),this.focusTracker=new Cs,this.keystrokes=new As,this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.set("_integrations",new ys),t)for(const[e,i]of Object.entries(t))"insertImageViaUrl"===e&&(i.fieldView.bind("value").to(this,"imageURLInputValue",(e=>e||"")),i.fieldView.on("input",(()=>{this.imageURLInputValue=i.fieldView.element.value.trim()}))),i.name=e,this._integrations.add(i);this.setTemplate({tag:"form",attributes:{class:["ck","ck-image-insert-form"],tabindex:"-1"},children:[...this._integrations,new Sv(e,{children:[this.insertButtonView,this.cancelButtonView],class:"ck-image-insert-form__action-row"})]})}render(){super.render(),Vu({view:this});const e=[...this._integrations,this.insertButtonView,this.cancelButtonView];e.forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element);const t=e=>e.stopPropagation();this.keystrokes.set("arrowright",t),this.keystrokes.set("arrowleft",t),this.keystrokes.set("arrowup",t),this.keystrokes.set("arrowdown",t),this.listenTo(e[0].element,"selectstart",((e,t)=>{t.stopPropagation()}),{priority:"high"})}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}getIntegration(e){return this._integrations.find((t=>t.name===e))}_createActionButtons(e){const t=e.t,i=new Mu(e),n=new Mu(e);return i.set({label:t("Insert"),icon:Pu.check,class:"ck-button-save",type:"submit",withText:!0,isEnabled:this.imageURLInputValue}),n.set({label:t("Cancel"),icon:Pu.cancel,class:"ck-button-cancel",withText:!0}),i.bind("isEnabled").to(this,"imageURLInputValue",(e=>!!e)),i.delegate("execute").to(this,"submit"),n.delegate("execute").to(this,"cancel"),{insertButtonView:i,cancelButtonView:n}}focus(){this._focusCycler.focusFirst()}}function Iv(e){const t=e.t,i=new ym(e,km);return i.set({label:t("Insert image via URL")}),i.fieldView.placeholder="https://example.com/image.png",i}class Rv extends Is{static get pluginName(){return"ImageInsertUI"}init(){const e=this.editor,t=e=>this._createDropdownView(e);e.ui.componentFactory.add("insertImage",t),e.ui.componentFactory.add("imageInsert",t)}_createDropdownView(e){const t=this.editor,i=e.t,n=t.commands.get("uploadImage"),s=t.commands.get("insertImage");this.dropdownView=lm(e,n?qu:void 0);const o=this.dropdownView.buttonView,r=this.dropdownView.panelView;if(o.set({label:i("Insert image"),icon:Pu.image,tooltip:!0}),r.extendTemplate({attributes:{class:"ck-image-insert__panel"}}),n){const e=this.dropdownView.buttonView;e.actionView=t.ui.componentFactory.create("uploadImage"),e.actionView.extendTemplate({attributes:{class:"ck ck-button ck-splitbutton__action"}})}return this._setUpDropdown(n||s)}_setUpDropdown(e){const t=this.editor,i=t.t,n=new Pv(t.locale,function(e){const t=e.config.get("image.insert.integrations"),i=e.plugins.get("ImageInsertUI"),n={insertImageViaUrl:Iv(e.locale)};if(!t)return n;if(t.find((e=>"openCKFinder"===e))&&e.ui.componentFactory.has("ckfinder")){const t=e.ui.componentFactory.create("ckfinder");t.set({withText:!0,class:"ck-image-insert__ck-finder-button"}),t.delegate("execute").to(i,"cancel"),n.openCKFinder=t}return t.reduce(((t,i)=>(n[i]?t[i]=n[i]:e.ui.componentFactory.has(i)&&(t[i]=e.ui.componentFactory.create(i)),t)),{})}(t)),s=n.insertButtonView,o=n.getIntegration("insertImageViaUrl"),r=this.dropdownView,a=r.panelView,l=this.editor.plugins.get("ImageUtils");function c(){t.editing.view.focus(),r.isOpen=!1}return r.bind("isEnabled").to(e),r.once("change:isOpen",(()=>{a.children.add(n)})),r.on("change:isOpen",(()=>{const e=t.model.document.selection.getSelectedElement();r.isOpen&&(l.isImage(e)?(n.imageURLInputValue=e.getAttribute("src"),s.label=i("Update"),o.label=i("Update image URL")):(n.imageURLInputValue="",s.label=i("Insert"),o.label=i("Insert image via URL")))}),{priority:"low"}),n.delegate("submit","cancel").to(r),this.delegate("cancel").to(r),r.on("submit",(()=>{c(),function(){const e=t.model.document.selection.getSelectedElement();l.isImage(e)?t.model.change((t=>{t.setAttribute("src",n.imageURLInputValue,e),t.removeAttribute("srcset",e),t.removeAttribute("sizes",e)})):t.execute("insertImage",{source:n.imageURLInputValue})}()})),r.on("cancel",(()=>{c()})),r}}class Vv extends Is{static get pluginName(){return"ImageInsertViaUrl"}static get requires(){return[Rv]}}class Lv extends Vs{refresh(){const e=this.editor,t=e.plugins.get("ImageUtils").getClosestSelectedImageElement(e.model.document.selection);this.isEnabled=!!t,t&&t.hasAttribute("width")?this.value={width:t.getAttribute("width"),height:null}:this.value=null}execute(e){const t=this.editor,i=t.model,n=t.plugins.get("ImageUtils").getClosestSelectedImageElement(i.document.selection);this.value={width:e.width,height:null},n&&i.change((t=>{t.setAttribute("width",e.width,n)}))}}class Ov extends Is{static get requires(){return[Qf]}static get pluginName(){return"ImageResizeEditing"}constructor(e){super(e),e.config.define("image",{resizeUnit:"%",resizeOptions:[{name:"resizeImage:original",value:null,icon:"original"},{name:"resizeImage:25",value:"25",icon:"small"},{name:"resizeImage:50",value:"50",icon:"medium"},{name:"resizeImage:75",value:"75",icon:"large"}]})}init(){const e=this.editor,t=new Lv(e);this._registerSchema(),this._registerConverters("imageBlock"),this._registerConverters("imageInline"),e.commands.add("resizeImage",t),e.commands.add("imageResize",t)}_registerSchema(){this.editor.plugins.has("ImageBlockEditing")&&this.editor.model.schema.extend("imageBlock",{allowAttributes:"width"}),this.editor.plugins.has("ImageInlineEditing")&&this.editor.model.schema.extend("imageInline",{allowAttributes:"width"})}_registerConverters(e){const t=this.editor;t.conversion.for("downcast").add((t=>t.on(`attribute:width:${e}`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.writer,s=i.mapper.toViewElement(t.item);null!==t.attributeNewValue?(n.setStyle("width",t.attributeNewValue,s),n.addClass("image_resized",s)):(n.removeStyle("width",s),n.removeClass("image_resized",s))})))),t.conversion.for("upcast").attributeToAttribute({view:{name:"imageBlock"===e?"figure":"img",styles:{width:/.+/}},model:{key:"width",value:e=>e.getStyle("width")}})}}const Bv={small:Pu.objectSizeSmall,medium:Pu.objectSizeMedium,large:Pu.objectSizeLarge,original:Pu.objectSizeFull};class Mv extends Is{static get requires(){return[Ov]}static get pluginName(){return"ImageResizeButtons"}constructor(e){super(e),this._resizeUnit=e.config.get("image.resizeUnit")}init(){const e=this.editor,t=e.config.get("image.resizeOptions"),i=e.commands.get("resizeImage");this.bind("isEnabled").to(i);for(const e of t)this._registerImageResizeButton(e);this._registerImageResizeDropdown(t)}_registerImageResizeButton(e){const t=this.editor,{name:i,value:n,icon:s}=e,o=n?n+this._resizeUnit:null;t.ui.componentFactory.add(i,(i=>{const n=new Mu(i),r=t.commands.get("resizeImage"),a=this._getOptionLabelValue(e,!0);if(!Bv[s])throw new b("imageresizebuttons-missing-icon",t,e);return n.set({label:a,icon:Bv[s],tooltip:a,isToggleable:!0}),n.bind("isEnabled").to(this),n.bind("isOn").to(r,"value",Nv(o)),this.listenTo(n,"execute",(()=>{t.execute("resizeImage",{width:o})})),n}))}_registerImageResizeDropdown(e){const t=this.editor,i=t.t,n=e.find((e=>!e.value)),s=s=>{const o=t.commands.get("resizeImage"),r=lm(s,ju),a=r.buttonView;return a.set({tooltip:i("Resize image"),commandValue:n.value,icon:Bv.medium,isToggleable:!0,label:this._getOptionLabelValue(n),withText:!0,class:"ck-resize-image-button"}),a.bind("label").to(o,"value",(e=>e&&e.width?e.width:this._getOptionLabelValue(n))),r.bind("isOn").to(o),r.bind("isEnabled").to(this),dm(r,this._getResizeDropdownListItemDefinitions(e,o)),r.listView.ariaLabel=i("Image resize list"),this.listenTo(r,"execute",(e=>{t.execute(e.source.commandName,{width:e.source.commandValue}),t.editing.view.focus()})),r};t.ui.componentFactory.add("resizeImage",s),t.ui.componentFactory.add("imageResize",s)}_getOptionLabelValue(e,t){const i=this.editor.t;return e.label?e.label:t?e.value?i("Resize image to %0",e.value+this._resizeUnit):i("Resize image to the original size"):e.value?e.value+this._resizeUnit:i("Original")}_getResizeDropdownListItemDefinitions(e,t){const i=new ys;return e.map((e=>{const n=e.value?e.value+this._resizeUnit:null,s={type:"button",model:new Tm({commandName:"resizeImage",commandValue:n,label:this._getOptionLabelValue(e),withText:!0,icon:null})};s.model.bind("isOn").to(t,"value",Nv(n)),i.add(s)})),i}}function Nv(e){return t=>null===e&&t===e||t&&t.width===e}const Dv=/(image|image-inline)/,Fv="image_resized";class zv extends Is{static get requires(){return[Pf]}static get pluginName(){return"ImageResizeHandles"}init(){const e=this.editor.commands.get("resizeImage");this.bind("isEnabled").to(e),this._setupResizerCreator()}_setupResizerCreator(){const e=this.editor,t=e.editing.view;t.addObserver(Qb),this.listenTo(t.document,"imageLoaded",((i,n)=>{if(!n.target.matches("figure.image.ck-widget > img,figure.image.ck-widget > picture > img,figure.image.ck-widget > a > img,figure.image.ck-widget > a > picture > img,span.image-inline.ck-widget > img,span.image-inline.ck-widget > picture > img"))return;const s=e.editing.view.domConverter,o=s.domToView(n.target).findAncestor({classes:Dv});let r=this.editor.plugins.get(Pf).getResizerByViewElement(o);if(r)return void r.redraw();const a=e.editing.mapper,l=a.toModelElement(o);r=e.plugins.get(Pf).attachTo({unit:e.config.get("image.resizeUnit"),modelElement:l,viewElement:o,editor:e,getHandleHost:e=>e.querySelector("img"),getResizeHost:()=>s.mapViewToDom(a.toViewElement(l.parent)),isCentered(){const e=l.getAttribute("imageStyle");return!e||"block"==e||"alignCenter"==e},onCommit(i){t.change((e=>{e.removeClass(Fv,o)})),e.execute("resizeImage",{width:i})}}),r.on("updateSize",(()=>{o.hasClass(Fv)||t.change((e=>{e.addClass(Fv,o)}))})),r.bind("isEnabled").to(this)}))}}class Hv extends Vs{constructor(e,t){super(e),this._defaultStyles={imageBlock:!1,imageInline:!1},this._styles=new Map(t.map((e=>{if(e.isDefault)for(const t of e.modelElements)this._defaultStyles[t]=e.name;return[e.name,e]})))}refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled?e.hasAttribute("imageStyle")?this.value=e.getAttribute("imageStyle"):this.value=this._defaultStyles[e.name]:this.value=!1}execute(e={}){const t=this.editor,i=t.model,n=t.plugins.get("ImageUtils");i.change((t=>{const s=e.value;let o=n.getClosestSelectedImageElement(i.document.selection);s&&this.shouldConvertImageType(s,o)&&(this.editor.execute(n.isBlockImage(o)?"imageTypeInline":"imageTypeBlock"),o=n.getClosestSelectedImageElement(i.document.selection)),!s||this._styles.get(s).isDefault?t.removeAttribute("imageStyle",o):t.setAttribute("imageStyle",s,o)}))}shouldConvertImageType(e,t){return!this._styles.get(e).modelElements.includes(t.name)}}const{objectFullWidth:$v,objectInline:Wv,objectLeft:jv,objectRight:qv,objectCenter:Uv,objectBlockLeft:Gv,objectBlockRight:Kv}=Pu,Jv={get inline(){return{name:"inline",title:"In line",icon:Wv,modelElements:["imageInline"],isDefault:!0}},get alignLeft(){return{name:"alignLeft",title:"Left aligned image",icon:jv,modelElements:["imageBlock","imageInline"],className:"image-style-align-left"}},get alignBlockLeft(){return{name:"alignBlockLeft",title:"Left aligned image",icon:Gv,modelElements:["imageBlock"],className:"image-style-block-align-left"}},get alignCenter(){return{name:"alignCenter",title:"Centered image",icon:Uv,modelElements:["imageBlock"],className:"image-style-align-center"}},get alignRight(){return{name:"alignRight",title:"Right aligned image",icon:qv,modelElements:["imageBlock","imageInline"],className:"image-style-align-right"}},get alignBlockRight(){return{name:"alignBlockRight",title:"Right aligned image",icon:Kv,modelElements:["imageBlock"],className:"image-style-block-align-right"}},get block(){return{name:"block",title:"Centered image",icon:Uv,modelElements:["imageBlock"],isDefault:!0}},get side(){return{name:"side",title:"Side image",icon:qv,modelElements:["imageBlock"],className:"image-style-side"}}},Qv={full:$v,left:Gv,right:Kv,center:Uv,inlineLeft:jv,inlineRight:qv,inline:Wv},Yv=[{name:"imageStyle:wrapText",title:"Wrap text",defaultItem:"imageStyle:alignLeft",items:["imageStyle:alignLeft","imageStyle:alignRight"]},{name:"imageStyle:breakText",title:"Break text",defaultItem:"imageStyle:block",items:["imageStyle:alignBlockLeft","imageStyle:block","imageStyle:alignBlockRight"]}];function Xv(e){v("image-style-configuration-definition-invalid",e)}const Zv={normalizeStyles:function(e){return(e.configuredStyles.options||[]).map((e=>function(e){e="string"==typeof e?Jv[e]?{...Jv[e]}:{name:e}:function(e,t){const i={...t};for(const n in e)Object.prototype.hasOwnProperty.call(t,n)||(i[n]=e[n]);return i}(Jv[e.name],e);"string"==typeof e.icon&&(e.icon=Qv[e.icon]||e.icon);return e}(e))).filter((t=>function(e,{isBlockPluginLoaded:t,isInlinePluginLoaded:i}){const{modelElements:n,name:s}=e;if(!(n&&n.length&&s))return Xv({style:e}),!1;{const s=[t?"imageBlock":null,i?"imageInline":null];if(!n.some((e=>s.includes(e))))return v("image-style-missing-dependency",{style:e,missingPlugins:n.map((e=>"imageBlock"===e?"ImageBlockEditing":"ImageInlineEditing"))}),!1}return!0}(t,e)))},getDefaultStylesConfiguration:function(e,t){return e&&t?{options:["inline","alignLeft","alignRight","alignCenter","alignBlockLeft","alignBlockRight","block","side"]}:e?{options:["block","side"]}:t?{options:["inline","alignLeft","alignRight"]}:{}},getDefaultDropdownDefinitions:function(e){return e.has("ImageBlockEditing")&&e.has("ImageInlineEditing")?[...Yv]:[]},warnInvalidStyle:Xv,DEFAULT_OPTIONS:Jv,DEFAULT_ICONS:Qv,DEFAULT_DROPDOWN_DEFINITIONS:Yv};function e_(e,t){for(const i of t)if(i.name===e)return i}class t_ extends Is{static get pluginName(){return"ImageStyleEditing"}static get requires(){return[Qf]}init(){const{normalizeStyles:e,getDefaultStylesConfiguration:t}=Zv,i=this.editor,n=i.plugins.has("ImageBlockEditing"),s=i.plugins.has("ImageInlineEditing");i.config.define("image.styles",t(n,s)),this.normalizedStyles=e({configuredStyles:i.config.get("image.styles"),isBlockPluginLoaded:n,isInlinePluginLoaded:s}),this._setupConversion(n,s),this._setupPostFixer(),i.commands.add("imageStyle",new Hv(i,this.normalizedStyles))}_setupConversion(e,t){const i=this.editor,n=i.model.schema,s=(o=this.normalizedStyles,(e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=e_(t.attributeNewValue,o),s=e_(t.attributeOldValue,o),r=i.mapper.toViewElement(t.item),a=i.writer;s&&a.removeClass(s.className,r),n&&a.addClass(n.className,r)});var o;const r=function(e){const t={imageInline:e.filter((e=>!e.isDefault&&e.modelElements.includes("imageInline"))),imageBlock:e.filter((e=>!e.isDefault&&e.modelElements.includes("imageBlock")))};return(e,i,n)=>{if(!i.modelRange)return;const s=i.viewItem,o=ks(i.modelRange.getItems());if(o&&n.schema.checkAttribute(o,"imageStyle"))for(const e of t[o.name])n.consumable.consume(s,{classes:e.className})&&n.writer.setAttribute("imageStyle",e.name,o)}}(this.normalizedStyles);i.editing.downcastDispatcher.on("attribute:imageStyle",s),i.data.downcastDispatcher.on("attribute:imageStyle",s),e&&(n.extend("imageBlock",{allowAttributes:"imageStyle"}),i.data.upcastDispatcher.on("element:figure",r,{priority:"low"})),t&&(n.extend("imageInline",{allowAttributes:"imageStyle"}),i.data.upcastDispatcher.on("element:img",r,{priority:"low"}))}_setupPostFixer(){const e=this.editor,t=e.model.document,i=e.plugins.get(Qf),n=new Map(this.normalizedStyles.map((e=>[e.name,e])));t.registerPostFixer((e=>{let s=!1;for(const o of t.differ.getChanges())if("insert"==o.type||"attribute"==o.type&&"imageStyle"==o.attributeKey){let t="insert"==o.type?o.position.nodeAfter:o.range.start.nodeAfter;if(t&&t.is("element","paragraph")&&t.childCount>0&&(t=t.getChild(0)),!i.isImage(t))continue;const r=t.getAttribute("imageStyle");if(!r)continue;const a=n.get(r);a&&a.modelElements.includes(t.name)||(e.removeAttribute("imageStyle",t),s=!0)}return s}))}}class i_ extends Is{static get requires(){return[t_]}static get pluginName(){return"ImageStyleUI"}get localizedDefaultStylesTitles(){const e=this.editor.t;return{"Wrap text":e("Wrap text"),"Break text":e("Break text"),"In line":e("In line"),"Full size image":e("Full size image"),"Side image":e("Side image"),"Left aligned image":e("Left aligned image"),"Centered image":e("Centered image"),"Right aligned image":e("Right aligned image")}}init(){const e=this.editor.plugins,t=this.editor.config.get("image.toolbar")||[],i=n_(e.get("ImageStyleEditing").normalizedStyles,this.localizedDefaultStylesTitles);for(const e of i)this._createButton(e);const n=n_([...t.filter(M),...Zv.getDefaultDropdownDefinitions(e)],this.localizedDefaultStylesTitles);for(const e of n)this._createDropdown(e,i)}_createDropdown(e,t){const i=this.editor.ui.componentFactory;i.add(e.name,(n=>{let s;const{defaultItem:o,items:r,title:a}=e,l=r.filter((e=>t.find((({name:t})=>s_(t)===e)))).map((e=>{const t=i.create(e);return e===o&&(s=t),t}));r.length!==l.length&&Zv.warnInvalidStyle({dropdown:e});const c=lm(n,qu),d=c.buttonView,h=d.arrowView;return cm(c,l,{enableActiveItemFocusOnDropdownOpen:!0}),d.set({label:o_(a,s.label),class:null,tooltip:!0}),h.unbind("label"),h.set({label:a}),d.bind("icon").toMany(l,"isOn",((...e)=>{const t=e.findIndex(Io);return t<0?s.icon:l[t].icon})),d.bind("label").toMany(l,"isOn",((...e)=>{const t=e.findIndex(Io);return o_(a,t<0?s.label:l[t].label)})),d.bind("isOn").toMany(l,"isOn",((...e)=>e.some(Io))),d.bind("class").toMany(l,"isOn",((...e)=>e.some(Io)?"ck-splitbutton_flatten":null)),d.on("execute",(()=>{l.some((({isOn:e})=>e))?c.isOpen=!c.isOpen:s.fire("execute")})),c.bind("isEnabled").toMany(l,"isEnabled",((...e)=>e.some(Io))),this.listenTo(c,"execute",(()=>{this.editor.editing.view.focus()})),c}))}_createButton(e){const t=e.name;this.editor.ui.componentFactory.add(s_(t),(i=>{const n=this.editor.commands.get("imageStyle"),s=new Mu(i);return s.set({label:e.title,icon:e.icon,tooltip:!0,isToggleable:!0}),s.bind("isEnabled").to(n,"isEnabled"),s.bind("isOn").to(n,"value",(e=>e===t)),s.on("execute",this._executeCommand.bind(this,t)),s}))}_executeCommand(e){this.editor.execute("imageStyle",{value:e}),this.editor.editing.view.focus()}}function n_(e,t){for(const i of e)t[i.title]&&(i.title=t[i.title]);return e}function s_(e){return`imageStyle:${e}`}function o_(e,t){return(e?e+": ":"")+t}class r_ extends Is{static get pluginName(){return"IndentEditing"}init(){const e=this.editor;e.commands.add("indent",new Os(e)),e.commands.add("outdent",new Os(e))}}const a_='',l_='';class c_ extends Is{static get pluginName(){return"IndentUI"}init(){const e=this.editor,t=e.locale,i=e.t,n="ltr"==t.uiLanguageDirection?a_:l_,s="ltr"==t.uiLanguageDirection?l_:a_;this._defineButton("indent",i("Increase indent"),n),this._defineButton("outdent",i("Decrease indent"),s)}_defineButton(e,t,i){const n=this.editor;n.ui.componentFactory.add(e,(s=>{const o=n.commands.get(e),r=new Mu(s);return r.set({label:t,icon:i,tooltip:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),this.listenTo(r,"execute",(()=>{n.execute(e),n.editing.view.focus()})),r}))}}class d_ extends Vs{constructor(e,t){super(e),this._indentBehavior=t}refresh(){const e=this.editor.model,t=ks(e.document.selection.getSelectedBlocks());t&&e.schema.checkAttribute(t,"blockIndent")?this.isEnabled=this._indentBehavior.checkEnabled(t.getAttribute("blockIndent")):this.isEnabled=!1}execute(){const e=this.editor.model,t=function(e){const t=e.document.selection,i=e.schema;return Array.from(t.getSelectedBlocks()).filter((e=>i.checkAttribute(e,"blockIndent")))}(e);e.change((e=>{for(const i of t){const t=i.getAttribute("blockIndent"),n=this._indentBehavior.getNextIndent(t);n?e.setAttribute("blockIndent",n,i):e.removeAttribute("blockIndent",i)}}))}}class h_{constructor(e){this.isForward="forward"===e.direction,this.offset=e.offset,this.unit=e.unit}checkEnabled(e){const t=parseFloat(e||0);return this.isForward||t>0}getNextIndent(e){const t=parseFloat(e||0);if(!(!e||e.endsWith(this.unit)))return this.isForward?this.offset+this.unit:void 0;const i=t+(this.isForward?this.offset:-this.offset);return i>0?i+this.unit:void 0}}class u_{constructor(e){this.isForward="forward"===e.direction,this.classes=e.classes}checkEnabled(e){const t=this.classes.indexOf(e);return this.isForward?t=0}getNextIndent(e){const t=this.classes.indexOf(e),i=this.isForward?1:-1;return this.classes[t+i]}}const m_=["paragraph","heading1","heading2","heading3","heading4","heading5","heading6"];const g_="italic";class f_ extends Is{static get pluginName(){return"ItalicEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:g_}),e.model.schema.setAttributeProperties(g_,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:g_,view:"i",upcastAlso:["em",{styles:{"font-style":"italic"}}]}),e.commands.add(g_,new Dp(e,g_)),e.keystrokes.set("CTRL+I",g_)}}const p_="italic";class w_ extends Is{static get pluginName(){return"ItalicUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(p_,(i=>{const n=e.commands.get(p_),s=new Mu(i);return s.set({label:t("Italic"),icon:'',keystroke:"CTRL+I",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(p_),e.editing.view.focus()})),s}))}}class b_{constructor(){this._definitions=new Set}get length(){return this._definitions.size}add(e){Array.isArray(e)?e.forEach((e=>this._definitions.add(e))):this._definitions.add(e)}getDispatcher(){return e=>{e.on("attribute:linkHref",((e,t,i)=>{if(!i.consumable.test(t.item,"attribute:linkHref"))return;if(!t.item.is("selection")&&!i.schema.isInline(t.item))return;const n=i.writer,s=n.document.selection;for(const e of this._definitions){const o=n.createAttributeElement("a",e.attributes,{priority:5});e.classes&&n.addClass(e.classes,o);for(const t in e.styles)n.setStyle(t,e.styles[t],o);n.setCustomProperty("link",!0,o),e.callback(t.attributeNewValue)?t.item.is("selection")?n.wrap(s.getFirstRange(),o):n.wrap(i.mapper.toViewRange(t.range),o):n.unwrap(i.mapper.toViewRange(t.range),o)}}),{priority:"high"})}}getDispatcherForLinkedImage(){return e=>{e.on("attribute:linkHref:imageBlock",((e,t,{writer:i,mapper:n})=>{const s=n.toViewElement(t.item),o=Array.from(s.getChildren()).find((e=>"a"===e.name));for(const e of this._definitions){const n=xs(e.attributes);if(e.callback(t.attributeNewValue)){for(const[e,t]of n)"class"===e?i.addClass(t,o):i.setAttribute(e,t,o);e.classes&&i.addClass(e.classes,o);for(const t in e.styles)i.setStyle(t,e.styles[t],o)}else{for(const[e,t]of n)"class"===e?i.removeClass(t,o):i.removeAttribute(e,o);e.classes&&i.removeClass(e.classes,o);for(const t in e.styles)i.removeStyle(t,o)}}}))}}}class v_ extends Vs{constructor(e){super(e),this.manualDecorators=new ys,this.automaticDecorators=new b_}restoreManualDecoratorStates(){for(const e of this.manualDecorators)e.value=this._getDecoratorStateFromModel(e.id)}refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement()||ks(t.getSelectedBlocks());xp(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"));for(const e of this.manualDecorators)e.value=this._getDecoratorStateFromModel(e.id)}execute(e,t={}){const i=this.editor.model,n=i.document.selection,s=[],o=[];for(const e in t)t[e]?s.push(e):o.push(e);i.change((t=>{if(n.isCollapsed){const r=n.getFirstPosition();if(n.hasAttribute("linkHref")){const a=Tg(r,"linkHref",n.getAttribute("linkHref"),i);t.setAttribute("linkHref",e,a),s.forEach((e=>{t.setAttribute(e,!0,a)})),o.forEach((e=>{t.removeAttribute(e,a)})),t.setSelection(t.createPositionAfter(a.end.nodeBefore))}else if(""!==e){const o=xs(n.getAttributes());o.set("linkHref",e),s.forEach((e=>{o.set(e,!0)}));const{end:a}=i.insertContent(t.createText(e,o),r);t.setSelection(a)}["linkHref",...s,...o].forEach((e=>{t.removeSelectionAttribute(e)}))}else{const r=i.schema.getValidRanges(n.getRanges(),"linkHref"),a=[];for(const e of n.getSelectedBlocks())i.schema.checkAttribute(e,"linkHref")&&a.push(t.createRangeOn(e));const l=a.slice();for(const e of r)this._isRangeToUpdate(e,a)&&l.push(e);for(const i of l)t.setAttribute("linkHref",e,i),s.forEach((e=>{t.setAttribute(e,!0,i)})),o.forEach((e=>{t.removeAttribute(e,i)}))}}))}_getDecoratorStateFromModel(e){const t=this.editor.model,i=t.document.selection,n=i.getSelectedElement();return xp(n,t.schema)?n.getAttribute(e):i.getAttribute(e)}_isRangeToUpdate(e,t){for(const i of t)if(i.containsRange(e))return!1;return!0}}class __ extends Vs{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement();xp(i,e.schema)?this.isEnabled=e.schema.checkAttribute(i,"linkHref"):this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref")}execute(){const e=this.editor,t=this.editor.model,i=t.document.selection,n=e.commands.get("link");t.change((e=>{const s=i.isCollapsed?[Tg(i.getFirstPosition(),"linkHref",i.getAttribute("linkHref"),t)]:t.schema.getValidRanges(i.getRanges(),"linkHref");for(const t of s)if(e.removeAttribute("linkHref",t),n)for(const i of n.manualDecorators)e.removeAttribute(i.id,t)}))}}class y_{constructor({id:e,label:t,attributes:i,classes:n,styles:s,defaultValue:o}){this.id=e,this.set("value"),this.defaultValue=o,this.label=t,this.attributes=i,this.classes=n,this.styles=s}_createPattern(){return{attributes:this.attributes,classes:this.classes,styles:this.styles}}}d(y_,W);const k_="automatic",C_=/^(https?:)?\/\//;class A_ extends Is{static get pluginName(){return"LinkEditing"}static get requires(){return[hg,Xm,Mg]}constructor(e){super(e),e.config.define("link",{addTargetToExternalLinks:!1})}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:"linkHref"}),e.conversion.for("dataDowncast").attributeToElement({model:"linkHref",view:Cp}),e.conversion.for("editingDowncast").attributeToElement({model:"linkHref",view:(e,t)=>Cp(Ap(e),t)}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{href:!0}},model:{key:"linkHref",value:e=>e.getAttribute("href")}}),e.commands.add("link",new v_(e)),e.commands.add("unlink",new __(e));const t=function(e,t){const i={"Open in a new tab":e("Open in a new tab"),Downloadable:e("Downloadable")};return t.forEach((e=>(e.label&&i[e.label]&&(e.label=i[e.label]),e))),t}(e.t,function(e){const t=[];if(e)for(const[i,n]of Object.entries(e)){const e=Object.assign({},n,{id:`link${wp(i)}`});t.push(e)}return t}(e.config.get("link.decorators")));this._enableAutomaticDecorators(t.filter((e=>e.mode===k_))),this._enableManualDecorators(t.filter((e=>"manual"===e.mode)));e.plugins.get(hg).registerAttribute("linkHref"),Sg(e,"linkHref","a","ck-link_selected"),this._enableLinkOpen(),this._enableInsertContentSelectionAttributesFixer(),this._enableClickingAfterLink(),this._enableTypingOverLink(),this._handleDeleteContentAfterLink()}_enableAutomaticDecorators(e){const t=this.editor,i=t.commands.get("link").automaticDecorators;t.config.get("link.addTargetToExternalLinks")&&i.add({id:"linkIsExternal",mode:k_,callback:e=>C_.test(e),attributes:{target:"_blank",rel:"noopener noreferrer"}}),i.add(e),i.length&&t.conversion.for("downcast").add(i.getDispatcher())}_enableManualDecorators(e){if(!e.length)return;const t=this.editor,i=t.commands.get("link").manualDecorators;e.forEach((e=>{t.model.schema.extend("$text",{allowAttributes:e.id}),e=new y_(e),i.add(e),t.conversion.for("downcast").attributeToElement({model:e.id,view:(t,{writer:i,schema:n},{item:s})=>{if((s.is("selection")||n.isInline(s))&&t){const t=i.createAttributeElement("a",e.attributes,{priority:5});e.classes&&i.addClass(e.classes,t);for(const n in e.styles)i.setStyle(n,e.styles[n],t);return i.setCustomProperty("link",!0,t),t}}}),t.conversion.for("upcast").elementToAttribute({view:{name:"a",...e._createPattern()},model:{key:e.id}})}))}_enableLinkOpen(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"click",((e,t)=>{if(!(s.isMac?t.domEvent.metaKey:t.domEvent.ctrlKey))return;let i=t.domTarget;if("a"!=i.tagName.toLowerCase()&&(i=i.closest("a")),!i)return;const n=i.getAttribute("href");n&&(e.stop(),t.preventDefault(),Sp(n))}),{context:"$capture"}),this.listenTo(t,"keydown",((t,i)=>{const n=e.commands.get("link").value;n&&i.keyCode===ds.enter&&i.altKey&&(t.stop(),Sp(n))}))}_enableInsertContentSelectionAttributesFixer(){const e=this.editor.model,t=e.document.selection;this.listenTo(e,"insertContent",(()=>{const i=t.anchor.nodeBefore,n=t.anchor.nodeAfter;t.hasAttribute("linkHref")&&i&&i.hasAttribute("linkHref")&&(n&&n.hasAttribute("linkHref")||e.change((t=>{x_(t,E_(e.schema))})))}),{priority:"low"})}_enableClickingAfterLink(){const e=this.editor,t=e.model;e.editing.view.addObserver(th);let i=!1;this.listenTo(e.editing.view.document,"mousedown",(()=>{i=!0})),this.listenTo(e.editing.view.document,"selectionChange",(()=>{if(!i)return;i=!1;const e=t.document.selection;if(!e.isCollapsed)return;if(!e.hasAttribute("linkHref"))return;const n=e.getFirstPosition(),s=Tg(n,"linkHref",e.getAttribute("linkHref"),t);(n.isTouching(s.start)||n.isTouching(s.end))&&t.change((e=>{x_(e,E_(t.schema))}))}))}_enableTypingOverLink(){const e=this.editor,t=e.editing.view;let i,n;this.listenTo(t.document,"delete",(()=>{n=!0}),{priority:"high"}),this.listenTo(e.model,"deleteContent",(()=>{const t=e.model.document.selection;t.isCollapsed||(n?n=!1:T_(e)&&function(e){const t=e.document.selection,i=t.getFirstPosition(),n=t.getLastPosition(),s=i.nodeAfter;if(!s)return!1;if(!s.is("$text"))return!1;if(!s.hasAttribute("linkHref"))return!1;const o=n.textNode||n.nodeBefore;if(s===o)return!0;return Tg(i,"linkHref",s.getAttribute("linkHref"),e).containsRange(e.createRange(i,n),!0)}(e.model)&&(i=t.getAttributes()))}),{priority:"high"}),this.listenTo(e.model,"insertContent",((t,[s])=>{n=!1,T_(e)&&i&&(e.model.change((e=>{for(const[t,n]of i)e.setAttribute(t,n,s)})),i=null)}),{priority:"high"})}_handleDeleteContentAfterLink(){const e=this.editor,t=e.model,i=t.document.selection,n=e.editing.view;let s=!1,o=!1;this.listenTo(n.document,"delete",((e,t)=>{o="backward"===t.direction}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{s=!1;const e=i.getFirstPosition(),n=i.getAttribute("linkHref");if(!n)return;const o=Tg(e,"linkHref",n,t);s=o.containsPosition(e)||o.end.isEqual(e)}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{o&&(o=!1,s||e.model.enqueueChange((e=>{x_(e,E_(t.schema))})))}),{priority:"low"})}}function x_(e,t){e.removeSelectionAttribute("linkHref");for(const i of t)e.removeSelectionAttribute(i)}function T_(e){return e.model.change((e=>e.batch)).isTyping}function E_(e){return e.getDefinition("$text").allowAttributes.filter((e=>e.startsWith("link")))}class S_ extends fu{constructor(e,t){super(e);const i=e.t;this.focusTracker=new Cs,this.keystrokes=new As,this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("Save"),Pu.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(i("Cancel"),Pu.cancel,"ck-button-cancel","cancel"),this._manualDecoratorSwitches=this._createManualDecoratorSwitches(t),this.children=this._createFormChildren(t.manualDecorators),this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}});const n=["ck","ck-link-form","ck-responsive-form"];t.manualDecorators.length&&n.push("ck-link-form_layout-vertical","ck-vertical-form"),this.setTemplate({tag:"form",attributes:{class:n,tabindex:"-1"},children:this.children}),Ru(this)}getDecoratorSwitchesState(){return Array.from(this._manualDecoratorSwitches).reduce(((e,t)=>(e[t.name]=t.isOn,e)),{})}render(){super.render(),Vu({view:this});[this.urlInputView,...this._manualDecoratorSwitches,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createUrlInput(){const e=this.locale.t,t=new ym(this.locale,km);return t.label=e("Link URL"),t}_createButton(e,t,i,n){const s=new Mu(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}_createManualDecoratorSwitches(e){const t=this.createCollection();for(const i of e.manualDecorators){const n=new Nu(this.locale);n.set({name:i.id,label:i.label,withText:!0}),n.bind("isOn").toMany([i,e],"value",((e,t)=>void 0===t&&void 0===e?i.defaultValue:e)),n.on("execute",(()=>{i.set("value",!n.isOn)})),t.add(n)}return t}_createFormChildren(e){const t=this.createCollection();if(t.add(this.urlInputView),e.length){const e=new fu;e.setTemplate({tag:"ul",children:this._manualDecoratorSwitches.map((e=>({tag:"li",children:[e],attributes:{class:["ck","ck-list__item"]}}))),attributes:{class:["ck","ck-reset","ck-list"]}}),t.add(e)}return t.add(this.saveButtonView),t.add(this.cancelButtonView),t}}class P_ extends fu{constructor(e){super(e);const t=e.t;this.focusTracker=new Cs,this.keystrokes=new As,this.previewButtonView=this._createPreviewButton(),this.unlinkButtonView=this._createButton(t("Unlink"),'',"unlink"),this.editButtonView=this._createButton(t("Edit link"),Pu.pencil,"edit"),this.set("href"),this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-link-actions","ck-responsive-form"],tabindex:"-1"},children:[this.previewButtonView,this.editButtonView,this.unlinkButtonView]})}render(){super.render();[this.previewButtonView,this.editButtonView,this.unlinkButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createButton(e,t,i){const n=new Mu(this.locale);return n.set({label:e,icon:t,tooltip:!0}),n.delegate("execute").to(this,i),n}_createPreviewButton(){const e=new Mu(this.locale),t=this.bindTemplate,i=this.t;return e.set({withText:!0,tooltip:i("Open link in new tab")}),e.extendTemplate({attributes:{class:["ck","ck-link-actions__preview"],href:t.to("href",(e=>e&&Ap(e))),target:"_blank",rel:"noopener noreferrer"}}),e.bind("label").to(this,"href",(e=>e||i("This link has no URL"))),e.bind("isEnabled").to(this,"href",(e=>!!e)),e.template.tag="a",e.template.eventListeners={},e}}const I_='',R_="link-ui";class V_ extends Is{static get requires(){return[Pm]}static get pluginName(){return"LinkUI"}init(){const e=this.editor;e.editing.view.addObserver(eh),this.actionsView=this._createActionsView(),this.formView=this._createFormView(),this._balloon=e.plugins.get(Pm),this._createToolbarLinkButton(),this._enableUserBalloonInteractions(),e.conversion.for("editingDowncast").markerToHighlight({model:R_,view:{classes:["ck-fake-link-selection"]}}),e.conversion.for("editingDowncast").markerToElement({model:R_,view:{name:"span",classes:["ck-fake-link-selection","ck-fake-link-selection_collapsed"]}})}destroy(){super.destroy(),this.formView.destroy()}_createActionsView(){const e=this.editor,t=new P_(e.locale),i=e.commands.get("link"),n=e.commands.get("unlink");return t.bind("href").to(i,"value"),t.editButtonView.bind("isEnabled").to(i),t.unlinkButtonView.bind("isEnabled").to(n),this.listenTo(t,"edit",(()=>{this._addFormView()})),this.listenTo(t,"unlink",(()=>{e.execute("unlink"),this._hideUI()})),t.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),t.keystrokes.set(kp,((e,t)=>{this._addFormView(),t()})),t}_createFormView(){const e=this.editor,t=e.commands.get("link"),i=e.config.get("link.defaultProtocol"),n=new S_(e.locale,t);return n.urlInputView.fieldView.bind("value").to(t,"value"),n.urlInputView.bind("isReadOnly").to(t,"isEnabled",(e=>!e)),n.saveButtonView.bind("isEnabled").to(t),this.listenTo(n,"submit",(()=>{const{value:t}=n.urlInputView.fieldView.element,s=Tp(t,i);e.execute("link",s,n.getDecoratorSwitchesState()),this._closeFormView()})),this.listenTo(n,"cancel",(()=>{this._closeFormView()})),n.keystrokes.set("Esc",((e,t)=>{this._closeFormView(),t()})),n}_createToolbarLinkButton(){const e=this.editor,t=e.commands.get("link"),i=e.t;e.keystrokes.set(kp,((e,i)=>{i(),t.isEnabled&&this._showUI(!0)})),e.ui.componentFactory.add("link",(e=>{const n=new Mu(e);return n.isEnabled=!0,n.label=i("Link"),n.icon=I_,n.keystroke=kp,n.tooltip=!0,n.isToggleable=!0,n.bind("isEnabled").to(t,"isEnabled"),n.bind("isOn").to(t,"value",(e=>!!e)),this.listenTo(n,"execute",(()=>this._showUI(!0))),n}))}_enableUserBalloonInteractions(){const e=this.editor.editing.view.document;this.listenTo(e,"click",(()=>{this._getSelectedLinkElement()&&this._showUI()})),this.editor.keystrokes.set("Tab",((e,t)=>{this._areActionsVisible&&!this.actionsView.focusTracker.isFocused&&(this.actionsView.focus(),t())}),{priority:"high"}),this.editor.keystrokes.set("Esc",((e,t)=>{this._isUIVisible&&(this._hideUI(),t())})),Iu({emitter:this.formView,activator:()=>this._isUIInPanel,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()})}_addActionsView(){this._areActionsInPanel||this._balloon.add({view:this.actionsView,position:this._getBalloonPositionData()})}_addFormView(){if(this._isFormInPanel)return;const e=this.editor.commands.get("link");this.formView.disableCssTransitions(),this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),this._balloon.visibleView===this.formView&&this.formView.urlInputView.fieldView.select(),this.formView.enableCssTransitions(),this.formView.urlInputView.fieldView.element.value=e.value||""}_closeFormView(){const e=this.editor.commands.get("link");e.restoreManualDecoratorStates(),void 0!==e.value?this._removeFormView():this._hideUI()}_removeFormView(){this._isFormInPanel&&(this.formView.saveButtonView.focus(),this._balloon.remove(this.formView),this.editor.editing.view.focus(),this._hideFakeVisualSelection())}_showUI(e=!1){this._getSelectedLinkElement()?(this._areActionsVisible?this._addFormView():this._addActionsView(),e&&this._balloon.showStack("main")):(this._showFakeVisualSelection(),this._addActionsView(),e&&this._balloon.showStack("main"),this._addFormView()),this._startUpdatingUI()}_hideUI(){if(!this._isUIInPanel)return;const e=this.editor;this.stopListening(e.ui,"update"),this.stopListening(this._balloon,"change:visibleView"),e.editing.view.focus(),this._removeFormView(),this._balloon.remove(this.actionsView),this._hideFakeVisualSelection()}_startUpdatingUI(){const e=this.editor,t=e.editing.view.document;let i=this._getSelectedLinkElement(),n=o();const s=()=>{const e=this._getSelectedLinkElement(),t=o();i&&!e||!i&&t!==n?this._hideUI():this._isUIVisible&&this._balloon.updatePosition(this._getBalloonPositionData()),i=e,n=t};function o(){return t.selection.focus.getAncestors().reverse().find((e=>e.is("element")))}this.listenTo(e.ui,"update",s),this.listenTo(this._balloon,"change:visibleView",s)}get _isFormInPanel(){return this._balloon.hasView(this.formView)}get _areActionsInPanel(){return this._balloon.hasView(this.actionsView)}get _areActionsVisible(){return this._balloon.visibleView===this.actionsView}get _isUIInPanel(){return this._isFormInPanel||this._areActionsInPanel}get _isUIVisible(){return this._balloon.visibleView==this.formView||this._areActionsVisible}_getBalloonPositionData(){const e=this.editor.editing.view,t=this.editor.model,i=e.document;let n=null;if(t.markers.has(R_)){const t=Array.from(this.editor.editing.mapper.markerNameToElements(R_)),i=e.createRange(e.createPositionBefore(t[0]),e.createPositionAfter(t[t.length-1]));n=e.domConverter.viewRangeToDom(i)}else n=()=>{const t=this._getSelectedLinkElement();return t?e.domConverter.mapViewToDom(t):e.domConverter.viewRangeToDom(i.selection.getFirstRange())};return{target:n}}_getSelectedLinkElement(){const e=this.editor.editing.view,t=e.document.selection,i=t.getSelectedElement();if(t.isCollapsed||i&&ef(i))return L_(t.getFirstPosition());{const i=t.getFirstRange().getTrimmed(),n=L_(i.start),s=L_(i.end);return n&&n==s&&e.createRangeIn(n).getTrimmed().isEqual(i)?n:null}}_showFakeVisualSelection(){const e=this.editor.model;e.change((t=>{const i=e.document.selection.getFirstRange();if(e.markers.has(R_))t.updateMarker(R_,{range:i});else if(i.start.isAtEnd){const n=i.start.getLastMatchingPosition((({item:t})=>!e.schema.isContent(t)),{boundaries:i});t.addMarker(R_,{usingOperation:!1,affectsData:!1,range:t.createRange(n,i.end)})}else t.addMarker(R_,{usingOperation:!1,affectsData:!1,range:i})}))}_hideFakeVisualSelection(){const e=this.editor.model;e.markers.has(R_)&&e.change((e=>{e.removeMarker(R_)}))}}function L_(e){return e.getAncestors().find((e=>{return(t=e).is("attributeElement")&&!!t.getCustomProperty("link");var t}))}class O_ extends Is{static get requires(){return["ImageEditing","ImageUtils",A_]}static get pluginName(){return"LinkImageEditing"}init(){const e=this.editor,t=e.model.schema;e.plugins.has("ImageBlockEditing")&&t.extend("imageBlock",{allowAttributes:["linkHref"]}),e.conversion.for("upcast").add(function(e){const t=e.plugins.has("ImageInlineEditing"),i=e.plugins.get("ImageUtils");return e=>{e.on("element:a",((e,n,s)=>{const o=n.viewItem,r=i.findViewImgElement(o);if(!r)return;const a=r.findAncestor((e=>i.isBlockImageView(e)));if(t&&!a)return;const l={attributes:["href"]};if(!s.consumable.consume(o,l))return;const c=o.getAttribute("href");if(!c)return;let d=n.modelCursor.parent;if(!d.is("element","imageBlock")){const e=s.convertItem(r,n.modelCursor);n.modelRange=e.modelRange,n.modelCursor=e.modelCursor,d=n.modelCursor.nodeBefore}d&&d.is("element","imageBlock")&&s.writer.setAttribute("linkHref",c,d)}),{priority:"high"})}}(e)),e.conversion.for("downcast").add(function(e){const t=e.plugins.get("ImageUtils");return e=>{e.on("attribute:linkHref:imageBlock",((e,i,n)=>{if(!n.consumable.consume(i.item,e.name))return;const s=n.mapper.toViewElement(i.item),o=n.writer,r=Array.from(s.getChildren()).find((e=>"a"===e.name)),a=t.findViewImgElement(s),l=a.parent.is("element","picture")?a.parent:a;if(r)i.attributeNewValue?o.setAttribute("href",i.attributeNewValue,r):(o.move(o.createRangeOn(l),o.createPositionAt(s,0)),o.remove(r));else{const e=o.createContainerElement("a",{href:i.attributeNewValue});o.insert(o.createPositionAt(s,0),e),o.move(o.createRangeOn(l),o.createPositionAt(e,0))}}),{priority:"high"})}}(e)),this._enableAutomaticDecorators(),this._enableManualDecorators()}_enableAutomaticDecorators(){const e=this.editor,t=e.commands.get("link").automaticDecorators;t.length&&e.conversion.for("downcast").add(t.getDispatcherForLinkedImage())}_enableManualDecorators(){const e=this.editor,t=e.commands.get("link");for(const i of t.manualDecorators)e.plugins.has("ImageBlockEditing")&&e.model.schema.extend("imageBlock",{allowAttributes:i.id}),e.plugins.has("ImageInlineEditing")&&e.model.schema.extend("imageInline",{allowAttributes:i.id}),e.conversion.for("downcast").add(B_(i)),e.conversion.for("upcast").add(M_(e,i))}}function B_(e){return t=>{t.on(`attribute:${e.id}:imageBlock`,((t,i,n)=>{const s=n.mapper.toViewElement(i.item),o=Array.from(s.getChildren()).find((e=>"a"===e.name));if(o){for(const[t,i]of xs(e.attributes))n.writer.setAttribute(t,i,o);e.classes&&n.writer.addClass(e.classes,o);for(const t in e.styles)n.writer.setStyle(t,e.styles[t],o)}}))}}function M_(e,t){const i=e.plugins.has("ImageInlineEditing"),n=e.plugins.get("ImageUtils");return e=>{e.on("element:a",((e,s,o)=>{const r=s.viewItem,a=n.findViewImgElement(r);if(!a)return;const l=a.findAncestor((e=>n.isBlockImageView(e)));if(i&&!l)return;const c=new Js(t._createPattern()).match(r);if(!c)return;if(!o.consumable.consume(r,c.match))return;const d=s.modelCursor.nodeBefore||s.modelCursor.parent;o.writer.setAttribute(t.id,!0,d)}),{priority:"high"})}}class N_ extends Is{static get requires(){return[A_,V_,"ImageBlockEditing"]}static get pluginName(){return"LinkImageUI"}init(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"click",((t,i)=>{this._isSelectedLinkedImage(e.model.document.selection)&&(i.preventDefault(),t.stop())}),{priority:"high"}),this._createToolbarLinkImageButton()}_createToolbarLinkImageButton(){const e=this.editor,t=e.t;e.ui.componentFactory.add("linkImage",(i=>{const n=new Mu(i),s=e.plugins.get("LinkUI"),o=e.commands.get("link");return n.set({isEnabled:!0,label:t("Link image"),icon:I_,keystroke:kp,tooltip:!0,isToggleable:!0}),n.bind("isEnabled").to(o,"isEnabled"),n.bind("isOn").to(o,"value",(e=>!!e)),this.listenTo(n,"execute",(()=>{this._isSelectedLinkedImage(e.model.document.selection)?s._addActionsView():s._showUI(!0)})),n}))}_isSelectedLinkedImage(e){const t=e.getSelectedElement();return this.editor.plugins.get("ImageUtils").isImage(t)&&t.hasAttribute("linkHref")}}class D_ extends Vs{constructor(e,t){super(e),this.type=t}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor.model,i=t.document,n=Array.from(i.selection.getSelectedBlocks()).filter((e=>z_(e,t.schema))),s=void 0!==e.forceValue?!e.forceValue:this.value;t.change((e=>{if(s){let t=n[n.length-1].nextSibling,i=Number.POSITIVE_INFINITY,s=[];for(;t&&"listItem"==t.name&&0!==t.getAttribute("listIndent");){const e=t.getAttribute("listIndent");e=i;)o>s.getAttribute("listIndent")&&(o=s.getAttribute("listIndent")),s.getAttribute("listIndent")==o&&e[t?"unshift":"push"](s),s=s[t?"previousSibling":"nextSibling"]}}function z_(e,t){return t.checkChild(e.parent,"listItem")&&!t.isObject(e)}class H_ extends Vs{constructor(e,t){super(e),this._indentBy="forward"==t?1:-1}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model,t=e.document;let i=Array.from(t.selection.getSelectedBlocks());e.change((e=>{const t=i[i.length-1];let n=t.nextSibling;for(;n&&"listItem"==n.name&&n.getAttribute("listIndent")>t.getAttribute("listIndent");)i.push(n),n=n.nextSibling;this._indentBy<0&&(i=i.reverse());for(const t of i){const i=t.getAttribute("listIndent")+this._indentBy;i<0?e.rename(t,"paragraph"):e.setAttribute("listIndent",i,t)}this.fire("_executeCleanup",i)}))}_checkEnabled(){const e=ks(this.editor.model.document.selection.getSelectedBlocks());if(!e||!e.is("element","listItem"))return!1;if(this._indentBy>0){const t=e.getAttribute("listIndent"),i=e.getAttribute("listType");let n=e.previousSibling;for(;n&&n.is("element","listItem")&&n.getAttribute("listIndent")>=t;){if(n.getAttribute("listIndent")==t)return n.getAttribute("listType")==i;n=n.previousSibling}return!1}return!0}}function $_(e,t){const i=t.mapper,n=t.writer,s="numbered"==e.getAttribute("listType")?"ol":"ul",o=function(e){const t=e.createContainerElement("li");return t.getFillerOffset=ey,t}(n),r=n.createContainerElement(s,null);return n.insert(n.createPositionAt(r,0),o),i.bindElements(e,o),o}function W_(e,t,i,n){const s=t.parent,o=i.mapper,r=i.writer;let a=o.toViewPosition(n.createPositionBefore(e));const l=U_(e.previousSibling,{sameIndent:!0,smallerIndent:!0,listIndent:e.getAttribute("listIndent")}),c=e.previousSibling;if(l&&l.getAttribute("listIndent")==e.getAttribute("listIndent")){const e=o.toViewElement(l);a=r.breakContainer(r.createPositionAfter(e))}else if(c&&"listItem"==c.name){a=o.toViewPosition(n.createPositionAt(c,"end"));const e=o.findMappedViewAncestor(a),t=K_(e);a=t?r.createPositionBefore(t):r.createPositionAt(e,"end")}else a=o.toViewPosition(n.createPositionBefore(e));if(a=q_(a),r.insert(a,s),c&&"listItem"==c.name){const e=o.toViewElement(c),i=r.createRange(r.createPositionAt(e,0),a).getWalker({ignoreElementEnd:!0});for(const e of i)if(e.item.is("element","li")){const n=r.breakContainer(r.createPositionBefore(e.item)),s=e.item.parent,o=r.createPositionAt(t,"end");j_(r,o.nodeBefore,o.nodeAfter),r.move(r.createRangeOn(s),o),i.position=n}}else{const i=s.nextSibling;if(i&&(i.is("element","ul")||i.is("element","ol"))){let n=null;for(const t of i.getChildren()){const i=o.toModelElement(t);if(!(i&&i.getAttribute("listIndent")>e.getAttribute("listIndent")))break;n=t}n&&(r.breakContainer(r.createPositionAfter(n)),r.move(r.createRangeOn(n.parent),r.createPositionAt(t,"end")))}}j_(r,s,s.nextSibling),j_(r,s.previousSibling,s)}function j_(e,t,i){return!t||!i||"ul"!=t.name&&"ol"!=t.name||t.name!=i.name||t.getAttribute("class")!==i.getAttribute("class")?null:e.mergeContainers(e.createPositionAfter(t))}function q_(e){return e.getLastMatchingPosition((e=>e.item.is("uiElement")))}function U_(e,t){const i=!!t.sameIndent,n=!!t.smallerIndent,s=t.listIndent;let o=e;for(;o&&"listItem"==o.name;){const e=o.getAttribute("listIndent");if(i&&s==e||n&&s>e)return o;o="forward"===t.direction?o.nextSibling:o.previousSibling}return null}function G_(e,t,i,n){e.ui.componentFactory.add(t,(s=>{const o=e.commands.get(t),r=new Mu(s);return r.set({label:i,icon:n,tooltip:!0,isToggleable:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),r.on("execute",(()=>{e.execute(t),e.editing.view.focus()})),r}))}function K_(e){for(const t of e.getChildren())if("ul"==t.name||"ol"==t.name)return t;return null}function J_(e,t){const i=[],n=e.parent,s={ignoreElementEnd:!1,startPosition:e,shallow:!0,direction:t},o=n.getAttribute("listIndent"),r=[...new dl(s)].filter((e=>e.item.is("element"))).map((e=>e.item));for(const e of r){if(!e.is("element","listItem"))break;if(e.getAttribute("listIndent")o)){if(e.getAttribute("listType")!==n.getAttribute("listType"))break;if(e.getAttribute("listStyle")!==n.getAttribute("listStyle"))break;if(e.getAttribute("listReversed")!==n.getAttribute("listReversed"))break;if(e.getAttribute("listStart")!==n.getAttribute("listStart"))break;"backward"===t?i.unshift(e):i.push(e)}}return i}function Q_(e){let t=[...e.document.selection.getSelectedBlocks()].filter((e=>e.is("element","listItem"))).map((t=>{const i=e.change((e=>e.createPositionAt(t,0)));return[...J_(i,"backward"),...J_(i,"forward")]})).flat();return t=[...new Set(t)],t}const Y_=["disc","circle","square"],X_=["decimal","decimal-leading-zero","lower-roman","upper-roman","lower-latin","upper-latin"];function Z_(e){return Y_.includes(e)?"bulleted":X_.includes(e)?"numbered":null}function ey(){const e=!this.isEmpty&&("ul"==this.getChild(0).name||"ol"==this.getChild(0).name);return this.isEmpty||e?0:Xo.call(this)}class ty extends Is{static get pluginName(){return"ListUtils"}getListTypeFromListStyleType(e){return Z_(e)}getSelectedListItems(e){return Q_(e)}getSiblingNodes(e,t){return J_(e,t)}}function iy(e){return(t,i,n)=>{const s=n.consumable;if(!s.test(i.item,"insert")||!s.test(i.item,"attribute:listType")||!s.test(i.item,"attribute:listIndent"))return;s.consume(i.item,"insert"),s.consume(i.item,"attribute:listType"),s.consume(i.item,"attribute:listIndent");const o=i.item;W_(o,$_(o,n),n,e)}}function ny(e,t,i){if(!i.consumable.test(t.item,e.name))return;const n=i.mapper.toViewElement(t.item),s=i.writer;s.breakContainer(s.createPositionBefore(n)),s.breakContainer(s.createPositionAfter(n));const o=n.parent,r="numbered"==t.attributeNewValue?"ol":"ul";s.rename(r,o)}function sy(e,t,i){i.consumable.consume(t.item,e.name);const n=i.mapper.toViewElement(t.item).parent,s=i.writer;j_(s,n,n.nextSibling),j_(s,n.previousSibling,n)}function oy(e,t,i){if(i.consumable.test(t.item,e.name)&&"listItem"!=t.item.name){let e=i.mapper.toViewPosition(t.range.start);const n=i.writer,s=[];for(;("ul"==e.parent.name||"ol"==e.parent.name)&&(e=n.breakContainer(e),"li"==e.parent.name);){const t=e,i=n.createPositionAt(e.parent,"end");if(!t.isEqual(i)){const e=n.remove(n.createRange(t,i));s.push(e)}e=n.createPositionAfter(e.parent)}if(s.length>0){for(let t=0;t0){const t=j_(n,i,i.nextSibling);t&&t.parent==i&&e.offset--}}j_(n,e.nodeBefore,e.nodeAfter)}}}function ry(e,t,i){const n=i.mapper.toViewPosition(t.position),s=n.nodeBefore,o=n.nodeAfter;j_(i.writer,s,o)}function ay(e,t,i){if(i.consumable.consume(t.viewItem,{name:!0})){const e=i.writer,n=e.createElement("listItem"),s=function(e){let t=0,i=e.parent;for(;i;){if(i.is("element","li"))t++;else{const e=i.previousSibling;e&&e.is("element","li")&&t++}i=i.parent}return t}(t.viewItem);e.setAttribute("listIndent",s,n);const o=t.viewItem.parent&&"ol"==t.viewItem.parent.name?"numbered":"bulleted";if(e.setAttribute("listType",o,n),!i.safeInsert(n,t.modelCursor))return;const r=function(e,t,i){const{writer:n,schema:s}=i;let o=n.createPositionAfter(e);for(const r of t)if("ul"==r.name||"ol"==r.name)o=i.convertItem(r,o).modelCursor;else{const t=i.convertItem(r,n.createPositionAt(e,"end")),a=t.modelRange.start.nodeAfter;a&&a.is("element")&&!s.checkChild(e,a.name)&&(e=t.modelCursor.parent.is("element","listItem")?t.modelCursor.parent:uy(t.modelCursor),o=n.createPositionAfter(e))}return o}(n,t.viewItem.getChildren(),i);t.modelRange=e.createRange(t.modelCursor,r),i.updateConversionResult(n,t)}}function ly(e,t,i){if(i.consumable.test(t.viewItem,{name:!0})){const e=Array.from(t.viewItem.getChildren());for(const t of e){!(t.is("element","li")||gy(t))&&t._remove()}}}function cy(e,t,i){if(i.consumable.test(t.viewItem,{name:!0})){if(0===t.viewItem.childCount)return;const e=[...t.viewItem.getChildren()];let i=!1;for(const t of e)i&&!gy(t)&&t._remove(),gy(t)&&(i=!0)}}function dy(e){return(t,i)=>{if(i.isPhantom)return;const n=i.modelPosition.nodeBefore;if(n&&n.is("element","listItem")){const t=i.mapper.toViewElement(n),s=t.getAncestors().find(gy),o=e.createPositionAt(t,0).getWalker();for(const e of o){if("elementStart"==e.type&&e.item.is("element","li")){i.viewPosition=e.previousPosition;break}if("elementEnd"==e.type&&e.item==s){i.viewPosition=e.nextPosition;break}}}}}function hy(e,[t,i,n]){let s,o=t.is("documentFragment")?t.getChild(0):t;if(s=i?this.createSelection(i,n):this.document.selection,o&&o.is("element","listItem")){const e=s.getFirstPosition();let t=null;if(e.parent.is("element","listItem")?t=e.parent:e.nodeBefore&&e.nodeBefore.is("element","listItem")&&(t=e.nodeBefore),t){const e=t.getAttribute("listIndent");if(e>0)for(;o&&o.is("element","listItem");)o._setAttribute("listIndent",o.getAttribute("listIndent")+e),o=o.nextSibling}}}function uy(e){const t=new dl({startPosition:e});let i;do{i=t.next()}while(!i.value.item.is("element","listItem"));return i.value.item}function my(e,t,i,n,s,o){const r=U_(t.nodeBefore,{sameIndent:!0,smallerIndent:!0,listIndent:e,foo:"b"}),a=s.mapper,l=s.writer,c=r?r.getAttribute("listIndent"):null;let d;if(r)if(c==e){const e=a.toViewElement(r).parent;d=l.createPositionAfter(e)}else{const e=o.createPositionAt(r,"end");d=a.toViewPosition(e)}else d=i;d=q_(d);for(const e of[...n.getChildren()])gy(e)&&(d=l.move(l.createRangeOn(e),d).end,j_(l,e,e.nextSibling),j_(l,e.previousSibling,e))}function gy(e){return e.is("element","ol")||e.is("element","ul")}class fy extends Is{static get pluginName(){return"ListEditing"}static get requires(){return[$g,ag,ty]}init(){const e=this.editor;e.model.schema.register("listItem",{inheritAllFrom:"$block",allowAttributes:["listType","listIndent"]});const t=e.data,i=e.editing;var n;e.model.document.registerPostFixer((t=>function(e,t){const i=e.document.differ.getChanges(),n=new Map;let s=!1;for(const n of i)if("insert"==n.type&&"listItem"==n.name)o(n.position);else if("insert"==n.type&&"listItem"!=n.name){if("$text"!=n.name){const i=n.position.nodeAfter;i.hasAttribute("listIndent")&&(t.removeAttribute("listIndent",i),s=!0),i.hasAttribute("listType")&&(t.removeAttribute("listType",i),s=!0),i.hasAttribute("listStyle")&&(t.removeAttribute("listStyle",i),s=!0),i.hasAttribute("listReversed")&&(t.removeAttribute("listReversed",i),s=!0),i.hasAttribute("listStart")&&(t.removeAttribute("listStart",i),s=!0);for(const t of Array.from(e.createRangeIn(i)).filter((e=>e.item.is("element","listItem"))))o(t.previousPosition)}o(n.position.getShiftedBy(n.length))}else"remove"==n.type&&"listItem"==n.name?o(n.position):("attribute"==n.type&&"listIndent"==n.attributeKey||"attribute"==n.type&&"listType"==n.attributeKey)&&o(n.range.start);for(const e of n.values())r(e),a(e);return s;function o(e){const t=e.nodeBefore;if(t&&t.is("element","listItem")){let e=t;if(n.has(e))return;for(let t=e.previousSibling;t&&t.is("element","listItem");t=e.previousSibling)if(e=t,n.has(e))return;n.set(t,e)}else{const t=e.nodeAfter;t&&t.is("element","listItem")&&n.set(t,t)}}function r(e){let i=0,n=null;for(;e&&e.is("element","listItem");){const o=e.getAttribute("listIndent");if(o>i){let r;null===n?(n=o-i,r=i):(n>o&&(n=o),r=o-n),t.setAttribute("listIndent",r,e),s=!0}else n=null,i=e.getAttribute("listIndent")+1;e=e.nextSibling}}function a(e){let i=[],n=null;for(;e&&e.is("element","listItem");){const o=e.getAttribute("listIndent");if(n&&n.getAttribute("listIndent")>o&&(i=i.slice(0,o+1)),0!=o)if(i[o]){const n=i[o];e.getAttribute("listType")!=n&&(t.setAttribute("listType",n,e),s=!0)}else i[o]=e.getAttribute("listType");n=e,e=e.nextSibling}}}(e.model,t))),i.mapper.registerViewToModelLength("li",py),t.mapper.registerViewToModelLength("li",py),i.mapper.on("modelToViewPosition",dy(i.view)),i.mapper.on("viewToModelPosition",(n=e.model,(e,t)=>{const i=t.viewPosition,s=i.parent,o=t.mapper;if("ul"==s.name||"ol"==s.name){if(i.isAtEnd){const e=o.toModelElement(i.nodeBefore),s=o.getModelLength(i.nodeBefore);t.modelPosition=n.createPositionBefore(e).getShiftedBy(s)}else{const e=o.toModelElement(i.nodeAfter);t.modelPosition=n.createPositionBefore(e)}e.stop()}else if("li"==s.name&&i.nodeBefore&&("ul"==i.nodeBefore.name||"ol"==i.nodeBefore.name)){const r=o.toModelElement(s);let a=1,l=i.nodeBefore;for(;l&&gy(l);)a+=o.getModelLength(l),l=l.previousSibling;t.modelPosition=n.createPositionBefore(r).getShiftedBy(a),e.stop()}})),t.mapper.on("modelToViewPosition",dy(i.view)),e.conversion.for("editingDowncast").add((t=>{t.on("insert",oy,{priority:"high"}),t.on("insert:listItem",iy(e.model)),t.on("attribute:listType:listItem",ny,{priority:"high"}),t.on("attribute:listType:listItem",sy,{priority:"low"}),t.on("attribute:listIndent:listItem",function(e){return(t,i,n)=>{if(!n.consumable.consume(i.item,"attribute:listIndent"))return;const s=n.mapper.toViewElement(i.item),o=n.writer;o.breakContainer(o.createPositionBefore(s)),o.breakContainer(o.createPositionAfter(s));const r=s.parent,a=r.previousSibling,l=o.createRangeOn(r);o.remove(l),a&&a.nextSibling&&j_(o,a,a.nextSibling),my(i.attributeOldValue+1,i.range.start,l.start,s,n,e),W_(i.item,s,n,e);for(const e of i.item.getChildren())n.consumable.consume(e,"insert")}}(e.model)),t.on("remove:listItem",function(e){return(t,i,n)=>{const s=n.mapper.toViewPosition(i.position).getLastMatchingPosition((e=>!e.item.is("element","li"))).nodeAfter,o=n.writer;o.breakContainer(o.createPositionBefore(s)),o.breakContainer(o.createPositionAfter(s));const r=s.parent,a=r.previousSibling,l=o.createRangeOn(r),c=o.remove(l);a&&a.nextSibling&&j_(o,a,a.nextSibling),my(n.mapper.toModelElement(s).getAttribute("listIndent")+1,i.position,l.start,s,n,e);for(const e of o.createRangeIn(c).getItems())n.mapper.unbindViewElement(e);t.stop()}}(e.model)),t.on("remove",ry,{priority:"low"})})),e.conversion.for("dataDowncast").add((t=>{t.on("insert",oy,{priority:"high"}),t.on("insert:listItem",iy(e.model))})),e.conversion.for("upcast").add((e=>{e.on("element:ul",ly,{priority:"high"}),e.on("element:ol",ly,{priority:"high"}),e.on("element:li",cy,{priority:"high"}),e.on("element:li",ay)})),e.model.on("insertContent",hy,{priority:"high"}),e.commands.add("numberedList",new D_(e,"numbered")),e.commands.add("bulletedList",new D_(e,"bulleted")),e.commands.add("indentList",new H_(e,"forward")),e.commands.add("outdentList",new H_(e,"backward"));const s=i.view.document;this.listenTo(s,"enter",((e,t)=>{const i=this.editor.model.document,n=i.selection.getLastPosition().parent;i.selection.isCollapsed&&"listItem"==n.name&&n.isEmpty&&(this.editor.execute("outdentList"),t.preventDefault(),e.stop())}),{context:"li"}),this.listenTo(s,"delete",((e,t)=>{if("backward"!==t.direction)return;const i=this.editor.model.document.selection;if(!i.isCollapsed)return;const n=i.getFirstPosition();if(!n.isAtStart)return;const s=n.parent;if("listItem"!==s.name)return;s.previousSibling&&"listItem"===s.previousSibling.name||(this.editor.execute("outdentList"),t.preventDefault(),e.stop())}),{context:"li"}),this.listenTo(e.editing.view.document,"tab",((t,i)=>{const n=i.shiftKey?"outdentList":"indentList";this.editor.commands.get(n).isEnabled&&(e.execute(n),i.stopPropagation(),i.preventDefault(),t.stop())}),{context:"li"})}afterInit(){const e=this.editor.commands,t=e.get("indent"),i=e.get("outdent");t&&t.registerChildCommand(e.get("indentList")),i&&i.registerChildCommand(e.get("outdentList"))}}function py(e){let t=1;for(const i of e.getChildren())if("ul"==i.name||"ol"==i.name)for(const e of i.getChildren())t+=py(e);return t}const wy='',by='';class vy extends Is{static get pluginName(){return"ListUI"}init(){const e=this.editor.t;G_(this.editor,"numberedList",e("Numbered List"),wy),G_(this.editor,"bulletedList",e("Bulleted List"),by)}}class _y extends Vs{constructor(e,t){super(e),this._defaultType=t}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){this._tryToConvertItemsToList(e);const t=this.editor.model,i=Q_(t);i.length&&t.change((t=>{for(const n of i)t.setAttribute("listStyle",e.type||this._defaultType,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")?e.getAttribute("listStyle"):null}_checkEnabled(){const e=this.editor,t=e.commands.get("numberedList"),i=e.commands.get("bulletedList");return t.isEnabled||i.isEnabled}_tryToConvertItemsToList(e){if(!e.type)return;const t=Z_(e.type);if(!t)return;const i=this.editor,n=t+"List";i.commands.get(n).value||i.execute(n)}}class yy extends Vs{refresh(){const e=this._getValue();this.value=e,this.isEnabled=null!=e}execute(e={}){const t=this.editor.model,i=Q_(t).filter((e=>"numbered"==e.getAttribute("listType")));t.change((t=>{for(const n of i)t.setAttribute("listReversed",!!e.reversed,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")&&"numbered"==e.getAttribute("listType")?e.getAttribute("listReversed"):null}}class ky extends Vs{refresh(){const e=this._getValue();this.value=e,this.isEnabled=null!=e}execute(e={}){const t=this.editor.model,i=Q_(t).filter((e=>"numbered"==e.getAttribute("listType")));t.change((t=>{for(const n of i)t.setAttribute("listStart",e.startIndex>=0?e.startIndex:1,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")&&"numbered"==e.getAttribute("listType")?e.getAttribute("listStart"):null}}const Cy="default";class Ay extends Is{static get requires(){return[fy]}static get pluginName(){return"ListPropertiesEditing"}constructor(e){super(e),e.config.define("list",{properties:{styles:!0,startIndex:!1,reversed:!1}})}init(){const e=this.editor,t=e.model,i=function(e){const t=[];e.styles&&t.push({attributeName:"listStyle",defaultValue:Cy,addCommand(e){e.commands.add("listStyle",new _y(e,Cy))},appliesToListItem:()=>!0,setAttributeOnDowncast(e,t,i){t&&t!==Cy?e.setStyle("list-style-type",t,i):e.removeStyle("list-style-type",i)},getAttributeOnUpcast:e=>e.getStyle("list-style-type")||Cy});e.reversed&&t.push({attributeName:"listReversed",defaultValue:!1,addCommand(e){e.commands.add("listReversed",new yy(e))},appliesToListItem:e=>"numbered"==e.getAttribute("listType"),setAttributeOnDowncast(e,t,i){t?e.setAttribute("reversed","reversed",i):e.removeAttribute("reversed",i)},getAttributeOnUpcast:e=>e.hasAttribute("reversed")});e.startIndex&&t.push({attributeName:"listStart",defaultValue:1,addCommand(e){e.commands.add("listStart",new ky(e))},appliesToListItem:e=>"numbered"==e.getAttribute("listType"),setAttributeOnDowncast(e,t,i){0==t||t>1?e.setAttribute("start",t,i):e.removeAttribute("start",i)},getAttributeOnUpcast(e){const t=e.getAttribute("start");return t>=0?t:1}});return t}(e.config.get("list.properties"));t.schema.extend("listItem",{allowAttributes:i.map((e=>e.attributeName))});for(const t of i)t.addCommand(e);var n;this.listenTo(e.commands.get("indentList"),"_executeCleanup",function(e,t){return(i,n)=>{const s=n[0],o=s.getAttribute("listIndent"),r=n.filter((e=>e.getAttribute("listIndent")===o));let a=null;s.previousSibling.getAttribute("listIndent")+1!==o&&(a=U_(s.previousSibling,{sameIndent:!0,direction:"backward",listIndent:o})),e.model.change((e=>{for(const i of r)for(const n of t)if(n.appliesToListItem(i)){const t=null==a?n.defaultValue:a.getAttribute(n.attributeName);e.setAttribute(n.attributeName,t,i)}}))}}(e,i)),this.listenTo(e.commands.get("outdentList"),"_executeCleanup",function(e,t){return(i,n)=>{if(!(n=n.reverse().filter((e=>e.is("element","listItem")))).length)return;const s=n[0].getAttribute("listIndent"),o=n[0].getAttribute("listType");let r=n[0].previousSibling;if(r.is("element","listItem"))for(;r.getAttribute("listIndent")!==s;)r=r.previousSibling;else r=null;r||(r=n[n.length-1].nextSibling),r&&r.is("element","listItem")&&r.getAttribute("listType")===o&&e.model.change((e=>{const i=n.filter((e=>e.getAttribute("listIndent")===s));for(const n of i)for(const i of t)if(i.appliesToListItem(n)){const t=i.attributeName,s=r.getAttribute(t);e.setAttribute(t,s,n)}}))}}(e,i)),this.listenTo(e.commands.get("bulletedList"),"_executeCleanup",Ey(e)),this.listenTo(e.commands.get("numberedList"),"_executeCleanup",Ey(e)),t.document.registerPostFixer(function(e,t){return i=>{let n=!1;const s=Sy(e.model.document.differ.getChanges()).filter((e=>"todo"!==e.getAttribute("listType")));if(!s.length)return n;let o=s[s.length-1].nextSibling;if((!o||!o.is("element","listItem"))&&(o=s[0].previousSibling,o)){const e=s[0].getAttribute("listIndent");for(;o.is("element","listItem")&&o.getAttribute("listIndent")!==e&&(o=o.previousSibling,o););}for(const e of t){const t=e.attributeName;for(const r of s)if(e.appliesToListItem(r))if(r.hasAttribute(t)){const s=r.previousSibling;Ty(s,r,e.attributeName)&&(i.setAttribute(t,s.getAttribute(t),r),n=!0)}else xy(o,r,e)?i.setAttribute(t,o.getAttribute(t),r):i.setAttribute(t,e.defaultValue,r),n=!0;else i.removeAttribute(t,r)}return n}}(e,i)),e.conversion.for("upcast").add((n=i,e=>{e.on("element:li",((e,t,i)=>{const s=t.viewItem.parent,o=t.modelRange.start.nodeAfter||t.modelRange.end.nodeBefore;for(const e of n)if(e.appliesToListItem(o)){const t=e.getAttributeOnUpcast(s);i.writer.setAttribute(e.attributeName,t,o)}}),{priority:"low"})})),e.conversion.for("downcast").add(function(e){return i=>{for(const n of e)i.on(`attribute:${n.attributeName}:listItem`,((e,i,s)=>{const o=s.writer,r=i.item,a=U_(r.previousSibling,{sameIndent:!0,listIndent:r.getAttribute("listIndent"),direction:"backward"}),l=s.mapper.toViewElement(r);t(r,a)||o.breakContainer(o.createPositionBefore(l)),n.setAttributeOnDowncast(o,i.attributeNewValue,l.parent)}),{priority:"low"})};function t(e,t){return t&&e.getAttribute("listType")===t.getAttribute("listType")&&e.getAttribute("listIndent")===t.getAttribute("listIndent")&&e.getAttribute("listStyle")===t.getAttribute("listStyle")&&e.getAttribute("listReversed")===t.getAttribute("listReversed")&&e.getAttribute("listStart")===t.getAttribute("listStart")}}(i)),this._mergeListAttributesWhileMergingLists(i)}afterInit(){const e=this.editor;e.commands.get("todoList")&&e.model.document.registerPostFixer(function(e){return t=>{const i=Sy(e.model.document.differ.getChanges()).filter((e=>"todo"===e.getAttribute("listType")&&(e.hasAttribute("listStyle")||e.hasAttribute("listReversed")||e.hasAttribute("listStart"))));if(!i.length)return!1;for(const e of i)t.removeAttribute("listStyle",e),t.removeAttribute("listReversed",e),t.removeAttribute("listStart",e);return!0}}(e))}_mergeListAttributesWhileMergingLists(e){const t=this.editor.model;let i;this.listenTo(t,"deleteContent",((e,[t])=>{const n=t.getFirstPosition(),s=t.getLastPosition();if(n.parent===s.parent)return;if(!n.parent.is("element","listItem"))return;const o=s.parent.nextSibling;if(!o||!o.is("element","listItem"))return;const r=U_(n.parent,{sameIndent:!0,listIndent:o.getAttribute("listIndent")});r&&r.getAttribute("listType")===o.getAttribute("listType")&&(i=r)}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{i&&(t.change((t=>{const n=U_(i.nextSibling,{sameIndent:!0,listIndent:i.getAttribute("listIndent"),direction:"forward"});if(!n)return void(i=null);const s=[n,...J_(t.createPositionAt(n,0),"forward")];for(const n of s)for(const s of e)if(s.appliesToListItem(n)){const e=s.attributeName,o=i.getAttribute(e);t.setAttribute(e,o,n)}})),i=null)}),{priority:"low"})}}function xy(e,t,i){if(!e)return!1;const n=e.getAttribute(i.attributeName);return!!n&&(n!=i.defaultValue&&e.getAttribute("listType")===t.getAttribute("listType"))}function Ty(e,t,i){if(!e||!e.is("element","listItem"))return!1;if(t.getAttribute("listType")!==e.getAttribute("listType"))return!1;const n=e.getAttribute("listIndent");if(n<1||n!==t.getAttribute("listIndent"))return!1;const s=e.getAttribute(i);return!(!s||s===t.getAttribute(i))}function Ey(e){return(t,i)=>{i=i.filter((e=>e.is("element","listItem"))),e.model.change((e=>{for(const t of i)e.removeAttribute("listStyle",t)}))}}function Sy(e){const t=[];for(const i of e){const e=Py(i);e&&e.is("element","listItem")&&t.push(e)}return t}function Py(e){return"attribute"===e.type?e.range.start.nodeAfter:"insert"===e.type?e.position.nodeAfter:null}class Iy extends fu{constructor(e,t){super(e);const i=this.bindTemplate;this.set("isCollapsed",!1),this.set("label",""),this.buttonView=this._createButtonView(),this.children=this.createCollection(),this.set("_collapsibleAriaLabelUid"),t&&this.children.addMany(t),this.setTemplate({tag:"div",attributes:{class:["ck","ck-collapsible",i.if("isCollapsed","ck-collapsible_collapsed")]},children:[this.buttonView,{tag:"div",attributes:{class:["ck","ck-collapsible__children"],role:"region",hidden:i.if("isCollapsed","hidden"),"aria-labelledby":i.to("_collapsibleAriaLabelUid")},children:this.children}]})}render(){super.render(),this._collapsibleAriaLabelUid=this.buttonView.labelView.element.id}_createButtonView(){const e=new Mu(this.locale),t=e.bindTemplate;return e.set({withText:!0,icon:Wu}),e.extendTemplate({attributes:{"aria-expanded":t.to("isOn",(e=>String(e)))}}),e.bind("label").to(this),e.bind("isOn").to(this,"isCollapsed",(e=>!e)),e.on("execute",(()=>{this.isCollapsed=!this.isCollapsed})),e}}class Ry extends fu{constructor(e,{enabledProperties:t,styleButtonViews:i,styleGridAriaLabel:n}){super(e);const s=["ck","ck-list-properties"];this.children=this.createCollection(),this.stylesView=null,this.additionalPropertiesCollapsibleView=null,this.startIndexFieldView=null,this.reversedSwitchButtonView=null,this.focusTracker=new Cs,this.keystrokes=new As,this.focusables=new Gh,this.focusCycler=new Ku({focusables:this.focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),t.styles?(this.stylesView=this._createStylesView(i,n),this.children.add(this.stylesView)):s.push("ck-list-properties_without-styles"),(t.startIndex||t.reversed)&&(this._addNumberedListPropertyViews(t,i),s.push("ck-list-properties_with-numbered-properties")),this.setTemplate({tag:"div",attributes:{class:s},children:this.children})}render(){if(super.render(),this.stylesView){this.focusables.add(this.stylesView),this.focusTracker.add(this.stylesView.element),(this.startIndexFieldView||this.reversedSwitchButtonView)&&(this.focusables.add(this.children.last.buttonView),this.focusTracker.add(this.children.last.buttonView.element));for(const e of this.stylesView.children)this.stylesView.focusTracker.add(e.element);Lu({keystrokeHandler:this.stylesView.keystrokes,focusTracker:this.stylesView.focusTracker,gridItems:this.stylesView.children,numberOfColumns:()=>Rn.window.getComputedStyle(this.stylesView.element).getPropertyValue("grid-template-columns").split(" ").length,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection})}if(this.startIndexFieldView){this.focusables.add(this.startIndexFieldView),this.focusTracker.add(this.startIndexFieldView.element),this.listenTo(this.startIndexFieldView.element,"selectstart",((e,t)=>{t.stopPropagation()}),{priority:"high"});const e=e=>e.stopPropagation();this.keystrokes.set("arrowright",e),this.keystrokes.set("arrowleft",e),this.keystrokes.set("arrowup",e),this.keystrokes.set("arrowdown",e)}this.reversedSwitchButtonView&&(this.focusables.add(this.reversedSwitchButtonView),this.focusTracker.add(this.reversedSwitchButtonView.element)),this.keystrokes.listenTo(this.element)}focus(){this.focusCycler.focusFirst()}focusLast(){this.focusCycler.focusLast()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createStylesView(e,t){const i=new fu(this.locale);return i.children=i.createCollection(this.locale),i.children.addMany(e),i.setTemplate({tag:"div",attributes:{"aria-label":t,class:["ck","ck-list-styles-list"]},children:i.children}),i.children.delegate("execute").to(this),i.focus=function(){this.children.first.focus()},i.focusTracker=new Cs,i.keystrokes=new As,i.render(),i.keystrokes.listenTo(i.element),i}_addNumberedListPropertyViews(e){const t=this.locale.t,i=[];e.startIndex&&(this.startIndexFieldView=this._createStartIndexField(),i.push(this.startIndexFieldView)),e.reversed&&(this.reversedSwitchButtonView=this._createReversedSwitchButton(),i.push(this.reversedSwitchButtonView)),e.styles?(this.additionalPropertiesCollapsibleView=new Iy(this.locale,i),this.additionalPropertiesCollapsibleView.set({label:t("List properties"),isCollapsed:!0}),this.additionalPropertiesCollapsibleView.buttonView.bind("isEnabled").toMany(i,"isEnabled",((...e)=>e.some((e=>e)))),this.additionalPropertiesCollapsibleView.buttonView.on("change:isEnabled",((e,t,i)=>{i||(this.additionalPropertiesCollapsibleView.isCollapsed=!0)})),this.children.add(this.additionalPropertiesCollapsibleView)):this.children.addMany(i)}_createStartIndexField(){const e=this.locale.t,t=new ym(this.locale,Cm);return t.set({label:e("Start at"),class:"ck-numbered-list-properties__start-index"}),t.fieldView.set({min:0,step:1,value:1,inputMode:"numeric"}),t.fieldView.on("input",(()=>{const i=t.fieldView.element,n=i.valueAsNumber;Number.isNaN(n)||(i.checkValidity()?this.fire("listStart",{startIndex:n}):t.errorText=e("Start index must be greater than 0."))})),t}_createReversedSwitchButton(){const e=this.locale.t,t=new Nu(this.locale);return t.set({withText:!0,label:e("Reversed order"),class:"ck-numbered-list-properties__reversed-order"}),t.delegate("execute").to(this,"listReversed"),t}}class Vy extends Is{static get pluginName(){return"ListPropertiesUI"}init(){const e=this.editor,t=e.locale.t,i=e.config.get("list.properties");i.styles&&e.ui.componentFactory.add("bulletedList",Ly({editor:e,parentCommandName:"bulletedList",buttonLabel:t("Bulleted List"),buttonIcon:by,styleGridAriaLabel:t("Bulleted list styles toolbar"),styleDefinitions:[{label:t("Toggle the disc list style"),tooltip:t("Disc"),type:"disc",icon:''},{label:t("Toggle the circle list style"),tooltip:t("Circle"),type:"circle",icon:''},{label:t("Toggle the square list style"),tooltip:t("Square"),type:"square",icon:''}]})),(i.styles||i.startIndex||i.reversed)&&e.ui.componentFactory.add("numberedList",Ly({editor:e,parentCommandName:"numberedList",buttonLabel:t("Numbered List"),buttonIcon:wy,styleGridAriaLabel:t("Numbered list styles toolbar"),styleDefinitions:[{label:t("Toggle the decimal list style"),tooltip:t("Decimal"),type:"decimal",icon:''},{label:t("Toggle the decimal with leading zero list style"),tooltip:t("Decimal with leading zero"),type:"decimal-leading-zero",icon:''},{label:t("Toggle the lower–roman list style"),tooltip:t("Lower–roman"),type:"lower-roman",icon:''},{label:t("Toggle the upper–roman list style"),tooltip:t("Upper-roman"),type:"upper-roman",icon:''},{label:t("Toggle the lower–latin list style"),tooltip:t("Lower-latin"),type:"lower-latin",icon:''},{label:t("Toggle the upper–latin list style"),tooltip:t("Upper-latin"),type:"upper-latin",icon:''}]}))}}function Ly({editor:e,parentCommandName:t,buttonLabel:i,buttonIcon:n,styleGridAriaLabel:s,styleDefinitions:o}){const r=e.commands.get(t);return a=>{const l=lm(a,qu),c=l.buttonView;l.bind("isEnabled").to(r),l.class="ck-list-styles-dropdown",c.on("execute",(()=>{e.execute(t),e.editing.view.focus()})),c.set({label:i,icon:n,tooltip:!0,isToggleable:!0}),c.bind("isOn").to(r,"value",(e=>!!e));const d=function({editor:e,dropdownView:t,parentCommandName:i,styleDefinitions:n,styleGridAriaLabel:s}){const o=e.locale,r=e.config.get("list.properties");let a;"numberedList"!=i&&(r.startIndex=!1,r.reversed=!1);if(r.styles){const t=e.commands.get("listStyle"),s=function({editor:e,listStyleCommand:t,parentCommandName:i}){const n=e.locale,s=e.commands.get(i);return({label:i,type:o,icon:r,tooltip:a})=>{const l=new Mu(n);return l.set({label:i,icon:r,tooltip:a}),t.on("change:value",(()=>{l.isOn=t.value===o})),l.on("execute",(()=>{s.value?t.value!==o?e.execute("listStyle",{type:o}):e.execute("listStyle",{type:t._defaultType}):e.model.change((()=>{e.execute("listStyle",{type:o})}))})),l}}({editor:e,parentCommandName:i,listStyleCommand:t}),o="function"==typeof t.isStyleTypeSupported?e=>t.isStyleTypeSupported(e.type):()=>!0;a=n.filter(o).map(s)}const l=new Ry(o,{styleGridAriaLabel:s,enabledProperties:r,styleButtonViews:a});r.styles&&hm(t,(()=>l.stylesView.children.find((e=>e.isOn))));if(r.startIndex){const t=e.commands.get("listStart");l.startIndexFieldView.bind("isEnabled").to(t),l.startIndexFieldView.fieldView.bind("value").to(t),l.on("listStart",((t,i)=>e.execute("listStart",i)))}if(r.reversed){const t=e.commands.get("listReversed");l.reversedSwitchButtonView.bind("isEnabled").to(t),l.reversedSwitchButtonView.bind("isOn").to(t,"value"),l.on("listReversed",(()=>{const i=t.value;e.execute("listReversed",{reversed:!i})}))}return l.delegate("execute").to(t),l}({editor:e,dropdownView:l,parentCommandName:t,styleGridAriaLabel:s,styleDefinitions:o});return l.panelView.children.add(d),l.on("execute",(()=>{e.editing.view.focus()})),l}}function Oy(e,t){return e=>{e.on("attribute:url:media",i)};function i(i,n,s){if(!s.consumable.consume(n.item,i.name))return;const o=n.attributeNewValue,r=s.writer,a=s.mapper.toViewElement(n.item),l=[...a.getChildren()].find((e=>e.getCustomProperty("media-content")));r.remove(l);const c=e.getMediaViewElement(r,o,t);r.insert(r.createPositionAt(a,0),c)}}function By(e){const t=e.getSelectedElement();return t&&function(e){return!!e.getCustomProperty("media")&&ef(e)}(t)?t:null}function My(e,t,i,n){return e.createContainerElement("figure",{class:"media"},[t.getMediaViewElement(e,i,n),e.createSlot()])}function Ny(e){const t=e.getSelectedElement();return t&&t.is("element","media")?t:null}function Dy(e,t,i,n){e.change((s=>{const o=s.createElement("media",{url:t});e.insertObject(o,i,null,{setSelection:"on",findOptimalPosition:n})}))}class Fy extends Vs{refresh(){const e=this.editor.model,t=e.document.selection,i=Ny(t);this.value=i?i.getAttribute("url"):null,this.isEnabled=function(e){const t=e.getSelectedElement();return!!t&&"media"===t.name}(t)||function(e,t){const i=af(e,t);let n=i.start.parent;n.isEmpty&&!t.schema.isLimit(n)&&(n=n.parent);return t.schema.checkChild(n,"media")}(t,e)}execute(e){const t=this.editor.model,i=t.document.selection,n=Ny(i);n?t.change((t=>{t.setAttribute("url",e,n)})):Dy(t,e,i,!0)}}class zy{constructor(e,t){const i=t.providers,n=t.extraProviders||[],s=new Set(t.removeProviders),o=i.concat(n).filter((e=>{const t=e.name;return t?!s.has(t):(v("media-embed-no-provider-name",{provider:e}),!1)}));this.locale=e,this.providerDefinitions=o}hasMedia(e){return!!this._getMedia(e)}getMediaViewElement(e,t,i){return this._getMedia(t).getViewElement(e,i)}_getMedia(e){if(!e)return new Hy(this.locale);e=e.trim();for(const t of this.providerDefinitions){const i=t.html,n=ps(t.url);for(const t of n){const n=this._getUrlMatches(e,t);if(n)return new Hy(this.locale,e,n,i)}}return null}_getUrlMatches(e,t){let i=e.match(t);if(i)return i;let n=e.replace(/^https?:\/\//,"");return i=n.match(t),i||(n=n.replace(/^www\./,""),i=n.match(t),i||null)}}class Hy{constructor(e,t,i,n){this.url=this._getValidUrl(t),this._locale=e,this._match=i,this._previewRenderer=n}getViewElement(e,t){const i={};let n;if(t.renderForEditingView||t.renderMediaPreview&&this.url&&this._previewRenderer){this.url&&(i["data-oembed-url"]=this.url),t.renderForEditingView&&(i.class="ck-media__wrapper");const s=this._getPreviewHtml(t);n=e.createRawElement("div",i,((e,t)=>{t.setContentOf(e,s)}))}else this.url&&(i.url=this.url),n=e.createEmptyElement(t.elementName,i);return e.setCustomProperty("media-content",!0,n),n}_getPreviewHtml(e){return this._previewRenderer?this._previewRenderer(this._match):this.url&&e.renderForEditingView?this._getPlaceholderHtml():""}_getPlaceholderHtml(){const e=new Bu,t=this._locale.t;e.content='',e.viewBox="0 0 64 42";return new Kh({tag:"div",attributes:{class:"ck ck-reset_all ck-media__placeholder"},children:[{tag:"div",attributes:{class:"ck-media__placeholder__icon"},children:[e]},{tag:"a",attributes:{class:"ck-media__placeholder__url",target:"_blank",rel:"noopener noreferrer",href:this.url,"data-cke-tooltip-text":t("Open media in new tab")},children:[{tag:"span",attributes:{class:"ck-media__placeholder__url__text"},children:[this.url]}]}]}).render().outerHTML}_getValidUrl(e){return e?e.match(/^https?/)?e:"https://"+e:null}}class $y extends Is{static get pluginName(){return"MediaEmbedEditing"}constructor(e){super(e),e.config.define("mediaEmbed",{elementName:"oembed",providers:[{name:"dailymotion",url:/^dailymotion\.com\/video\/(\w+)/,html:e=>`
    `},{name:"spotify",url:[/^open\.spotify\.com\/(artist\/\w+)/,/^open\.spotify\.com\/(album\/\w+)/,/^open\.spotify\.com\/(track\/\w+)/],html:e=>`
    `},{name:"youtube",url:[/^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)(?:&t=(\d+))?/,/^(?:m\.)?youtube\.com\/v\/([\w-]+)(?:\?t=(\d+))?/,/^youtube\.com\/embed\/([\w-]+)(?:\?start=(\d+))?/,/^youtu\.be\/([\w-]+)(?:\?t=(\d+))?/],html:e=>{const t=e[1],i=e[2];return`
    `}},{name:"vimeo",url:[/^vimeo\.com\/(\d+)/,/^vimeo\.com\/[^/]+\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/album\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/channels\/[^/]+\/(\d+)/,/^vimeo\.com\/groups\/[^/]+\/videos\/(\d+)/,/^vimeo\.com\/ondemand\/[^/]+\/(\d+)/,/^player\.vimeo\.com\/video\/(\d+)/],html:e=>`
    `},{name:"instagram",url:/^instagram\.com\/p\/(\w+)/},{name:"twitter",url:/^twitter\.com/},{name:"googleMaps",url:[/^google\.com\/maps/,/^goo\.gl\/maps/,/^maps\.google\.com/,/^maps\.app\.goo\.gl/]},{name:"flickr",url:/^flickr\.com/},{name:"facebook",url:/^facebook\.com/}]}),this.registry=new zy(e.locale,e.config.get("mediaEmbed"))}init(){const e=this.editor,t=e.model.schema,i=e.t,n=e.conversion,s=e.config.get("mediaEmbed.previewsInData"),o=e.config.get("mediaEmbed.elementName"),r=this.registry;e.commands.add("mediaEmbed",new Fy(e)),t.register("media",{inheritAllFrom:"$blockObject",allowAttributes:["url"]}),n.for("dataDowncast").elementToStructure({model:"media",view:(e,{writer:t})=>{const i=e.getAttribute("url");return My(t,r,i,{elementName:o,renderMediaPreview:i&&s})}}),n.for("dataDowncast").add(Oy(r,{elementName:o,renderMediaPreview:s})),n.for("editingDowncast").elementToStructure({model:"media",view:(e,{writer:t})=>{const n=e.getAttribute("url");return function(e,t,i){return t.setCustomProperty("media",!0,e),tf(e,t,{label:i})}(My(t,r,n,{elementName:o,renderForEditingView:!0}),t,i("media widget"))}}),n.for("editingDowncast").add(Oy(r,{elementName:o,renderForEditingView:!0})),n.for("upcast").elementToElement({view:e=>["oembed",o].includes(e.name)&&e.getAttribute("url")?{name:!0}:null,model:(e,{writer:t})=>{const i=e.getAttribute("url");if(r.hasMedia(i))return t.createElement("media",{url:i})}}).elementToElement({view:{name:"div",attributes:{"data-oembed-url":!0}},model:(e,{writer:t})=>{const i=e.getAttribute("data-oembed-url");if(r.hasMedia(i))return t.createElement("media",{url:i})}}).add((e=>{e.on("element:figure",(function(e,t,i){if(!i.consumable.consume(t.viewItem,{name:!0,classes:"media"}))return;const{modelRange:n,modelCursor:s}=i.convertChildren(t.viewItem,t.modelCursor);t.modelRange=n,t.modelCursor=s;ks(n.getItems())||i.consumable.revert(t.viewItem,{name:!0,classes:"media"})}))}))}}const Wy=/^(?:http(s)?:\/\/)?[\w-]+\.[\w-.~:/?#[\]@!$&'()*+,;=%]+$/;class jy extends Is{static get requires(){return[Mf,ag,Uf]}static get pluginName(){return"AutoMediaEmbed"}constructor(e){super(e),this._timeoutId=null,this._positionToInsert=null}init(){const e=this.editor,t=e.model.document;this.listenTo(e.plugins.get("ClipboardPipeline"),"inputTransformation",(()=>{const e=t.selection.getFirstRange(),i=hd.fromPosition(e.start);i.stickiness="toPrevious";const n=hd.fromPosition(e.end);n.stickiness="toNext",t.once("change:data",(()=>{this._embedMediaBetweenPositions(i,n),i.detach(),n.detach()}),{priority:"high"})})),e.commands.get("undo").on("execute",(()=>{this._timeoutId&&(Rn.window.clearTimeout(this._timeoutId),this._positionToInsert.detach(),this._timeoutId=null,this._positionToInsert=null)}),{priority:"high"})}_embedMediaBetweenPositions(e,t){const i=this.editor,n=i.plugins.get($y).registry,s=new Il(e,t),o=s.getWalker({ignoreElementEnd:!0});let r="";for(const e of o)e.item.is("$textProxy")&&(r+=e.item.data);if(r=r.trim(),!r.match(Wy))return void s.detach();if(!n.hasMedia(r))return void s.detach();i.commands.get("mediaEmbed").isEnabled?(this._positionToInsert=hd.fromPosition(e),this._timeoutId=Rn.window.setTimeout((()=>{i.model.change((e=>{let t;this._timeoutId=null,e.remove(s),s.detach(),"$graveyard"!==this._positionToInsert.root.rootName&&(t=this._positionToInsert),Dy(i.model,r,t,!1),this._positionToInsert.detach(),this._positionToInsert=null})),i.plugins.get("Delete").requestUndoOnBackspace()}),100)):s.detach()}}class qy extends fu{constructor(e,t){super(t);const i=t.t;this.focusTracker=new Cs,this.keystrokes=new As,this.set("mediaURLInputValue",""),this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("Save"),Pu.check,"ck-button-save"),this.saveButtonView.type="submit",this.saveButtonView.bind("isEnabled").to(this,"mediaURLInputValue",(e=>!!e)),this.cancelButtonView=this._createButton(i("Cancel"),Pu.cancel,"ck-button-cancel","cancel"),this._focusables=new Gh,this._focusCycler=new Ku({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this._validators=e,this.setTemplate({tag:"form",attributes:{class:["ck","ck-media-form","ck-responsive-form"],tabindex:"-1"},children:[this.urlInputView,this.saveButtonView,this.cancelButtonView]}),Ru(this)}render(){super.render(),Vu({view:this});[this.urlInputView,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element);const e=e=>e.stopPropagation();this.keystrokes.set("arrowright",e),this.keystrokes.set("arrowleft",e),this.keystrokes.set("arrowup",e),this.keystrokes.set("arrowdown",e),this.listenTo(this.urlInputView.element,"selectstart",((e,t)=>{t.stopPropagation()}),{priority:"high"})}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}get url(){return this.urlInputView.fieldView.element.value.trim()}set url(e){this.urlInputView.fieldView.element.value=e.trim()}isValid(){this.resetFormStatus();for(const e of this._validators){const t=e(this);if(t)return this.urlInputView.errorText=t,!1}return!0}resetFormStatus(){this.urlInputView.errorText=null,this.urlInputView.infoText=this._urlInputViewInfoDefault}_createUrlInput(){const e=this.locale.t,t=new ym(this.locale,km),i=t.fieldView;return this._urlInputViewInfoDefault=e("Paste the media URL in the input."),this._urlInputViewInfoTip=e("Tip: Paste the URL into the content to embed faster."),t.label=e("Media URL"),t.infoText=this._urlInputViewInfoDefault,i.on("input",(()=>{t.infoText=i.element.value?this._urlInputViewInfoTip:this._urlInputViewInfoDefault,this.mediaURLInputValue=i.element.value.trim()})),t}_createButton(e,t,i,n){const s=new Mu(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}}class Uy extends Is{static get requires(){return[$y]}static get pluginName(){return"MediaEmbedUI"}init(){const e=this.editor,t=e.commands.get("mediaEmbed"),i=e.plugins.get($y).registry;e.ui.componentFactory.add("mediaEmbed",(n=>{const s=lm(n),o=new qy(function(e,t){return[t=>{if(!t.url.length)return e("The URL must not be empty.")},i=>{if(!t.hasMedia(i.url))return e("This media URL is not supported.")}]}(e.t,i),e.locale);return this._setUpDropdown(s,o,t,e),this._setUpForm(s,o,t),s}))}_setUpDropdown(e,t,i){const n=this.editor,s=n.t,o=e.buttonView;e.bind("isEnabled").to(i),e.panelView.children.add(t),o.set({label:s("Insert media"),icon:'',tooltip:!0}),o.on("open",(()=>{t.disableCssTransitions(),t.url=i.value||"",t.urlInputView.fieldView.select(),t.enableCssTransitions()}),{priority:"low"}),e.on("submit",(()=>{t.isValid()&&(n.execute("mediaEmbed",t.url),n.editing.view.focus())})),e.on("change:isOpen",(()=>t.resetFormStatus())),e.on("cancel",(()=>{n.editing.view.focus()}))}_setUpForm(e,t,i){t.delegate("submit","cancel").to(e),t.urlInputView.bind("value").to(i,"value"),t.urlInputView.bind("isReadOnly").to(i,"isEnabled",(e=>!e))}}class Gy extends Vs{refresh(){const e=this.editor.model,t=e.document;this.isEnabled=e.schema.checkAttributeInSelection(t.selection,"mention")}execute(e){const t=this.editor.model,i=t.document.selection,n="string"==typeof e.mention?{id:e.mention}:e.mention,s=n.id,o=e.range||i.getFirstRange(),r=e.text||s,a=Jy({_text:r,id:s},n);if(1!=e.marker.length)throw new b("mentioncommand-incorrect-marker",this);if(s.charAt(0)!=e.marker)throw new b("mentioncommand-incorrect-id",this);t.change((e=>{const n=xs(i.getAttributes()),s=new Map(n.entries());s.set("mention",a),t.insertContent(e.createText(r,s),o),t.insertContent(e.createText(" ",n),o.start.getShiftedBy(r.length))}))}}class Ky extends Is{static get pluginName(){return"MentionEditing"}init(){const e=this.editor,t=e.model,i=t.document;t.schema.extend("$text",{allowAttributes:"mention"}),e.conversion.for("upcast").elementToAttribute({view:{name:"span",key:"data-mention",classes:"mention"},model:{key:"mention",value:e=>Qy(e)}}),e.conversion.for("downcast").attributeToElement({model:"mention",view:Xy}),e.conversion.for("downcast").add(Yy),i.registerPostFixer((e=>function(e,t,i){const n=t.differ.getChanges();let s=!1;for(const t of n){const n=t.position;if("$text"==t.name){const t=n.textNode&&n.textNode.nextSibling;s=ek(n.textNode,e)||s,s=ek(t,e)||s,s=ek(n.nodeBefore,e)||s,s=ek(n.nodeAfter,e)||s}if("$text"!=t.name&&"insert"==t.type){const t=n.nodeAfter;for(const i of e.createRangeIn(t).getItems())s=ek(i,e)||s}if("insert"==t.type&&i.isInline(t.name)){const t=n.nodeAfter&&n.nodeAfter.nextSibling;s=ek(n.nodeBefore,e)||s,s=ek(t,e)||s}}return s}(e,i,t.schema))),i.registerPostFixer((e=>function(e,t){const i=t.differ.getChanges();let n=!1;for(const t of i)if("attribute"===t.type&&"mention"!=t.attributeKey){const i=t.range.start.nodeBefore,s=t.range.end.nodeAfter;for(const o of[i,s])Zy(o)&&o.getAttribute(t.attributeKey)!=t.attributeNewValue&&(e.setAttribute(t.attributeKey,t.attributeNewValue,o),n=!0)}return n}(e,i))),i.registerPostFixer((e=>function(e,t){const i=t.selection,n=i.focus;if(i.isCollapsed&&i.hasAttribute("mention")&&function(e){const t=e.isAtStart;return e.nodeBefore&&e.nodeBefore.is("$text")||t}(n))return e.removeSelectionAttribute("mention"),!0}(e,i))),e.commands.add("mention",new Gy(e))}}function Jy(e,t){return Object.assign({uid:g()},e,t||{})}function Qy(e,t){const i=e.getAttribute("data-mention"),n=e.getChild(0);if(!n)return;return Jy({id:i,_text:n.data},t)}function Yy(e){e.on("attribute:mention",((e,t,i)=>{const n=t.attributeNewValue;if(!t.item.is("$textProxy")||!n)return;const s=t.range.start;(s.textNode||s.nodeAfter).data!=n._text&&i.consumable.consume(t.item,e.name)}),{priority:"highest"})}function Xy(e,{writer:t}){if(!e)return;const i={class:"mention","data-mention":e.id},n={id:e.uid,priority:20};return t.createAttributeElement("span",i,n)}function Zy(e){if(!e||!e.is("$text")&&!e.is("$textProxy")||!e.hasAttribute("mention"))return!1;return e.data!=e.getAttribute("mention")._text}function ek(e,t){return!!Zy(e)&&(t.removeAttribute("mention",e),!0)}class tk extends om{constructor(e){super(e),this.extendTemplate({attributes:{class:["ck-mentions"],tabindex:"-1"}})}selectFirst(){this.select(0)}selectNext(){const e=this.selected,t=this.items.getIndex(e);this.select(t+1)}selectPrevious(){const e=this.selected,t=this.items.getIndex(e);this.select(t-1)}select(e){let t=0;e>0&&e{i?(this.domElement.classList.add("ck-on"),this.domElement.classList.remove("ck-off")):(this.domElement.classList.add("ck-off"),this.domElement.classList.remove("ck-on"))})),this.listenTo(this.domElement,"click",(()=>{this.fire("execute")}))}render(){super.render(),this.element=this.domElement}}class nk extends rm{highlight(){this.children.first.isOn=!0}removeHighlight(){this.children.first.isOn=!1}}const sk=[ds.arrowup,ds.arrowdown,ds.esc],ok=[ds.enter,ds.tab];class rk extends Is{static get pluginName(){return"MentionUI"}static get requires(){return[Pm]}constructor(e){super(e),this._mentionsView=this._createMentionView(),this._mentionsConfigurations=new Map,this._requestFeedDebounced=xa(this._requestFeed,100),e.config.define("mention",{feeds:[]})}init(){const e=this.editor,t=e.config.get("mention.commitKeys")||ok,i=sk.concat(t);this._balloon=e.plugins.get(Pm),e.editing.view.document.on("keydown",((e,n)=>{var s;s=n.keyCode,i.includes(s)&&this._isUIVisible&&(n.preventDefault(),e.stop(),n.keyCode==ds.arrowdown&&this._mentionsView.selectNext(),n.keyCode==ds.arrowup&&this._mentionsView.selectPrevious(),t.includes(n.keyCode)&&this._mentionsView.executeSelected(),n.keyCode==ds.esc&&this._hideUIAndRemoveMarker())}),{priority:"highest"}),Iu({emitter:this._mentionsView,activator:()=>this._isUIVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideUIAndRemoveMarker()});const n=e.config.get("mention.feeds");for(const e of n){const t=e.feed,i=e.marker;if(!hk(i))throw new b("mentionconfig-incorrect-marker",null,{marker:i});const n={marker:i,feedCallback:"function"==typeof t?t.bind(this.editor):dk(t),itemRenderer:e.itemRenderer};this._mentionsConfigurations.set(i,n)}this._setupTextWatcher(n),this.listenTo(e,"change:isReadOnly",(()=>{this._hideUIAndRemoveMarker()})),this.on("requestFeed:response",((e,t)=>this._handleFeedResponse(t))),this.on("requestFeed:error",(()=>this._hideUIAndRemoveMarker()))}destroy(){super.destroy(),this._mentionsView.destroy()}get _isUIVisible(){return this._balloon.visibleView===this._mentionsView}_createMentionView(){const e=this.editor.locale,t=new tk(e);return this._items=new ys,t.items.bindTo(this._items).using((i=>{const{item:n,marker:s}=i,o=this.editor.config.get("mention.dropdownLimit")||10;if(t.items.length>=o)return;const r=new nk(e),a=this._renderItem(n,s);return a.delegate("execute").to(r),r.children.add(a),r.item=n,r.marker=s,r.on("execute",(()=>{t.fire("execute",{item:n,marker:s})})),r})),t.on("execute",((e,t)=>{const i=this.editor,n=i.model,s=t.item,o=t.marker,r=i.model.markers.get("mention"),a=n.createPositionAt(n.document.selection.focus),l=n.createPositionAt(r.getStart()),c=n.createRange(l,a);this._hideUIAndRemoveMarker(),i.execute("mention",{mention:s,text:s.text,marker:o,range:c}),i.editing.view.focus()})),t}_getItemRenderer(e){const{itemRenderer:t}=this._mentionsConfigurations.get(e);return t}_requestFeed(e,t){this._lastRequested=t;const{feedCallback:i}=this._mentionsConfigurations.get(e),n=i(t);n instanceof Promise?n.then((i=>{this._lastRequested==t?this.fire("requestFeed:response",{feed:i,marker:e,feedText:t}):this.fire("requestFeed:discarded",{feed:i,marker:e,feedText:t})})).catch((t=>{this.fire("requestFeed:error",{error:t}),v("mention-feed-callback-error",{marker:e})})):this.fire("requestFeed:response",{feed:n,marker:e,feedText:t})}_setupTextWatcher(e){const t=this.editor,i=e.map((e=>({...e,pattern:ck(e.marker,e.minimumCharacters||0)}))),n=new dg(t.model,function(e){const t=t=>{const i=lk(e,t);if(!i)return!1;let n=0;0!==i.position&&(n=i.position-1);const s=t.substring(n);return i.pattern.test(s)};return t}(i));n.on("matched",((e,n)=>{const s=lk(i,n.text),o=t.model.document.selection.focus,r=t.model.createPositionAt(o.parent,s.position);if(function(e){const t=e.textNode&&e.textNode.hasAttribute("mention"),i=e.nodeBefore;return t||i&&i.is("$text")&&i.hasAttribute("mention")}(o)||function(e){const t=e.nodeAfter;return t&&t.is("$text")&&t.hasAttribute("mention")}(r))return void this._hideUIAndRemoveMarker();const a=function(e,t){let i=0;0!==e.position&&(i=e.position-1);const n=ck(e.marker,0),s=t.substring(i);return s.match(n)[2]}(s,n.text),l=s.marker.length+a.length,c=o.getShiftedBy(-l),d=o.getShiftedBy(-a.length),h=t.model.createRange(c,d);if(uk(t)){const e=t.model.markers.get("mention");t.model.change((t=>{t.updateMarker(e,{range:h})}))}else t.model.change((e=>{e.addMarker("mention",{range:h,usingOperation:!1,affectsData:!1})}));this._requestFeedDebounced(s.marker,a)})),n.on("unmatched",(()=>{this._hideUIAndRemoveMarker()}));const s=t.commands.get("mention");return n.bind("isEnabled").to(s),n}_handleFeedResponse(e){const{feed:t,marker:i}=e;if(!uk(this.editor))return;this._items.clear();for(const e of t){const t="object"!=typeof e?{id:e,text:e}:e;this._items.add({item:t,marker:i})}const n=this.editor.model.markers.get("mention");this._items.length?this._showOrUpdateUI(n):this._hideUIAndRemoveMarker()}_showOrUpdateUI(e){this._isUIVisible?this._balloon.updatePosition(this._getBalloonPanelPositionData(e,this._mentionsView.position)):this._balloon.add({view:this._mentionsView,position:this._getBalloonPanelPositionData(e,this._mentionsView.position),singleViewMode:!0}),this._mentionsView.position=this._balloon.view.position,this._mentionsView.selectFirst()}_hideUIAndRemoveMarker(){this._balloon.hasView(this._mentionsView)&&this._balloon.remove(this._mentionsView),uk(this.editor)&&this.editor.model.change((e=>e.removeMarker("mention"))),this._mentionsView.position=void 0}_renderItem(e,t){const i=this.editor;let n,s=e.id;const o=this._getItemRenderer(t);if(o){const t=o(e);"string"!=typeof t?n=new ik(i.locale,t):s=t}if(!n){const e=new Mu(i.locale);e.label=s,e.withText=!0,n=e}return n}_getBalloonPanelPositionData(e,t){const i=this.editor,n=i.editing,s=n.view.domConverter,o=n.mapper;return{target:()=>{let t=e.getRange();"$graveyard"==t.start.root.rootName&&(t=i.model.document.selection.getFirstRange());const n=o.toViewRange(t);return Nn.getDomRangeRects(s.viewRangeToDom(n)).pop()},limiter:()=>{const e=this.editor.editing.view,t=e.document.selection.editableElement;return t?e.domConverter.mapViewToDom(t.root):null},positions:ak(t)}}}function ak(e){const t={caret_se:e=>({top:e.bottom+3,left:e.right,name:"caret_se",config:{withArrow:!1}}),caret_ne:(e,t)=>({top:e.top-t.height-3,left:e.right,name:"caret_ne",config:{withArrow:!1}}),caret_sw:(e,t)=>({top:e.bottom+3,left:e.right-t.width,name:"caret_sw",config:{withArrow:!1}}),caret_nw:(e,t)=>({top:e.top-t.height-3,left:e.right-t.width,name:"caret_nw",config:{withArrow:!1}})};return Object.prototype.hasOwnProperty.call(t,e)?[t[e]]:[t.caret_se,t.caret_sw,t.caret_ne,t.caret_nw]}function lk(e,t){let i;for(const n of e){const e=t.lastIndexOf(n.marker);e>0&&!t.substring(e-1).match(n.pattern)||(!i||e>=i.position)&&(i={marker:n.marker,position:e,minimumCharacters:n.minimumCharacters,pattern:n.pattern})}return i}function ck(e,t){const i=0==t?"*":`{${t},}`,n=s.features.isRegExpUnicodePropertySupported?"\\p{Ps}\\p{Pi}\"'":"\\(\\[{\"'";return new RegExp(`(?:^|[ ${n}])([${e}])(.${i})$`,"u")}function dk(e){return t=>e.filter((e=>("string"==typeof e?e:String(e.id)).toLowerCase().includes(t.toLowerCase())))}function hk(e){return e&&1==e.length}function uk(e){return e.model.markers.has("mention")}function mk(e,t,i,{blockElements:n,inlineObjectElements:s}){let o=i.createPositionAt(e,"forward"==t?"after":"before");return o=o.getLastMatchingPosition((({item:e})=>e.is("element")&&!n.includes(e.name)&&!s.includes(e.name)),{direction:t}),"forward"==t?o.nodeAfter:o.nodeBefore}function gk(e,t){return!!e&&e.is("element")&&t.includes(e.name)}function fk(e,t){if(!e.childCount)return;const i=new ih(e.document),n=function(e,t){const i=t.createRangeIn(e),n=new Js({name:/^p|h\d+$/,styles:{"mso-list":/.*/}}),s=[];for(const e of i)if("elementStart"===e.type&&n.match(e.item)){const t=bk(e.item);s.push({element:e.item,id:t.id,order:t.order,indent:t.indent})}return s}(e,i);if(!n.length)return;let s=null,o=1;n.forEach(((e,r)=>{const a=function(e,t){if(!e)return!0;if(e.id!==t.id)return t.indent-e.indent!=1;const i=t.element.previousSibling;if(!i)return!0;return n=i,!(n.is("element","ol")||n.is("element","ul"));var n}(n[r-1],e),l=a?null:n[r-1],c=(h=e,(d=l)?h.indent-d.indent:h.indent-1);var d,h;if(a&&(s=null,o=1),!s||0!==c){const n=function(e,t){const i=new RegExp(`@list l${e.id}:level${e.indent}\\s*({[^}]*)`,"gi"),n=/mso-level-number-format:([^;]{0,100});/gi,s=/mso-level-start-at:\s{0,100}([0-9]{0,10})\s{0,100};/gi,o=i.exec(t);let r="decimal",a="ol",l=null;if(o&&o[1]){const t=n.exec(o[1]);if(t&&t[1]&&(r=t[1].trim(),a="bullet"!==r&&"image"!==r?"ol":"ul"),"bullet"===r){const t=function(e){const t=function(e){if(e.getChild(0).is("$text"))return null;for(const t of e.getChildren()){if(!t.is("element","span"))continue;const e=t.getChild(0);return e.is("$text")?e:e.getChild(0)}}(e);if(!t)return null;const i=t._data;if("o"===i)return"circle";if("·"===i)return"disc";if("§"===i)return"square";return null}(e.element);t&&(r=t)}else{const e=s.exec(o[1]);e&&e[1]&&(l=parseInt(e[1]))}}return{type:a,startIndex:l,style:pk(r)}}(e,t);if(s){if(e.indent>o){const e=s.getChild(s.childCount-1),t=e.getChild(e.childCount-1);s=wk(n,t,i),o+=1}else if(e.indent1&&i.setAttribute("start",e.startIndex,s),s}function bk(e){const t={},i=e.getStyle("mso-list");if(i){const e=i.match(/(^|\s{1,100})l(\d+)/i),n=i.match(/\s{0,100}lfo(\d+)/i),s=i.match(/\s{0,100}level(\d+)/i);e&&n&&s&&(t.id=e[2],t.order=n[1],t.indent=s[1])}return t}const vk=/id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;class _k{constructor(e){this.document=e}isActive(e){return vk.test(e)}execute(e){const t=new ih(this.document),{body:i}=e._parsedData;!function(e,t){for(const i of e.getChildren())if(i.is("element","b")&&"normal"===i.getStyle("font-weight")){const n=e.getChildIndex(i);t.remove(i),t.insertChild(n,i.getChildren(),e)}}(i,t),function(e,t){for(const i of t.createRangeIn(e)){const e=i.item;if(e.is("element","li")){const i=e.getChild(0);i&&i.is("element","p")&&t.unwrapElement(i)}}}(i,t),function(e,t){const i=new fr(t.document.stylesProcessor),n=new sa(i,{renderingMode:"data"}),s=n.blockElements,o=n.inlineObjectElements,r=[];for(const i of t.createRangeIn(e)){const e=i.item;if(e.is("element","br")){const i=mk(e,"forward",t,{blockElements:s,inlineObjectElements:o}),n=mk(e,"backward",t,{blockElements:s,inlineObjectElements:o}),a=gk(i,s);(gk(n,s)||a)&&r.push(e)}}for(const e of r)e.hasClass("Apple-interchange-newline")?t.remove(e):t.replace(e,t.createElement("p"))}(i,t),e.content=i}}function yk(e,t){if(!e.childCount)return;const i=new ih,n=function(e,t){const i=t.createRangeIn(e),n=new Js({name:/v:(.+)/}),s=[];for(const e of i){if("elementStart"!=e.type)continue;const t=e.item,i=t.previousSibling&&t.previousSibling.name||null;n.match(t)&&t.getAttribute("o:gfxdata")&&"v:shapetype"!==i&&s.push(e.item.getAttribute("id"))}return s}(e,i);!function(e,t,i){const n=i.createRangeIn(t),s=new Js({name:"img"}),o=[];for(const t of n)if(s.match(t.item)){const i=t.item,n=i.getAttribute("v:shapes")?i.getAttribute("v:shapes").split(" "):[];n.length&&n.every((t=>e.indexOf(t)>-1))?o.push(i):i.getAttribute("src")||o.push(i)}for(const e of o)i.remove(e)}(n,e,i),function(e,t){const i=t.createRangeIn(e),n=new Js({name:/v:(.+)/}),s=[];for(const e of i)"elementStart"==e.type&&n.match(e.item)&&s.push(e.item);for(const e of s)t.remove(e)}(e,i);const s=function(e,t){const i=t.createRangeIn(e),n=new Js({name:"img"}),s=[];for(const e of i)n.match(e.item)&&e.item.getAttribute("src").startsWith("file://")&&s.push(e.item);return s}(e,i);s.length&&function(e,t,i){if(e.length===t.length)for(let n=0;nString.fromCharCode(parseInt(e,16)))).join(""))}const Ck=//i,Ak=/xmlns:o="urn:schemas-microsoft-com/i;class xk{constructor(e){this.document=e}isActive(e){return Ck.test(e)||Ak.test(e)}execute(e){const{body:t,stylesString:i}=e._parsedData;fk(t,i),yk(t,e.dataTransfer.getData("text/rtf")),e.content=t}}function Tk(e){return e.replace(/(\s+)<\/span>/g,((e,t)=>1===t.length?" ":Array(t.length+1).join("  ").substr(0,t.length)))}function Ek(e,t){const i=new DOMParser,n=function(e){return Tk(Tk(e)).replace(/([^\S\r\n]*?)[\r\n]+([^\S\r\n]*<\/span>)/g,"$1$2").replace(/<\/span>/g,"").replace(/ <\//g," <\/o:p>/g," ").replace(/( |\u00A0)<\/o:p>/g,"").replace(/>([^\S\r\n]*[\r\n]\s*)<")}(function(e){const t="",i="",n=e.indexOf(t);if(n<0)return e;const s=e.indexOf(i,n+t.length);return e.substring(0,n+t.length)+(s>=0?e.substring(s):"")}(e=e.replace(//g,"")}(n.getData("text/html")):n.getData("text/plain")&&(((o=(o=n.getData("text/plain")).replace(//g,">").replace(/\r?\n\r?\n/g,"

    ").replace(/\r?\n/g,"
    ").replace(/\t/g,"    ").replace(/^\s/," ").replace(/\s$/," ").replace(/\s\s/g,"  ")).includes("

    ")||o.includes("
    "))&&(o=`

    ${o}

    `),e=o),s=this.editor.data.htmlProcessor.toView(e)}var o;const r=new g(this,"inputTransformation");this.fire(r,{content:s,dataTransfer:n,targetRanges:t.targetRanges,method:t.method}),r.stop.called&&e.stop(),i.scrollToTheSelection()}),{priority:"low"}),this.listenTo(this,"inputTransformation",((e,i)=>{if(i.content.isEmpty)return;const n=this.editor.data.toModel(i.content,"$clipboardHolder");0!=n.childCount&&(e.stop(),t.change((()=>{this.fire("contentInsertion",{content:n,method:i.method,dataTransfer:i.dataTransfer,targetRanges:i.targetRanges})})))}),{priority:"low"}),this.listenTo(this,"contentInsertion",((e,i)=>{i.resultRange=t.insertContent(i.content)}),{priority:"low"})}_setupCopyCut(){const e=this.editor,t=e.model.document,i=e.editing.view.document,n=(e,i)=>{const n=i.dataTransfer;i.preventDefault(),this._fireOutputTransformationEvent(n,t.selection,e.name)};this.listenTo(i,"copy",n,{priority:"low"}),this.listenTo(i,"cut",((t,i)=>{e.model.canEditAt(e.model.document.selection)?n(t,i):i.preventDefault()}),{priority:"low"}),this.listenTo(this,"outputTransformation",((t,n)=>{const s=e.data.toView(n.content);i.fire("clipboardOutput",{dataTransfer:n.dataTransfer,content:s,method:n.method})}),{priority:"low"}),this.listenTo(i,"clipboardOutput",((i,n)=>{n.content.isEmpty||(n.dataTransfer.setData("text/html",this.editor.data.htmlProcessor.toData(n.content)),n.dataTransfer.setData("text/plain",Dg(n.content))),"cut"==n.method&&e.model.deleteContent(t.selection)}),{priority:"low"})}}function*Hg(e,t){for(const i of t)i&&e.getAttributeProperties(i[0]).copyOnEnter&&(yield i)}class $g extends so{execute(){this.editor.model.change((e=>{this.enterBlock(e),this.fire("afterExecute",{writer:e})}))}enterBlock(e){const t=this.editor.model,i=t.document.selection,n=t.schema,s=i.isCollapsed,o=i.getFirstRange(),r=o.start.parent,a=o.end.parent;if(n.isLimit(r)||n.isLimit(a))return s||r!=a||t.deleteContent(i),!1;if(s){const t=Hg(e.model.schema,i.getAttributes());return Wg(e,o.start),e.setSelectionAttribute(t),!0}{const n=!(o.start.isAtStart&&o.end.isAtEnd),s=r==a;if(t.deleteContent(i,{leaveUnmerged:n}),n){if(s)return Wg(e,i.focus),!0;e.setSelection(a,0)}}return!1}}function Wg(e,t){e.split(t),e.setSelection(t.parent.nextSibling,0)}const Ug={insertParagraph:{isSoft:!1},insertLineBreak:{isSoft:!0}};class jg extends _a{constructor(e){super(e);const t=this.document;let i=!1;t.on("keydown",((e,t)=>{i=t.shiftKey})),t.on("beforeinput",((n,s)=>{if(!this.isEnabled)return;let o=s.inputType;l.isSafari&&i&&"insertParagraph"==o&&(o="insertLineBreak");const r=s.domEvent,a=Ug[o];if(!a)return;const c=new yr(t,"enter",s.targetRanges[0]);t.fire(c,new ka(e,r,{isSoft:a.isSoft})),c.stop.called&&n.stop()}))}observe(){}stopObserving(){}}class qg extends io{static get pluginName(){return"Enter"}init(){const e=this.editor,t=e.editing.view,i=t.document;t.addObserver(jg),e.commands.add("enter",new $g(e)),this.listenTo(i,"enter",((n,s)=>{i.isComposing||s.preventDefault(),s.isSoft||(e.execute("enter"),t.scrollToTheSelection())}),{priority:"low"})}}class Gg extends so{execute(){const e=this.editor.model,t=e.document;e.change((i=>{!function(e,t,i){const n=i.isCollapsed,s=i.getFirstRange(),o=s.start.parent,r=s.end.parent,a=o==r;if(n){const n=Hg(e.schema,i.getAttributes());Kg(e,t,s.end),t.removeSelectionAttribute(i.getAttributeKeys()),t.setSelectionAttribute(n)}else{const n=!(s.start.isAtStart&&s.end.isAtEnd);e.deleteContent(i,{leaveUnmerged:n}),a?Kg(e,t,i.focus):n&&t.setSelection(r,0)}}(e,i,t.selection),this.fire("afterExecute",{writer:i})}))}refresh(){const e=this.editor.model,t=e.document;this.isEnabled=function(e,t){if(t.rangeCount>1)return!1;const i=t.anchor;if(!i||!e.checkChild(i,"softBreak"))return!1;const n=t.getFirstRange(),s=n.start.parent,o=n.end.parent;return!Jg(s,e)&&!Jg(o,e)||s===o}(e.schema,t.selection)}}function Kg(e,t,i){const n=t.createElement("softBreak");e.insertContent(n,i),t.setSelection(n,"after")}function Jg(e,t){return!e.is("rootElement")&&(t.isLimit(e)||Jg(e.parent,t))}class Qg extends io{static get pluginName(){return"ShiftEnter"}init(){const e=this.editor,t=e.model.schema,i=e.conversion,n=e.editing.view,s=n.document;t.register("softBreak",{allowWhere:"$text",isInline:!0}),i.for("upcast").elementToElement({model:"softBreak",view:"br"}),i.for("downcast").elementToElement({model:"softBreak",view:(e,{writer:t})=>t.createEmptyElement("br")}),n.addObserver(jg),e.commands.add("shiftEnter",new Gg(e)),this.listenTo(s,"enter",((t,i)=>{s.isComposing||i.preventDefault(),i.isSoft&&(e.execute("shiftEnter"),n.scrollToTheSelection())}),{priority:"low"})}}class Zg extends(S()){constructor(){super(...arguments),this._stack=[]}add(e,t){const i=this._stack,n=i[0];this._insertDescriptor(e);const s=i[0];n===s||Yg(n,s)||this.fire("change:top",{oldDescriptor:n,newDescriptor:s,writer:t})}remove(e,t){const i=this._stack,n=i[0];this._removeDescriptor(e);const s=i[0];n===s||Yg(n,s)||this.fire("change:top",{oldDescriptor:n,newDescriptor:s,writer:t})}_insertDescriptor(e){const t=this._stack,i=t.findIndex((t=>t.id===e.id));if(Yg(e,t[i]))return;i>-1&&t.splice(i,1);let n=0;for(;t[n]&&(s=t[n],o=e,s.priority>o.priority||!(s.priorityXg(o.classes));)n++;var s,o;t.splice(n,0,e)}_removeDescriptor(e){const t=this._stack,i=t.findIndex((t=>t.id===e));i>-1&&t.splice(i,1)}}function Yg(e,t){return e&&t&&e.priority==t.priority&&Xg(e.classes)==Xg(t.classes)}function Xg(e){return Array.isArray(e)?e.sort().join(","):e}const ef='',tf="ck-widget",nf="ck-widget_selected";function sf(e){return!!e.is("element")&&!!e.getCustomProperty("widget")}function of(e,t,i={}){if(!e.is("containerElement"))throw new _("widget-to-widget-wrong-element-type",null,{element:e});return t.setAttribute("contenteditable","false",e),t.addClass(tf,e),t.setCustomProperty("widget",!0,e),e.getFillerOffset=hf,t.setCustomProperty("widgetLabel",[],e),i.label&&function(e,t){e.getCustomProperty("widgetLabel").push(t)}(e,i.label),i.hasSelectionHandle&&function(e,t){const i=t.createUIElement("div",{class:"ck ck-widget__selection-handle"},(function(e){const t=this.toDomElement(e),i=new ms;return i.set("content",ef),i.render(),t.appendChild(i.element),t}));t.insert(t.createPositionAt(e,0),i),t.addClass(["ck-widget_with-selection-handle"],e)}(e,t),lf(e,t),e}function rf(e,t,i){if(t.classes&&i.addClass(Pn(t.classes),e),t.attributes)for(const n in t.attributes)i.setAttribute(n,t.attributes[n],e)}function af(e,t,i){if(t.classes&&i.removeClass(Pn(t.classes),e),t.attributes)for(const n in t.attributes)i.removeAttribute(n,e)}function lf(e,t,i=rf,n=af){const s=new Zg;s.on("change:top",((t,s)=>{s.oldDescriptor&&n(e,s.oldDescriptor,s.writer),s.newDescriptor&&i(e,s.newDescriptor,s.writer)})),t.setCustomProperty("addHighlight",((e,t,i)=>s.add(t,i)),e),t.setCustomProperty("removeHighlight",((e,t,i)=>s.remove(t,i)),e)}function cf(e,t,i={}){return t.addClass(["ck-editor__editable","ck-editor__nested-editable"],e),t.setAttribute("role","textbox",e),i.label&&t.setAttribute("aria-label",i.label,e),t.setAttribute("contenteditable",e.isReadOnly?"false":"true",e),e.on("change:isReadOnly",((i,n,s)=>{t.setAttribute("contenteditable",s?"false":"true",e)})),e.on("change:isFocused",((i,n,s)=>{s?t.addClass("ck-editor__nested-editable_focused",e):t.removeClass("ck-editor__nested-editable_focused",e)})),lf(e,t),e}function df(e,t){const i=e.getSelectedElement();if(i){const n=gf(e);if(n)return t.createRange(t.createPositionAt(i,n))}return Wd(e,t)}function hf(){return null}const uf="widget-type-around";function mf(e,t,i){return!!e&&sf(e)&&!i.isInline(t)}function gf(e){return e.getAttribute(uf)}const ff=["before","after"],pf=(new DOMParser).parseFromString('',"image/svg+xml").firstChild,bf="ck-widget__type-around_disabled";class wf extends io{constructor(){super(...arguments),this._currentFakeCaretModelElement=null}static get pluginName(){return"WidgetTypeAround"}static get requires(){return[qg,bg]}init(){const e=this.editor,t=e.editing.view;this.on("change:isEnabled",((i,n,s)=>{t.change((e=>{for(const i of t.document.roots)s?e.removeClass(bf,i):e.addClass(bf,i)})),s||e.model.change((e=>{e.removeSelectionAttribute(uf)}))})),this._enableTypeAroundUIInjection(),this._enableInsertingParagraphsOnButtonClick(),this._enableInsertingParagraphsOnEnterKeypress(),this._enableInsertingParagraphsOnTypingKeystroke(),this._enableTypeAroundFakeCaretActivationUsingKeyboardArrows(),this._enableDeleteIntegration(),this._enableInsertContentIntegration(),this._enableInsertObjectIntegration(),this._enableDeleteContentIntegration()}destroy(){super.destroy(),this._currentFakeCaretModelElement=null}_insertParagraph(e,t){const i=this.editor,n=i.editing.view,s=i.model.schema.getAttributesWithProperty(e,"copyOnReplace",!0);i.execute("insertParagraph",{position:i.model.createPositionAt(e,t),attributes:s}),n.focus(),n.scrollToTheSelection()}_listenToIfEnabled(e,t,i,n){this.listenTo(e,t,((...e)=>{this.isEnabled&&i(...e)}),n)}_insertParagraphAccordingToFakeCaretPosition(){const e=this.editor.model.document.selection,t=gf(e);if(!t)return!1;const i=e.getSelectedElement();return this._insertParagraph(i,t),!0}_enableTypeAroundUIInjection(){const e=this.editor,t=e.model.schema,i=e.locale.t,n={before:i("Insert paragraph before block"),after:i("Insert paragraph after block")};e.editing.downcastDispatcher.on("insert",((e,s,o)=>{const r=o.mapper.toViewElement(s.item);r&&mf(r,s.item,t)&&(!function(e,t,i){const n=e.createUIElement("div",{class:"ck ck-reset_all ck-widget__type-around"},(function(e){const i=this.toDomElement(e);return function(e,t){for(const i of ff){const n=new jn({tag:"div",attributes:{class:["ck","ck-widget__type-around__button",`ck-widget__type-around__button_${i}`],title:t[i],"aria-hidden":"true"},children:[e.ownerDocument.importNode(pf,!0)]});e.appendChild(n.render())}}(i,t),function(e){const t=new jn({tag:"div",attributes:{class:["ck","ck-widget__type-around__fake-caret"]}});e.appendChild(t.render())}(i),i}));e.insert(e.createPositionAt(i,"end"),n)}(o.writer,n,r),r.getCustomProperty("widgetLabel").push((()=>this.isEnabled?i("Press Enter to type after or press Shift + Enter to type before the widget"):"")))}),{priority:"low"})}_enableTypeAroundFakeCaretActivationUsingKeyboardArrows(){const e=this.editor,t=e.model,i=t.document.selection,n=t.schema,s=e.editing.view;function o(e){return`ck-widget_type-around_show-fake-caret_${e}`}this._listenToIfEnabled(s.document,"arrowKey",((e,t)=>{this._handleArrowKeyPress(e,t)}),{context:[sf,"$text"],priority:"high"}),this._listenToIfEnabled(i,"change:range",((t,i)=>{i.directChange&&e.model.change((e=>{e.removeSelectionAttribute(uf)}))})),this._listenToIfEnabled(t.document,"change:data",(()=>{const t=i.getSelectedElement();t&&mf(e.editing.mapper.toViewElement(t),t,n)||e.model.change((e=>{e.removeSelectionAttribute(uf)}))})),this._listenToIfEnabled(e.editing.downcastDispatcher,"selection",((e,t,i)=>{const s=i.writer;if(this._currentFakeCaretModelElement){const e=i.mapper.toViewElement(this._currentFakeCaretModelElement);e&&(s.removeClass(ff.map(o),e),this._currentFakeCaretModelElement=null)}const r=t.selection.getSelectedElement();if(!r)return;const a=i.mapper.toViewElement(r);if(!mf(a,r,n))return;const l=gf(t.selection);l&&(s.addClass(o(l),a),this._currentFakeCaretModelElement=r)})),this._listenToIfEnabled(e.ui.focusTracker,"change:isFocused",((t,i,n)=>{n||e.model.change((e=>{e.removeSelectionAttribute(uf)}))}))}_handleArrowKeyPress(e,t){const i=this.editor,n=i.model,s=n.document.selection,o=n.schema,r=i.editing.view,a=function(e,t){const i=Sn(e,t);return"down"===i||"right"===i}(t.keyCode,i.locale.contentLanguageDirection),l=r.document.selection.getSelectedElement();let c;mf(l,i.editing.mapper.toModelElement(l),o)?c=this._handleArrowKeyPressOnSelectedWidget(a):s.isCollapsed?c=this._handleArrowKeyPressWhenSelectionNextToAWidget(a):t.shiftKey||(c=this._handleArrowKeyPressWhenNonCollapsedSelection(a)),c&&(t.preventDefault(),e.stop())}_handleArrowKeyPressOnSelectedWidget(e){const t=this.editor.model,i=gf(t.document.selection);return t.change((t=>i?i!==(e?"after":"before")&&(t.removeSelectionAttribute(uf),!0):(t.setSelectionAttribute(uf,e?"after":"before"),!0)))}_handleArrowKeyPressWhenSelectionNextToAWidget(e){const t=this.editor,i=t.model,n=i.schema,s=t.plugins.get("Widget"),o=s._getObjectElementNextToSelection(e);return!!mf(t.editing.mapper.toViewElement(o),o,n)&&(i.change((t=>{s._setSelectionOverElement(o),t.setSelectionAttribute(uf,e?"before":"after")})),!0)}_handleArrowKeyPressWhenNonCollapsedSelection(e){const t=this.editor,i=t.model,n=i.schema,s=t.editing.mapper,o=i.document.selection,r=e?o.getLastPosition().nodeBefore:o.getFirstPosition().nodeAfter;return!!mf(s.toViewElement(r),r,n)&&(i.change((t=>{t.setSelection(r,"on"),t.setSelectionAttribute(uf,e?"after":"before")})),!0)}_enableInsertingParagraphsOnButtonClick(){const e=this.editor,t=e.editing.view;this._listenToIfEnabled(t.document,"mousedown",((i,n)=>{const s=n.domTarget.closest(".ck-widget__type-around__button");if(!s)return;const o=s.classList.contains("ck-widget__type-around__button_before")?"before":"after",r=function(e,t){const i=e.closest(".ck-widget");return t.mapDomToView(i)}(s,t.domConverter),a=e.editing.mapper.toModelElement(r);this._insertParagraph(a,o),n.preventDefault(),i.stop()}))}_enableInsertingParagraphsOnEnterKeypress(){const e=this.editor,t=e.model.document.selection,i=e.editing.view;this._listenToIfEnabled(i.document,"enter",((i,n)=>{if("atTarget"!=i.eventPhase)return;const s=t.getSelectedElement(),o=e.editing.mapper.toViewElement(s),r=e.model.schema;let a;this._insertParagraphAccordingToFakeCaretPosition()?a=!0:mf(o,s,r)&&(this._insertParagraph(s,n.isSoft?"before":"after"),a=!0),a&&(n.preventDefault(),i.stop())}),{context:sf})}_enableInsertingParagraphsOnTypingKeystroke(){const e=this.editor.editing.view.document;this._listenToIfEnabled(e,"insertText",((t,i)=>{this._insertParagraphAccordingToFakeCaretPosition()&&(i.selection=e.selection)}),{priority:"high"}),l.isAndroid?this._listenToIfEnabled(e,"keydown",((e,t)=>{229==t.keyCode&&this._insertParagraphAccordingToFakeCaretPosition()})):this._listenToIfEnabled(e,"compositionstart",(()=>{this._insertParagraphAccordingToFakeCaretPosition()}),{priority:"high"})}_enableDeleteIntegration(){const e=this.editor,t=e.editing.view,i=e.model,n=i.schema;this._listenToIfEnabled(t.document,"delete",((t,s)=>{if("atTarget"!=t.eventPhase)return;const o=gf(i.document.selection);if(!o)return;const r=s.direction,a=i.document.selection.getSelectedElement(),l="forward"==r;if("before"===o===l)e.execute("delete",{selection:i.createSelection(a,"on")});else{const t=n.getNearestSelectionRange(i.createPositionAt(a,o),r);if(t)if(t.isCollapsed){const s=i.createSelection(t.start);if(i.modifySelection(s,{direction:r}),s.focus.isEqual(t.start)){const e=function(e,t){let i=t;for(const n of t.getAncestors({parentFirst:!0})){if(n.childCount>1||e.isLimit(n))break;i=n}return i}(n,t.start.parent);i.deleteContent(i.createSelection(e,"on"),{doNotAutoparagraph:!0})}else i.change((i=>{i.setSelection(t),e.execute(l?"deleteForward":"delete")}))}else i.change((i=>{i.setSelection(t),e.execute(l?"deleteForward":"delete")}))}s.preventDefault(),t.stop()}),{context:sf})}_enableInsertContentIntegration(){const e=this.editor,t=this.editor.model,i=t.document.selection;this._listenToIfEnabled(e.model,"insertContent",((e,[n,s])=>{if(s&&!s.is("documentSelection"))return;const o=gf(i);return o?(e.stop(),t.change((e=>{const s=i.getSelectedElement(),r=t.createPositionAt(s,o),a=e.createSelection(r),l=t.insertContent(n,a);return e.setSelection(a),l}))):void 0}),{priority:"high"})}_enableInsertObjectIntegration(){const e=this.editor,t=this.editor.model.document.selection;this._listenToIfEnabled(e.model,"insertObject",((e,i)=>{const[,n,s={}]=i;if(n&&!n.is("documentSelection"))return;const o=gf(t);o&&(s.findOptimalPosition=o,i[3]=s)}),{priority:"high"})}_enableDeleteContentIntegration(){const e=this.editor,t=this.editor.model.document.selection;this._listenToIfEnabled(e.model,"deleteContent",((e,[i])=>{i&&!i.is("documentSelection")||gf(t)&&e.stop()}),{priority:"high"})}}function vf(e,t,i){const n=e.schema,s=e.createRangeIn(t.root),o="forward"==i?"elementStart":"elementEnd";for(const{previousPosition:e,item:r,type:a}of s.getWalker({startPosition:t,direction:i})){if(n.isLimit(r)&&!n.isInline(r))return e;if(a==o&&n.isBlock(r))return null}return null}function _f(e,t,i){const n="backward"==i?t.end:t.start;if(e.checkChild(n,"$text"))return n;for(const{nextPosition:n}of t.getWalker({direction:i}))if(e.checkChild(n,"$text"))return n;return null}class yf extends io{constructor(){super(...arguments),this._previouslySelected=new Set}static get pluginName(){return"Widget"}static get requires(){return[wf,bg]}init(){const e=this.editor,t=e.editing.view,i=t.document;this.editor.editing.downcastDispatcher.on("selection",((t,i,n)=>{const s=n.writer,o=i.selection;if(o.isCollapsed)return;const r=o.getSelectedElement();if(!r)return;const a=e.editing.mapper.toViewElement(r);var l;sf(a)&&n.consumable.consume(o,"selection")&&s.setSelection(s.createRangeOn(a),{fake:!0,label:(l=a,l.getCustomProperty("widgetLabel").reduce(((e,t)=>"function"==typeof t?e?e+". "+t():t():e?e+". "+t:t),""))})})),this.editor.editing.downcastDispatcher.on("selection",((e,t,i)=>{this._clearPreviouslySelectedWidgets(i.writer);const n=i.writer,s=n.document.selection;let o=null;for(const e of s.getRanges())for(const t of e){const e=t.item;sf(e)&&(r=e,!(a=o)||!Array.from(r.getAncestors()).includes(a))&&(n.addClass(nf,e),this._previouslySelected.add(e),o=e)}var r,a}),{priority:"low"}),t.addObserver(Yd),this.listenTo(i,"mousedown",((...e)=>this._onMousedown(...e))),this.listenTo(i,"arrowKey",((...e)=>{this._handleSelectionChangeOnArrowKeyPress(...e)}),{context:[sf,"$text"]}),this.listenTo(i,"arrowKey",((...e)=>{this._preventDefaultOnArrowKeyPress(...e)}),{context:"$root"}),this.listenTo(i,"arrowKey",function(e){const t=e.model;return(i,n)=>{const s=n.keyCode==Cn.arrowup,o=n.keyCode==Cn.arrowdown,r=n.shiftKey,a=t.document.selection;if(!s&&!o)return;const l=o;if(r&&function(e,t){return!e.isCollapsed&&e.isBackward==t}(a,l))return;const c=function(e,t,i){const n=e.model;if(i){const e=t.isCollapsed?t.focus:t.getLastPosition(),i=vf(n,e,"forward");if(!i)return null;const s=n.createRange(e,i),o=_f(n.schema,s,"backward");return o?n.createRange(e,o):null}{const e=t.isCollapsed?t.focus:t.getFirstPosition(),i=vf(n,e,"backward");if(!i)return null;const s=n.createRange(i,e),o=_f(n.schema,s,"forward");return o?n.createRange(o,e):null}}(e,a,l);if(c){if(c.isCollapsed){if(a.isCollapsed)return;if(r)return}(c.isCollapsed||function(e,t,i){const n=e.model,s=e.view.domConverter;if(i){const e=n.createSelection(t.start);n.modifySelection(e),e.focus.isAtEnd||t.start.isEqual(e.focus)||(t=n.createRange(e.focus,t.end))}const o=e.mapper.toViewRange(t),r=s.viewRangeToDom(o),a=Ki.getDomRangeRects(r);let l;for(const e of a)if(void 0!==l){if(Math.round(e.top)>=l)return!1;l=Math.max(l,Math.round(e.bottom))}else l=Math.round(e.bottom);return!0}(e,c,l))&&(t.change((e=>{const i=l?c.end:c.start;if(r){const n=t.createSelection(a.anchor);n.setFocus(i),e.setSelection(n)}else e.setSelection(i)})),i.stop(),n.preventDefault(),n.stopPropagation())}}}(this.editor.editing),{context:"$text"}),this.listenTo(i,"delete",((e,t)=>{this._handleDelete("forward"==t.direction)&&(t.preventDefault(),e.stop())}),{context:"$root"})}_onMousedown(e,t){const i=this.editor,n=i.editing.view,s=n.document;let o=t.target;if(function(e){let t=e;for(;t;){if(t.is("editableElement")&&!t.is("rootElement"))return!0;if(sf(t))return!1;t=t.parent}return!1}(o)){if((l.isSafari||l.isGecko)&&t.domEvent.detail>=3){const e=i.editing.mapper,n=o.is("attributeElement")?o.findAncestor((e=>!e.is("attributeElement"))):o,s=e.toModelElement(n);t.preventDefault(),this.editor.model.change((e=>{e.setSelection(s,"in")}))}return}if(!sf(o)&&(o=o.findAncestor(sf),!o))return;l.isAndroid&&t.preventDefault(),s.isFocused||n.focus();const r=i.editing.mapper.toModelElement(o);this._setSelectionOverElement(r)}_handleSelectionChangeOnArrowKeyPress(e,t){const i=t.keyCode,n=this.editor.model,s=n.schema,o=n.document.selection,r=o.getSelectedElement(),a=Sn(i,this.editor.locale.contentLanguageDirection),l="down"==a||"right"==a,c="up"==a||"down"==a;if(r&&s.isObject(r)){const i=l?o.getLastPosition():o.getFirstPosition(),r=s.getNearestSelectionRange(i,l?"forward":"backward");return void(r&&(n.change((e=>{e.setSelection(r)})),t.preventDefault(),e.stop()))}if(!o.isCollapsed&&!t.shiftKey){const i=o.getFirstPosition(),r=o.getLastPosition(),a=i.nodeAfter,c=r.nodeBefore;return void((a&&s.isObject(a)||c&&s.isObject(c))&&(n.change((e=>{e.setSelection(l?r:i)})),t.preventDefault(),e.stop()))}if(!o.isCollapsed)return;const d=this._getObjectElementNextToSelection(l);if(d&&s.isObject(d)){if(s.isInline(d)&&c)return;this._setSelectionOverElement(d),t.preventDefault(),e.stop()}}_preventDefaultOnArrowKeyPress(e,t){const i=this.editor.model,n=i.schema,s=i.document.selection.getSelectedElement();s&&n.isObject(s)&&(t.preventDefault(),e.stop())}_handleDelete(e){const t=this.editor.model.document.selection;if(!this.editor.model.canEditAt(t))return;if(!t.isCollapsed)return;const i=this._getObjectElementNextToSelection(e);return i?(this.editor.model.change((e=>{let n=t.anchor.parent;for(;n.isEmpty;){const t=n;n=t.parent,e.remove(t)}this._setSelectionOverElement(i)})),!0):void 0}_setSelectionOverElement(e){this.editor.model.change((t=>{t.setSelection(t.createRangeOn(e))}))}_getObjectElementNextToSelection(e){const t=this.editor.model,i=t.schema,n=t.document.selection,s=t.createSelection(n);if(t.modifySelection(s,{direction:e?"forward":"backward"}),s.isEqual(n))return null;const o=e?s.focus.nodeBefore:s.focus.nodeAfter;return o&&i.isObject(o)?o:null}_clearPreviouslySelectedWidgets(e){for(const t of this._previouslySelected)e.removeClass(nf,t);this._previouslySelected.clear()}}class kf extends io{constructor(){super(...arguments),this._toolbarDefinitions=new Map}static get requires(){return[Cm]}static get pluginName(){return"WidgetToolbarRepository"}init(){const e=this.editor;if(e.plugins.has("BalloonToolbar")){const t=e.plugins.get("BalloonToolbar");this.listenTo(t,"show",(t=>{(function(e){const t=e.getSelectedElement();return!(!t||!sf(t))})(e.editing.view.document.selection)&&t.stop()}),{priority:"high"})}this._balloon=this.editor.plugins.get("ContextualBalloon"),this.on("change:isEnabled",(()=>{this._updateToolbarsVisibility()})),this.listenTo(e.ui,"update",(()=>{this._updateToolbarsVisibility()})),this.listenTo(e.ui.focusTracker,"change:isFocused",(()=>{this._updateToolbarsVisibility()}),{priority:"low"})}destroy(){super.destroy();for(const e of this._toolbarDefinitions.values())e.view.destroy()}register(e,{ariaLabel:t,items:i,getRelatedElement:n,balloonClassName:s="ck-toolbar-container"}){if(!i.length)return void y("widget-toolbar-no-items",{toolbarId:e});const o=this.editor,r=o.t,a=new Zh(o.locale);if(a.ariaLabel=t||r("Widget toolbar"),this._toolbarDefinitions.has(e))throw new _("widget-toolbar-duplicated",this,{toolbarId:e});const l={view:a,getRelatedElement:n,balloonClassName:s,itemsConfig:i,initialized:!1};o.ui.addToolbar(a,{isContextual:!0,beforeFocus:()=>{const e=n(o.editing.view.document.selection);e&&this._showToolbar(l,e)},afterBlur:()=>{this._hideToolbar(l)}}),this._toolbarDefinitions.set(e,l)}_updateToolbarsVisibility(){let e=0,t=null,i=null;for(const n of this._toolbarDefinitions.values()){const s=n.getRelatedElement(this.editor.editing.view.document.selection);if(this.isEnabled&&s)if(this.editor.ui.focusTracker.isFocused){const o=s.getAncestors().length;o>e&&(e=o,t=s,i=n)}else this._isToolbarVisible(n)&&this._hideToolbar(n);else this._isToolbarInBalloon(n)&&this._hideToolbar(n)}i&&this._showToolbar(i,t)}_hideToolbar(e){this._balloon.remove(e.view),this.stopListening(this._balloon,"change:visibleView")}_showToolbar(e,t){this._isToolbarVisible(e)?Cf(this.editor,t):this._isToolbarInBalloon(e)||(e.initialized||(e.initialized=!0,e.view.fillFromConfig(e.itemsConfig,this.editor.ui.componentFactory)),this._balloon.add({view:e.view,position:Af(this.editor,t),balloonClassName:e.balloonClassName}),this.listenTo(this._balloon,"change:visibleView",(()=>{for(const e of this._toolbarDefinitions.values())if(this._isToolbarVisible(e)){const t=e.getRelatedElement(this.editor.editing.view.document.selection);Cf(this.editor,t)}})))}_isToolbarVisible(e){return this._balloon.visibleView===e.view}_isToolbarInBalloon(e){return this._balloon.hasView(e.view)}}function Cf(e,t){const i=e.plugins.get("ContextualBalloon"),n=Af(e,t);i.updatePosition(n)}function Af(e,t){const i=e.editing.view,n=tm.defaultPositions;return{target:i.domConverter.mapViewToDom(t),positions:[n.northArrowSouth,n.northArrowSouthWest,n.northArrowSouthEast,n.southArrowNorth,n.southArrowNorthWest,n.southArrowNorthEast,n.viewportStickyNorth]}}class xf extends(W()){constructor(e){super(),this.set("activeHandlePosition",null),this.set("proposedWidthPercents",null),this.set("proposedWidth",null),this.set("proposedHeight",null),this.set("proposedHandleHostWidth",null),this.set("proposedHandleHostHeight",null),this._options=e,this._referenceCoordinates=null}get originalWidth(){return this._originalWidth}get originalHeight(){return this._originalHeight}get originalWidthPercents(){return this._originalWidthPercents}get aspectRatio(){return this._aspectRatio}begin(e,t,i){const n=new Ki(t);this.activeHandlePosition=function(e){const t=["top-left","top-right","bottom-right","bottom-left"];for(const i of t)if(e.classList.contains(`ck-widget__resizer__handle-${i}`))return i}(e),this._referenceCoordinates=function(e,t){const i=new Ki(e),n=t.split("-"),s={x:"right"==n[1]?i.right:i.left,y:"bottom"==n[0]?i.bottom:i.top};return s.x+=e.ownerDocument.defaultView.scrollX,s.y+=e.ownerDocument.defaultView.scrollY,s}(t,function(e){const t=e.split("-"),i={top:"bottom",bottom:"top",left:"right",right:"left"};return`${i[t[0]]}-${i[t[1]]}`}(this.activeHandlePosition)),this._originalWidth=n.width,this._originalHeight=n.height,this._aspectRatio=n.width/n.height;const s=i.style.width;s&&s.match(/^\d+(\.\d*)?%$/)?this._originalWidthPercents=parseFloat(s):this._originalWidthPercents=function(e,t){const i=e.parentElement;let n=parseFloat(i.ownerDocument.defaultView.getComputedStyle(i).width);let s=0,o=i;for(;isNaN(n);){if(o=o.parentElement,++s>5)return 0;n=parseFloat(i.ownerDocument.defaultView.getComputedStyle(o).width)}return t.width/n*100}(i,n)}update(e){this.proposedWidth=e.width,this.proposedHeight=e.height,this.proposedWidthPercents=e.widthPercents,this.proposedHandleHostWidth=e.handleHostWidth,this.proposedHandleHostHeight=e.handleHostHeight}}class Tf extends Un{constructor(){super();const e=this.bindTemplate;this.setTemplate({tag:"div",attributes:{class:["ck","ck-size-view",e.to("_viewPosition",(e=>e?`ck-orientation-${e}`:""))],style:{display:e.if("_isVisible","none",(e=>!e))}},children:[{text:e.to("_label")}]})}_bindToState(e,t){this.bind("_isVisible").to(t,"proposedWidth",t,"proposedHeight",((e,t)=>null!==e&&null!==t)),this.bind("_label").to(t,"proposedHandleHostWidth",t,"proposedHandleHostHeight",t,"proposedWidthPercents",((t,i,n)=>"px"===e.unit?`${t}×${i}`:`${n}%`)),this.bind("_viewPosition").to(t,"activeHandlePosition",t,"proposedHandleHostWidth",t,"proposedHandleHostHeight",((e,t,i)=>t<50||i<50?"above-center":e))}_dismiss(){this.unbind(),this._isVisible=!1}}class Ef extends(W()){constructor(e){super(),this._viewResizerWrapper=null,this._options=e,this.set("isEnabled",!0),this.set("isSelected",!1),this.bind("isVisible").to(this,"isEnabled",this,"isSelected",((e,t)=>e&&t)),this.decorate("begin"),this.decorate("cancel"),this.decorate("commit"),this.decorate("updateSize"),this.on("commit",(e=>{this.state.proposedWidth||this.state.proposedWidthPercents||(this._cleanup(),e.stop())}),{priority:"high"})}get state(){return this._state}show(){this._options.editor.editing.view.change((e=>{e.removeClass("ck-hidden",this._viewResizerWrapper)}))}hide(){this._options.editor.editing.view.change((e=>{e.addClass("ck-hidden",this._viewResizerWrapper)}))}attach(){const e=this,t=this._options.viewElement;this._options.editor.editing.view.change((i=>{const n=i.createUIElement("div",{class:"ck ck-reset_all ck-widget__resizer"},(function(t){const i=this.toDomElement(t);return e._appendHandles(i),e._appendSizeUI(i),i}));i.insert(i.createPositionAt(t,"end"),n),i.addClass("ck-widget_with-resizer",t),this._viewResizerWrapper=n,this.isVisible||this.hide()})),this.on("change:isVisible",(()=>{this.isVisible?(this.show(),this.redraw()):this.hide()}))}begin(e){this._state=new xf(this._options),this._sizeView._bindToState(this._options,this.state),this._initialViewWidth=this._options.viewElement.getStyle("width"),this.state.begin(e,this._getHandleHost(),this._getResizeHost())}updateSize(e){const t=this._proposeNewSize(e);this._options.editor.editing.view.change((e=>{const i=this._options.unit||"%",n=("%"===i?t.widthPercents:t.width)+i;e.setStyle("width",n,this._options.viewElement)}));const i=this._getHandleHost(),n=new Ki(i),s=Math.round(n.width),o=Math.round(n.height),r=new Ki(i);t.width=Math.round(r.width),t.height=Math.round(r.height),this.redraw(n),this.state.update({...t,handleHostWidth:s,handleHostHeight:o})}commit(){const e=this._options.unit||"%",t=("%"===e?this.state.proposedWidthPercents:this.state.proposedWidth)+e;this._options.editor.editing.view.change((()=>{this._cleanup(),this._options.onCommit(t)}))}cancel(){this._cleanup()}destroy(){this.cancel()}redraw(e){const t=this._domResizerWrapper;if(!((i=t)&&i.ownerDocument&&i.ownerDocument.contains(i)))return;var i;const n=t.parentElement,s=this._getHandleHost(),o=this._viewResizerWrapper,r=[o.getStyle("width"),o.getStyle("height"),o.getStyle("left"),o.getStyle("top")];let a;if(n.isSameNode(s)){const t=e||new Ki(s);a=[t.width+"px",t.height+"px",void 0,void 0]}else a=[s.offsetWidth+"px",s.offsetHeight+"px",s.offsetLeft+"px",s.offsetTop+"px"];"same"!==Z(r,a)&&this._options.editor.editing.view.change((e=>{e.setStyle({width:a[0],height:a[1],left:a[2],top:a[3]},o)}))}containsHandle(e){return this._domResizerWrapper.contains(e)}static isResizeHandle(e){return e.classList.contains("ck-widget__resizer__handle")}_cleanup(){this._sizeView._dismiss(),this._options.editor.editing.view.change((e=>{e.setStyle("width",this._initialViewWidth,this._options.viewElement)}))}_proposeNewSize(e){const t=this.state,i=(s=e).pageX,n=s.pageY;var s;const o=!this._options.isCentered||this._options.isCentered(this),r={x:t._referenceCoordinates.x-(i+t.originalWidth),y:n-t.originalHeight-t._referenceCoordinates.y};o&&t.activeHandlePosition.endsWith("-right")&&(r.x=i-(t._referenceCoordinates.x+t.originalWidth)),o&&(r.x*=2);let a=Math.abs(t.originalWidth+r.x),l=Math.abs(t.originalHeight+r.y);return"width"==(a/t.aspectRatio>l?"width":"height")?l=a/t.aspectRatio:a=l*t.aspectRatio,{width:Math.round(a),height:Math.round(l),widthPercents:Math.min(Math.round(t.originalWidthPercents/t.originalWidth*a*100)/100,100)}}_getResizeHost(){const e=this._domResizerWrapper.parentElement;return this._options.getResizeHost(e)}_getHandleHost(){const e=this._domResizerWrapper.parentElement;return this._options.getHandleHost(e)}get _domResizerWrapper(){return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper)}_appendHandles(e){const t=["top-left","top-right","bottom-right","bottom-left"];for(const n of t)e.appendChild(new jn({tag:"div",attributes:{class:"ck-widget__resizer__handle "+(i=n,`ck-widget__resizer__handle-${i}`)}}).render());var i}_appendSizeUI(e){this._sizeView=new Tf,this._sizeView.render(),e.appendChild(this._sizeView.element)}}class Sf extends io{constructor(){super(...arguments),this._resizers=new Map}static get pluginName(){return"WidgetResize"}init(){const e=this.editor.editing,t=$i.window.document;this.set("selectedResizer",null),this.set("_activeResizer",null),e.view.addObserver(Yd),this._observer=new(Fi()),this.listenTo(e.view.document,"mousedown",this._mouseDownListener.bind(this),{priority:"high"}),this._observer.listenTo(t,"mousemove",this._mouseMoveListener.bind(this)),this._observer.listenTo(t,"mouseup",this._mouseUpListener.bind(this)),this._redrawSelectedResizerThrottled=am((()=>this.redrawSelectedResizer()),200),this.editor.ui.on("update",this._redrawSelectedResizerThrottled),this.editor.model.document.on("change",(()=>{for(const[e,t]of this._resizers)e.isAttached()||(this._resizers.delete(e),t.destroy())}),{priority:"lowest"}),this._observer.listenTo($i.window,"resize",this._redrawSelectedResizerThrottled);const i=this.editor.editing.view.document.selection;i.on("change",(()=>{const e=i.getSelectedElement(),t=this.getResizerByViewElement(e)||null;t?this.select(t):this.deselect()}))}redrawSelectedResizer(){this.selectedResizer&&this.selectedResizer.isVisible&&this.selectedResizer.redraw()}destroy(){super.destroy(),this._observer.stopListening();for(const e of this._resizers.values())e.destroy();this._redrawSelectedResizerThrottled.cancel()}select(e){this.deselect(),this.selectedResizer=e,this.selectedResizer.isSelected=!0}deselect(){this.selectedResizer&&(this.selectedResizer.isSelected=!1),this.selectedResizer=null}attachTo(e){const t=new Ef(e),i=this.editor.plugins;if(t.attach(),i.has("WidgetToolbarRepository")){const e=i.get("WidgetToolbarRepository");t.on("begin",(()=>{e.forceDisabled("resize")}),{priority:"lowest"}),t.on("cancel",(()=>{e.clearForceDisabled("resize")}),{priority:"highest"}),t.on("commit",(()=>{e.clearForceDisabled("resize")}),{priority:"highest"})}this._resizers.set(e.viewElement,t);const n=this.editor.editing.view.document.selection.getSelectedElement();return this.getResizerByViewElement(n)==t&&this.select(t),t}getResizerByViewElement(e){return this._resizers.get(e)}_getResizerByHandle(e){for(const t of this._resizers.values())if(t.containsHandle(e))return t}_mouseDownListener(e,t){const i=t.domTarget;Ef.isResizeHandle(i)&&(this._activeResizer=this._getResizerByHandle(i)||null,this._activeResizer&&(this._activeResizer.begin(i),e.stop(),t.preventDefault()))}_mouseMoveListener(e,t){this._activeResizer&&this._activeResizer.updateSize(t)}_mouseUpListener(){this._activeResizer&&(this._activeResizer.commit(),this._activeResizer=null)}}const Pf=en("px");class If extends Un{constructor(){super();const e=this.bindTemplate;this.set({isVisible:!1,left:null,top:null,width:null}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-clipboard-drop-target-line",e.if("isVisible","ck-hidden",(e=>!e))],style:{left:e.to("left",(e=>Pf(e))),top:e.to("top",(e=>Pf(e))),width:e.to("width",(e=>Pf(e)))}}})}}class Vf extends io{constructor(){super(...arguments),this.removeDropMarkerDelayed=Fn((()=>this.removeDropMarker()),40),this._updateDropMarkerThrottled=am((e=>this._updateDropMarker(e)),40),this._reconvertMarkerThrottled=am((()=>{this.editor.model.markers.has("drop-target")&&this.editor.editing.reconvertMarker("drop-target")}),0),this._dropTargetLineView=new If,this._domEmitter=new(Fi()),this._scrollables=new Map}static get pluginName(){return"DragDropTarget"}init(){this._setupDropMarker()}destroy(){this._domEmitter.stopListening();for(const{resizeObserver:e}of this._scrollables.values())e.destroy();return this._updateDropMarkerThrottled.cancel(),this.removeDropMarkerDelayed.cancel(),this._reconvertMarkerThrottled.cancel(),super.destroy()}updateDropMarker(e,t,i,n,s){this.removeDropMarkerDelayed.cancel();const o=Rf(this.editor,e,t,i,n,s);o&&this._updateDropMarkerThrottled(o)}getFinalDropRange(e,t,i,n,s){const o=Rf(this.editor,e,t,i,n,s);return this.removeDropMarker(),o}removeDropMarker(){const e=this.editor.model;this.removeDropMarkerDelayed.cancel(),this._updateDropMarkerThrottled.cancel(),this._dropTargetLineView.isVisible=!1,e.markers.has("drop-target")&&e.change((e=>{e.removeMarker("drop-target")}))}_setupDropMarker(){const e=this.editor;e.ui.view.body.add(this._dropTargetLineView),e.conversion.for("editingDowncast").markerToHighlight({model:"drop-target",view:{classes:["ck-clipboard-drop-target-range"]}}),e.conversion.for("editingDowncast").markerToElement({model:"drop-target",view:(t,{writer:i})=>{if(e.model.schema.checkChild(t.markerRange.start,"$text"))return this._dropTargetLineView.isVisible=!1,this._createDropTargetPosition(i);t.markerRange.isCollapsed?this._updateDropTargetLine(t.markerRange):this._dropTargetLineView.isVisible=!1}})}_updateDropMarker(e){const t=this.editor,i=t.model.markers;t.model.change((t=>{i.has("drop-target")?i.get("drop-target").getRange().isEqual(e)||t.updateMarker("drop-target",{range:e}):t.addMarker("drop-target",{range:e,usingOperation:!1,affectsData:!1})}))}_createDropTargetPosition(e){return e.createUIElement("span",{class:"ck ck-clipboard-drop-target-position"},(function(e){const t=this.toDomElement(e);return t.append("⁠",e.createElement("span"),"⁠"),t}))}_updateDropTargetLine(e){const t=this.editor.editing,i=e.start.nodeBefore,n=e.start.nodeAfter,s=e.start.parent,o=i?t.mapper.toViewElement(i):null,r=o?t.view.domConverter.mapViewToDom(o):null,a=n?t.mapper.toViewElement(n):null,l=a?t.view.domConverter.mapViewToDom(a):null,c=t.mapper.toViewElement(s),d=t.view.domConverter.mapViewToDom(c),h=this._getScrollableRect(c),{scrollX:u,scrollY:m}=$i.window,g=r?new Ki(r):null,f=l?new Ki(l):null,p=new Ki(d).excludeScrollbarsAndBorders(),b=g?g.bottom:p.top,w=f?f.top:p.bottom,v=$i.window.getComputedStyle(d),_=b<=w?(b+w)/2:w;if(h.top<_&&_t.is("element")&&!Lf(e,t)));let i=0,o=t.length;if(0==o)return r.createRange(r.createPositionAt(l,"end"));for(;i{i?(this.forceDisabled("readOnlyMode"),this._isBlockDragging=!1):this.clearForceDisabled("readOnlyMode")})),l.isAndroid&&this.forceDisabled("noAndroidSupport"),e.plugins.has("BlockToolbar")){const t=e.plugins.get("BlockToolbar").buttonView.element;this._domEmitter.listenTo(t,"dragstart",((e,t)=>this._handleBlockDragStart(t))),this._domEmitter.listenTo($i.document,"dragover",((e,t)=>this._handleBlockDragging(t))),this._domEmitter.listenTo($i.document,"drop",((e,t)=>this._handleBlockDragging(t))),this._domEmitter.listenTo($i.document,"dragend",(()=>this._handleBlockDragEnd()),{useCapture:!0}),this.isEnabled&&t.setAttribute("draggable","true"),this.on("change:isEnabled",((e,i,n)=>{t.setAttribute("draggable",n?"true":"false")}))}}destroy(){return this._domEmitter.stopListening(),super.destroy()}_handleBlockDragStart(e){if(!this.isEnabled)return;const t=this.editor.model,i=t.document.selection,n=this.editor.editing.view,s=Array.from(i.getSelectedBlocks()),o=t.createRange(t.createPositionBefore(s[0]),t.createPositionAfter(s[s.length-1]));t.change((e=>e.setSelection(o))),this._isBlockDragging=!0,n.focus(),n.getObserver(Ng).onDomEvent(e)}_handleBlockDragging(e){if(!this.isEnabled||!this._isBlockDragging)return;const t=e.clientX+("ltr"==this.editor.locale.contentLanguageDirection?100:-100),i=e.clientY,n=document.elementFromPoint(t,i),s=this.editor.editing.view;n&&n.closest(".ck-editor__editable")&&s.getObserver(Ng).onDomEvent({...e,type:e.type,dataTransfer:e.dataTransfer,target:n,clientX:t,clientY:i,preventDefault:()=>e.preventDefault(),stopPropagation:()=>e.stopPropagation()})}_handleBlockDragEnd(){this._isBlockDragging=!1}}class Ff extends io{constructor(){super(...arguments),this._clearDraggableAttributesDelayed=Fn((()=>this._clearDraggableAttributes()),40),this._blockMode=!1,this._domEmitter=new(Fi())}static get pluginName(){return"DragDrop"}static get requires(){return[zg,yf,Vf,Nf]}init(){const e=this.editor,t=e.editing.view;this._draggedRange=null,this._draggingUid="",this._draggableElement=null,t.addObserver(Ng),t.addObserver(Yd),this._setupDragging(),this._setupContentInsertionIntegration(),this._setupClipboardInputIntegration(),this._setupDraggableAttributeHandling(),this.listenTo(e,"change:isReadOnly",((e,t,i)=>{i?this.forceDisabled("readOnlyMode"):this.clearForceDisabled("readOnlyMode")})),this.on("change:isEnabled",((e,t,i)=>{i||this._finalizeDragging(!1)})),l.isAndroid&&this.forceDisabled("noAndroidSupport")}destroy(){return this._draggedRange&&(this._draggedRange.detach(),this._draggedRange=null),this._previewContainer&&this._previewContainer.remove(),this._domEmitter.stopListening(),this._clearDraggableAttributesDelayed.cancel(),super.destroy()}_setupDragging(){const e=this.editor,t=e.model,i=e.editing.view,n=i.document,s=e.plugins.get(Vf);this.listenTo(n,"dragstart",((e,i)=>{if(i.target&&i.target.is("editableElement"))return void i.preventDefault();if(this._prepareDraggedRange(i.target),!this._draggedRange)return void i.preventDefault();this._draggingUid=p(),i.dataTransfer.effectAllowed=this.isEnabled?"copyMove":"copy",i.dataTransfer.setData("application/ckeditor5-dragging-uid",this._draggingUid);const n=t.createSelection(this._draggedRange.toRange());this.editor.plugins.get("ClipboardPipeline")._fireOutputTransformationEvent(i.dataTransfer,n,"dragstart");const{dataTransfer:s,domTarget:o,domEvent:r}=i,{clientX:a}=r;this._updatePreview({dataTransfer:s,domTarget:o,clientX:a}),i.stopPropagation(),this.isEnabled||(this._draggedRange.detach(),this._draggedRange=null,this._draggingUid="")}),{priority:"low"}),this.listenTo(n,"dragend",((e,t)=>{this._finalizeDragging(!t.dataTransfer.isCanceled&&"move"==t.dataTransfer.dropEffect)}),{priority:"low"}),this._domEmitter.listenTo($i.document,"dragend",(()=>{this._blockMode=!1}),{useCapture:!0}),this.listenTo(n,"dragenter",(()=>{this.isEnabled&&i.focus()})),this.listenTo(n,"dragleave",(()=>{s.removeDropMarkerDelayed()})),this.listenTo(n,"dragging",((e,t)=>{if(!this.isEnabled)return void(t.dataTransfer.dropEffect="none");const{clientX:i,clientY:n}=t.domEvent;s.updateDropMarker(t.target,t.targetRanges,i,n,this._blockMode),this._draggedRange||(t.dataTransfer.dropEffect="copy"),l.isGecko||("copy"==t.dataTransfer.effectAllowed?t.dataTransfer.dropEffect="copy":["all","copyMove"].includes(t.dataTransfer.effectAllowed)&&(t.dataTransfer.dropEffect="move")),e.stop()}),{priority:"low"})}_setupClipboardInputIntegration(){const e=this.editor,t=e.editing.view.document,i=e.plugins.get(Vf);this.listenTo(t,"clipboardInput",((t,n)=>{if("drop"!=n.method)return;const{clientX:s,clientY:o}=n.domEvent,r=i.getFinalDropRange(n.target,n.targetRanges,s,o,this._blockMode);return r?(this._draggedRange&&this._draggingUid!=n.dataTransfer.getData("application/ckeditor5-dragging-uid")&&(this._draggedRange.detach(),this._draggedRange=null,this._draggingUid=""),"move"==Df(n.dataTransfer)&&this._draggedRange&&this._draggedRange.containsRange(r,!0)?(this._finalizeDragging(!1),void t.stop()):void(n.targetRanges=[e.editing.mapper.toViewRange(r)])):(this._finalizeDragging(!1),void t.stop())}),{priority:"high"})}_setupContentInsertionIntegration(){const e=this.editor.plugins.get(zg);e.on("contentInsertion",((e,t)=>{if(!this.isEnabled||"drop"!==t.method)return;const i=t.targetRanges.map((e=>this.editor.editing.mapper.toModelRange(e)));this.editor.model.change((e=>e.setSelection(i)))}),{priority:"high"}),e.on("contentInsertion",((e,t)=>{if(!this.isEnabled||"drop"!==t.method)return;const i="move"==Df(t.dataTransfer),n=!t.resultRange||!t.resultRange.isCollapsed;this._finalizeDragging(n&&i)}),{priority:"lowest"})}_setupDraggableAttributeHandling(){const e=this.editor,t=e.editing.view,i=t.document;this.listenTo(i,"mousedown",((n,s)=>{if(l.isAndroid||!s)return;this._clearDraggableAttributesDelayed.cancel();let o=zf(s.target);if(l.isBlink&&!e.isReadOnly&&!o&&!i.selection.isCollapsed){const e=i.selection.getSelectedElement();e&&sf(e)||(o=i.selection.editableElement)}o&&(t.change((e=>{e.setAttribute("draggable","true",o)})),this._draggableElement=e.editing.mapper.toModelElement(o))})),this.listenTo(i,"mouseup",(()=>{l.isAndroid||this._clearDraggableAttributesDelayed()}))}_clearDraggableAttributes(){const e=this.editor.editing;e.view.change((t=>{this._draggableElement&&"$graveyard"!=this._draggableElement.root.rootName&&t.removeAttribute("draggable",e.mapper.toViewElement(this._draggableElement)),this._draggableElement=null}))}_finalizeDragging(e){const t=this.editor,i=t.model;t.plugins.get(Vf).removeDropMarker(),this._clearDraggableAttributes(),t.plugins.has("WidgetToolbarRepository")&&t.plugins.get("WidgetToolbarRepository").clearForceDisabled("dragDrop"),this._draggingUid="",this._previewContainer&&(this._previewContainer.remove(),this._previewContainer=void 0),this._draggedRange&&(e&&this.isEnabled&&i.change((e=>{const t=i.createSelection(this._draggedRange);i.deleteContent(t,{doNotAutoparagraph:!0});const n=t.getFirstPosition().parent;n.isEmpty&&!i.schema.checkChild(n,"$text")&&i.schema.checkChild(n,"paragraph")&&e.insertElement("paragraph",n,0)})),this._draggedRange.detach(),this._draggedRange=null)}_prepareDraggedRange(e){const t=this.editor,i=t.model,n=i.document.selection,s=e?zf(e):null;if(s){const e=t.editing.mapper.toModelElement(s);return this._draggedRange=Sl.fromRange(i.createRangeOn(e)),this._blockMode=i.schema.isBlock(e),void(t.plugins.has("WidgetToolbarRepository")&&t.plugins.get("WidgetToolbarRepository").forceDisabled("dragDrop"))}if(n.isCollapsed&&!n.getFirstPosition().parent.isEmpty)return;const o=Array.from(n.getSelectedBlocks()),r=n.getFirstRange();if(0==o.length)return void(this._draggedRange=Sl.fromRange(r));const a=Hf(i,o);if(o.length>1)this._draggedRange=Sl.fromRange(a),this._blockMode=!0;else if(1==o.length){const e=r.start.isTouching(a.start)&&r.end.isTouching(a.end);this._draggedRange=Sl.fromRange(e?a:r),this._blockMode=e}i.change((e=>e.setSelection(this._draggedRange.toRange())))}_updatePreview({dataTransfer:e,domTarget:t,clientX:i}){const n=this.editor.editing.view,s=n.document.selection.editableElement,o=n.domConverter.mapViewToDom(s),r=$i.window.getComputedStyle(o);this._previewContainer?this._previewContainer.firstElementChild&&this._previewContainer.removeChild(this._previewContainer.firstElementChild):(this._previewContainer=me($i.document,"div",{style:"position: fixed; left: -999999px;"}),$i.document.body.appendChild(this._previewContainer));const a=new Ki(o);if(o.contains(t))return;const c=parseFloat(r.paddingLeft),d=me($i.document,"div");d.className="ck ck-content",d.style.width=r.width,d.style.paddingLeft=`${a.left-i+c}px`,l.isiOS&&(d.style.backgroundColor="white"),d.innerHTML=e.getData("text/html"),e.setDragImage(d,0,0),this._previewContainer.appendChild(d)}}function Df(e){return l.isGecko?e.dropEffect:["all","copyMove"].includes(e.effectAllowed)?"move":"copy"}function zf(e){if(e.is("editableElement"))return null;if(e.hasClass("ck-widget__selection-handle"))return e.findAncestor(sf);if(sf(e))return e;const t=e.findAncestor((e=>sf(e)||e.is("editableElement")));return sf(t)?t:null}function Hf(e,t){const i=t[0],n=t[t.length-1],s=i.getCommonAncestor(n),o=e.createPositionBefore(i),r=e.createPositionAfter(n);if(s&&s.is("element")&&!e.schema.isLimit(s)){const t=e.createRangeOn(s),i=o.isTouching(t.start),n=r.isTouching(t.end);if(i&&n)return Hf(e,[s])}return e.createRange(o,r)}class $f extends io{static get pluginName(){return"PastePlainText"}static get requires(){return[zg]}init(){const e=this.editor,t=e.model,i=e.editing.view,n=i.document,s=t.document.selection;let o=!1;i.addObserver(Ng),this.listenTo(n,"keydown",((e,t)=>{o=t.shiftKey})),e.plugins.get(zg).on("contentInsertion",((e,i)=>{(o||function(e,t){if(e.childCount>1)return!1;const i=e.getChild(0);return!t.isObject(i)&&0==Array.from(i.getAttributeKeys()).length}(i.content,t.schema))&&t.change((e=>{const n=Array.from(s.getAttributes()).filter((([e])=>t.schema.getAttributeProperties(e).isFormatting));s.isCollapsed||t.deleteContent(s,{doNotAutoparagraph:!0}),n.push(...s.getAttributes());const o=e.createRangeIn(i.content);for(const t of o.getItems())t.is("$textProxy")&&e.setAttributes(n,t)}))}))}}class Wf extends io{static get pluginName(){return"Clipboard"}static get requires(){return[zg,Ff,$f]}}class Uf extends so{constructor(e){super(e),this._stack=[],this._createdBatches=new WeakSet,this.refresh(),this._isEnabledBasedOnSelection=!1,this.listenTo(e.data,"set",((e,t)=>{t[1]={...t[1]};const i=t[1];i.batchType||(i.batchType={isUndoable:!1})}),{priority:"high"}),this.listenTo(e.data,"set",((e,t)=>{t[1].batchType.isUndoable||this.clearStack()}))}refresh(){this.isEnabled=this._stack.length>0}get createdBatches(){return this._createdBatches}addBatch(e){const t=this.editor.model.document.selection,i={ranges:t.hasOwnRange?Array.from(t.getRanges()):[],isBackward:t.isBackward};this._stack.push({batch:e,selection:i}),this.refresh()}clearStack(){this._stack=[],this.refresh()}_restoreSelection(e,t,i){const n=this.editor.model,s=n.document,o=[],r=e.map((e=>e.getTransformedByOperations(i))),a=r.flat();for(const e of r){const t=e.filter((e=>e.root!=s.graveyard)).filter((e=>!qf(e,a)));t.length&&(jf(t),o.push(t[0]))}o.length&&n.change((e=>{e.setSelection(o,{backward:t})}))}_undo(e,t){const i=this.editor.model,n=i.document;this._createdBatches.add(t);const s=e.operations.slice().filter((e=>e.isDocumentOperation));s.reverse();for(const e of s){const s=e.baseVersion+1,o=Array.from(n.history.getOperations(s)),r=od([e.getReversed()],o,{useRelations:!0,document:this.editor.model.document,padWithNoOps:!1,forceWeakRemove:!0}).operationsA;for(let s of r){const o=s.affectedSelectable;o&&!i.canEditAt(o)&&(s=new Jc(s.baseVersion)),t.addOperation(s),i.applyOperation(s),n.history.setOperationAsUndone(e,s)}}}}function jf(e){e.sort(((e,t)=>e.start.isBefore(t.start)?-1:1));for(let t=1;tt!==e&&t.containsRange(e,!0)))}class Gf extends Uf{execute(e=null){const t=e?this._stack.findIndex((t=>t.batch==e)):this._stack.length-1,i=this._stack.splice(t,1)[0],n=this.editor.model.createBatch({isUndo:!0});this.editor.model.enqueueChange(n,(()=>{this._undo(i.batch,n);const e=this.editor.model.document.history.getOperations(i.batch.baseVersion);this._restoreSelection(i.selection.ranges,i.selection.isBackward,e)})),this.fire("revert",i.batch,n),this.refresh()}}class Kf extends Uf{execute(){const e=this._stack.pop(),t=this.editor.model.createBatch({isUndo:!0});this.editor.model.enqueueChange(t,(()=>{const i=e.batch.operations[e.batch.operations.length-1].baseVersion+1,n=this.editor.model.document.history.getOperations(i);this._restoreSelection(e.selection.ranges,e.selection.isBackward,n),this._undo(e.batch,t)})),this.refresh()}}class Jf extends io{constructor(){super(...arguments),this._batchRegistry=new WeakSet}static get pluginName(){return"UndoEditing"}init(){const e=this.editor;this._undoCommand=new Gf(e),this._redoCommand=new Kf(e),e.commands.add("undo",this._undoCommand),e.commands.add("redo",this._redoCommand),this.listenTo(e.model,"applyOperation",((e,t)=>{const i=t[0];if(!i.isDocumentOperation)return;const n=i.batch,s=this._redoCommand.createdBatches.has(n),o=this._undoCommand.createdBatches.has(n);this._batchRegistry.has(n)||(this._batchRegistry.add(n),n.isUndoable&&(s?this._undoCommand.addBatch(n):o||(this._undoCommand.addBatch(n),this._redoCommand.clearStack())))}),{priority:"highest"}),this.listenTo(this._undoCommand,"revert",((e,t,i)=>{this._redoCommand.addBatch(i)})),e.keystrokes.set("CTRL+Z","undo"),e.keystrokes.set("CTRL+Y","redo"),e.keystrokes.set("CTRL+SHIFT+Z","redo")}}const Qf='',Zf='';class Yf extends io{static get pluginName(){return"UndoUI"}init(){const e=this.editor,t=e.locale,i=e.t,n="ltr"==t.uiLanguageDirection?Qf:Zf,s="ltr"==t.uiLanguageDirection?Zf:Qf;this._addButton("undo",i("Undo"),"CTRL+Z",n),this._addButton("redo",i("Redo"),"CTRL+Y",s)}_addButton(e,t,i,n){const s=this.editor;s.ui.componentFactory.add(e,(o=>{const r=s.commands.get(e),a=new fs(o);return a.set({label:t,icon:n,keystroke:i,tooltip:!0}),a.bind("isEnabled").to(r,"isEnabled"),this.listenTo(a,"execute",(()=>{s.execute(e),s.editing.view.focus()})),a}))}}class Xf extends io{static get requires(){return[Jf,Yf]}static get pluginName(){return"Undo"}}function ep(e){return e.createContainerElement("figure",{class:"image"},[e.createEmptyElement("img"),e.createSlot("children")])}function tp(e,t){const i=e.plugins.get("ImageUtils"),n=e.plugins.has("ImageInlineEditing")&&e.plugins.has("ImageBlockEditing");return e=>i.isInlineImageView(e)?n&&("block"==e.getStyle("display")||e.findAncestor(i.isBlockImageView)?"imageBlock":"imageInline")!==t?null:s(e):null;function s(e){const t={name:!0};return e.hasAttribute("src")&&(t.attributes=["src"]),t}}function ip(e,t){const i=On(t.getSelectedBlocks());return!i||e.isObject(i)||i.isEmpty&&"listItem"!=i.name?"imageBlock":"imageInline"}function np(e){return e&&e.endsWith("px")?parseInt(e):null}function sp(e){const t=np(e.getStyle("width")),i=np(e.getStyle("height"));return!(!t||!i)}const op=/^(image|image-inline)$/;class rp extends io{constructor(){super(...arguments),this._domEmitter=new(Fi())}static get pluginName(){return"ImageUtils"}isImage(e){return this.isInlineImage(e)||this.isBlockImage(e)}isInlineImageView(e){return!!e&&e.is("element","img")}isBlockImageView(e){return!!e&&e.is("element","figure")&&e.hasClass("image")}insertImage(e={},t=null,i=null,n={}){const s=this.editor,o=s.model,r=o.document.selection;i=ap(s,t||r,i),e={...Object.fromEntries(r.getAttributes()),...e};for(const t in e)o.schema.checkAttribute(i,t)||delete e[t];return o.change((s=>{const{setImageSizes:r=!0}=n,a=s.createElement(i,e);return o.insertObject(a,t,null,{setSelection:"on",findOptimalPosition:t||"imageInline"==i?void 0:"auto"}),a.parent?(r&&this.setImageNaturalSizeAttributes(a),a):null}))}setImageNaturalSizeAttributes(e){const t=e.getAttribute("src");t&&(e.getAttribute("width")||e.getAttribute("height")||this.editor.model.change((i=>{const n=new $i.window.Image;this._domEmitter.listenTo(n,"load",(()=>{e.getAttribute("width")||e.getAttribute("height")||this.editor.model.enqueueChange(i.batch,(t=>{t.setAttribute("width",n.naturalWidth,e),t.setAttribute("height",n.naturalHeight,e)})),this._domEmitter.stopListening(n,"load")})),n.src=t})))}getClosestSelectedImageWidget(e){const t=e.getFirstPosition();if(!t)return null;const i=e.getSelectedElement();if(i&&this.isImageWidget(i))return i;let n=t.parent;for(;n;){if(n.is("element")&&this.isImageWidget(n))return n;n=n.parent}return null}getClosestSelectedImageElement(e){const t=e.getSelectedElement();return this.isImage(t)?t:e.getFirstPosition().findAncestor("imageBlock")}getImageWidgetFromImageView(e){return e.findAncestor({classes:op})}isImageAllowed(){const e=this.editor.model.document.selection;return function(e,t){if("imageBlock"==ap(e,t,null)){const i=function(e,t){const i=df(e,t).start.parent;return i.isEmpty&&!i.is("element","$root")?i.parent:i}(t,e.model);if(e.model.schema.checkChild(i,"imageBlock"))return!0}else if(e.model.schema.checkChild(t.focus,"imageInline"))return!0;return!1}(this.editor,e)&&function(e){return[...e.focus.getAncestors()].every((e=>!e.is("element","imageBlock")))}(e)}toImageWidget(e,t,i){return t.setCustomProperty("image",!0,e),of(e,t,{label:()=>{const t=this.findViewImgElement(e).getAttribute("alt");return t?`${t} ${i}`:i}})}isImageWidget(e){return!!e.getCustomProperty("image")&&sf(e)}isBlockImage(e){return!!e&&e.is("element","imageBlock")}isInlineImage(e){return!!e&&e.is("element","imageInline")}findViewImgElement(e){if(this.isInlineImageView(e))return e;const t=this.editor.editing.view;for(const{item:i}of t.createRangeIn(e))if(this.isInlineImageView(i))return i}destroy(){return this._domEmitter.stopListening(),super.destroy()}}function ap(e,t,i){const n=e.model.schema,s=e.config.get("image.insert.type");return e.plugins.has("ImageBlockEditing")?e.plugins.has("ImageInlineEditing")?i||("inline"===s?"imageInline":"block"===s?"imageBlock":t.is("selection")?ip(n,t):n.checkChild(t,"imageInline")?"imageInline":"imageBlock"):"imageBlock":"imageInline"}const lp=new RegExp(String(/^(http(s)?:\/\/)?[\w-]+\.[\w.~:/[\]@!$&'()*+,;=%-]+/.source+/\.(jpg|jpeg|png|gif|ico|webp|JPG|JPEG|PNG|GIF|ICO|WEBP)/.source+/(\?[\w.~:/[\]@!$&'()*+,;=%-]*)?/.source+/(#[\w.~:/[\]@!$&'()*+,;=%-]*)?$/.source));var cp=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");const dp=function(e){return cp.test(e)};var hp="\\ud800-\\udfff",up="["+hp+"]",mp="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",gp="\\ud83c[\\udffb-\\udfff]",fp="[^"+hp+"]",pp="(?:\\ud83c[\\udde6-\\uddff]){2}",bp="[\\ud800-\\udbff][\\udc00-\\udfff]",wp="(?:"+mp+"|"+gp+")?",vp="[\\ufe0e\\ufe0f]?",_p=vp+wp+"(?:\\u200d(?:"+[fp,pp,bp].join("|")+")"+vp+wp+")*",yp="(?:"+[fp+mp+"?",mp,pp,bp,up].join("|")+")",kp=RegExp(gp+"(?="+gp+")|"+yp+_p,"g");const Cp=function(e){return dp(e)?function(e){return e.match(kp)||[]}(e):function(e){return e.split("")}(e)},Ap=function(e){e=No(e);var t,i,n,s,o=dp(e)?Cp(e):void 0,r=o?o[0]:e.charAt(0),a=o?(t=o,i=1,s=t.length,n=void 0===n?s:n,!i&&n>=s?t:Ho(t,i,n)).join(""):e.slice(1);return r.toUpperCase()+a},xp=/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g,Tp=/^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i,Ep=/^[\S]+@((?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.))+(?:[a-z\u00a1-\uffff]{2,})$/i,Sp=/^((\w+:(\/{2,})?)|(\W))/i,Pp="Ctrl+K";function Ip(e,{writer:t}){const i=t.createAttributeElement("a",{href:e},{priority:5});return t.setCustomProperty("link",!0,i),i}function Vp(e){const t=String(e);return function(e){return!!e.replace(xp,"").match(Tp)}(t)?t:"#"}function Rp(e,t){return!!e&&t.checkAttribute(e.name,"linkHref")}function Lp(e,t){const i=(n=e,Ep.test(n)?"mailto:":t);var n;const s=!!i&&!Op(e);return e&&s?i+e:e}function Op(e){return Sp.test(e)}function Bp(e){window.open(e,"_blank","noopener")}const Mp=new RegExp("(^|\\s)(((?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(((?!www\\.)|(www\\.))(?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.)+(?:[a-z\\u00a1-\\uffff]{2,63})))(?::\\d{2,5})?(?:[/?#]\\S*)?)|((www.|(\\S+@))((?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.))+(?:[a-z\\u00a1-\\uffff]{2,63})))$","i");class Np extends io{static get requires(){return[bg]}static get pluginName(){return"AutoLink"}init(){const e=this.editor.model.document.selection;e.on("change:range",(()=>{this.isEnabled=!e.anchor.parent.is("element","codeBlock")})),this._enableTypingHandling()}afterInit(){this._enableEnterHandling(),this._enableShiftEnterHandling()}_enableTypingHandling(){const e=this.editor,t=new _g(e.model,(e=>{if(!function(e){return e.length>4&&" "===e[e.length-1]&&" "!==e[e.length-2]}(e))return;const t=Fp(e.substr(0,e.length-1));return t?{url:t}:void 0}));t.on("matched:data",((t,i)=>{const{batch:n,range:s,url:o}=i;if(!n.isTyping)return;const r=s.end.getShiftedBy(-1),a=r.getShiftedBy(-o.length),l=e.model.createRange(a,r);this._applyAutoLink(o,l)})),t.bind("isEnabled").to(this)}_enableEnterHandling(){const e=this.editor,t=e.model,i=e.commands.get("enter");i&&i.on("execute",(()=>{const e=t.document.selection.getFirstPosition();if(!e.parent.previousSibling)return;const i=t.createRangeIn(e.parent.previousSibling);this._checkAndApplyAutoLinkOnRange(i)}))}_enableShiftEnterHandling(){const e=this.editor,t=e.model,i=e.commands.get("shiftEnter");i&&i.on("execute",(()=>{const e=t.document.selection.getFirstPosition(),i=t.createRange(t.createPositionAt(e.parent,0),e.getShiftedBy(-1));this._checkAndApplyAutoLinkOnRange(i)}))}_checkAndApplyAutoLinkOnRange(e){const t=this.editor.model,{text:i,range:n}=vg(e,t),s=Fp(i);if(s){const e=t.createRange(n.end.getShiftedBy(-s.length),n.end);this._applyAutoLink(s,e)}}_applyAutoLink(e,t){const i=this.editor.model,n=Lp(e,this.editor.config.get("link.defaultProtocol"));this.isEnabled&&function(e,t){return t.schema.checkAttributeInSelection(t.createSelection(e),"linkHref")}(t,i)&&Op(n)&&!function(e){const t=e.start.nodeAfter;return!!t&&t.hasAttribute("linkHref")}(t)&&this._persistAutoLink(n,t)}_persistAutoLink(e,t){const i=this.editor.model,n=this.editor.plugins.get("Delete");i.enqueueChange((s=>{s.setAttribute("linkHref",e,t),i.enqueueChange((()=>{n.requestUndoOnBackspace()}))}))}}function Fp(e){const t=Mp.exec(e);return t?t[2]:null}class Dp extends so{refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor.model,i=t.schema,n=t.document.selection,s=Array.from(n.getSelectedBlocks()),o=void 0===e.forceValue?!this.value:e.forceValue;t.change((e=>{if(o){const t=s.filter((e=>zp(e)||$p(i,e)));this._applyQuote(e,t)}else this._removeQuote(e,s.filter(zp))}))}_getValue(){const e=On(this.editor.model.document.selection.getSelectedBlocks());return!(!e||!zp(e))}_checkEnabled(){if(this.value)return!0;const e=this.editor.model.document.selection,t=this.editor.model.schema,i=On(e.getSelectedBlocks());return!!i&&$p(t,i)}_removeQuote(e,t){Hp(e,t).reverse().forEach((t=>{if(t.start.isAtStart&&t.end.isAtEnd)return void e.unwrap(t.start.parent);if(t.start.isAtStart){const i=e.createPositionBefore(t.start.parent);return void e.move(t,i)}t.end.isAtEnd||e.split(t.end);const i=e.createPositionAfter(t.end.parent);e.move(t,i)}))}_applyQuote(e,t){const i=[];Hp(e,t).reverse().forEach((t=>{let n=zp(t.start);n||(n=e.createElement("blockQuote"),e.wrap(t,n)),i.push(n)})),i.reverse().reduce(((t,i)=>t.nextSibling==i?(e.merge(e.createPositionAfter(t)),t):i))}}function zp(e){return"blockQuote"==e.parent.name?e.parent:null}function Hp(e,t){let i,n=0;const s=[];for(;n{const n=e.model.document.differ.getChanges();for(const e of n)if("insert"==e.type){const n=e.position.nodeAfter;if(!n)continue;if(n.is("element","blockQuote")&&n.isEmpty)return i.remove(n),!0;if(n.is("element","blockQuote")&&!t.checkChild(e.position,n))return i.unwrap(n),!0;if(n.is("element")){const e=i.createRangeIn(n);for(const n of e.getItems())if(n.is("element","blockQuote")&&!t.checkChild(i.createPositionBefore(n),n))return i.unwrap(n),!0}}else if("remove"==e.type){const t=e.position.parent;if(t.is("element","blockQuote")&&t.isEmpty)return i.remove(t),!0}return!1}));const i=this.editor.editing.view.document,n=e.model.document.selection,s=e.commands.get("blockQuote");this.listenTo(i,"enter",((t,i)=>{n.isCollapsed&&s.value&&n.getLastPosition().parent.isEmpty&&(e.execute("blockQuote"),e.editing.view.scrollToTheSelection(),i.preventDefault(),t.stop())}),{context:"blockquote"}),this.listenTo(i,"delete",((t,i)=>{if("backward"!=i.direction||!n.isCollapsed||!s.value)return;const o=n.getLastPosition().parent;o.isEmpty&&!o.previousSibling&&(e.execute("blockQuote"),e.editing.view.scrollToTheSelection(),i.preventDefault(),t.stop())}),{context:"blockquote"})}}class Up extends io{static get pluginName(){return"BlockQuoteUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("blockQuote",(i=>{const n=e.commands.get("blockQuote"),s=new fs(i);return s.set({label:t("Block quote"),icon:Kh.quote,tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("blockQuote"),e.editing.view.focus()})),s}))}}class jp extends so{constructor(e,t){super(e),this.attributeKey=t}refresh(){const e=this.editor.model,t=e.document;this.value=this._getValueFromFirstAllowedNode(),this.isEnabled=e.schema.checkAttributeInSelection(t.selection,this.attributeKey)}execute(e={}){const t=this.editor.model,i=t.document.selection,n=void 0===e.forceValue?!this.value:e.forceValue;t.change((e=>{if(i.isCollapsed)n?e.setSelectionAttribute(this.attributeKey,!0):e.removeSelectionAttribute(this.attributeKey);else{const s=t.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const t of s)n?e.setAttribute(this.attributeKey,n,t):e.removeAttribute(this.attributeKey,t)}}))}_getValueFromFirstAllowedNode(){const e=this.editor.model,t=e.schema,i=e.document.selection;if(i.isCollapsed)return i.hasAttribute(this.attributeKey);for(const e of i.getRanges())for(const i of e.getItems())if(t.checkAttribute(i,this.attributeKey))return i.hasAttribute(this.attributeKey);return!1}}const qp="bold";class Gp extends io{static get pluginName(){return"BoldEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:qp}),e.model.schema.setAttributeProperties(qp,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:qp,view:"strong",upcastAlso:["b",e=>{const t=e.getStyle("font-weight");return t&&("bold"==t||Number(t)>=600)?{name:!0,styles:["font-weight"]}:null}]}),e.commands.add(qp,new jp(e,qp)),e.keystrokes.set("CTRL+B",qp)}}const Kp="bold";class Jp extends io{static get pluginName(){return"BoldUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(Kp,(i=>{const n=e.commands.get(Kp),s=new fs(i);return s.set({label:t("Bold"),icon:Kh.bold,keystroke:"CTRL+B",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(Kp),e.editing.view.focus()})),s}))}}const Qp="code";class Zp extends io{static get pluginName(){return"CodeEditing"}static get requires(){return[yg]}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:Qp}),e.model.schema.setAttributeProperties(Qp,{isFormatting:!0,copyOnEnter:!1}),e.conversion.attributeToElement({model:Qp,view:"code",upcastAlso:{styles:{"word-wrap":"break-word"}}}),e.commands.add(Qp,new jp(e,Qp)),e.plugins.get(yg).registerAttribute(Qp),Rg(e,Qp,"code","ck-code_selected")}}const Yp="code";class Xp extends io{static get pluginName(){return"CodeUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(Yp,(i=>{const n=e.commands.get(Yp),s=new fs(i);return s.set({label:t("Code"),icon:'',tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(Yp),e.editing.view.focus()})),s}))}}function eb(e){const t=e.t,i=e.config.get("codeBlock.languages");for(const e of i)"Plain text"===e.label&&(e.label=t("Plain text")),void 0===e.class&&(e.class=`language-${e.language}`);return i}function tb(e,t,i){const n={};for(const s of e)"class"===t?n[s[t].split(" ").shift()]=s[i]:n[s[t]]=s[i];return n}function ib(e){return e.data.match(/^(\s*)/)[0]}function nb(e){const t=e.document.selection,i=[];if(t.isCollapsed)return[t.anchor];const n=t.getFirstRange().getWalker({ignoreElementEnd:!0,direction:"backward"});for(const{item:t}of n){if(!t.is("$textProxy"))continue;const{parent:n,startOffset:s}=t.textNode;if(!n.is("element","codeBlock"))continue;const o=ib(t.textNode),r=e.createPositionAt(n,s+o.length);i.push(r)}return i}function sb(e){const t=On(e.getSelectedBlocks());return!!t&&t.is("element","codeBlock")}function ob(e,t){return!t.is("rootElement")&&!e.isLimit(t)&&e.checkChild(t.parent,"codeBlock")}class rb extends so{constructor(e){super(e),this._lastLanguage=null}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor,i=t.model,n=i.document.selection,s=eb(t)[0],o=Array.from(n.getSelectedBlocks()),r=null==e.forceValue?!this.value:e.forceValue,a=function(e,t,i){return e.language?e.language:e.usePreviousLanguageChoice&&t?t:i}(e,this._lastLanguage,s.language);i.change((e=>{r?this._applyCodeBlock(e,o,a):this._removeCodeBlock(e,o)}))}_getValue(){const e=On(this.editor.model.document.selection.getSelectedBlocks());return!(!e||!e.is("element","codeBlock"))&&e.getAttribute("language")}_checkEnabled(){if(this.value)return!0;const e=this.editor.model.document.selection,t=this.editor.model.schema,i=On(e.getSelectedBlocks());return!!i&&ob(t,i)}_applyCodeBlock(e,t,i){this._lastLanguage=i;const n=this.editor.model.schema,s=t.filter((e=>ob(n,e)));for(const t of s)e.rename(t,"codeBlock"),e.setAttribute("language",i,t),n.removeDisallowedAttributes([t],e),Array.from(t.getChildren()).filter((e=>!n.checkChild(t,e))).forEach((t=>e.remove(t)));s.reverse().forEach(((t,i)=>{const n=s[i+1];t.previousSibling===n&&(e.appendElement("softBreak",n),e.merge(e.createPositionBefore(t)))}))}_removeCodeBlock(e,t){const i=t.filter((e=>e.is("element","codeBlock")));for(const t of i){const i=e.createRangeOn(t);for(const t of Array.from(i.getItems()).reverse())if(t.is("element","softBreak")&&t.parent.is("element","codeBlock")){const{position:i}=e.split(e.createPositionBefore(t)),n=i.nodeAfter;e.rename(n,"paragraph"),e.removeAttribute("language",n),e.remove(t)}e.rename(t,"paragraph"),e.removeAttribute("language",t)}}}class ab extends so{constructor(e){super(e),this._indentSequence=e.config.get("codeBlock.indentSequence")}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model;e.change((t=>{const i=nb(e);for(const n of i){const i=t.createText(this._indentSequence);e.insertContent(i,n)}}))}_checkEnabled(){return!!this._indentSequence&&sb(this.editor.model.document.selection)}}class lb extends so{constructor(e){super(e),this._indentSequence=e.config.get("codeBlock.indentSequence")}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model;e.change((()=>{const t=nb(e);for(const i of t){const t=cb(e,i,this._indentSequence);t&&e.deleteContent(e.createSelection(t))}}))}_checkEnabled(){if(!this._indentSequence)return!1;const e=this.editor.model;return!!sb(e.document.selection)&&nb(e).some((t=>cb(e,t,this._indentSequence)))}}function cb(e,t,i){const n=function(e){let t=e.parent.getChild(e.index);return t&&!t.is("element","softBreak")||(t=e.nodeBefore),!t||t.is("element","softBreak")?null:t}(t);if(!n)return null;const s=ib(n),o=s.lastIndexOf(i);if(o+i.length!==s.length)return null;if(-1===o)return null;const{parent:r,startOffset:a}=n;return e.createRange(e.createPositionAt(r,a+o),e.createPositionAt(r,a+o+i.length))}function db(e,t,i=!1){const n=tb(t,"language","class"),s=tb(t,"language","label");return(t,o,r)=>{const{writer:a,mapper:l,consumable:c}=r;if(!c.consume(o.item,"insert"))return;const d=o.item.getAttribute("language"),h=l.toViewPosition(e.createPositionBefore(o.item)),u={};i&&(u["data-language"]=s[d],u.spellcheck="false");const m=n[d]?{class:n[d]}:void 0,g=a.createContainerElement("code",m),f=a.createContainerElement("pre",u,g);a.insert(h,f),l.bindElements(o.item,g)}}const hb="paragraph";class ub extends io{static get pluginName(){return"CodeBlockEditing"}static get requires(){return[Qg]}constructor(e){super(e),e.config.define("codeBlock",{languages:[{language:"plaintext",label:"Plain text"},{language:"c",label:"C"},{language:"cs",label:"C#"},{language:"cpp",label:"C++"},{language:"css",label:"CSS"},{language:"diff",label:"Diff"},{language:"html",label:"HTML"},{language:"java",label:"Java"},{language:"javascript",label:"JavaScript"},{language:"php",label:"PHP"},{language:"python",label:"Python"},{language:"ruby",label:"Ruby"},{language:"typescript",label:"TypeScript"},{language:"xml",label:"XML"}],indentSequence:"\t"})}init(){const e=this.editor,t=e.model.schema,i=e.model,n=e.editing.view,s=e.plugins.has("DocumentListEditing")?e.plugins.get("DocumentListEditing"):null,o=eb(e);e.commands.add("codeBlock",new rb(e)),e.commands.add("indentCodeBlock",new ab(e)),e.commands.add("outdentCodeBlock",new lb(e)),this.listenTo(n.document,"tab",((t,i)=>{const n=i.shiftKey?"outdentCodeBlock":"indentCodeBlock";e.commands.get(n).isEnabled&&(e.execute(n),i.stopPropagation(),i.preventDefault(),t.stop())}),{context:"pre"}),t.register("codeBlock",{allowWhere:"$block",allowChildren:"$text",isBlock:!0,allowAttributes:["language"]}),t.addAttributeCheck(((e,t)=>!!(e.endsWith("codeBlock")&&s&&s.getListAttributeNames().includes(t))||!e.endsWith("codeBlock $text")&&void 0)),e.model.schema.addChildCheck(((e,t)=>{if(e.endsWith("codeBlock")&&t.isObject)return!1})),e.editing.downcastDispatcher.on("insert:codeBlock",db(i,o,!0)),e.data.downcastDispatcher.on("insert:codeBlock",db(i,o)),e.data.downcastDispatcher.on("insert:softBreak",function(e){return(t,i,n)=>{if("codeBlock"!==i.item.parent.name)return;const{writer:s,mapper:o,consumable:r}=n;if(!r.consume(i.item,"insert"))return;const a=o.toViewPosition(e.createPositionBefore(i.item));s.insert(a,s.createText("\n"))}}(i),{priority:"high"}),e.data.upcastDispatcher.on("element:code",function(e,t){const i=tb(t,"class","language"),n=t[0].language;return(e,t,s)=>{const o=t.viewItem,r=o.parent;if(!r||!r.is("element","pre"))return;if(t.modelCursor.findAncestor("codeBlock"))return;const{consumable:a,writer:l}=s;if(!a.test(o,{name:!0}))return;const c=l.createElement("codeBlock"),d=[...o.getClassNames()];d.length||d.push("");for(const e of d){const t=i[e];if(t){l.setAttribute("language",t,c);break}}c.hasAttribute("language")||l.setAttribute("language",n,c),s.convertChildren(o,c),s.safeInsert(c,t.modelCursor)&&(a.consume(o,{name:!0}),s.updateConversionResult(c,t))}}(0,o)),e.data.upcastDispatcher.on("text",((e,t,{consumable:i,writer:n})=>{let s=t.modelCursor;if(!i.test(t.viewItem))return;if(!s.findAncestor("codeBlock"))return;i.consume(t.viewItem);const o=t.viewItem.data.split("\n").map((e=>n.createText(e))),r=o[o.length-1];for(const e of o)if(n.insert(e,s),s=s.getShiftedBy(e.offsetSize),e!==r){const e=n.createElement("softBreak");n.insert(e,s),s=n.createPositionAfter(e)}t.modelRange=n.createRange(t.modelCursor,s),t.modelCursor=s})),e.data.upcastDispatcher.on("element:pre",((e,t,{consumable:i})=>{const n=t.viewItem;if(n.findAncestor("pre"))return;const s=Array.from(n.getChildren()),o=s.find((e=>e.is("element","code")));if(o)for(const e of s)e!==o&&e.is("$text")&&i.consume(e,{name:!0})}),{priority:"high"}),this.listenTo(e.editing.view.document,"clipboardInput",((t,n)=>{let s=i.createRange(i.document.selection.anchor);if(n.targetRanges&&(s=e.editing.mapper.toModelRange(n.targetRanges[0])),!s.start.parent.is("element","codeBlock"))return;const o=n.dataTransfer.getData("text/plain"),r=new Xd(e.editing.view.document);n.content=function(e,t){const i=e.createDocumentFragment(),n=t.split("\n"),s=n.reduce(((t,i,s)=>(t.push(i),s{const s=n.anchor;!n.isCollapsed&&s.parent.is("element","codeBlock")&&s.hasSameParentAs(n.focus)&&i.change((i=>{const o=e.return;if(s.parent.is("element")&&(o.childCount>1||n.containsEntireContent(s.parent))){const t=i.createElement("codeBlock",s.parent.getAttributes());i.append(o,t);const n=i.createDocumentFragment();return i.append(t,n),void(e.return=n)}const r=o.getChild(0);t.checkAttribute(r,"code")&&i.setAttribute("code",!0,r)}))}))}afterInit(){const e=this.editor,t=e.commands,i=t.get("indent"),n=t.get("outdent");i&&i.registerChildCommand(t.get("indentCodeBlock"),{priority:"highest"}),n&&n.registerChildCommand(t.get("outdentCodeBlock")),this.listenTo(e.editing.view.document,"enter",((t,i)=>{e.model.document.selection.getLastPosition().parent.is("element","codeBlock")&&(function(e,t){const i=e.model.document,n=e.editing.view,s=i.selection.getLastPosition(),o=s.nodeAfter;return!(t||!i.selection.isCollapsed||!s.isAtStart)&&(!!gb(o)&&(e.model.change((t=>{e.execute("enter");const n=i.selection.anchor.parent.previousSibling;t.rename(n,hb),t.setSelection(n,"in"),e.model.schema.removeDisallowedAttributes([n],t),t.remove(o)})),n.scrollToTheSelection(),!0))}(e,i.isSoft)||function(e,t){const i=e.model,n=i.document,s=e.editing.view,o=n.selection.getLastPosition(),r=o.nodeBefore;let a;if(t||!n.selection.isCollapsed||!o.isAtEnd||!r||!r.previousSibling)return!1;if(gb(r)&&gb(r.previousSibling))a=i.createRange(i.createPositionBefore(r.previousSibling),i.createPositionAfter(r));else if(mb(r)&&gb(r.previousSibling)&&gb(r.previousSibling.previousSibling))a=i.createRange(i.createPositionBefore(r.previousSibling.previousSibling),i.createPositionAfter(r));else{if(!(mb(r)&&gb(r.previousSibling)&&mb(r.previousSibling.previousSibling)&&r.previousSibling.previousSibling&&gb(r.previousSibling.previousSibling.previousSibling)))return!1;a=i.createRange(i.createPositionBefore(r.previousSibling.previousSibling.previousSibling),i.createPositionAfter(r))}return e.model.change((t=>{t.remove(a),e.execute("enter");const i=n.selection.anchor.parent;t.rename(i,hb),e.model.schema.removeDisallowedAttributes([i],t)})),s.scrollToTheSelection(),!0}(e,i.isSoft)||function(e){const t=e.model.document,i=t.selection.getLastPosition(),n=i.nodeBefore||i.textNode;let s;n&&n.is("$text")&&(s=ib(n)),e.model.change((i=>{e.execute("shiftEnter"),s&&i.insertText(s,t.selection.anchor)}))}(e),i.preventDefault(),t.stop())}),{context:"pre"})}}function mb(e){return e&&e.is("$text")&&!e.data.match(/\S/)}function gb(e){return e&&e.is("element","softBreak")}class fb extends io{static get pluginName(){return"CodeBlockUI"}init(){const e=this.editor,t=e.t,i=e.ui.componentFactory,n=eb(e);i.add("codeBlock",(i=>{const s=e.commands.get("codeBlock"),o=ru(i,ou),r=o.buttonView,a=t("Insert code block");return r.set({label:a,tooltip:!0,icon:'',isToggleable:!0}),r.bind("isOn").to(s,"value",(e=>!!e)),r.on("execute",(()=>{e.execute("codeBlock",{usePreviousLanguageChoice:!0}),e.editing.view.focus()})),o.on("execute",(t=>{e.execute("codeBlock",{language:t.source._codeBlockLanguage,forceValue:!0}),e.editing.view.focus()})),o.class="ck-code-block-dropdown",o.bind("isEnabled").to(s),cu(o,(()=>this._getLanguageListItemDefinitions(n)),{role:"menu",ariaLabel:a}),o}))}_getLanguageListItemDefinitions(e){const t=this.editor.commands.get("codeBlock"),i=new Ln;for(const n of e){const e={type:"button",model:new _m({_codeBlockLanguage:n.language,label:n.label,role:"menuitemradio",withText:!0})};e.model.bind("isOn").to(t,"value",(t=>t===e.model._codeBlockLanguage)),i.add(e)}return i}}const pb=(bb={À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"},function(e){return null==bb?void 0:bb[e]});var bb,wb=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,vb=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g");var _b=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;var yb=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;var kb="\\ud800-\\udfff",Cb="\\u2700-\\u27bf",Ab="a-z\\xdf-\\xf6\\xf8-\\xff",xb="A-Z\\xc0-\\xd6\\xd8-\\xde",Tb="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Eb="["+Tb+"]",Sb="\\d+",Pb="["+Cb+"]",Ib="["+Ab+"]",Vb="[^"+kb+Tb+Sb+Cb+Ab+xb+"]",Rb="(?:\\ud83c[\\udde6-\\uddff]){2}",Lb="[\\ud800-\\udbff][\\udc00-\\udfff]",Ob="["+xb+"]",Bb="(?:"+Ib+"|"+Vb+")",Mb="(?:"+Ob+"|"+Vb+")",Nb="(?:['’](?:d|ll|m|re|s|t|ve))?",Fb="(?:['’](?:D|LL|M|RE|S|T|VE))?",Db="(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?",zb="[\\ufe0e\\ufe0f]?",Hb=zb+Db+"(?:\\u200d(?:"+["[^"+kb+"]",Rb,Lb].join("|")+")"+zb+Db+")*",$b="(?:"+[Pb,Rb,Lb].join("|")+")"+Hb,Wb=RegExp([Ob+"?"+Ib+"+"+Nb+"(?="+[Eb,Ob,"$"].join("|")+")",Mb+"+"+Fb+"(?="+[Eb,Ob+Bb,"$"].join("|")+")",Ob+"?"+Bb+"+"+Nb,Ob+"+"+Fb,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Sb,$b].join("|"),"g");const Ub=function(e,t,i){return e=No(e),void 0===(t=i?void 0:t)?function(e){return yb.test(e)}(e)?function(e){return e.match(Wb)||[]}(e):function(e){return e.match(_b)||[]}(e):e.match(t)||[]};var jb=RegExp("['’]","g");const qb=(Gb=function(e,t,i){return e+(i?" ":"")+Ap(t)},function(e){return function(e,t,i,n){var s=-1,o=null==e?0:e.length;for(n&&o&&(i=e[++s]);++si.writer.createElement(e,{htmlContent:t.getCustomProperty("$rawContent")})}function Xb(e,{view:t,isInline:i}){const n=e.t;return(e,{writer:s})=>{const o=n("HTML object"),r=ew(t,e,s),a=e.getAttribute(Zb(t));return s.addClass("html-object-embed__content",r),a&&Jb(s,a,r),of(s.createContainerElement(i?"span":"div",{class:"html-object-embed","data-html-object-embed-label":o},r),s,{label:o})}}function ew(e,t,i){return i.createRawElement(e,null,((e,i)=>{i.setContentOf(e,t.getAttribute("htmlContent"))}))}function tw({model:e,view:t},i){return(n,{writer:s,consumable:o})=>{if(!n.hasAttribute(e))return null;const r=s.createContainerElement(t),a=n.getAttribute(e);return o.consume(n,`attribute:${e}`),Jb(s,a,r),r.getFillerOffset=()=>null,i?of(r,s):r}}function iw({priority:e,view:t}){return(i,n)=>{if(!i)return;const{writer:s}=n,o=s.createAttributeElement(t,null,{priority:e});return Jb(s,i,o),o}}function nw({view:e},t){return i=>{i.on(`element:${e}`,((e,i,n)=>{if(!i.modelRange||i.modelRange.isCollapsed)return;const s=t.processViewAttributes(i.viewItem,n);s&&n.writer.setAttribute(Zb(i.viewItem.name),s,i.modelRange)}),{priority:"low"})}}function sw({view:e,model:t}){return i=>{i.on(`attribute:${Zb(e)}:${t}`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t;Kb(i.writer,n,s,i.mapper.toViewElement(t.item))}))}}const ow=[{model:"codeBlock",view:"pre"},{model:"paragraph",view:"p"},{model:"blockQuote",view:"blockquote"},{model:"listItem",view:"li"},{model:"pageBreak",view:"div"},{model:"rawHtml",view:"div"},{model:"table",view:"table"},{model:"tableRow",view:"tr"},{model:"tableCell",view:"td"},{model:"tableCell",view:"th"},{model:"tableColumnGroup",view:"colgroup"},{model:"tableColumn",view:"col"},{model:"caption",view:"caption"},{model:"caption",view:"figcaption"},{model:"imageBlock",view:"img"},{model:"imageInline",view:"img"},{model:"htmlP",view:"p",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlBlockquote",view:"blockquote",modelSchema:{inheritAllFrom:"$container"}},{model:"htmlTable",view:"table",modelSchema:{allowWhere:"$block",isBlock:!0}},{model:"htmlTbody",view:"tbody",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlThead",view:"thead",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlTfoot",view:"tfoot",modelSchema:{allowIn:"htmlTable",isBlock:!1}},{model:"htmlCaption",view:"caption",modelSchema:{allowIn:"htmlTable",allowChildren:"$text",isBlock:!1}},{model:"htmlColgroup",view:"colgroup",modelSchema:{allowIn:"htmlTable",allowChildren:"col",isBlock:!1}},{model:"htmlCol",view:"col",modelSchema:{allowIn:"htmlColgroup",isBlock:!1}},{model:"htmlTr",view:"tr",modelSchema:{allowIn:["htmlTable","htmlThead","htmlTbody"],isLimit:!0}},{model:"htmlTd",view:"td",modelSchema:{allowIn:"htmlTr",allowContentOf:"$container",isLimit:!0,isBlock:!1}},{model:"htmlTh",view:"th",modelSchema:{allowIn:"htmlTr",allowContentOf:"$container",isLimit:!0,isBlock:!1}},{model:"htmlFigure",view:"figure",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlFigcaption",view:"figcaption",modelSchema:{allowIn:"htmlFigure",allowChildren:"$text",isBlock:!1}},{model:"htmlAddress",view:"address",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlAside",view:"aside",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlMain",view:"main",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlDetails",view:"details",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlSummary",view:"summary",modelSchema:{allowChildren:"$text",allowIn:"htmlDetails",isBlock:!1}},{model:"htmlDiv",view:"div",paragraphLikeModel:"htmlDivParagraph",modelSchema:{inheritAllFrom:"$container"}},{model:"htmlFieldset",view:"fieldset",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlLegend",view:"legend",modelSchema:{allowIn:"htmlFieldset",allowChildren:"$text"}},{model:"htmlHeader",view:"header",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlFooter",view:"footer",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlForm",view:"form",modelSchema:{inheritAllFrom:"$container",isBlock:!0}},{model:"htmlHgroup",view:"hgroup",modelSchema:{allowChildren:["htmlH1","htmlH2","htmlH3","htmlH4","htmlH5","htmlH6"],isBlock:!1}},{model:"htmlH1",view:"h1",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH2",view:"h2",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH3",view:"h3",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH4",view:"h4",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH5",view:"h5",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlH6",view:"h6",modelSchema:{inheritAllFrom:"$block"}},{model:"$htmlList",modelSchema:{allowWhere:"$container",allowChildren:["$htmlList","htmlLi"],isBlock:!1}},{model:"htmlDir",view:"dir",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlMenu",view:"menu",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlUl",view:"ul",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlOl",view:"ol",modelSchema:{inheritAllFrom:"$htmlList"}},{model:"htmlLi",view:"li",modelSchema:{allowIn:"$htmlList",allowChildren:"$text",isBlock:!1}},{model:"htmlPre",view:"pre",modelSchema:{inheritAllFrom:"$block"}},{model:"htmlArticle",view:"article",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlSection",view:"section",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlNav",view:"nav",modelSchema:{inheritAllFrom:"$container",isBlock:!1}},{model:"htmlDivDl",view:"div",modelSchema:{allowChildren:["htmlDt","htmlDd"],allowIn:"htmlDl"}},{model:"htmlDl",view:"dl",modelSchema:{allowWhere:"$container",allowChildren:["htmlDt","htmlDd","htmlDivDl"],isBlock:!1}},{model:"htmlDt",view:"dt",modelSchema:{allowChildren:"$block",isBlock:!1}},{model:"htmlDd",view:"dd",modelSchema:{allowChildren:"$block",isBlock:!1}},{model:"htmlCenter",view:"center",modelSchema:{inheritAllFrom:"$container",isBlock:!1}}],rw=[{model:"htmlLiAttributes",view:"li",appliesToBlock:!0,coupledAttribute:"listItemId"},{model:"htmlOlAttributes",view:"ol",appliesToBlock:!0,coupledAttribute:"listItemId"},{model:"htmlUlAttributes",view:"ul",appliesToBlock:!0,coupledAttribute:"listItemId"},{model:"htmlFigureAttributes",view:"figure",appliesToBlock:"table"},{model:"htmlTheadAttributes",view:"thead",appliesToBlock:"table"},{model:"htmlTbodyAttributes",view:"tbody",appliesToBlock:"table"},{model:"htmlFigureAttributes",view:"figure",appliesToBlock:"imageBlock"},{model:"htmlAcronym",view:"acronym",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlTt",view:"tt",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlFont",view:"font",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlTime",view:"time",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlVar",view:"var",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlBig",view:"big",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSmall",view:"small",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSamp",view:"samp",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlQ",view:"q",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlOutput",view:"output",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlKbd",view:"kbd",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlBdi",view:"bdi",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlBdo",view:"bdo",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlAbbr",view:"abbr",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlA",view:"a",priority:5,coupledAttribute:"linkHref",attributeProperties:{copyOnEnter:!0}},{model:"htmlStrong",view:"strong",coupledAttribute:"bold",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlB",view:"b",coupledAttribute:"bold",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlI",view:"i",coupledAttribute:"italic",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlEm",view:"em",coupledAttribute:"italic",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlS",view:"s",coupledAttribute:"strikethrough",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlDel",view:"del",coupledAttribute:"strikethrough",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlIns",view:"ins",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlU",view:"u",coupledAttribute:"underline",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSub",view:"sub",coupledAttribute:"subscript",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSup",view:"sup",coupledAttribute:"superscript",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlCode",view:"code",coupledAttribute:"code",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlMark",view:"mark",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlSpan",view:"span",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlCite",view:"cite",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlLabel",view:"label",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlDfn",view:"dfn",attributeProperties:{copyOnEnter:!0,isFormatting:!0}},{model:"htmlObject",view:"object",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlIframe",view:"iframe",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlInput",view:"input",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlButton",view:"button",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlTextarea",view:"textarea",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlSelect",view:"select",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlVideo",view:"video",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlEmbed",view:"embed",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlOembed",view:"oembed",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlAudio",view:"audio",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlImg",view:"img",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlCanvas",view:"canvas",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlMeter",view:"meter",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlProgress",view:"progress",isObject:!0,modelSchema:{inheritAllFrom:"$inlineObject"}},{model:"htmlScript",view:"script",modelSchema:{allowWhere:["$text","$block"],isInline:!0}},{model:"htmlStyle",view:"style",modelSchema:{allowWhere:["$text","$block"],isInline:!0}},{model:"htmlCustomElement",view:"$customElement",modelSchema:{allowWhere:["$text","$block"],allowAttributesOf:"$inlineObject",isInline:!0}}],aw=tr((function(e,t,i,n){Ko(e,t,i,n)}));class lw extends io{constructor(){super(...arguments),this._definitions=[]}static get pluginName(){return"DataSchema"}init(){for(const e of ow)this.registerBlockElement(e);for(const e of rw)this.registerInlineElement(e)}registerBlockElement(e){this._definitions.push({...e,isBlock:!0})}registerInlineElement(e){this._definitions.push({...e,isInline:!0})}extendBlockElement(e){this._extendDefinition({...e,isBlock:!0})}extendInlineElement(e){this._extendDefinition({...e,isInline:!0})}getDefinitionsForView(e,t=!1){const i=new Set;for(const n of this._getMatchingViewDefinitions(e)){if(t)for(const e of this._getReferences(n.model))i.add(e);i.add(n)}return i}getDefinitionsForModel(e){return this._definitions.filter((t=>t.model==e))}_getMatchingViewDefinitions(e){return this._definitions.filter((t=>t.view&&function(e,t){return"string"==typeof e?e===t:e instanceof RegExp&&e.test(t)}(e,t.view)))}*_getReferences(e){const t=["inheritAllFrom","inheritTypesFrom","allowWhere","allowContentOf","allowAttributesOf"],i=this._definitions.filter((t=>t.model==e));for(const{modelSchema:n}of i)if(n)for(const i of t)for(const t of Pn(n[i]||[])){const i=this._definitions.filter((e=>e.model==t));for(const n of i)t!==e&&(yield*this._getReferences(n.model),yield n)}}_extendDefinition(e){const t=Array.from(this._definitions.entries()).filter((([,t])=>t.model==e.model));if(0!=t.length)for(const[i,n]of t)this._definitions[i]=aw({},n,e,((e,t)=>Array.isArray(e)?e.concat(t):void 0));else this._definitions.push(e)}}const cw=function(e){return e!=e},dw=function(e,t,i){return t==t?function(e,t,i){for(var n=i-1,s=e.length;++n-1;)a!==e&&uw.call(a,l,1),uw.call(e,l,1);return e}(e,t):e}));class gw extends io{constructor(e){super(e),this._dataSchema=e.plugins.get("DataSchema"),this._allowedAttributes=new ko,this._disallowedAttributes=new ko,this._allowedElements=new Set,this._disallowedElements=new Set,this._dataInitialized=!1,this._coupledAttributes=null,this._registerElementsAfterInit(),this._registerElementHandlers(),this._registerCoupledAttributesPostFixer(),this._registerAssociatedHtmlAttributesPostFixer()}static get pluginName(){return"DataFilter"}static get requires(){return[lw,yf]}loadAllowedConfig(e){for(const t of e){const e=t.name||/[\s\S]+/,i=vw(t);this.allowElement(e),i.forEach((e=>this.allowAttributes(e)))}}loadDisallowedConfig(e){for(const t of e){const e=t.name||/[\s\S]+/,i=vw(t);0==i.length?this.disallowElement(e):i.forEach((e=>this.disallowAttributes(e)))}}loadAllowedEmptyElementsConfig(e){for(const t of e)this.allowEmptyElement(t)}allowElement(e){for(const t of this._dataSchema.getDefinitionsForView(e,!0))this._addAllowedElement(t),this._coupledAttributes=null}disallowElement(e){for(const t of this._dataSchema.getDefinitionsForView(e,!1))this._disallowedElements.add(t.view)}allowEmptyElement(e){for(const t of this._dataSchema.getDefinitionsForView(e,!0))t.isInline&&this._dataSchema.extendInlineElement({...t,allowEmpty:!0})}allowAttributes(e){this._allowedAttributes.add(e)}disallowAttributes(e){this._disallowedAttributes.add(e)}processViewAttributes(e,t){return fw(e,t,this._disallowedAttributes),fw(e,t,this._allowedAttributes)}_addAllowedElement(e){if(!this._allowedElements.has(e)){if(this._allowedElements.add(e),"appliesToBlock"in e&&"string"==typeof e.appliesToBlock)for(const t of this._dataSchema.getDefinitionsForModel(e.appliesToBlock))t.isBlock&&this._addAllowedElement(t);this._dataInitialized&&this.editor.data.once("set",(()=>{this._fireRegisterEvent(e)}),{priority:b.highest+1})}}_registerElementsAfterInit(){this.editor.data.on("init",(()=>{this._dataInitialized=!0;for(const e of this._allowedElements)this._fireRegisterEvent(e)}),{priority:b.highest+1})}_registerElementHandlers(){this.on("register",((e,t)=>{const i=this.editor.model.schema;if(t.isObject&&!i.isRegistered(t.model))this._registerObjectElement(t);else if(t.isBlock)this._registerBlockElement(t);else{if(!t.isInline)throw new _("data-filter-invalid-definition",null,t);this._registerInlineElement(t)}e.stop()}),{priority:"lowest"})}_registerCoupledAttributesPostFixer(){const e=this.editor.model;e.document.registerPostFixer((t=>{const i=e.document.differ.getChanges();let n=!1;const s=this._getCoupledAttributesMap();for(const e of i){if("attribute"!=e.type||null!==e.attributeNewValue)continue;const i=s.get(e.attributeKey);if(i)for(const{item:s}of e.range.getWalker({shallow:!0}))for(const e of i)s.hasAttribute(e)&&(t.removeAttribute(e,s),n=!0)}return n}))}_registerAssociatedHtmlAttributesPostFixer(){const e=this.editor.model;e.document.registerPostFixer((t=>{const i=e.document.differ.getChanges();let n=!1;for(const s of i)if("insert"===s.type&&"$text"!==s.name)for(const i of s.attributes.keys())i.startsWith("html")&&i.endsWith("Attributes")&&(e.schema.checkAttribute(s.name,i)||(t.removeAttribute(i,s.position.nodeAfter),n=!0));return n}))}_getCoupledAttributesMap(){if(this._coupledAttributes)return this._coupledAttributes;this._coupledAttributes=new Map;for(const e of this._allowedElements)if(e.coupledAttribute&&e.model){const t=this._coupledAttributes.get(e.coupledAttribute);t?t.push(e.model):this._coupledAttributes.set(e.coupledAttribute,[e.model])}return this._coupledAttributes}_fireRegisterEvent(e){e.view&&this._disallowedElements.has(e.view)||this.fire(e.view?`register:${e.view}`:"register",e)}_registerObjectElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,{view:s,model:o}=e;i.register(o,e.modelSchema),s&&(i.extend(e.model,{allowAttributes:[Zb(s),"htmlContent"]}),t.data.registerRawContentMatcher({name:s}),n.for("upcast").elementToElement({view:s,model:Yb(e),converterPriority:b.low+2}),n.for("upcast").add(nw(e,this)),n.for("editingDowncast").elementToStructure({model:{name:o,attributes:[Zb(s)]},view:Xb(t,e)}),n.for("dataDowncast").elementToElement({model:o,view:(e,{writer:t})=>ew(s,e,t)}),n.for("dataDowncast").add(sw(e)))}_registerBlockElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,{view:s,model:o}=e;if(!i.isRegistered(e.model)){if(i.register(e.model,e.modelSchema),!s)return;n.for("upcast").elementToElement({model:o,view:s,converterPriority:b.low+2}),n.for("downcast").elementToElement({model:o,view:s})}s&&(i.extend(e.model,{allowAttributes:Zb(s)}),n.for("upcast").add(nw(e,this)),n.for("downcast").add(sw(e)))}_registerInlineElement(e){const t=this.editor,i=t.model.schema,n=t.conversion,s=e.model;e.appliesToBlock||(i.extend("$text",{allowAttributes:s}),e.attributeProperties&&i.setAttributeProperties(s,e.attributeProperties),n.for("upcast").add(function({view:e,model:t,allowEmpty:i},n){return t=>{t.on(`element:${e}`,((e,t,o)=>{let r=n.processViewAttributes(t.viewItem,o);if(r||o.consumable.test(t.viewItem,{name:!0})){if(r=r||{},o.consumable.consume(t.viewItem,{name:!0}),t.modelRange||(t=Object.assign(t,o.convertChildren(t.viewItem,t.modelCursor))),i&&t.modelRange.isCollapsed&&Object.keys(r).length){const e=o.writer.createElement("htmlEmptyElement");if(!o.safeInsert(e,t.modelCursor))return;const i=o.getSplitParts(e);return t.modelRange=o.writer.createRange(t.modelRange.start,o.writer.createPositionAfter(i[i.length-1])),o.updateConversionResult(e,t),void s(e,r,o)}for(const e of t.modelRange.getItems())s(e,r,o)}}),{priority:"low"})};function s(e,i,n){if(n.schema.checkAttribute(e,t)){const s=function(e,t){const i=Ya(e);let n="attributes";for(n in t)i[n]="classes"==n?Array.from(new Set([...e[n]||[],...t[n]])):{...e[n],...t[n]};return i}(i,e.getAttribute(t)||{});n.writer.setAttribute(t,s,e)}}}(e,this)),n.for("downcast").attributeToElement({model:s,view:iw(e)}),e.allowEmpty&&(i.setAttributeProperties(s,{copyFromObject:!1}),i.isRegistered("htmlEmptyElement")||i.register("htmlEmptyElement",{inheritAllFrom:"$inlineObject"}),t.data.htmlProcessor.domConverter.registerInlineObjectMatcher((t=>t.name==e.view&&t.isEmpty&&Array.from(t.getAttributeKeys()).length?{name:!0}:null)),n.for("editingDowncast").elementToElement({model:"htmlEmptyElement",view:tw(e,!0)}),n.for("dataDowncast").elementToElement({model:"htmlEmptyElement",view:tw(e)})))}}function fw(e,t,i){const n=function(e,{consumable:t},i){const n=i.matchAll(e)||[],s=[];for(const i of n)pw(t,e,i),delete i.match.name,t.consume(e,i.match),s.push(i);return s}(e,t,i),{attributes:s,styles:o,classes:r}=function(e){const t={attributes:new Set,classes:new Set,styles:new Set};for(const i of e)for(const e in t)(i.match[e]||[]).forEach((i=>t[e].add(i)));return t}(n),a={};if(s.size)for(const e of s)on(e)||s.delete(e);return s.size&&(a.attributes=bw(s,(t=>e.getAttribute(t)))),o.size&&(a.styles=bw(o,(t=>e.getStyle(t)))),r.size&&(a.classes=Array.from(r)),Object.keys(a).length?a:null}function pw(e,t,i){for(const n of["attributes","classes","styles"]){const s=i.match[n];if(s)for(const i of Array.from(s))e.test(t,{[n]:[i]})||mw(s,i)}}function bw(e,t){const i={};for(const n of e)void 0!==t(n)&&(i[n]=t(n));return i}function ww(e,t){const{name:i}=e,n=e[t];return ye(n)?Object.entries(n).map((([e,n])=>({name:i,[t]:{[e]:n}}))):Array.isArray(n)?n.map((e=>({name:i,[t]:[e]}))):[e]}function vw(e){const{name:t,attributes:i,classes:n,styles:s}=e,o=[];return i&&o.push(...ww({name:t,attributes:i},"attributes")),n&&o.push(...ww({name:t,classes:n},"classes")),s&&o.push(...ww({name:t,styles:s},"styles")),o}class _w extends so{constructor(e){super(e),this.affectsData=!1}execute(){const e=this.editor.model,t=e.document.selection;let i=e.schema.getLimitElement(t);if(t.containsEntireContent(i)||!yw(e.schema,i))do{if(i=i.parent,!i)return}while(!yw(e.schema,i));e.change((e=>{e.setSelection(i,"in")}))}}function yw(e,t){return e.isLimit(t)&&(e.checkChild(t,"$text")||e.checkChild(t,"paragraph"))}const kw=Tn("Ctrl+A");class Cw extends io{static get pluginName(){return"SelectAllEditing"}init(){const e=this.editor,t=e.editing.view.document;e.commands.add("selectAll",new _w(e)),this.listenTo(t,"keydown",((t,i)=>{xn(i)===kw&&(e.execute("selectAll"),i.preventDefault())}))}}class Aw extends io{static get pluginName(){return"SelectAllUI"}init(){const e=this.editor;e.ui.componentFactory.add("selectAll",(t=>{const i=e.commands.get("selectAll"),n=new fs(t),s=t.t;return n.set({label:s("Select all"),icon:'',keystroke:"Ctrl+A",tooltip:!0}),n.bind("isEnabled").to(i,"isEnabled"),this.listenTo(n,"execute",(()=>{e.execute("selectAll"),e.editing.view.focus()})),n}))}}class xw extends io{static get requires(){return[Cw,Aw]}static get pluginName(){return"SelectAll"}}class Tw extends Un{constructor(e){super(e);const t=e.t;this.set("matchCount",0),this.set("highlightOffset",0),this.set("isDirty",!1),this.set("_areCommandsEnabled",{}),this.set("_resultsCounterText",""),this.set("_matchCase",!1),this.set("_wholeWordsOnly",!1),this.bind("_searchResultsFound").to(this,"matchCount",this,"isDirty",((e,t)=>e>0&&!t)),this._findInputView=this._createInputField(t("Find in text…")),this._replaceInputView=this._createInputField(t("Replace with…")),this._findButtonView=this._createButton({label:t("Find"),class:"ck-button-find ck-button-action",withText:!0}),this._findPrevButtonView=this._createButton({label:t("Previous result"),class:"ck-button-prev",icon:ym,keystroke:"Shift+F3",tooltip:!0}),this._findNextButtonView=this._createButton({label:t("Next result"),class:"ck-button-next",icon:ym,keystroke:"F3",tooltip:!0}),this._optionsDropdown=this._createOptionsDropdown(),this._replaceButtonView=this._createButton({label:t("Replace"),class:"ck-button-replace",withText:!0}),this._replaceAllButtonView=this._createButton({label:t("Replace all"),class:"ck-button-replaceall",withText:!0}),this._findFieldsetView=this._createFindFieldset(),this._replaceFieldsetView=this._createReplaceFieldset(),this._focusTracker=new Bn,this._keystrokes=new Mn,this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this._focusTracker,keystrokeHandler:this._keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-find-and-replace-form"],tabindex:"-1"},children:[new wm(e,{label:t("Find and replace")}),this._findFieldsetView,this._replaceFieldsetView]})}render(){super.render(),s({view:this}),this._initFocusCycling(),this._initKeystrokeHandling()}destroy(){super.destroy(),this._focusTracker.destroy(),this._keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}reset(){this._findInputView.errorText=null,this.isDirty=!0}get _textToFind(){return this._findInputView.fieldView.element.value}get _textToReplace(){return this._replaceInputView.fieldView.element.value}_createFindFieldset(){const e=this.locale,t=new Un(e);return this._findInputView.fieldView.on("input",(()=>{this.isDirty=!0})),this._findButtonView.on("execute",this._onFindButtonExecute.bind(this)),this._findPrevButtonView.delegate("execute").to(this,"findPrevious"),this._findNextButtonView.delegate("execute").to(this,"findNext"),this._findPrevButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",(({findPrevious:e})=>e)),this._findNextButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",(({findNext:e})=>e)),this._injectFindResultsCounter(),t.setTemplate({tag:"fieldset",attributes:{class:["ck","ck-find-and-replace-form__find"]},children:[this._findInputView,this._findButtonView,this._findPrevButtonView,this._findNextButtonView]}),t}_onFindButtonExecute(){if(this._textToFind)this.isDirty=!1,this.fire("findNext",{searchText:this._textToFind,matchCase:this._matchCase,wholeWords:this._wholeWordsOnly});else{const e=this.t;this._findInputView.errorText=e("Text to find must not be empty.")}}_injectFindResultsCounter(){const e=this.locale,t=e.t,i=this.bindTemplate,n=new Un(this.locale);this.bind("_resultsCounterText").to(this,"highlightOffset",this,"matchCount",((e,i)=>t("%0 of %1",[e,i]))),n.setTemplate({tag:"span",attributes:{class:["ck","ck-results-counter",i.if("isDirty","ck-hidden")]},children:[{text:i.to("_resultsCounterText")}]});const s=()=>{const t=this._findInputView.fieldView.element;if(!t||!rn(t))return;const i=new Ki(n.element).width,s="ltr"===e.uiLanguageDirection?"paddingRight":"paddingLeft";t.style[s]=i?`calc( 2 * var(--ck-spacing-standard) + ${i}px )`:""};this.on("change:_resultsCounterText",s,{priority:"low"}),this.on("change:isDirty",s,{priority:"low"}),this._findInputView.template.children[0].children.push(n)}_createReplaceFieldset(){const e=this.locale.t,t=new Un(this.locale);return this._replaceButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replace:e},t)=>e&&t)),this._replaceAllButtonView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replaceAll:e},t)=>e&&t)),this._replaceInputView.bind("isEnabled").to(this,"_areCommandsEnabled",this,"_searchResultsFound",(({replace:e},t)=>e&&t)),this._replaceInputView.bind("infoText").to(this._replaceInputView,"isEnabled",this._replaceInputView,"isFocused",((t,i)=>t||!i?"":e("Tip: Find some text first in order to replace it."))),this._replaceButtonView.on("execute",(()=>{this.fire("replace",{searchText:this._textToFind,replaceText:this._textToReplace})})),this._replaceAllButtonView.on("execute",(()=>{this.fire("replaceAll",{searchText:this._textToFind,replaceText:this._textToReplace}),this.focus()})),t.setTemplate({tag:"fieldset",attributes:{class:["ck","ck-find-and-replace-form__replace"]},children:[this._replaceInputView,this._optionsDropdown,this._replaceButtonView,this._replaceAllButtonView]}),t}_createOptionsDropdown(){const e=this.locale.t,t=ru(this.locale);t.class="ck-options-dropdown",t.buttonView.set({withText:!1,label:e("Show options"),icon:Kh.cog,tooltip:!0});const i=new _m({withText:!0,label:e("Match case"),_isMatchCaseSwitch:!0}),n=new _m({withText:!0,label:e("Whole words only")});return i.bind("isOn").to(this,"_matchCase"),n.bind("isOn").to(this,"_wholeWordsOnly"),t.on("execute",(e=>{e.source._isMatchCaseSwitch?this._matchCase=!this._matchCase:this._wholeWordsOnly=!this._wholeWordsOnly,this.isDirty=!0})),cu(t,new Ln([{type:"switchbutton",model:i},{type:"switchbutton",model:n}])),t}_initFocusCycling(){[this._findInputView,this._findButtonView,this._findPrevButtonView,this._findNextButtonView,this._replaceInputView,this._optionsDropdown,this._replaceButtonView,this._replaceAllButtonView].forEach((e=>{this._focusables.add(e),this._focusTracker.add(e.element)}))}_initKeystrokeHandling(){const e=e=>e.stopPropagation(),t=e=>{e.stopPropagation(),e.preventDefault()};this._keystrokes.listenTo(this.element),this._keystrokes.set("f3",(e=>{t(e),this._findNextButtonView.fire("execute")})),this._keystrokes.set("shift+f3",(e=>{t(e),this._findPrevButtonView.fire("execute")})),this._keystrokes.set("enter",(e=>{const i=e.target;i===this._findInputView.fieldView.element?(this._areCommandsEnabled.findNext?this._findNextButtonView.fire("execute"):this._findButtonView.fire("execute"),t(e)):i!==this._replaceInputView.fieldView.element||this.isDirty||(this._replaceButtonView.fire("execute"),t(e))})),this._keystrokes.set("shift+enter",(e=>{e.target===this._findInputView.fieldView.element&&(this._areCommandsEnabled.findPrevious?this._findPrevButtonView.fire("execute"):this._findButtonView.fire("execute"),t(e))})),this._keystrokes.set("arrowright",e),this._keystrokes.set("arrowleft",e),this._keystrokes.set("arrowup",e),this._keystrokes.set("arrowdown",e)}_createButton(e){const t=new fs(this.locale);return t.set(e),t}_createInputField(e){const t=new $s(this.locale,mu);return t.label=e,t}}class Ew extends io{static get pluginName(){return"FindAndReplaceUI"}constructor(e){super(e),this.formView=null}init(){const e=this.editor;e.ui.componentFactory.add("findAndReplace",(i=>{const n=ru(i),s=e.commands.get("find");return n.bind("isEnabled").to(s),n.once("change:isOpen",(()=>{this.formView=new(t(Tw))(e.locale),n.panelView.children.add(this.formView),this._setupFormView(this.formView)})),n.on("change:isOpen",((e,t,i)=>{i?(this.formView.disableCssTransitions(),this.formView.reset(),this.formView._findInputView.fieldView.select(),this.formView.enableCssTransitions()):this.fire("searchReseted")}),{priority:"low"}),this._setupDropdownButton(n),n}))}_setupDropdownButton(e){const t=this.editor,i=t.locale.t;e.buttonView.set({icon:'',label:i("Find and replace"),keystroke:"CTRL+F",tooltip:!0}),t.keystrokes.set("Ctrl+F",((t,i)=>{e.isEnabled&&(e.isOpen=!0,i())}))}_setupFormView(e){const t=this.editor.commands,i=this.editor.plugins.get("FindAndReplaceEditing").state,n={before:-1,same:0,after:1,different:1};e.bind("highlightOffset").to(i,"highlightedResult",(e=>e?Array.from(i.results).sort(((e,t)=>n[e.marker.getStart().compareWith(t.marker.getStart())])).indexOf(e)+1:0)),e.listenTo(i.results,"change",(()=>{e.matchCount=i.results.length}));const s=t.get("findNext"),o=t.get("findPrevious"),r=t.get("replace"),a=t.get("replaceAll");e.bind("_areCommandsEnabled").to(s,"isEnabled",o,"isEnabled",r,"isEnabled",a,"isEnabled",((e,t,i,n)=>({findNext:e,findPrevious:t,replace:i,replaceAll:n}))),e.delegate("findNext","findPrevious","replace","replaceAll").to(this),e.on("change:isDirty",((e,t,i)=>{i&&this.fire("searchReseted")}))}}class Sw extends so{constructor(e,t){super(e),this.isEnabled=!0,this.affectsData=!1,this._state=t}execute(e,{matchCase:t,wholeWords:i}={}){const{editor:n}=this,{model:s}=n,o=n.plugins.get("FindAndReplaceUtils");let r;"string"==typeof e?(r=o.findByTextCallback(e,{matchCase:t,wholeWords:i}),this._state.searchText=e):r=e;const a=s.document.getRootNames().reduce(((e,t)=>o.updateFindResultFromRange(s.createRangeIn(s.document.getRoot(t)),s,r,e)),null);return this._state.clear(s),this._state.results.addMany(a),this._state.highlightedResult=a.get(0),"string"==typeof e&&(this._state.searchText=e),this._state.matchCase=!!t,this._state.matchWholeWords=!!i,{results:a,findCallback:r}}}class Pw extends so{constructor(e,t){super(e),this.isEnabled=!0,this._state=t,this._isEnabledBasedOnSelection=!1}_replace(e,t){const{model:i}=this.editor,n=t.marker.getRange();i.canEditAt(n)&&i.change((s=>{if("$graveyard"===n.root.rootName)return void this._state.results.remove(t);let o={};for(const e of n.getItems())if(e.is("$text")||e.is("$textProxy")){o=e.getAttributes();break}i.insertContent(s.createText(e,o),n),this._state.results.has(t)&&this._state.results.remove(t)}))}}class Iw extends Pw{execute(e,t){this._replace(e,t)}}class Vw extends Pw{execute(e,t){const{editor:i}=this,{model:n}=i,s=i.plugins.get("FindAndReplaceUtils"),o=t instanceof Ln?t:n.document.getRootNames().reduce(((e,i)=>s.updateFindResultFromRange(n.createRangeIn(n.document.getRoot(i)),n,s.findByTextCallback(t,this._state),e)),null);o.length&&n.change((()=>{[...o].forEach((t=>{this._replace(e,t)}))}))}}class Rw extends so{constructor(e,t){super(e),this.affectsData=!1,this._state=t,this.isEnabled=!1,this.listenTo(this._state.results,"change",(()=>{this.isEnabled=this._state.results.length>1}))}refresh(){this.isEnabled=this._state.results.length>1}execute(){const e=this._state.results,t=e.getIndex(this._state.highlightedResult),i=t+1>=e.length?0:t+1;this._state.highlightedResult=this._state.results.get(i)}}class Lw extends Rw{execute(){const e=this._state.results.getIndex(this._state.highlightedResult),t=e-1<0?this._state.results.length-1:e-1;this._state.highlightedResult=this._state.results.get(t)}}class Ow extends(W()){constructor(e){super(),this.set("results",new Ln),this.set("highlightedResult",null),this.set("searchText",""),this.set("replaceText",""),this.set("matchCase",!1),this.set("matchWholeWords",!1),this.results.on("change",((t,{removed:i,index:n})=>{if(Array.from(i).length){let t=!1;if(e.change((n=>{for(const s of i)this.highlightedResult===s&&(t=!0),e.markers.has(s.marker.name)&&n.removeMarker(s.marker)})),t){const e=n>=this.results.length?0:n;this.highlightedResult=this.results.get(e)}}}))}clear(e){this.searchText="",e.change((t=>{if(this.highlightedResult){const i=this.highlightedResult.marker.name.split(":")[1],n=e.markers.get(`findResultHighlighted:${i}`);n&&t.removeMarker(n)}[...this.results].forEach((({marker:e})=>{t.removeMarker(e)}))})),this.results.clear()}}class Bw extends io{static get pluginName(){return"FindAndReplaceUtils"}updateFindResultFromRange(e,t,i,n){const s=n||new Ln;return t.change((n=>{[...e].forEach((({type:e,item:o})=>{if("elementStart"===e&&t.schema.checkChild(o,"$text")){const e=i({item:o,text:this.rangeToText(t.createRangeIn(o))});if(!e)return;e.forEach((e=>{const t=`findResult:${p()}`,i=n.addMarker(t,{usingOperation:!1,affectsData:!1,range:n.createRange(n.createPositionAt(o,e.start),n.createPositionAt(o,e.end))}),r=function(e,t){const i=e.find((({marker:e})=>t.getStart().isBefore(e.getStart())));return i?e.getIndex(i):e.length}(s,i);s.add({id:t,label:e.label,marker:i},r)}))}}))})),s}rangeToText(e){return Array.from(e.getItems()).reduce(((e,t)=>t.is("$text")||t.is("$textProxy")?e+t.data:`${e}\n`),"")}findByTextCallback(e,t){let i="gu";t.matchCase||(i+="i");let n=`(${Lm(e)})`;if(t.wholeWords){const t="[^a-zA-ZÀ-ɏḀ-ỿ]";new RegExp("^"+t).test(e)||(n=`(^|${t}|_)${n}`),new RegExp(t+"$").test(e)||(n=`${n}(?=_|${t}|$)`)}const s=new RegExp(n,i);return function({text:e}){return[...e.matchAll(s)].map(Mw)}}}function Mw(e){const t=e.length-1;let i=e.index;return 3===e.length&&(i+=e[1].length),{label:e[t],start:i,end:i+e[t].length}}class Nw extends io{static get requires(){return[Bw]}static get pluginName(){return"FindAndReplaceEditing"}init(){this._activeResults=null,this.state=new Ow(this.editor.model),this._defineConverters(),this._defineCommands(),this.listenTo(this.state,"change:highlightedResult",((e,t,i,n)=>{const{model:s}=this.editor;s.change((e=>{if(n){const t=n.marker.name.split(":")[1],i=s.markers.get(`findResultHighlighted:${t}`);i&&e.removeMarker(i)}if(i){const t=i.marker.name.split(":")[1];e.addMarker(`findResultHighlighted:${t}`,{usingOperation:!1,affectsData:!1,range:i.marker.getRange()})}}))}));const e=zs(((e,t,i)=>{if(i){const e=this.editor.editing.view.domConverter,t=this.editor.editing.mapper.toViewRange(i.marker.getRange());hn({target:e.viewRangeToDom(t),viewportOffset:40})}}).bind(this),32);this.listenTo(this.state,"change:highlightedResult",e,{priority:"low"}),this.listenTo(this.editor,"destroy",e.cancel)}find(e){const{editor:t}=this,{model:i}=t,{findCallback:n,results:s}=t.execute("find",e);return this._activeResults=s,this.listenTo(i.document,"change:data",(()=>function(e,t,i){const n=new Set,s=new Set,o=t.model;o.document.differ.getChanges().forEach((e=>{"$text"===e.name||o.schema.isInline(e.position.nodeAfter)?(n.add(e.position.parent),[...o.markers.getMarkersAtPosition(e.position)].forEach((e=>{s.add(e.name)}))):"insert"===e.type&&n.add(e.position.nodeAfter)})),o.document.differ.getChangedMarkers().forEach((({name:e,data:{newRange:t}})=>{t&&"$graveyard"===t.start.root.rootName&&s.add(e)})),n.forEach((e=>{[...o.markers.getMarkersIntersectingRange(o.createRangeIn(e))].forEach((e=>s.add(e.name)))})),o.change((t=>{s.forEach((i=>{e.has(i)&&e.remove(i),t.removeMarker(i)}))})),n.forEach((n=>{t.plugins.get("FindAndReplaceUtils").updateFindResultFromRange(o.createRangeOn(n),o,i,e)}))}(this._activeResults,t,n))),this._activeResults}stop(){this._activeResults&&(this.stopListening(this.editor.model.document),this.state.clear(this.editor.model),this._activeResults=null)}_defineCommands(){this.editor.commands.add("find",new Sw(this.editor,this.state)),this.editor.commands.add("findNext",new Rw(this.editor,this.state)),this.editor.commands.add("findPrevious",new Lw(this.editor,this.state)),this.editor.commands.add("replace",new Iw(this.editor,this.state)),this.editor.commands.add("replaceAll",new Vw(this.editor,this.state))}_defineConverters(){const{editor:e}=this;e.conversion.for("editingDowncast").markerToHighlight({model:"findResult",view:({markerName:e})=>{const[,t]=e.split(":");return{name:"span",classes:["ck-find-result"],attributes:{"data-find-result":t}}}}),e.conversion.for("editingDowncast").markerToHighlight({model:"findResultHighlighted",view:({markerName:e})=>{const[,t]=e.split(":");return{name:"span",classes:["ck-find-result_selected"],attributes:{"data-find-result":t}}}})}}class Fw extends so{constructor(e,t){super(e),this.attributeKey=t}refresh(){const e=this.editor.model,t=e.document;this.value=t.selection.getAttribute(this.attributeKey),this.isEnabled=e.schema.checkAttributeInSelection(t.selection,this.attributeKey)}execute(e={}){const t=this.editor.model,i=t.document.selection,n=e.value,s=e.batch,o=e=>{if(i.isCollapsed)n?e.setSelectionAttribute(this.attributeKey,n):e.removeSelectionAttribute(this.attributeKey);else{const s=t.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const t of s)n?e.setAttribute(this.attributeKey,n,t):e.removeAttribute(this.attributeKey,t)}};s?t.enqueueChange(s,(e=>{o(e)})):t.change((e=>{o(e)}))}}const Dw="fontSize";class zw extends Fw{constructor(e){super(e,Dw)}}function Hw(e){return e.map((e=>function(e){if("number"==typeof e&&(e=String(e)),"object"==typeof e&&((t=e).title&&t.model&&t.view))return Ww(e);var t;const i=function(e){return"string"==typeof e?$w[e]:$w[e.model]}(e);return i?Ww(i):"default"===e?{model:void 0,title:"Default"}:function(e){let t;if("object"==typeof e){if(!e.model)throw new _("font-size-invalid-definition",null,e);t=parseFloat(e.model)}else t=parseFloat(e);return isNaN(t)}(e)?void 0:function(e){return"string"==typeof e&&(e={title:e,model:`${parseFloat(e)}px`}),e.view={name:"span",styles:{"font-size":e.model}},Ww(e)}(e)}(e))).filter((e=>void 0!==e))}const $w={get tiny(){return{title:"Tiny",model:"tiny",view:{name:"span",classes:"text-tiny",priority:7}}},get small(){return{title:"Small",model:"small",view:{name:"span",classes:"text-small",priority:7}}},get big(){return{title:"Big",model:"big",view:{name:"span",classes:"text-big",priority:7}}},get huge(){return{title:"Huge",model:"huge",view:{name:"span",classes:"text-huge",priority:7}}}};function Ww(e){return e.view&&"string"!=typeof e.view&&!e.view.priority&&(e.view.priority=7),e}const Uw=["x-small","x-small","small","medium","large","x-large","xx-large","xxx-large"];class jw extends io{static get pluginName(){return"FontSizeEditing"}constructor(e){super(e),e.config.define(Dw,{options:["tiny","small","default","big","huge"],supportAllValues:!1})}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:Dw}),e.model.schema.setAttributeProperties(Dw,{isFormatting:!0,copyOnEnter:!0});const t=e.config.get("fontSize.supportAllValues"),i=Hw(this.editor.config.get("fontSize.options")).filter((e=>e.model)),n=function(e,t){const i={model:{key:e,values:[]},view:{},upcastAlso:{}};for(const e of t)i.model.values.push(e.model),i.view[e.model]=e.view,e.upcastAlso&&(i.upcastAlso[e.model]=e.upcastAlso);return i}(Dw,i);t?(this._prepareAnyValueConverters(n),this._prepareCompatibilityConverter()):e.conversion.attributeToElement(n),e.commands.add(Dw,new zw(e))}_prepareAnyValueConverters(e){const t=this.editor,i=e.model.values.filter((e=>!hh(String(e))&&!mh(String(e))));if(i.length)throw new _("font-size-invalid-use-of-named-presets",null,{presets:i});t.conversion.for("downcast").attributeToElement({model:Dw,view:(e,{writer:t})=>{if(e)return t.createAttributeElement("span",{style:"font-size:"+e},{priority:7})}}),t.conversion.for("upcast").elementToAttribute({model:{key:Dw,value:e=>e.getStyle("font-size")},view:{name:"span",styles:{"font-size":/.*/}}})}_prepareCompatibilityConverter(){this.editor.conversion.for("upcast").elementToAttribute({view:{name:"font",attributes:{size:/^[+-]?\d{1,3}$/}},model:{key:Dw,value:e=>{const t=e.getAttribute("size"),i="-"===t[0]||"+"===t[0];let n=parseInt(t,10);i&&(n=3+n);const s=Uw.length-1,o=Math.min(Math.max(n,0),s);return Uw[o]}}})}}class qw extends io{static get pluginName(){return"FontSizeUI"}init(){const e=this.editor,t=e.t,i=this._getLocalizedOptions(),n=e.commands.get(Dw),s=t("Font Size");e.ui.componentFactory.add(Dw,(t=>{const o=ru(t);return cu(o,(()=>function(e,t){const i=new Ln;for(const n of e){const e={type:"button",model:new _m({commandName:Dw,commandParam:n.model,label:n.title,class:"ck-fontsize-option",role:"menuitemradio",withText:!0})};n.view&&"string"!=typeof n.view&&(n.view.styles&&e.model.set("labelStyle",`font-size:${n.view.styles["font-size"]}`),n.view.classes&&e.model.set("class",`${e.model.class} ${n.view.classes}`)),e.model.bind("isOn").to(t,"value",(e=>e===n.model)),i.add(e)}return i}(i,n)),{role:"menu",ariaLabel:s}),o.buttonView.set({label:s,icon:'',tooltip:!0}),o.extendTemplate({attributes:{class:["ck-font-size-dropdown"]}}),o.bind("isEnabled").to(n),this.listenTo(o,"execute",(t=>{e.execute(t.source.commandName,{value:t.source.commandParam}),e.editing.view.focus()})),o}))}_getLocalizedOptions(){const e=this.editor,t=e.t,i={Default:t("Default"),Tiny:t("Tiny"),Small:t("Small"),Big:t("Big"),Huge:t("Huge")};return Hw(e.config.get(Dw).options).map((e=>{const t=i[e.title];return t&&t!=e.title&&(e=Object.assign({},e,{title:t})),e}))}}class Gw extends io{static get requires(){return[gw]}static get pluginName(){return"CodeBlockElementSupport"}init(){if(!this.editor.plugins.has("CodeBlockEditing"))return;const e=this.editor.plugins.get(gw);e.on("register:pre",((t,i)=>{if("codeBlock"!==i.model)return;const n=this.editor,s=n.model.schema,o=n.conversion;s.extend("codeBlock",{allowAttributes:["htmlPreAttributes","htmlContentAttributes"]}),o.for("upcast").add(function(e){return t=>{t.on("element:code",((t,i,n)=>{const s=i.viewItem,o=s.parent;function r(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}o&&o.is("element","pre")&&(r(o,"htmlPreAttributes"),r(s,"htmlContentAttributes"))}),{priority:"low"})}}(e)),o.for("downcast").add((e=>{e.on("attribute:htmlPreAttributes:codeBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item).parent;Kb(i.writer,n,s,o)})),e.on("attribute:htmlContentAttributes:codeBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item);Kb(i.writer,n,s,o)}))})),t.stop()}))}}class Kw extends io{static get requires(){return[gw]}static get pluginName(){return"DualContentModelElementSupport"}init(){this.editor.plugins.get(gw).on("register",((e,t)=>{const i=t,n=this.editor,s=n.model.schema,o=n.conversion;if(!i.paragraphLikeModel)return;if(s.isRegistered(i.model)||s.isRegistered(i.paragraphLikeModel))return;const r={model:i.paragraphLikeModel,view:i.view};s.register(i.model,i.modelSchema),s.register(r.model,{inheritAllFrom:"$block"}),o.for("upcast").elementToElement({view:i.view,model:(e,{writer:t})=>this._hasBlockContent(e)?t.createElement(i.model):t.createElement(r.model),converterPriority:b.low+.5}),o.for("downcast").elementToElement({view:i.view,model:i.model}),this._addAttributeConversion(i),o.for("downcast").elementToElement({view:r.view,model:r.model}),this._addAttributeConversion(r),e.stop()}))}_hasBlockContent(e){const t=this.editor.editing.view,i=t.domConverter.blockElements;for(const n of t.createRangeIn(e).getItems())if(n.is("element")&&i.includes(n.name))return!0;return!1}_addAttributeConversion(e){const t=this.editor,i=t.conversion,n=t.plugins.get(gw);t.model.schema.extend(e.model,{allowAttributes:Zb(e.view)}),i.for("upcast").add(nw(e,n)),i.for("downcast").add(sw(e))}}class Jw extends io{static get requires(){return[lw,qg]}static get pluginName(){return"HeadingElementSupport"}init(){const e=this.editor;if(!e.plugins.has("HeadingEditing"))return;const t=e.config.get("heading.options");this.registerHeadingElements(e,t)}registerHeadingElements(e,t){const i=e.plugins.get(lw),n=[];for(const e of t)"model"in e&&"view"in e&&(i.registerBlockElement({view:e.view,model:e.model}),n.push(e.model));i.extendBlockElement({model:"htmlHgroup",modelSchema:{allowChildren:n}})}}function Qw(e,t,i){const n=e.createRangeOn(t);for(const{item:e}of n.getWalker())if(e.is("element",i))return e}class Zw extends io{static get requires(){return[gw]}static get pluginName(){return"ImageElementSupport"}init(){const e=this.editor;if(!e.plugins.has("ImageInlineEditing")&&!e.plugins.has("ImageBlockEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(gw);n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("image"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on("register:img",((s,o)=>{"imageBlock"!==o.model&&"imageInline"!==o.model||(t.isRegistered("imageBlock")&&t.extend("imageBlock",{allowAttributes:["htmlImgAttributes","htmlFigureAttributes","htmlLinkAttributes"]}),t.isRegistered("imageInline")&&t.extend("imageInline",{allowAttributes:["htmlA","htmlImgAttributes"]}),i.for("upcast").add(function(e){return t=>{t.on("element:img",((t,i,n)=>{if(!i.modelRange)return;const s=i.viewItem,o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlImgAttributes",o,i.modelRange)}),{priority:"low"})}}(n)),i.for("downcast").add((e=>{function t(t,i){e.on(`attribute:${i}:imageBlock`,((e,i,n)=>{if(!n.consumable.test(i.item,e.name))return;const{attributeOldValue:s,attributeNewValue:o}=i,r=n.mapper.toViewElement(i.item),a=Qw(n.writer,r,t);a&&(Kb(n.writer,s,o,a),n.consumable.consume(i.item,e.name))}),{priority:"low"}),"a"===t&&e.on("attribute:linkHref:imageBlock",((e,t,i)=>{if(!i.consumable.consume(t.item,"attribute:htmlLinkAttributes:imageBlock"))return;const n=i.mapper.toViewElement(t.item),s=Qw(i.writer,n,"a");Jb(i.writer,t.item.getAttribute("htmlLinkAttributes"),s)}),{priority:"low"})}var i;i="htmlImgAttributes",e.on(`attribute:${i}:imageInline`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const{attributeOldValue:n,attributeNewValue:s}=t,o=i.mapper.toViewElement(t.item);Kb(i.writer,n,s,o)}),{priority:"low"}),t("img","htmlImgAttributes"),t("figure","htmlFigureAttributes"),t("a","htmlLinkAttributes")})),e.plugins.has("LinkImage")&&i.for("upcast").add(function(e,t){const i=t.plugins.get("ImageUtils");return t=>{t.on("element:a",((t,n,s)=>{const o=n.viewItem;if(!i.findViewImgElement(o))return;const r=n.modelCursor.parent;if(!r.is("element","imageBlock"))return;const a=e.processViewAttributes(o,s);a&&s.writer.setAttribute("htmlLinkAttributes",a,r)}),{priority:"low"})}}(n,e)),s.stop())}))}}class Yw extends io{static get requires(){return[gw]}static get pluginName(){return"MediaEmbedElementSupport"}init(){const e=this.editor;if(!e.plugins.has("MediaEmbed")||e.config.get("mediaEmbed.previewsInData"))return;const t=e.model.schema,i=e.conversion,n=this.editor.plugins.get(gw),s=this.editor.plugins.get(lw),o=e.config.get("mediaEmbed.elementName");s.registerBlockElement({model:"media",view:o}),n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("media"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on(`register:${o}`,((e,s)=>{"media"===s.model&&(t.extend("media",{allowAttributes:[Zb(o),"htmlFigureAttributes"]}),i.for("upcast").add(function(e,t){const i=(i,n,s)=>{!function(t,i){const o=e.processViewAttributes(t,s);o&&s.writer.setAttribute(i,o,n.modelRange)}(n.viewItem,Zb(t))};return e=>{e.on(`element:${t}`,i,{priority:"low"})}}(n,o)),i.for("dataDowncast").add(function(e){return t=>{function i(e,i){t.on(`attribute:${i}:media`,((t,i,n)=>{if(!n.consumable.consume(i.item,t.name))return;const{attributeOldValue:s,attributeNewValue:o}=i,r=n.mapper.toViewElement(i.item),a=Qw(n.writer,r,e);Kb(n.writer,s,o,a)}))}i(e,Zb(e)),i("figure","htmlFigureAttributes")}}(o)),e.stop())}))}}class Xw extends io{static get requires(){return[gw]}static get pluginName(){return"ScriptElementSupport"}init(){const e=this.editor.plugins.get(gw);e.on("register:script",((t,i)=>{const n=this.editor,s=n.model.schema,o=n.conversion;s.register("htmlScript",i.modelSchema),s.extend("htmlScript",{allowAttributes:["htmlScriptAttributes","htmlContent"],isContent:!0}),n.data.registerRawContentMatcher({name:"script"}),o.for("upcast").elementToElement({view:"script",model:Yb(i)}),o.for("upcast").add(nw(i,e)),o.for("downcast").elementToElement({model:"htmlScript",view:(e,{writer:t})=>ew("script",e,t)}),o.for("downcast").add(sw(i)),t.stop()}))}}class ev extends io{static get requires(){return[gw]}static get pluginName(){return"TableElementSupport"}init(){const e=this.editor;if(!e.plugins.has("TableEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(gw),s=e.plugins.get("TableUtils");n.on("register:figure",(()=>{i.for("upcast").add(function(e){return t=>{t.on("element:figure",((t,i,n)=>{const s=i.viewItem;if(!i.modelRange||!s.hasClass("table"))return;const o=e.processViewAttributes(s,n);o&&n.writer.setAttribute("htmlFigureAttributes",o,i.modelRange)}),{priority:"low"})}}(n))})),n.on("register:table",((o,r)=>{"table"===r.model&&(t.extend("table",{allowAttributes:["htmlTableAttributes","htmlFigureAttributes","htmlTheadAttributes","htmlTbodyAttributes"]}),i.for("upcast").add(function(e){return t=>{t.on("element:table",((t,i,n)=>{if(!i.modelRange)return;const s=i.viewItem;o(s,"htmlTableAttributes");for(const e of s.getChildren())e.is("element","thead")&&o(e,"htmlTheadAttributes"),e.is("element","tbody")&&o(e,"htmlTbodyAttributes");function o(t,s){const o=e.processViewAttributes(t,n);o&&n.writer.setAttribute(s,o,i.modelRange)}}),{priority:"low"})}}(n)),i.for("downcast").add((e=>{function t(t,i){e.on(`attribute:${i}:table`,((e,i,n)=>{if(!n.consumable.test(i.item,e.name))return;const s=n.mapper.toViewElement(i.item),o=Qw(n.writer,s,t);o&&(n.consumable.consume(i.item,e.name),Kb(n.writer,i.attributeOldValue,i.attributeNewValue,o))}))}t("table","htmlTableAttributes"),t("figure","htmlFigureAttributes"),t("thead","htmlTheadAttributes"),t("tbody","htmlTbodyAttributes")})),e.model.document.registerPostFixer(function(e,t){return i=>{const n=e.document.differ.getChanges();let s=!1;for(const e of n){if("attribute"!=e.type||"headingRows"!=e.attributeKey)continue;const n=e.range.start.nodeAfter,o=n.getAttribute("htmlTheadAttributes"),r=n.getAttribute("htmlTbodyAttributes");o&&!e.attributeNewValue?(i.removeAttribute("htmlTheadAttributes",n),s=!0):r&&e.attributeNewValue==t.getRows(n)&&(i.removeAttribute("htmlTbodyAttributes",n),s=!0)}return s}}(e.model,s)),o.stop())}))}}class tv extends io{static get requires(){return[gw]}static get pluginName(){return"StyleElementSupport"}init(){const e=this.editor.plugins.get(gw);e.on("register:style",((t,i)=>{const n=this.editor,s=n.model.schema,o=n.conversion;s.register("htmlStyle",i.modelSchema),s.extend("htmlStyle",{allowAttributes:["htmlStyleAttributes","htmlContent"],isContent:!0}),n.data.registerRawContentMatcher({name:"style"}),o.for("upcast").elementToElement({view:"style",model:Yb(i)}),o.for("upcast").add(nw(i,e)),o.for("downcast").elementToElement({model:"htmlStyle",view:(e,{writer:t})=>ew("style",e,t)}),o.for("downcast").add(sw(i)),t.stop()}))}}class iv extends io{static get requires(){return[gw]}static get pluginName(){return"DocumentListElementSupport"}init(){const e=this.editor;if(!e.plugins.has("DocumentListEditing"))return;const t=e.model.schema,i=e.conversion,n=e.plugins.get(gw),s=e.plugins.get("DocumentListEditing"),o=["ul","ol","li"];s.registerDowncastStrategy({scope:"item",attributeName:"htmlLiAttributes",setAttributeOnDowncast:Jb}),s.registerDowncastStrategy({scope:"list",attributeName:"htmlUlAttributes",setAttributeOnDowncast:Jb}),s.registerDowncastStrategy({scope:"list",attributeName:"htmlOlAttributes",setAttributeOnDowncast:Jb}),n.on("register",((e,s)=>{if(!o.includes(s.view))return;if(e.stop(),t.checkAttribute("$block","htmlLiAttributes"))return;const r=o.map((e=>Zb(e)));t.extend("$listItem",{allowAttributes:r}),i.for("upcast").add((e=>{e.on("element:ul",nv("htmlUlAttributes",n),{priority:"low"}),e.on("element:ol",nv("htmlOlAttributes",n),{priority:"low"}),e.on("element:li",nv("htmlLiAttributes",n),{priority:"low"})}))})),s.on("postFixer",((e,{listNodes:t,writer:i})=>{for(const{node:n,previousNodeInList:s}of t)if(s){if(s.getAttribute("listType")==n.getAttribute("listType")){const t=sv(s.getAttribute("listType")),o=s.getAttribute(t);!Gc(n.getAttribute(t),o)&&i.model.schema.checkAttribute(n,t)&&(i.setAttribute(t,o,n),e.return=!0)}if(s.getAttribute("listItemId")==n.getAttribute("listItemId")){const t=s.getAttribute("htmlLiAttributes");!Gc(n.getAttribute("htmlLiAttributes"),t)&&i.model.schema.checkAttribute(n,"htmlLiAttributes")&&(i.setAttribute("htmlLiAttributes",t,n),e.return=!0)}}})),s.on("postFixer",((e,{listNodes:t,writer:i})=>{for(const{node:n}of t){const t=n.getAttribute("listType");"numbered"!==t&&n.getAttribute("htmlOlAttributes")&&(i.removeAttribute("htmlOlAttributes",n),e.return=!0),"numbered"===t&&n.getAttribute("htmlUlAttributes")&&(i.removeAttribute("htmlUlAttributes",n),e.return=!0)}}))}afterInit(){const e=this.editor;if(!e.commands.get("indentList"))return;const t=e.commands.get("indentList");this.listenTo(t,"afterExecute",((t,i)=>{e.model.change((t=>{for(const n of i){const i=sv(n.getAttribute("listType"));e.model.schema.checkAttribute(n,i)&&t.setAttribute(i,{},n)}}))}))}}function nv(e,t){return(i,n,s)=>{const o=n.viewItem;n.modelRange||Object.assign(n,s.convertChildren(n.viewItem,n.modelCursor));const r=t.processViewAttributes(o,s);for(const t of n.modelRange.getItems({shallow:!0}))t.hasAttribute("listItemId")&&(t.hasAttribute(e)||s.writer.model.schema.checkAttribute(t,e)&&s.writer.setAttribute(e,r||{},t))}}function sv(e){return"numbered"===e?"htmlOlAttributes":"htmlUlAttributes"}class ov extends io{static get requires(){return[gw,lw]}static get pluginName(){return"CustomElementSupport"}init(){const e=this.editor.plugins.get(gw),t=this.editor.plugins.get(lw);e.on("register:$customElement",((i,n)=>{i.stop();const s=this.editor,o=s.model.schema,r=s.conversion,a=s.editing.view.domConverter.unsafeElements,l=s.data.htmlProcessor.domConverter.preElements;o.register(n.model,n.modelSchema),o.extend(n.model,{allowAttributes:["htmlElementName","htmlCustomElementAttributes","htmlContent"],isContent:!0}),r.for("upcast").elementToElement({view:/.*/,model:(i,o)=>{if("$comment"==i.name)return null;if(!function(e){try{document.createElement(e)}catch(e){return!1}return!0}(i.name))return null;if(t.getDefinitionsForView(i.name).size)return null;a.includes(i.name)||a.push(i.name),l.includes(i.name)||l.push(i.name);const r=o.writer.createElement(n.model,{htmlElementName:i.name}),c=e.processViewAttributes(i,o);c&&o.writer.setAttribute("htmlCustomElementAttributes",c,r);const d=new Xd(i.document).createDocumentFragment(i),h=s.data.processor.toData(d);o.writer.setAttribute("htmlContent",h,r);for(const{item:e}of s.editing.view.createRangeIn(i))o.consumable.consume(e,{name:!0});return r},converterPriority:"low"}),r.for("editingDowncast").elementToElement({model:{name:n.model,attributes:["htmlElementName","htmlCustomElementAttributes","htmlContent"]},view:(e,{writer:t})=>{const i=e.getAttribute("htmlElementName"),n=t.createRawElement(i);return e.hasAttribute("htmlCustomElementAttributes")&&Jb(t,e.getAttribute("htmlCustomElementAttributes"),n),n}}),r.for("dataDowncast").elementToElement({model:{name:n.model,attributes:["htmlElementName","htmlCustomElementAttributes","htmlContent"]},view:(e,{writer:t})=>{const i=e.getAttribute("htmlElementName"),n=e.getAttribute("htmlContent"),s=t.createRawElement(i,null,((e,t)=>{t.setContentOf(e,n);const i=e.firstChild;for(i.remove();i.firstChild;)e.appendChild(i.firstChild)}));return e.hasAttribute("htmlCustomElementAttributes")&&Jb(t,e.getAttribute("htmlCustomElementAttributes"),s),s}})}))}}function*rv(e,t,i){if(t)if(!(Symbol.iterator in t)&&t.is("documentSelection")&&t.isCollapsed)e.schema.checkAttributeInSelection(t,i)&&(yield t);else for(const n of function(e,t,i){return!(Symbol.iterator in t)&&(t.is("node")||t.is("$text")||t.is("$textProxy"))?e.schema.checkAttribute(t,i)?[e.createRangeOn(t)]:[]:e.schema.getValidRanges(e.createSelection(t).getRanges(),i)}(e,t,i))yield*n.getItems({shallow:!0})}class av extends so{constructor(e){super(e),this._isEnabledBasedOnSelection=!1}refresh(){const e=this.editor.model,t=On(e.document.selection.getSelectedBlocks());this.value=!!t&&t.is("element","paragraph"),this.isEnabled=!!t&&lv(t,e.schema)}execute(e={}){const t=this.editor.model,i=t.document,n=e.selection||i.selection;t.canEditAt(n)&&t.change((e=>{const i=n.getSelectedBlocks();for(const n of i)!n.is("element","paragraph")&&lv(n,t.schema)&&e.rename(n,"paragraph")}))}}function lv(e,t){return t.checkChild(e.parent,"paragraph")&&!t.isObject(e)}class cv extends so{constructor(e){super(e),this._isEnabledBasedOnSelection=!1}execute(e){const t=this.editor.model,i=e.attributes;let n=e.position;t.canEditAt(n)&&t.change((e=>{if(n=this._findPositionToInsertParagraph(n,e),!n)return;const s=e.createElement("paragraph");i&&t.schema.setAllowedAttributes(s,i,e),t.insertContent(s,n),e.setSelection(s,"in")}))}_findPositionToInsertParagraph(e,t){const i=this.editor.model;if(i.schema.checkChild(e,"paragraph"))return e;const n=i.schema.findAllowedParent(e,"paragraph");if(!n)return null;const s=e.parent,o=i.schema.checkChild(s,"$text");return s.isEmpty||o&&e.isAtEnd?i.createPositionAfter(s):!s.isEmpty&&o&&e.isAtStart?i.createPositionBefore(s):t.split(e,n).position}}class dv extends io{static get pluginName(){return"Paragraph"}init(){const e=this.editor,t=e.model;e.commands.add("paragraph",new av(e)),e.commands.add("insertParagraph",new cv(e)),t.schema.register("paragraph",{inheritAllFrom:"$block"}),e.conversion.elementToElement({model:"paragraph",view:"p"}),e.conversion.for("upcast").elementToElement({model:(e,{writer:t})=>dv.paragraphLikeElements.has(e.name)?e.isEmpty?null:t.createElement("paragraph"):null,view:/.+/,converterPriority:"low"})}}dv.paragraphLikeElements=new Set(["blockquote","dd","div","dt","h1","h2","h3","h4","h5","h6","li","p","td","th"]);class hv extends so{constructor(e,t){super(e),this.modelElements=t}refresh(){const e=On(this.editor.model.document.selection.getSelectedBlocks());this.value=!!e&&this.modelElements.includes(e.name)&&e.name,this.isEnabled=!!e&&this.modelElements.some((t=>uv(e,t,this.editor.model.schema)))}execute(e){const t=this.editor.model,i=t.document,n=e.value;t.change((e=>{const s=Array.from(i.selection.getSelectedBlocks()).filter((e=>uv(e,n,t.schema)));for(const t of s)t.is("element",n)||e.rename(t,n)}))}}function uv(e,t,i){return i.checkChild(e.parent,t)&&!i.isObject(e)}const mv="paragraph";class gv extends io{static get pluginName(){return"HeadingEditing"}constructor(e){super(e),e.config.define("heading",{options:[{model:"paragraph",title:"Paragraph",class:"ck-heading_paragraph"},{model:"heading1",view:"h2",title:"Heading 1",class:"ck-heading_heading1"},{model:"heading2",view:"h3",title:"Heading 2",class:"ck-heading_heading2"},{model:"heading3",view:"h4",title:"Heading 3",class:"ck-heading_heading3"}]})}static get requires(){return[dv]}init(){const e=this.editor,t=e.config.get("heading.options"),i=[];for(const n of t)"paragraph"!==n.model&&(e.model.schema.register(n.model,{inheritAllFrom:"$block"}),e.conversion.elementToElement(n),i.push(n.model));this._addDefaultH1Conversion(e),e.commands.add("heading",new hv(e,i))}afterInit(){const e=this.editor,t=e.commands.get("enter"),i=e.config.get("heading.options");t&&this.listenTo(t,"afterExecute",((t,n)=>{const s=e.model.document.selection.getFirstPosition().parent;i.some((e=>s.is("element",e.model)))&&!s.is("element",mv)&&0===s.childCount&&n.writer.rename(s,mv)}))}_addDefaultH1Conversion(e){e.conversion.for("upcast").elementToElement({model:"heading1",view:"h1",converterPriority:b.low+1})}}class fv extends io{static get pluginName(){return"HeadingUI"}init(){const e=this.editor,t=e.t,i=function(e){const t=e.t,i={Paragraph:t("Paragraph"),"Heading 1":t("Heading 1"),"Heading 2":t("Heading 2"),"Heading 3":t("Heading 3"),"Heading 4":t("Heading 4"),"Heading 5":t("Heading 5"),"Heading 6":t("Heading 6")};return e.config.get("heading.options").map((e=>{const t=i[e.title];return t&&t!=e.title&&(e.title=t),e}))}(e),n=t("Choose heading"),s=t("Heading");e.ui.componentFactory.add("heading",(t=>{const o={},r=new Ln,a=e.commands.get("heading"),l=e.commands.get("paragraph"),c=[a];for(const e of i){const t={type:"button",model:new _m({label:e.title,class:e.class,role:"menuitemradio",withText:!0})};"paragraph"===e.model?(t.model.bind("isOn").to(l,"value"),t.model.set("commandName","paragraph"),c.push(l)):(t.model.bind("isOn").to(a,"value",(t=>t===e.model)),t.model.set({commandName:"heading",commandValue:e.model})),r.add(t),o[e.model]=e.title}const d=ru(t);return cu(d,r,{ariaLabel:s,role:"menu"}),d.buttonView.set({ariaLabel:s,ariaLabelledBy:void 0,isOn:!1,withText:!0,tooltip:s}),d.extendTemplate({attributes:{class:["ck-heading-dropdown"]}}),d.bind("isEnabled").toMany(c,"isEnabled",((...e)=>e.some((e=>e)))),d.buttonView.bind("label").to(a,"value",l,"value",((e,t)=>{const i=e||t&&"paragraph";return"boolean"==typeof i?n:o[i]?o[i]:n})),this.listenTo(d,"execute",(t=>{const{commandName:i,commandValue:n}=t.source;e.execute(i,n?{value:n}:void 0),e.editing.view.focus()})),d}))}}class pv extends so{refresh(){const e=this.editor.model,t=e.schema,i=e.document.selection;this.isEnabled=function(e,t,i){const n=function(e,t){const i=df(e,t).start.parent;return i.isEmpty&&!i.is("element","$root")?i.parent:i}(e,i);return t.checkChild(n,"horizontalLine")}(i,t,e)}execute(){const e=this.editor.model;e.change((t=>{const i=t.createElement("horizontalLine");e.insertObject(i,null,null,{setSelection:"after"})}))}}class bv extends io{static get pluginName(){return"HorizontalLineEditing"}init(){const e=this.editor,t=e.model.schema,i=e.t,n=e.conversion;t.register("horizontalLine",{inheritAllFrom:"$blockObject"}),n.for("dataDowncast").elementToElement({model:"horizontalLine",view:(e,{writer:t})=>t.createEmptyElement("hr")}),n.for("editingDowncast").elementToStructure({model:"horizontalLine",view:(e,{writer:t})=>{const n=i("Horizontal line"),s=t.createContainerElement("div",null,t.createEmptyElement("hr"));return t.addClass("ck-horizontal-line",s),t.setCustomProperty("hr",!0,s),function(e,t,i){return t.setCustomProperty("horizontalLine",!0,e),of(e,t,{label:i})}(s,t,n)}}),n.for("upcast").elementToElement({view:"hr",model:"horizontalLine"}),e.commands.add("horizontalLine",new pv(e))}}class wv extends io{static get pluginName(){return"HorizontalLineUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("horizontalLine",(i=>{const n=e.commands.get("horizontalLine"),s=new fs(i);return s.set({label:t("Horizontal line"),icon:'',tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("horizontalLine"),e.editing.view.focus()})),s}))}}class vv extends so{refresh(){const e=this.editor.model,t=e.schema,i=e.document.selection,n=_v(i);this.isEnabled=function(e,t,i){const n=function(e,t){const i=df(e,t).start.parent;return i.isEmpty&&!i.is("rootElement")?i.parent:i}(e,i);return t.checkChild(n,"rawHtml")}(i,t,e),this.value=n?n.getAttribute("value")||"":null}execute(e){const t=this.editor.model,i=t.document.selection;t.change((n=>{let s;null!==this.value?s=_v(i):(s=n.createElement("rawHtml"),t.insertObject(s,null,null,{setSelection:"on"})),n.setAttribute("value",e,s)}))}}function _v(e){const t=e.getSelectedElement();return t&&t.is("element","rawHtml")?t:null}class yv extends io{static get pluginName(){return"HtmlEmbedEditing"}constructor(e){super(e),this._widgetButtonViewReferences=new Set,e.config.define("htmlEmbed",{showPreviews:!1,sanitizeHtml:e=>(y("html-embed-provide-sanitize-function"),{html:e,hasChanged:!1})})}init(){const e=this.editor;e.model.schema.register("rawHtml",{inheritAllFrom:"$blockObject",allowAttributes:["value"]}),e.commands.add("htmlEmbed",new vv(e)),this._setupConversion()}_setupConversion(){const e=this.editor,t=e.t,i=e.editing.view,n=this._widgetButtonViewReferences,s=e.config.get("htmlEmbed");function o({editor:e,domElement:i,state:s,props:o}){i.textContent="";const a=i.ownerDocument;let l;if(s.isEditable){const e={isDisabled:!1,placeholder:o.textareaPlaceholder};l=r({domDocument:a,state:s,props:e}),i.append(l)}else if(s.showPreviews){const n={sanitizeHtml:o.sanitizeHtml};i.append(function({editor:e,domDocument:i,state:n,props:s}){const o=s.sanitizeHtml(n.getRawHtmlValue()),r=me(i,"div",{class:"ck ck-reset_all raw-html-embed__preview-placeholder"},n.getRawHtmlValue().length>0?t("No preview available"):t("Empty snippet content")),a=me(i,"div",{class:"raw-html-embed__preview-content",dir:e.locale.contentLanguageDirection}),l=i.createRange().createContextualFragment(o.html);a.appendChild(l);return me(i,"div",{class:"raw-html-embed__preview"},[r,a])}({domDocument:a,state:s,props:n,editor:e}))}else{const e={isDisabled:!0,placeholder:o.textareaPlaceholder};i.append(r({domDocument:a,state:s,props:e}))}const c={onEditClick:o.onEditClick,onSaveClick:()=>{o.onSaveClick(l.value)},onCancelClick:o.onCancelClick};i.prepend(function({editor:e,domDocument:t,state:i,props:s}){const o=me(t,"div",{class:"raw-html-embed__buttons-wrapper"});if(i.isEditable){const t=kv(e,"save",s.onSaveClick),i=kv(e,"cancel",s.onCancelClick);o.append(t.element,i.element),n.add(t).add(i)}else{const t=kv(e,"edit",s.onEditClick);o.append(t.element),n.add(t)}return o}({editor:e,domDocument:a,state:s,props:c}))}function r({domDocument:e,state:t,props:i}){const n=me(e,"textarea",{placeholder:i.placeholder,class:"ck ck-reset ck-input ck-input-text raw-html-embed__source"});return n.disabled=i.isDisabled,n.value=t.getRawHtmlValue(),n}this.editor.editing.view.on("render",(()=>{for(const e of n){if(e.element&&e.element.isConnected)return;e.destroy(),n.delete(e)}}),{priority:"lowest"}),e.data.registerRawContentMatcher({name:"div",classes:"raw-html-embed"}),e.conversion.for("upcast").elementToElement({view:{name:"div",classes:"raw-html-embed"},model:(e,{writer:t})=>t.createElement("rawHtml",{value:e.getCustomProperty("$rawContent")})}),e.conversion.for("dataDowncast").elementToElement({model:"rawHtml",view:(e,{writer:t})=>t.createRawElement("div",{class:"raw-html-embed"},(function(t){t.innerHTML=e.getAttribute("value")||""}))}),e.conversion.for("editingDowncast").elementToStructure({model:{name:"rawHtml",attributes:["value"]},view:(n,{writer:r})=>{let a,l,c;const d=r.createRawElement("div",{class:"raw-html-embed__content-wrapper"},(function(t){a=t,o({editor:e,domElement:t,state:l,props:c}),a.addEventListener("mousedown",(()=>{if(l.isEditable){const t=e.model;t.document.selection.getSelectedElement()!==n&&t.change((e=>e.setSelection(n,"on")))}}),!0)})),h={makeEditable(){l=Object.assign({},l,{isEditable:!0}),o({domElement:a,editor:e,state:l,props:c}),i.change((e=>{e.setAttribute("data-cke-ignore-events","true",d)})),a.querySelector("textarea").focus()},save(t){t!==l.getRawHtmlValue()?(e.execute("htmlEmbed",t),e.editing.view.focus()):this.cancel()},cancel(){l=Object.assign({},l,{isEditable:!1}),o({domElement:a,editor:e,state:l,props:c}),e.editing.view.focus(),i.change((e=>{e.removeAttribute("data-cke-ignore-events",d)}))}};l={showPreviews:s.showPreviews,isEditable:!1,getRawHtmlValue:()=>n.getAttribute("value")||""},c={sanitizeHtml:s.sanitizeHtml,textareaPlaceholder:t("Paste raw HTML here..."),onEditClick(){h.makeEditable()},onSaveClick(e){h.save(e)},onCancelClick(){h.cancel()}};const u=r.createContainerElement("div",{class:"raw-html-embed","data-html-embed-label":t("HTML snippet"),dir:e.locale.uiLanguageDirection},d);return r.setCustomProperty("rawHtmlApi",h,u),r.setCustomProperty("rawHtml",!0,u),of(u,r,{label:t("HTML snippet"),hasSelectionHandle:!0})}})}}function kv(e,t,i){const{t:n}=e.locale,s=new fs(e.locale),o=e.commands.get("htmlEmbed");return s.set({class:`raw-html-embed__${t}-button`,icon:Kh.pencil,tooltip:!0,tooltipPosition:"rtl"===e.locale.uiLanguageDirection?"e":"w"}),s.render(),"edit"===t?(s.set({icon:Kh.pencil,label:n("Edit source")}),s.bind("isEnabled").to(o)):"save"===t?(s.set({icon:Kh.check,label:n("Save changes")}),s.bind("isEnabled").to(o)):s.set({icon:Kh.cancel,label:n("Cancel")}),s.on("execute",i),s}class Cv extends io{static get pluginName(){return"HtmlEmbedUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add("htmlEmbed",(i=>{const n=e.commands.get("htmlEmbed"),s=new fs(i);return s.set({label:t("Insert HTML"),icon:'',tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),this.listenTo(s,"execute",(()=>{e.execute("htmlEmbed"),e.editing.view.focus(),e.editing.view.document.selection.getSelectedElement().getCustomProperty("rawHtmlApi").makeEditable()})),s}))}}class Av extends so{refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled&&e.hasAttribute("alt")?this.value=e.getAttribute("alt"):this.value=!1}execute(e){const t=this.editor,i=t.plugins.get("ImageUtils"),n=t.model,s=i.getClosestSelectedImageElement(n.document.selection);n.change((t=>{t.setAttribute("alt",e.newValue,s)}))}}class xv extends io{static get requires(){return[rp]}static get pluginName(){return"ImageTextAlternativeEditing"}init(){this.editor.commands.add("imageTextAlternative",new Av(this.editor))}}class Tv extends Un{constructor(e){super(e);const t=this.locale.t;this.focusTracker=new Bn,this.keystrokes=new Mn,this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(t("Save"),Kh.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(t("Cancel"),Kh.cancel,"ck-button-cancel","cancel"),this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-text-alternative-form","ck-responsive-form"],tabindex:"-1"},children:[this.labeledInput,this.saveButtonView,this.cancelButtonView]})}render(){super.render(),this.keystrokes.listenTo(this.element),s({view:this}),[this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)}))}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createButton(e,t,i,n){const s=new fs(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}_createLabeledInputView(){const e=this.locale.t,t=new $s(this.locale,mu);return t.label=e("Text alternative"),t}}function Ev(e){const t=e.editing.view,i=tm.defaultPositions,n=e.plugins.get("ImageUtils");return{target:t.domConverter.mapViewToDom(n.getClosestSelectedImageWidget(t.document.selection)),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast,i.viewportStickyNorth]}}class Sv extends io{static get requires(){return[Cm]}static get pluginName(){return"ImageTextAlternativeUI"}init(){this._createButton()}destroy(){super.destroy(),this._form&&this._form.destroy()}_createButton(){const e=this.editor,t=e.t;e.ui.componentFactory.add("imageTextAlternative",(i=>{const n=e.commands.get("imageTextAlternative"),s=new fs(i);return s.set({label:t("Change image text alternative"),icon:Kh.lowVision,tooltip:!0}),s.bind("isEnabled").to(n,"isEnabled"),s.bind("isOn").to(n,"value",(e=>!!e)),this.listenTo(s,"execute",(()=>{this._showForm()})),s}))}_createForm(){const i=this.editor,n=i.editing.view.document,s=i.plugins.get("ImageUtils");this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new(t(Tv))(i.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{i.execute("imageTextAlternative",{newValue:this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this._form.keystrokes.set("Esc",((e,t)=>{this._hideForm(!0),t()})),this.listenTo(i.ui,"update",(()=>{s.getClosestSelectedImageWidget(n.selection)?this._isVisible&&function(e){const t=e.plugins.get("ContextualBalloon");if(e.plugins.get("ImageUtils").getClosestSelectedImageWidget(e.editing.view.document.selection)){const i=Ev(e);t.updatePosition(i)}}(i):this._hideForm(!0)})),e({emitter:this._form,activator:()=>this._isVisible,contextElements:()=>[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;this._form||this._createForm();const e=this.editor,t=e.commands.get("imageTextAlternative"),i=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:Ev(e)}),i.fieldView.value=i.fieldView.element.value=t.value||"",this._form.labeledInput.fieldView.select(),this._form.enableCssTransitions()}_hideForm(e=!1){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),e&&this.editor.editing.view.focus())}get _isVisible(){return!!this._balloon&&this._balloon.visibleView===this._form}get _isInBalloon(){return!!this._balloon&&this._balloon.hasView(this._form)}}class Pv extends io{static get requires(){return[xv,Sv]}static get pluginName(){return"ImageTextAlternative"}}function Iv(e,t){const i=(t,i,n)=>{if(!n.consumable.consume(i.item,t.name))return;const s=n.writer,o=n.mapper.toViewElement(i.item),r=e.findViewImgElement(o);null===i.attributeNewValue?(s.removeAttribute("srcset",r),s.removeAttribute("sizes",r)):i.attributeNewValue&&(s.setAttribute("srcset",i.attributeNewValue,r),s.setAttribute("sizes","100vw",r))};return e=>{e.on(`attribute:srcset:${t}`,i)}}function Vv(e,t,i){const n=(t,i,n)=>{if(!n.consumable.consume(i.item,t.name))return;const s=n.writer,o=n.mapper.toViewElement(i.item),r=e.findViewImgElement(o);s.setAttribute(i.attributeKey,i.attributeNewValue||"",r)};return e=>{e.on(`attribute:${i}:${t}`,n)}}class Rv extends _a{observe(e){this.listenTo(e,"load",((e,t)=>{const i=t.target;this.checkShouldIgnoreEventFromTarget(i)||"IMG"==i.tagName&&this._fireEvents(t)}),{useCapture:!0})}stopObserving(e){this.stopListening(e)}_fireEvents(e){this.isEnabled&&(this.document.fire("layoutChanged"),this.document.fire("imageLoaded",e))}}class Lv extends so{constructor(e){super(e);const t=e.config.get("image.insert.type");e.plugins.has("ImageBlockEditing")||"block"===t&&y("image-block-plugin-required"),e.plugins.has("ImageInlineEditing")||"inline"===t&&y("image-inline-plugin-required")}refresh(){const e=this.editor.plugins.get("ImageUtils");this.isEnabled=e.isImageAllowed()}execute(e){const t=Pn(e.source),i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageUtils"),s=Object.fromEntries(i.getAttributes());t.forEach(((e,t)=>{const o=i.getSelectedElement();if("string"==typeof e&&(e={src:e}),t&&o&&n.isImage(o)){const t=this.editor.model.createPositionAfter(o);n.insertImage({...e,...s},t)}else n.insertImage({...e,...s})}))}}class Ov extends so{refresh(){const e=this.editor.plugins.get("ImageUtils"),t=this.editor.model.document.selection.getSelectedElement();this.isEnabled=e.isImage(t),this.value=this.isEnabled?t.getAttribute("src"):null}execute(e){const t=this.editor.model.document.selection.getSelectedElement();this.editor.model.change((i=>{i.setAttribute("src",e.source,t),i.removeAttribute("srcset",t),i.removeAttribute("sizes",t)}))}}class Bv extends io{static get requires(){return[rp]}static get pluginName(){return"ImageEditing"}init(){const e=this.editor,t=e.conversion;e.editing.view.addObserver(Rv),t.for("upcast").attributeToAttribute({view:{name:"img",key:"alt"},model:"alt"}).attributeToAttribute({view:{name:"img",key:"srcset"},model:"srcset"});const i=new Lv(e),n=new Ov(e);e.commands.add("insertImage",i),e.commands.add("replaceImageSource",n),e.commands.add("imageInsert",i)}}class Mv extends io{static get requires(){return[rp]}static get pluginName(){return"ImageSizeAttributes"}afterInit(){this._registerSchema(),this._registerConverters("imageBlock"),this._registerConverters("imageInline")}_registerSchema(){this.editor.plugins.has("ImageBlockEditing")&&this.editor.model.schema.extend("imageBlock",{allowAttributes:["width","height"]}),this.editor.plugins.has("ImageInlineEditing")&&this.editor.model.schema.extend("imageInline",{allowAttributes:["width","height"]})}_registerConverters(e){const t=this.editor,i=t.plugins.get("ImageUtils"),n="imageBlock"===e?"figure":"img";function s(t,n,s,o){t.on(`attribute:${n}:${e}`,((t,n,r)=>{if(!r.consumable.consume(n.item,t.name))return;const a=r.writer,l=r.mapper.toViewElement(n.item),c=i.findViewImgElement(l);if(null!==n.attributeNewValue?a.setAttribute(s,n.attributeNewValue,c):a.removeAttribute(s,c),n.item.hasAttribute("sources"))return;const d=n.item.hasAttribute("resizedWidth");if("imageInline"===e&&!d&&!o)return;const h=n.item.getAttribute("width"),u=n.item.getAttribute("height"),m=c.getStyle("aspect-ratio");h&&u&&!m&&a.setStyle("aspect-ratio",`${h}/${u}`,c)}))}t.conversion.for("upcast").attributeToAttribute({view:{name:n,styles:{width:/.+/}},model:{key:"width",value:e=>sp(e)?np(e.getStyle("width")):null}}).attributeToAttribute({view:{name:n,key:"width"},model:"width"}).attributeToAttribute({view:{name:n,styles:{height:/.+/}},model:{key:"height",value:e=>sp(e)?np(e.getStyle("height")):null}}).attributeToAttribute({view:{name:n,key:"height"},model:"height"}),t.conversion.for("editingDowncast").add((e=>{s(e,"width","width",!0),s(e,"height","height",!0)})),t.conversion.for("dataDowncast").add((e=>{s(e,"width","width",!1),s(e,"height","height",!1)}))}}class Nv extends so{constructor(e,t){super(e),this._modelElementName=t}refresh(){const e=this.editor.plugins.get("ImageUtils"),t=e.getClosestSelectedImageElement(this.editor.model.document.selection);"imageBlock"===this._modelElementName?this.isEnabled=e.isInlineImage(t):this.isEnabled=e.isBlockImage(t)}execute(e={}){const t=this.editor,i=this.editor.model,n=t.plugins.get("ImageUtils"),s=n.getClosestSelectedImageElement(i.document.selection),o=Object.fromEntries(s.getAttributes());return o.src||o.uploadId?i.change((t=>{const{setImageSizes:r=!0}=e,a=Array.from(i.markers).filter((e=>e.getRange().containsItem(s))),l=n.insertImage(o,i.createSelection(s,"on"),this._modelElementName,{setImageSizes:r});if(!l)return null;const c=t.createRangeOn(l);for(const e of a){const i=e.getRange(),n="$graveyard"!=i.root.rootName?i.getJoined(c,!0):c;t.updateMarker(e,{range:n})}return{oldElement:s,newElement:l}})):null}}class Fv extends io{static get requires(){return[Bv,Mv,rp,zg]}static get pluginName(){return"ImageBlockEditing"}init(){const e=this.editor;e.model.schema.register("imageBlock",{inheritAllFrom:"$blockObject",allowAttributes:["alt","src","srcset"]}),this._setupConversion(),e.plugins.has("ImageInlineEditing")&&(e.commands.add("imageTypeBlock",new Nv(this.editor,"imageBlock")),this._setupClipboardIntegration())}_setupConversion(){const e=this.editor,t=e.t,i=e.conversion,n=e.plugins.get("ImageUtils");i.for("dataDowncast").elementToStructure({model:"imageBlock",view:(e,{writer:t})=>ep(t)}),i.for("editingDowncast").elementToStructure({model:"imageBlock",view:(e,{writer:i})=>n.toImageWidget(ep(i),i,t("image widget"))}),i.for("downcast").add(Vv(n,"imageBlock","src")).add(Vv(n,"imageBlock","alt")).add(Iv(n,"imageBlock")),i.for("upcast").elementToElement({view:tp(e,"imageBlock"),model:(e,{writer:t})=>t.createElement("imageBlock",e.hasAttribute("src")?{src:e.getAttribute("src")}:void 0)}).add(function(e){const t=(t,i,n)=>{if(!n.consumable.test(i.viewItem,{name:!0,classes:"image"}))return;const s=e.findViewImgElement(i.viewItem);if(!s||!n.consumable.test(s,{name:!0}))return;n.consumable.consume(i.viewItem,{name:!0,classes:"image"});const o=On(n.convertItem(s,i.modelCursor).modelRange.getItems());o?(n.convertChildren(i.viewItem,o),n.updateConversionResult(o,i)):n.consumable.revert(i.viewItem,{name:!0,classes:"image"})};return e=>{e.on("element:figure",t)}}(n))}_setupClipboardIntegration(){const e=this.editor,t=e.model,i=e.editing.view,n=e.plugins.get("ImageUtils"),s=e.plugins.get("ClipboardPipeline");this.listenTo(s,"inputTransformation",((s,o)=>{const r=Array.from(o.content.getChildren());let a;if(!r.every(n.isInlineImageView))return;a=o.targetRanges?e.editing.mapper.toModelRange(o.targetRanges[0]):t.document.selection.getFirstRange();const l=t.createSelection(a);if("imageBlock"===ip(t.schema,l)){const e=new Xd(i.document),t=r.map((t=>e.createElement("figure",{class:"image"},t)));o.content=e.createDocumentFragment(t)}})),this.listenTo(s,"contentInsertion",((e,i)=>{"paste"===i.method&&t.change((e=>{const t=e.createRangeIn(i.content);for(const e of t.getItems())e.is("element","imageBlock")&&n.setImageNaturalSizeAttributes(e)}))}))}}class Dv extends io{static get requires(){return[Fv,yf,Pv]}static get pluginName(){return"ImageBlock"}}class zv extends io{static get requires(){return[Bv,Mv,rp,zg]}static get pluginName(){return"ImageInlineEditing"}init(){const e=this.editor,t=e.model.schema;t.register("imageInline",{inheritAllFrom:"$inlineObject",allowAttributes:["alt","src","srcset"]}),t.addChildCheck(((e,t)=>{if(e.endsWith("caption")&&"imageInline"===t.name)return!1})),this._setupConversion(),e.plugins.has("ImageBlockEditing")&&(e.commands.add("imageTypeInline",new Nv(this.editor,"imageInline")),this._setupClipboardIntegration())}_setupConversion(){const e=this.editor,t=e.t,i=e.conversion,n=e.plugins.get("ImageUtils");i.for("dataDowncast").elementToElement({model:"imageInline",view:(e,{writer:t})=>t.createEmptyElement("img")}),i.for("editingDowncast").elementToStructure({model:"imageInline",view:(e,{writer:i})=>n.toImageWidget(function(e){return e.createContainerElement("span",{class:"image-inline"},e.createEmptyElement("img"))}(i),i,t("image widget"))}),i.for("downcast").add(Vv(n,"imageInline","src")).add(Vv(n,"imageInline","alt")).add(Iv(n,"imageInline")),i.for("upcast").elementToElement({view:tp(e,"imageInline"),model:(e,{writer:t})=>t.createElement("imageInline",e.hasAttribute("src")?{src:e.getAttribute("src")}:void 0)})}_setupClipboardIntegration(){const e=this.editor,t=e.model,i=e.editing.view,n=e.plugins.get("ImageUtils"),s=e.plugins.get("ClipboardPipeline");this.listenTo(s,"inputTransformation",((s,o)=>{const r=Array.from(o.content.getChildren());let a;if(!r.every(n.isBlockImageView))return;a=o.targetRanges?e.editing.mapper.toModelRange(o.targetRanges[0]):t.document.selection.getFirstRange();const l=t.createSelection(a);if("imageInline"===ip(t.schema,l)){const e=new Xd(i.document),t=r.map((t=>1===t.childCount?(Array.from(t.getAttributes()).forEach((i=>e.setAttribute(...i,n.findViewImgElement(t)))),t.getChild(0)):t));o.content=e.createDocumentFragment(t)}})),this.listenTo(s,"contentInsertion",((e,i)=>{"paste"===i.method&&t.change((e=>{const t=e.createRangeIn(i.content);for(const e of t.getItems())e.is("element","imageInline")&&n.setImageNaturalSizeAttributes(e)}))}))}}class Hv extends io{static get requires(){return[zv,yf,Pv]}static get pluginName(){return"ImageInline"}}class $v extends so{refresh(){const e=this.editor,t=e.plugins.get("ImageCaptionUtils"),i=e.plugins.get("ImageUtils");if(!e.plugins.has(Fv))return this.isEnabled=!1,void(this.value=!1);const n=e.model.document.selection,s=n.getSelectedElement();if(!s){const e=t.getCaptionFromModelSelection(n);return this.isEnabled=!!e,void(this.value=!!e)}this.isEnabled=i.isImage(s),this.isEnabled?this.value=!!t.getCaptionFromImageModelElement(s):this.value=!1}execute(e={}){const{focusCaptionOnShow:t}=e;this.editor.model.change((e=>{this.value?this._hideImageCaption(e):this._showImageCaption(e,t)}))}_showImageCaption(e,t){const i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageCaptionEditing"),s=this.editor.plugins.get("ImageUtils");let o=i.getSelectedElement();const r=n._getSavedCaption(o);s.isInlineImage(o)&&(this.editor.execute("imageTypeBlock"),o=i.getSelectedElement());const a=r||e.createElement("caption");e.append(a,o),t&&e.setSelection(a,"in")}_hideImageCaption(e){const t=this.editor,i=t.model.document.selection,n=t.plugins.get("ImageCaptionEditing"),s=t.plugins.get("ImageCaptionUtils");let o,r=i.getSelectedElement();r?o=s.getCaptionFromImageModelElement(r):(o=s.getCaptionFromModelSelection(i),r=o.parent),n._saveCaption(r,o),e.setSelection(r,"on"),e.remove(o)}}class Wv extends io{static get pluginName(){return"ImageCaptionUtils"}static get requires(){return[rp]}getCaptionFromImageModelElement(e){for(const t of e.getChildren())if(t&&t.is("element","caption"))return t;return null}getCaptionFromModelSelection(e){const t=this.editor.plugins.get("ImageUtils"),i=e.getFirstPosition().findAncestor("caption");return i&&t.isBlockImage(i.parent)?i:null}matchImageCaptionViewElement(e){const t=this.editor.plugins.get("ImageUtils");return"figcaption"==e.name&&t.isBlockImageView(e.parent)?{name:!0}:null}}class Uv extends io{static get requires(){return[rp,Wv]}static get pluginName(){return"ImageCaptionEditing"}constructor(e){super(e),this._savedCaptionsMap=new WeakMap}init(){const e=this.editor,t=e.model.schema;t.isRegistered("caption")?t.extend("caption",{allowIn:"imageBlock"}):t.register("caption",{allowIn:"imageBlock",allowContentOf:"$block",isLimit:!0}),e.commands.add("toggleImageCaption",new $v(this.editor)),this._setupConversion(),this._setupImageTypeCommandsIntegration(),this._registerCaptionReconversion()}_setupConversion(){const e=this.editor,t=e.editing.view,i=e.plugins.get("ImageUtils"),n=e.plugins.get("ImageCaptionUtils"),s=e.t;e.conversion.for("upcast").elementToElement({view:e=>n.matchImageCaptionViewElement(e),model:"caption"}),e.conversion.for("dataDowncast").elementToElement({model:"caption",view:(e,{writer:t})=>i.isBlockImage(e.parent)?t.createContainerElement("figcaption"):null}),e.conversion.for("editingDowncast").elementToElement({model:"caption",view:(e,{writer:n})=>{if(!i.isBlockImage(e.parent))return null;const o=n.createEditableElement("figcaption");n.setCustomProperty("imageCaption",!0,o),o.placeholder=s("Enter image caption"),mo({view:t,element:o,keepOnFocus:!0});const r=e.parent.getAttribute("alt");return cf(o,n,{label:r?s("Caption for image: %0",[r]):s("Caption for the image")})}})}_setupImageTypeCommandsIntegration(){const e=this.editor,t=e.plugins.get("ImageUtils"),i=e.plugins.get("ImageCaptionUtils"),n=e.commands.get("imageTypeInline"),s=e.commands.get("imageTypeBlock"),o=e=>{if(!e.return)return;const{oldElement:n,newElement:s}=e.return;if(!n)return;if(t.isBlockImage(n)){const e=i.getCaptionFromImageModelElement(n);if(e)return void this._saveCaption(s,e)}const o=this._getSavedCaption(n);o&&this._saveCaption(s,o)};n&&this.listenTo(n,"execute",o,{priority:"low"}),s&&this.listenTo(s,"execute",o,{priority:"low"})}_getSavedCaption(e){const t=this._savedCaptionsMap.get(e);return t?ol.fromJSON(t):null}_saveCaption(e,t){this._savedCaptionsMap.set(e,t.toJSON())}_registerCaptionReconversion(){const e=this.editor,t=e.model,i=e.plugins.get("ImageUtils"),n=e.plugins.get("ImageCaptionUtils");t.document.on("change:data",(()=>{const s=t.document.differ.getChanges();for(const t of s){if("alt"!==t.attributeKey)continue;const s=t.range.start.nodeAfter;if(i.isBlockImage(s)){const t=n.getCaptionFromImageModelElement(s);if(!t)return;e.editing.reconvertItem(t)}}}))}}class jv extends io{static get requires(){return[Wv]}static get pluginName(){return"ImageCaptionUI"}init(){const e=this.editor,t=e.editing.view,i=e.plugins.get("ImageCaptionUtils"),n=e.t;e.ui.componentFactory.add("toggleImageCaption",(s=>{const o=e.commands.get("toggleImageCaption"),r=new fs(s);return r.set({icon:Kh.caption,tooltip:!0,isToggleable:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),r.bind("label").to(o,"value",(e=>n(e?"Toggle caption off":"Toggle caption on"))),this.listenTo(r,"execute",(()=>{e.execute("toggleImageCaption",{focusCaptionOnShow:!0});const n=i.getCaptionFromModelSelection(e.model.document.selection);if(n){const i=e.editing.mapper.toViewElement(n);t.scrollToTheSelection(),t.change((e=>{e.addClass("image__caption_highlighted",i)}))}e.editing.view.focus()})),r}))}}class qv extends(W()){constructor(){super();const e=new window.FileReader;this._reader=e,this._data=void 0,this.set("loaded",0),e.onprogress=e=>{this.loaded=e.loaded}}get error(){return this._reader.error}get data(){return this._data}read(e){const t=this._reader;return this.total=e.size,new Promise(((i,n)=>{t.onload=()=>{const e=t.result;this._data=e,i(e)},t.onerror=()=>{n("error")},t.onabort=()=>{n("aborted")},this._reader.readAsDataURL(e)}))}abort(){this._reader.abort()}}class Gv extends io{constructor(){super(...arguments),this.loaders=new Ln,this._loadersMap=new Map,this._pendingAction=null}static get pluginName(){return"FileRepository"}static get requires(){return[Uh]}init(){this.loaders.on("change",(()=>this._updatePendingAction())),this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",((e,t)=>t?e/t*100:0))}getLoader(e){return this._loadersMap.get(e)||null}createLoader(e){if(!this.createUploadAdapter)return y("filerepository-no-upload-adapter"),null;const t=new Kv(Promise.resolve(e),this.createUploadAdapter);return this.loaders.add(t),this._loadersMap.set(e,t),e instanceof Promise&&t.file.then((e=>{this._loadersMap.set(e,t)})).catch((()=>{})),t.on("change:uploaded",(()=>{let e=0;for(const t of this.loaders)e+=t.uploaded;this.uploaded=e})),t.on("change:uploadTotal",(()=>{let e=0;for(const t of this.loaders)t.uploadTotal&&(e+=t.uploadTotal);this.uploadTotal=e})),t}destroyLoader(e){const t=e instanceof Kv?e:this.getLoader(e);t._destroy(),this.loaders.remove(t),this._loadersMap.forEach(((e,i)=>{e===t&&this._loadersMap.delete(i)}))}_updatePendingAction(){const e=this.editor.plugins.get(Uh);if(this.loaders.length){if(!this._pendingAction){const t=this.editor.t,i=e=>`${t("Upload in progress")} ${parseInt(e)}%.`;this._pendingAction=e.add(i(this.uploadedPercent)),this._pendingAction.bind("message").to(this,"uploadedPercent",i)}}else e.remove(this._pendingAction),this._pendingAction=null}}class Kv extends(W()){constructor(e,t){super(),this.id=p(),this._filePromiseWrapper=this._createFilePromiseWrapper(e),this._adapter=t(this),this._reader=new qv,this.set("status","idle"),this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",((e,t)=>t?e/t*100:0)),this.set("uploadResponse",null)}get file(){return this._filePromiseWrapper?this._filePromiseWrapper.promise.then((e=>this._filePromiseWrapper?e:null)):Promise.resolve(null)}get data(){return this._reader.data}read(){if("idle"!=this.status)throw new _("filerepository-read-wrong-status",this);return this.status="reading",this.file.then((e=>this._reader.read(e))).then((e=>{if("reading"!==this.status)throw this.status;return this.status="idle",e})).catch((e=>{if("aborted"===e)throw this.status="aborted","aborted";throw this.status="error",this._reader.error?this._reader.error:e}))}upload(){if("idle"!=this.status)throw new _("filerepository-upload-wrong-status",this);return this.status="uploading",this.file.then((()=>this._adapter.upload())).then((e=>(this.uploadResponse=e,this.status="idle",e))).catch((e=>{if("aborted"===this.status)throw"aborted";throw this.status="error",e}))}abort(){const e=this.status;this.status="aborted",this._filePromiseWrapper.isFulfilled?"reading"==e?this._reader.abort():"uploading"==e&&this._adapter.abort&&this._adapter.abort():(this._filePromiseWrapper.promise.catch((()=>{})),this._filePromiseWrapper.rejecter("aborted")),this._destroy()}_destroy(){this._filePromiseWrapper=void 0,this._reader=void 0,this._adapter=void 0,this.uploadResponse=void 0}_createFilePromiseWrapper(e){const t={};return t.promise=new Promise(((i,n)=>{t.rejecter=n,t.isFulfilled=!1,e.then((e=>{t.isFulfilled=!0,i(e)})).catch((e=>{t.isFulfilled=!0,n(e)}))})),t}}class Jv extends Un{constructor(e){super(e),this.buttonView=new fs(e),this._fileInputView=new Qv(e),this._fileInputView.bind("acceptedType").to(this),this._fileInputView.bind("allowMultipleFiles").to(this),this._fileInputView.delegate("done").to(this),this.setTemplate({tag:"span",attributes:{class:"ck-file-dialog-button"},children:[this.buttonView,this._fileInputView]}),this.buttonView.on("execute",(()=>{this._fileInputView.open()}))}focus(){this.buttonView.focus()}}class Qv extends Un{constructor(e){super(e),this.set("acceptedType",void 0),this.set("allowMultipleFiles",!1);const t=this.bindTemplate;this.setTemplate({tag:"input",attributes:{class:["ck-hidden"],type:"file",tabindex:"-1",accept:t.to("acceptedType"),multiple:t.to("allowMultipleFiles")},on:{change:t.to((()=>{this.element&&this.element.files&&this.element.files.length&&this.fire("done",this.element.files),this.element.value=""}))}})}open(){this.element.click()}}class Zv{constructor(e,t){this.loader=e,this.options=t}upload(){return this.loader.file.then((e=>new Promise(((t,i)=>{this._initRequest(),this._initListeners(t,i,e),this._sendRequest(e)}))))}abort(){this.xhr&&this.xhr.abort()}_initRequest(){const e=this.xhr=new XMLHttpRequest;e.open("POST",this.options.uploadUrl,!0),e.responseType="json"}_initListeners(e,t,i){const n=this.xhr,s=this.loader,o=`Couldn't upload file: ${i.name}.`;n.addEventListener("error",(()=>t(o))),n.addEventListener("abort",(()=>t())),n.addEventListener("load",(()=>{const i=n.response;if(!i||i.error)return t(i&&i.error&&i.error.message?i.error.message:o);const s=i.url?{default:i.url}:i.urls;e({...i,urls:s})})),n.upload&&n.upload.addEventListener("progress",(e=>{e.lengthComputable&&(s.uploadTotal=e.total,s.uploaded=e.loaded)}))}_sendRequest(e){const t=this.options.headers||{},i=this.options.withCredentials||!1;for(const e of Object.keys(t))this.xhr.setRequestHeader(e,t[e]);this.xhr.withCredentials=i;const n=new FormData;n.append("upload",e),this.xhr.send(n)}}function Yv(e){const t=e.map((e=>e.replace("+","\\+")));return new RegExp(`^image\\/(${t.join("|")})$`)}function Xv(e,t){return e.type?e.type:t.match(/data:(image\/\w+);base64/)?t.match(/data:(image\/\w+);base64/)[1].toLowerCase():"image/jpeg"}class e_ extends io{static get pluginName(){return"ImageUploadUI"}init(){const e=this.editor,t=e.t,i=i=>{const n=new Jv(i),s=e.commands.get("uploadImage"),o=e.config.get("image.upload.types"),r=Yv(o);return n.set({acceptedType:o.map((e=>`image/${e}`)).join(","),allowMultipleFiles:!0}),n.buttonView.set({label:t("Insert image"),icon:Kh.image,tooltip:!0}),n.buttonView.bind("isEnabled").to(s),n.on("done",((t,i)=>{const n=Array.from(i).filter((e=>r.test(e.type)));n.length&&(e.execute("uploadImage",{file:n}),e.editing.view.focus())})),n};e.ui.componentFactory.add("uploadImage",i),e.ui.componentFactory.add("imageUpload",i)}}class t_ extends io{static get pluginName(){return"ImageUploadProgress"}constructor(e){super(e),this.uploadStatusChange=(e,t,i)=>{const n=this.editor,s=t.item,o=s.getAttribute("uploadId");if(!i.consumable.consume(t.item,e.name))return;const r=n.plugins.get("ImageUtils"),a=n.plugins.get(Gv),l=o?t.attributeNewValue:null,c=this.placeholder,d=n.editing.mapper.toViewElement(s),h=i.writer;if("reading"==l)return i_(d,h),void n_(r,c,d,h);if("uploading"==l){const e=a.loaders.get(o);return i_(d,h),void(e?(s_(d,h),function(e,t,i,n){const s=function(e){const t=e.createUIElement("div",{class:"ck-progress-bar"});return e.setCustomProperty("progressBar",!0,t),t}(t);t.insert(t.createPositionAt(e,"end"),s),i.on("change:uploadedPercent",((e,t,i)=>{n.change((e=>{e.setStyle("width",i+"%",s)}))}))}(d,h,e,n.editing.view),function(e,t,i,n){if(n.data){const s=e.findViewImgElement(t);i.setAttribute("src",n.data,s)}}(r,d,h,e)):n_(r,c,d,h))}"complete"==l&&a.loaders.get(o)&&function(e,t,i){const n=t.createUIElement("div",{class:"ck-image-upload-complete-icon"});t.insert(t.createPositionAt(e,"end"),n),setTimeout((()=>{i.change((e=>e.remove(e.createRangeOn(n))))}),3e3)}(d,h,n.editing.view),function(e,t){r_(e,t,"progressBar")}(d,h),s_(d,h),function(e,t){t.removeClass("ck-appear",e)}(d,h)},this.placeholder="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="}init(){const e=this.editor;e.plugins.has("ImageBlockEditing")&&e.editing.downcastDispatcher.on("attribute:uploadStatus:imageBlock",this.uploadStatusChange),e.plugins.has("ImageInlineEditing")&&e.editing.downcastDispatcher.on("attribute:uploadStatus:imageInline",this.uploadStatusChange)}}function i_(e,t){e.hasClass("ck-appear")||t.addClass("ck-appear",e)}function n_(e,t,i,n){i.hasClass("ck-image-upload-placeholder")||n.addClass("ck-image-upload-placeholder",i);const s=e.findViewImgElement(i);s.getAttribute("src")!==t&&n.setAttribute("src",t,s),o_(i,"placeholder")||n.insert(n.createPositionAfter(s),function(e){const t=e.createUIElement("div",{class:"ck-upload-placeholder-loader"});return e.setCustomProperty("placeholder",!0,t),t}(n))}function s_(e,t){e.hasClass("ck-image-upload-placeholder")&&t.removeClass("ck-image-upload-placeholder",e),r_(e,t,"placeholder")}function o_(e,t){for(const i of e.getChildren())if(i.getCustomProperty(t))return i}function r_(e,t,i){const n=o_(e,i);n&&t.remove(t.createRangeOn(n))}class a_ extends so{refresh(){const e=this.editor,t=e.plugins.get("ImageUtils"),i=e.model.document.selection.getSelectedElement();this.isEnabled=t.isImageAllowed()||t.isImage(i)}execute(e){const t=Pn(e.file),i=this.editor.model.document.selection,n=this.editor.plugins.get("ImageUtils"),s=Object.fromEntries(i.getAttributes());t.forEach(((e,t)=>{const o=i.getSelectedElement();if(t&&o&&n.isImage(o)){const t=this.editor.model.createPositionAfter(o);this._uploadImage(e,s,t)}else this._uploadImage(e,s)}))}_uploadImage(e,t,i){const n=this.editor,s=n.plugins.get(Gv).createLoader(e),o=n.plugins.get("ImageUtils");s&&o.insertImage({...t,uploadId:s.id},i)}}class l_ extends io{static get requires(){return[Gv,vm,zg,rp]}static get pluginName(){return"ImageUploadEditing"}constructor(e){super(e),e.config.define("image",{upload:{types:["jpeg","png","gif","bmp","webp","tiff"]}}),this._uploadImageElements=new Map}init(){const e=this.editor,t=e.model.document,i=e.conversion,n=e.plugins.get(Gv),s=e.plugins.get("ImageUtils"),o=e.plugins.get("ClipboardPipeline"),r=Yv(e.config.get("image.upload.types")),a=new a_(e);e.commands.add("uploadImage",a),e.commands.add("imageUpload",a),i.for("upcast").attributeToAttribute({view:{name:"img",key:"uploadId"},model:"uploadId"}),this.listenTo(e.editing.view.document,"clipboardInput",((t,i)=>{if(n=i.dataTransfer,Array.from(n.types).includes("text/html")&&""!==n.getData("text/html"))return;var n;const s=Array.from(i.dataTransfer.files).filter((e=>!!e&&r.test(e.type)));s.length&&(t.stop(),e.model.change((t=>{i.targetRanges&&t.setSelection(i.targetRanges.map((t=>e.editing.mapper.toModelRange(t)))),e.execute("uploadImage",{file:s})})))})),this.listenTo(o,"inputTransformation",((t,i)=>{const o=Array.from(e.editing.view.createRangeIn(i.content)).map((e=>e.item)).filter((e=>function(e,t){return!(!e.isInlineImageView(t)||!t.getAttribute("src")||!t.getAttribute("src").match(/^data:image\/\w+;base64,/g)&&!t.getAttribute("src").match(/^blob:/g))}(s,e)&&!e.getAttribute("uploadProcessed"))).map((e=>{return{promise:(t=e,new Promise(((e,i)=>{const n=t.getAttribute("src");fetch(n).then((e=>e.blob())).then((t=>{const i=Xv(t,n),s=i.replace("image/",""),o=new File([t],`image.${s}`,{type:i});e(o)})).catch((t=>t&&"TypeError"===t.name?function(e){return function(e){return new Promise(((t,i)=>{const n=$i.document.createElement("img");n.addEventListener("load",(()=>{const e=$i.document.createElement("canvas");e.width=n.width,e.height=n.height,e.getContext("2d").drawImage(n,0,0),e.toBlob((e=>e?t(e):i()))})),n.addEventListener("error",(()=>i())),n.src=e}))}(e).then((t=>{const i=Xv(t,e),n=i.replace("image/","");return new File([t],`image.${n}`,{type:i})}))}(n).then(e).catch(i):i(t)))}))),imageElement:e};var t}));if(!o.length)return;const r=new Xd(e.editing.view.document);for(const e of o){r.setAttribute("uploadProcessed",!0,e.imageElement);const t=n.createLoader(e.promise);t&&(r.setAttribute("src","",e.imageElement),r.setAttribute("uploadId",t.id,e.imageElement))}})),e.editing.view.document.on("dragover",((e,t)=>{t.preventDefault()})),t.on("change",(()=>{const i=t.differ.getChanges({includeChangesInGraveyard:!0}).reverse(),s=new Set;for(const t of i)if("insert"==t.type&&"$text"!=t.name){const i=t.position.nodeAfter,o="$graveyard"==t.position.root.rootName;for(const t of c_(e,i)){const e=t.getAttribute("uploadId");if(!e)continue;const i=n.loaders.get(e);i&&(o?s.has(e)||i.abort():(s.add(e),this._uploadImageElements.set(e,t),"idle"==i.status&&this._readAndUpload(i)))}}})),this.on("uploadComplete",((e,{imageElement:t,data:i})=>{const n=i.urls?i.urls:i;this.editor.model.change((e=>{e.setAttribute("src",n.default,t),this._parseAndSetSrcsetAttributeOnImage(n,t,e),s.setImageNaturalSizeAttributes(t)}))}),{priority:"low"})}afterInit(){const e=this.editor.model.schema;this.editor.plugins.has("ImageBlockEditing")&&e.extend("imageBlock",{allowAttributes:["uploadId","uploadStatus"]}),this.editor.plugins.has("ImageInlineEditing")&&e.extend("imageInline",{allowAttributes:["uploadId","uploadStatus"]})}_readAndUpload(e){const t=this.editor,i=t.model,n=t.locale.t,s=t.plugins.get(Gv),o=t.plugins.get(vm),r=t.plugins.get("ImageUtils"),a=this._uploadImageElements;return i.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("uploadStatus","reading",a.get(e.id))})),e.read().then((()=>{const n=e.upload(),s=a.get(e.id);if(l.isSafari){const e=t.editing.mapper.toViewElement(s),i=r.findViewImgElement(e);t.editing.view.once("render",(()=>{if(!i.parent)return;const e=t.editing.view.domConverter.mapViewToDom(i.parent);if(!e)return;const n=e.style.display;e.style.display="none",e._ckHack=e.offsetHeight,e.style.display=n}))}return i.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("uploadStatus","uploading",s)})),n})).then((t=>{i.enqueueChange({isUndoable:!1},(i=>{const n=a.get(e.id);i.setAttribute("uploadStatus","complete",n),this.fire("uploadComplete",{data:t,imageElement:n})})),c()})).catch((t=>{if("error"!==e.status&&"aborted"!==e.status)throw t;"error"==e.status&&t&&o.showWarning(t,{title:n("Upload failed"),namespace:"upload"}),i.enqueueChange({isUndoable:!1},(t=>{t.remove(a.get(e.id))})),c()}));function c(){i.enqueueChange({isUndoable:!1},(t=>{const i=a.get(e.id);t.removeAttribute("uploadId",i),t.removeAttribute("uploadStatus",i),a.delete(e.id)})),s.destroyLoader(e)}}_parseAndSetSrcsetAttributeOnImage(e,t,i){let n=0;const s=Object.keys(e).filter((e=>{const t=parseInt(e,10);if(!isNaN(t))return n=Math.max(n,t),!0})).map((t=>`${e[t]} ${t}w`)).join(", ");if(""!=s){const e={srcset:s};t.hasAttribute("width")||t.hasAttribute("height")||(e.width=n),i.setAttributes(e,t)}}}function c_(e,t){const i=e.plugins.get("ImageUtils");return Array.from(e.model.createRangeOn(t)).filter((e=>i.isImage(e.item))).map((e=>e.item))}class d_ extends io{static get pluginName(){return"ImageUpload"}static get requires(){return[l_,e_,t_]}}class h_ extends Un{constructor(e,t={}){super(e);const i=this.bindTemplate;this.set("class",t.class||null),this.children=this.createCollection(),t.children&&t.children.forEach((e=>this.children.add(e))),this.set("_role",null),this.set("_ariaLabelledBy",null),t.labelView&&this.set({_role:"group",_ariaLabelledBy:t.labelView.id}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-form__row",i.to("class")],role:i.to("_role"),"aria-labelledby":i.to("_ariaLabelledBy")},children:this.children})}}class u_ extends Un{constructor(e,t={}){super(e);const{insertButtonView:i,cancelButtonView:n}=this._createActionButtons(e);this.insertButtonView=i,this.cancelButtonView=n,this.set("imageURLInputValue",""),this.focusTracker=new Bn,this.keystrokes=new Mn,this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.set("_integrations",new Ln);for(const[e,i]of Object.entries(t))"insertImageViaUrl"===e&&(i.fieldView.bind("value").to(this,"imageURLInputValue",(e=>e||"")),i.fieldView.on("input",(()=>{this.imageURLInputValue=i.fieldView.element.value.trim()}))),i.name=e,this._integrations.add(i);this.setTemplate({tag:"form",attributes:{class:["ck","ck-image-insert-form"],tabindex:"-1"},children:[...this._integrations,new h_(e,{children:[this.insertButtonView,this.cancelButtonView],class:"ck-image-insert-form__action-row"})]})}render(){super.render(),s({view:this}),[...this._integrations,this.insertButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element);const e=e=>e.stopPropagation();this.keystrokes.set("arrowright",e),this.keystrokes.set("arrowleft",e),this.keystrokes.set("arrowup",e),this.keystrokes.set("arrowdown",e)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}getIntegration(e){return this._integrations.find((t=>t.name===e))}_createActionButtons(e){const t=e.t,i=new fs(e),n=new fs(e);return i.set({label:t("Insert"),icon:Kh.check,class:"ck-button-save",type:"submit",withText:!0,isEnabled:this.imageURLInputValue}),n.set({label:t("Cancel"),icon:Kh.cancel,class:"ck-button-cancel",withText:!0}),i.bind("isEnabled").to(this,"imageURLInputValue",(e=>!!e)),i.delegate("execute").to(this,"submit"),n.delegate("execute").to(this,"cancel"),{insertButtonView:i,cancelButtonView:n}}focus(){this._focusCycler.focusFirst()}}function m_(e){const t=e.t,i=new $s(e,mu);return i.set({label:t("Insert image via URL")}),i.fieldView.placeholder="https://example.com/image.png",i}class g_ extends io{static get pluginName(){return"ImageInsertUI"}init(){const e=this.editor,t=e=>this._createDropdownView(e);e.ui.componentFactory.add("insertImage",t),e.ui.componentFactory.add("imageInsert",t)}_createDropdownView(e){const t=this.editor,i=e.t,n=t.commands.get("uploadImage"),s=t.commands.get("insertImage");this.dropdownView=ru(e,n?ou:void 0);const o=this.dropdownView.buttonView,r=this.dropdownView.panelView;if(o.set({label:i("Insert image"),icon:Kh.image,tooltip:!0}),r.extendTemplate({attributes:{class:"ck-image-insert__panel"}}),n){const e=this.dropdownView.buttonView;e.actionView=t.ui.componentFactory.create("uploadImage"),e.actionView.extendTemplate({attributes:{class:"ck ck-button ck-splitbutton__action"}})}return this._setUpDropdown(n||s)}_setUpDropdown(e){const t=this.editor,i=t.t,n=this.dropdownView,s=n.panelView,o=this.editor.plugins.get("ImageUtils"),r=t.commands.get("replaceImageSource");let a;function l(){t.editing.view.focus(),n.isOpen=!1}return n.bind("isEnabled").to(e),n.once("change:isOpen",(()=>{a=new u_(t.locale,function(e){const t=e.config.get("image.insert.integrations"),i=e.plugins.get("ImageInsertUI"),n={insertImageViaUrl:m_(e.locale)};if(!t)return n;if(t.find((e=>"openCKFinder"===e))&&e.ui.componentFactory.has("ckfinder")){const t=e.ui.componentFactory.create("ckfinder");t.set({withText:!0,class:"ck-image-insert__ck-finder-button"}),t.delegate("execute").to(i,"cancel"),n.openCKFinder=t}return t.reduce(((t,i)=>(n[i]?t[i]=n[i]:e.ui.componentFactory.has(i)&&(t[i]=e.ui.componentFactory.create(i)),t)),{})}(t)),a.delegate("submit","cancel").to(n),s.children.add(a)})),n.on("change:isOpen",(()=>{const e=t.model.document.selection.getSelectedElement(),s=a.insertButtonView,l=a.getIntegration("insertImageViaUrl");n.isOpen&&(o.isImage(e)?(a.imageURLInputValue=r.value,s.label=i("Update"),l.label=i("Update image URL")):(a.imageURLInputValue="",s.label=i("Insert"),l.label=i("Insert image via URL")))}),{priority:"low"}),this.delegate("cancel").to(n),n.on("submit",(()=>{l(),function(){const e=t.model.document.selection.getSelectedElement();o.isImage(e)?t.execute("replaceImageSource",{source:a.imageURLInputValue}):t.execute("insertImage",{source:a.imageURLInputValue})}()})),n.on("cancel",(()=>{l()})),n}}class f_ extends io{static get pluginName(){return"ImageInsertViaUrl"}static get requires(){return[g_]}}class p_ extends so{refresh(){const e=this.editor,t=e.plugins.get("ImageUtils").getClosestSelectedImageElement(e.model.document.selection);this.isEnabled=!!t,t&&t.hasAttribute("resizedWidth")?this.value={width:t.getAttribute("resizedWidth"),height:null}:this.value=null}execute(e){const t=this.editor,i=t.model,n=t.plugins.get("ImageUtils"),s=n.getClosestSelectedImageElement(i.document.selection);this.value={width:e.width,height:null},s&&i.change((t=>{t.setAttribute("resizedWidth",e.width,s),t.removeAttribute("resizedHeight",s),n.setImageNaturalSizeAttributes(s)}))}}class b_ extends io{static get requires(){return[rp]}static get pluginName(){return"ImageResizeEditing"}constructor(e){super(e),e.config.define("image",{resizeUnit:"%",resizeOptions:[{name:"resizeImage:original",value:null,icon:"original"},{name:"resizeImage:25",value:"25",icon:"small"},{name:"resizeImage:50",value:"50",icon:"medium"},{name:"resizeImage:75",value:"75",icon:"large"}]})}init(){const e=this.editor,t=new p_(e);this._registerSchema(),this._registerConverters("imageBlock"),this._registerConverters("imageInline"),e.commands.add("resizeImage",t),e.commands.add("imageResize",t)}_registerSchema(){this.editor.plugins.has("ImageBlockEditing")&&this.editor.model.schema.extend("imageBlock",{allowAttributes:["resizedWidth","resizedHeight"]}),this.editor.plugins.has("ImageInlineEditing")&&this.editor.model.schema.extend("imageInline",{allowAttributes:["resizedWidth","resizedHeight"]})}_registerConverters(e){const t=this.editor,i=t.plugins.get("ImageUtils");t.conversion.for("downcast").add((t=>t.on(`attribute:resizedWidth:${e}`,((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.writer,s=i.mapper.toViewElement(t.item);null!==t.attributeNewValue?(n.setStyle("width",t.attributeNewValue,s),n.addClass("image_resized",s)):(n.removeStyle("width",s),n.removeClass("image_resized",s))})))),t.conversion.for("dataDowncast").attributeToAttribute({model:{name:e,key:"resizedHeight"},view:e=>({key:"style",value:{height:e}})}),t.conversion.for("editingDowncast").add((t=>t.on(`attribute:resizedHeight:${e}`,((t,n,s)=>{if(!s.consumable.consume(n.item,t.name))return;const o=s.writer,r=s.mapper.toViewElement(n.item),a="imageInline"===e?i.findViewImgElement(r):r;null!==n.attributeNewValue?o.setStyle("height",n.attributeNewValue,a):o.removeStyle("height",a)})))),t.conversion.for("upcast").attributeToAttribute({view:{name:"imageBlock"===e?"figure":"img",styles:{width:/.+/}},model:{key:"resizedWidth",value:e=>sp(e)?null:e.getStyle("width")}}),t.conversion.for("upcast").attributeToAttribute({view:{name:"imageBlock"===e?"figure":"img",styles:{height:/.+/}},model:{key:"resizedHeight",value:e=>sp(e)?null:e.getStyle("height")}})}}const w_={small:Kh.objectSizeSmall,medium:Kh.objectSizeMedium,large:Kh.objectSizeLarge,original:Kh.objectSizeFull};class v_ extends io{static get requires(){return[b_]}static get pluginName(){return"ImageResizeButtons"}constructor(e){super(e),this._resizeUnit=e.config.get("image.resizeUnit")}init(){const e=this.editor,t=e.config.get("image.resizeOptions"),i=e.commands.get("resizeImage");this.bind("isEnabled").to(i);for(const e of t)this._registerImageResizeButton(e);this._registerImageResizeDropdown(t)}_registerImageResizeButton(e){const t=this.editor,{name:i,value:n,icon:s}=e,o=n?n+this._resizeUnit:null;t.ui.componentFactory.add(i,(i=>{const n=new fs(i),r=t.commands.get("resizeImage"),a=this._getOptionLabelValue(e,!0);if(!w_[s])throw new _("imageresizebuttons-missing-icon",t,e);return n.set({label:a,icon:w_[s],tooltip:a,isToggleable:!0}),n.bind("isEnabled").to(this),n.bind("isOn").to(r,"value",__(o)),this.listenTo(n,"execute",(()=>{t.execute("resizeImage",{width:o})})),n}))}_registerImageResizeDropdown(e){const t=this.editor,i=t.t,n=e.find((e=>!e.value)),s=s=>{const o=t.commands.get("resizeImage"),r=ru(s,Qs),a=r.buttonView,l=i("Resize image");return a.set({tooltip:l,commandValue:n.value,icon:w_.medium,isToggleable:!0,label:this._getOptionLabelValue(n),withText:!0,class:"ck-resize-image-button",ariaLabel:l,ariaLabelledBy:void 0}),a.bind("label").to(o,"value",(e=>e&&e.width?e.width:this._getOptionLabelValue(n))),r.bind("isEnabled").to(this),cu(r,(()=>this._getResizeDropdownListItemDefinitions(e,o)),{ariaLabel:i("Image resize list"),role:"menu"}),this.listenTo(r,"execute",(e=>{t.execute(e.source.commandName,{width:e.source.commandValue}),t.editing.view.focus()})),r};t.ui.componentFactory.add("resizeImage",s),t.ui.componentFactory.add("imageResize",s)}_getOptionLabelValue(e,t=!1){const i=this.editor.t;return e.label?e.label:t?e.value?i("Resize image to %0",e.value+this._resizeUnit):i("Resize image to the original size"):e.value?e.value+this._resizeUnit:i("Original")}_getResizeDropdownListItemDefinitions(e,t){const i=new Ln;return e.map((e=>{const n=e.value?e.value+this._resizeUnit:null,s={type:"button",model:new _m({commandName:"resizeImage",commandValue:n,label:this._getOptionLabelValue(e),role:"menuitemradio",withText:!0,icon:null})};s.model.bind("isOn").to(t,"value",__(n)),i.add(s)})),i}}function __(e){return t=>null===e&&t===e||null!==t&&t.width===e}const y_="image_resized";class k_ extends io{static get requires(){return[Sf,rp]}static get pluginName(){return"ImageResizeHandles"}init(){const e=this.editor.commands.get("resizeImage");this.bind("isEnabled").to(e),this._setupResizerCreator()}_setupResizerCreator(){const e=this.editor,t=e.editing.view,i=e.plugins.get("ImageUtils");t.addObserver(Rv),this.listenTo(t.document,"imageLoaded",((n,s)=>{if(!s.target.matches("figure.image.ck-widget > img,figure.image.ck-widget > picture > img,figure.image.ck-widget > a > img,figure.image.ck-widget > a > picture > img,span.image-inline.ck-widget > img,span.image-inline.ck-widget > picture > img"))return;const o=e.editing.view.domConverter,r=o.domToView(s.target),a=i.getImageWidgetFromImageView(r);let l=this.editor.plugins.get(Sf).getResizerByViewElement(a);if(l)return void l.redraw();const c=e.editing.mapper,d=c.toModelElement(a);l=e.plugins.get(Sf).attachTo({unit:e.config.get("image.resizeUnit"),modelElement:d,viewElement:a,editor:e,getHandleHost:e=>e.querySelector("img"),getResizeHost:()=>o.mapViewToDom(c.toViewElement(d.parent)),isCentered(){const e=d.getAttribute("imageStyle");return!e||"block"==e||"alignCenter"==e},onCommit(i){t.change((e=>{e.removeClass(y_,a)})),e.execute("resizeImage",{width:i})}}),l.on("updateSize",(()=>{a.hasClass(y_)||t.change((e=>{e.addClass(y_,a)}));const e="imageInline"===d.name?r:a;e.getStyle("height")&&t.change((t=>{t.removeStyle("height",e)}))})),l.bind("isEnabled").to(this)}))}}class C_ extends so{constructor(e,t){super(e),this._defaultStyles={imageBlock:!1,imageInline:!1},this._styles=new Map(t.map((e=>{if(e.isDefault)for(const t of e.modelElements)this._defaultStyles[t]=e.name;return[e.name,e]})))}refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled?e.hasAttribute("imageStyle")?this.value=e.getAttribute("imageStyle"):this.value=this._defaultStyles[e.name]:this.value=!1}execute(e={}){const t=this.editor,i=t.model,n=t.plugins.get("ImageUtils");i.change((t=>{const s=e.value,{setImageSizes:o=!0}=e;let r=n.getClosestSelectedImageElement(i.document.selection);s&&this.shouldConvertImageType(s,r)&&(this.editor.execute(n.isBlockImage(r)?"imageTypeInline":"imageTypeBlock",{setImageSizes:o}),r=n.getClosestSelectedImageElement(i.document.selection)),!s||this._styles.get(s).isDefault?t.removeAttribute("imageStyle",r):t.setAttribute("imageStyle",s,r),o&&n.setImageNaturalSizeAttributes(r)}))}shouldConvertImageType(e,t){return!this._styles.get(e).modelElements.includes(t.name)}}const{objectFullWidth:A_,objectInline:x_,objectLeft:T_,objectRight:E_,objectCenter:S_,objectBlockLeft:P_,objectBlockRight:I_}=Kh,V_={get inline(){return{name:"inline",title:"In line",icon:x_,modelElements:["imageInline"],isDefault:!0}},get alignLeft(){return{name:"alignLeft",title:"Left aligned image",icon:T_,modelElements:["imageBlock","imageInline"],className:"image-style-align-left"}},get alignBlockLeft(){return{name:"alignBlockLeft",title:"Left aligned image",icon:P_,modelElements:["imageBlock"],className:"image-style-block-align-left"}},get alignCenter(){return{name:"alignCenter",title:"Centered image",icon:S_,modelElements:["imageBlock"],className:"image-style-align-center"}},get alignRight(){return{name:"alignRight",title:"Right aligned image",icon:E_,modelElements:["imageBlock","imageInline"],className:"image-style-align-right"}},get alignBlockRight(){return{name:"alignBlockRight",title:"Right aligned image",icon:I_,modelElements:["imageBlock"],className:"image-style-block-align-right"}},get block(){return{name:"block",title:"Centered image",icon:S_,modelElements:["imageBlock"],isDefault:!0}},get side(){return{name:"side",title:"Side image",icon:E_,modelElements:["imageBlock"],className:"image-style-side"}}},R_={full:A_,left:P_,right:I_,center:S_,inlineLeft:T_,inlineRight:E_,inline:x_},L_=[{name:"imageStyle:wrapText",title:"Wrap text",defaultItem:"imageStyle:alignLeft",items:["imageStyle:alignLeft","imageStyle:alignRight"]},{name:"imageStyle:breakText",title:"Break text",defaultItem:"imageStyle:block",items:["imageStyle:alignBlockLeft","imageStyle:block","imageStyle:alignBlockRight"]}];function O_(e){y("image-style-configuration-definition-invalid",e)}const B_={normalizeStyles:function(e){return(e.configuredStyles.options||[]).map((e=>{return"string"==typeof(t="string"==typeof(t=e)?V_[t]?{...V_[t]}:{name:t}:function(e,t){const i={...t};for(const n in e)Object.prototype.hasOwnProperty.call(t,n)||(i[n]=e[n]);return i}(V_[t.name],t)).icon&&(t.icon=R_[t.icon]||t.icon),t;var t})).filter((t=>function(e,{isBlockPluginLoaded:t,isInlinePluginLoaded:i}){const{modelElements:n,name:s}=e;if(!(n&&n.length&&s))return O_({style:e}),!1;{const s=[t?"imageBlock":null,i?"imageInline":null];if(!n.some((e=>s.includes(e))))return y("image-style-missing-dependency",{style:e,missingPlugins:n.map((e=>"imageBlock"===e?"ImageBlockEditing":"ImageInlineEditing"))}),!1}return!0}(t,e)))},getDefaultStylesConfiguration:function(e,t){return e&&t?{options:["inline","alignLeft","alignRight","alignCenter","alignBlockLeft","alignBlockRight","block","side"]}:e?{options:["block","side"]}:t?{options:["inline","alignLeft","alignRight"]}:{}},getDefaultDropdownDefinitions:function(e){return e.has("ImageBlockEditing")&&e.has("ImageInlineEditing")?[...L_]:[]},warnInvalidStyle:O_,DEFAULT_OPTIONS:V_,DEFAULT_ICONS:R_,DEFAULT_DROPDOWN_DEFINITIONS:L_};function M_(e,t){for(const i of t)if(i.name===e)return i}class N_ extends io{static get pluginName(){return"ImageStyleEditing"}static get requires(){return[rp]}init(){const{normalizeStyles:e,getDefaultStylesConfiguration:t}=B_,i=this.editor,n=i.plugins.has("ImageBlockEditing"),s=i.plugins.has("ImageInlineEditing");i.config.define("image.styles",t(n,s)),this.normalizedStyles=e({configuredStyles:i.config.get("image.styles"),isBlockPluginLoaded:n,isInlinePluginLoaded:s}),this._setupConversion(n,s),this._setupPostFixer(),i.commands.add("imageStyle",new C_(i,this.normalizedStyles))}_setupConversion(e,t){const i=this.editor,n=i.model.schema,s=(o=this.normalizedStyles,(e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=M_(t.attributeNewValue,o),s=M_(t.attributeOldValue,o),r=i.mapper.toViewElement(t.item),a=i.writer;s&&a.removeClass(s.className,r),n&&a.addClass(n.className,r)});var o;const r=function(e){const t={imageInline:e.filter((e=>!e.isDefault&&e.modelElements.includes("imageInline"))),imageBlock:e.filter((e=>!e.isDefault&&e.modelElements.includes("imageBlock")))};return(e,i,n)=>{if(!i.modelRange)return;const s=i.viewItem,o=On(i.modelRange.getItems());if(o&&n.schema.checkAttribute(o,"imageStyle"))for(const e of t[o.name])n.consumable.consume(s,{classes:e.className})&&n.writer.setAttribute("imageStyle",e.name,o)}}(this.normalizedStyles);i.editing.downcastDispatcher.on("attribute:imageStyle",s),i.data.downcastDispatcher.on("attribute:imageStyle",s),e&&(n.extend("imageBlock",{allowAttributes:"imageStyle"}),i.data.upcastDispatcher.on("element:figure",r,{priority:"low"})),t&&(n.extend("imageInline",{allowAttributes:"imageStyle"}),i.data.upcastDispatcher.on("element:img",r,{priority:"low"}))}_setupPostFixer(){const e=this.editor,t=e.model.document,i=e.plugins.get(rp),n=new Map(this.normalizedStyles.map((e=>[e.name,e])));t.registerPostFixer((e=>{let s=!1;for(const o of t.differ.getChanges())if("insert"==o.type||"attribute"==o.type&&"imageStyle"==o.attributeKey){let t="insert"==o.type?o.position.nodeAfter:o.range.start.nodeAfter;if(t&&t.is("element","paragraph")&&t.childCount>0&&(t=t.getChild(0)),!i.isImage(t))continue;const r=t.getAttribute("imageStyle");if(!r)continue;const a=n.get(r);a&&a.modelElements.includes(t.name)||(e.removeAttribute("imageStyle",t),s=!0)}return s}))}}class F_ extends io{static get requires(){return[N_]}static get pluginName(){return"ImageStyleUI"}get localizedDefaultStylesTitles(){const e=this.editor.t;return{"Wrap text":e("Wrap text"),"Break text":e("Break text"),"In line":e("In line"),"Full size image":e("Full size image"),"Side image":e("Side image"),"Left aligned image":e("Left aligned image"),"Centered image":e("Centered image"),"Right aligned image":e("Right aligned image")}}init(){const e=this.editor.plugins,t=this.editor.config.get("image.toolbar")||[],i=D_(e.get("ImageStyleEditing").normalizedStyles,this.localizedDefaultStylesTitles);for(const e of i)this._createButton(e);const n=D_([...t.filter(M),...B_.getDefaultDropdownDefinitions(e)],this.localizedDefaultStylesTitles);for(const e of n)this._createDropdown(e,i)}_createDropdown(e,t){const i=this.editor.ui.componentFactory;i.add(e.name,(n=>{let s;const{defaultItem:o,items:r,title:a}=e,l=r.filter((e=>t.find((({name:t})=>z_(t)===e)))).map((e=>{const t=i.create(e);return e===o&&(s=t),t}));r.length!==l.length&&B_.warnInvalidStyle({dropdown:e});const c=ru(n,ou),d=c.buttonView,h=d.arrowView;return au(c,l,{enableActiveItemFocusOnDropdownOpen:!0}),d.set({label:H_(a,s.label),class:null,tooltip:!0}),h.unbind("label"),h.set({label:a}),d.bind("icon").toMany(l,"isOn",((...e)=>{const t=e.findIndex(Jo);return t<0?s.icon:l[t].icon})),d.bind("label").toMany(l,"isOn",((...e)=>{const t=e.findIndex(Jo);return H_(a,t<0?s.label:l[t].label)})),d.bind("isOn").toMany(l,"isOn",((...e)=>e.some(Jo))),d.bind("class").toMany(l,"isOn",((...e)=>e.some(Jo)?"ck-splitbutton_flatten":void 0)),d.on("execute",(()=>{l.some((({isOn:e})=>e))?c.isOpen=!c.isOpen:s.fire("execute")})),c.bind("isEnabled").toMany(l,"isEnabled",((...e)=>e.some(Jo))),this.listenTo(c,"execute",(()=>{this.editor.editing.view.focus()})),c}))}_createButton(e){const t=e.name;this.editor.ui.componentFactory.add(z_(t),(i=>{const n=this.editor.commands.get("imageStyle"),s=new fs(i);return s.set({label:e.title,icon:e.icon,tooltip:!0,isToggleable:!0}),s.bind("isEnabled").to(n,"isEnabled"),s.bind("isOn").to(n,"value",(e=>e===t)),s.on("execute",this._executeCommand.bind(this,t)),s}))}_executeCommand(e){this.editor.execute("imageStyle",{value:e}),this.editor.editing.view.focus()}}function D_(e,t){for(const i of e)t[i.title]&&(i.title=t[i.title]);return e}function z_(e){return`imageStyle:${e}`}function H_(e,t){return(e?e+": ":"")+t}class $_ extends io{static get pluginName(){return"IndentEditing"}init(){const e=this.editor;e.commands.add("indent",new ro(e)),e.commands.add("outdent",new ro(e))}}const W_='',U_='';class j_ extends io{static get pluginName(){return"IndentUI"}init(){const e=this.editor,t=e.locale,i=e.t,n="ltr"==t.uiLanguageDirection?W_:U_,s="ltr"==t.uiLanguageDirection?U_:W_;this._defineButton("indent",i("Increase indent"),n),this._defineButton("outdent",i("Decrease indent"),s)}_defineButton(e,t,i){const n=this.editor;n.ui.componentFactory.add(e,(s=>{const o=n.commands.get(e),r=new fs(s);return r.set({label:t,icon:i,tooltip:!0}),r.bind("isEnabled").to(o,"isEnabled"),this.listenTo(r,"execute",(()=>{n.execute(e),n.editing.view.focus()})),r}))}}class q_ extends so{constructor(e,t){super(e),this._indentBehavior=t}refresh(){const e=On(this.editor.model.document.selection.getSelectedBlocks());e&&this._isIndentationChangeAllowed(e)?this.isEnabled=this._indentBehavior.checkEnabled(e.getAttribute("blockIndent")):this.isEnabled=!1}execute(){const e=this.editor.model,t=this._getBlocksToChange();e.change((e=>{for(const i of t){const t=i.getAttribute("blockIndent"),n=this._indentBehavior.getNextIndent(t);n?e.setAttribute("blockIndent",n,i):e.removeAttribute("blockIndent",i)}}))}_getBlocksToChange(){const e=this.editor.model.document.selection;return Array.from(e.getSelectedBlocks()).filter((e=>this._isIndentationChangeAllowed(e)))}_isIndentationChangeAllowed(e){const t=this.editor;return!!t.model.schema.checkAttribute(e,"blockIndent")&&(!t.plugins.has("DocumentListUtils")||(!this._indentBehavior.isForward||!t.plugins.get("DocumentListUtils").isListItemBlock(e)))}}class G_{constructor(e){this.isForward="forward"===e.direction,this.offset=e.offset,this.unit=e.unit}checkEnabled(e){const t=parseFloat(e||"0");return this.isForward||t>0}getNextIndent(e){const t=parseFloat(e||"0");if(e&&!e.endsWith(this.unit))return this.isForward?this.offset+this.unit:void 0;const i=t+(this.isForward?this.offset:-this.offset);return i>0?i+this.unit:void 0}}class K_{constructor(e){this.isForward="forward"===e.direction,this.classes=e.classes}checkEnabled(e){const t=this.classes.indexOf(e);return this.isForward?t=0}getNextIndent(e){const t=this.classes.indexOf(e),i=this.isForward?1:-1;return this.classes[t+i]}}const J_=["paragraph","heading1","heading2","heading3","heading4","heading5","heading6"],Q_="italic";class Z_ extends io{static get pluginName(){return"ItalicEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:Q_}),e.model.schema.setAttributeProperties(Q_,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:Q_,view:"i",upcastAlso:["em",{styles:{"font-style":"italic"}}]}),e.commands.add(Q_,new jp(e,Q_)),e.keystrokes.set("CTRL+I",Q_)}}const Y_="italic";class X_ extends io{static get pluginName(){return"ItalicUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(Y_,(i=>{const n=e.commands.get(Y_),s=new fs(i);return s.set({label:t("Italic"),icon:'',keystroke:"CTRL+I",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(Y_),e.editing.view.focus()})),s}))}}class ey{constructor(){this._definitions=new Set}get length(){return this._definitions.size}add(e){Array.isArray(e)?e.forEach((e=>this._definitions.add(e))):this._definitions.add(e)}getDispatcher(){return e=>{e.on("attribute:linkHref",((e,t,i)=>{if(!i.consumable.test(t.item,"attribute:linkHref"))return;if(!t.item.is("selection")&&!i.schema.isInline(t.item))return;const n=i.writer,s=n.document.selection;for(const e of this._definitions){const o=n.createAttributeElement("a",e.attributes,{priority:5});e.classes&&n.addClass(e.classes,o);for(const t in e.styles)n.setStyle(t,e.styles[t],o);n.setCustomProperty("link",!0,o),e.callback(t.attributeNewValue)?t.item.is("selection")?n.wrap(s.getFirstRange(),o):n.wrap(i.mapper.toViewRange(t.range),o):n.unwrap(i.mapper.toViewRange(t.range),o)}}),{priority:"high"})}}getDispatcherForLinkedImage(){return e=>{e.on("attribute:linkHref:imageBlock",((e,t,{writer:i,mapper:n})=>{const s=n.toViewElement(t.item),o=Array.from(s.getChildren()).find((e=>e.is("element","a")));for(const e of this._definitions){const n=Nn(e.attributes);if(e.callback(t.attributeNewValue)){for(const[e,t]of n)"class"===e?i.addClass(t,o):i.setAttribute(e,t,o);e.classes&&i.addClass(e.classes,o);for(const t in e.styles)i.setStyle(t,e.styles[t],o)}else{for(const[e,t]of n)"class"===e?i.removeClass(t,o):i.removeAttribute(e,o);e.classes&&i.removeClass(e.classes,o);for(const t in e.styles)i.removeStyle(t,o)}}}))}}}class ty extends so{constructor(){super(...arguments),this.manualDecorators=new Ln,this.automaticDecorators=new ey}restoreManualDecoratorStates(){for(const e of this.manualDecorators)e.value=this._getDecoratorStateFromModel(e.id)}refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement()||On(t.getSelectedBlocks());Rp(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"));for(const e of this.manualDecorators)e.value=this._getDecoratorStateFromModel(e.id)}execute(e,t={}){const i=this.editor.model,n=i.document.selection,s=[],o=[];for(const e in t)t[e]?s.push(e):o.push(e);i.change((t=>{if(n.isCollapsed){const r=n.getFirstPosition();if(n.hasAttribute("linkHref")){const a=iy(n);let l=Ig(r,"linkHref",n.getAttribute("linkHref"),i);n.getAttribute("linkHref")===a&&(l=this._updateLinkContent(i,t,l,e)),t.setAttribute("linkHref",e,l),s.forEach((e=>{t.setAttribute(e,!0,l)})),o.forEach((e=>{t.removeAttribute(e,l)})),t.setSelection(t.createPositionAfter(l.end.nodeBefore))}else if(""!==e){const o=Nn(n.getAttributes());o.set("linkHref",e),s.forEach((e=>{o.set(e,!0)}));const{end:a}=i.insertContent(t.createText(e,o),r);t.setSelection(a)}["linkHref",...s,...o].forEach((e=>{t.removeSelectionAttribute(e)}))}else{const r=i.schema.getValidRanges(n.getRanges(),"linkHref"),a=[];for(const e of n.getSelectedBlocks())i.schema.checkAttribute(e,"linkHref")&&a.push(t.createRangeOn(e));const l=a.slice();for(const e of r)this._isRangeToUpdate(e,a)&&l.push(e);for(const r of l){let a=r;if(1===l.length){const s=iy(n);n.getAttribute("linkHref")===s&&(a=this._updateLinkContent(i,t,r,e),t.setSelection(t.createSelection(a)))}t.setAttribute("linkHref",e,a),s.forEach((e=>{t.setAttribute(e,!0,a)})),o.forEach((e=>{t.removeAttribute(e,a)}))}}}))}_getDecoratorStateFromModel(e){const t=this.editor.model,i=t.document.selection,n=i.getSelectedElement();return Rp(n,t.schema)?n.getAttribute(e):i.getAttribute(e)}_isRangeToUpdate(e,t){for(const i of t)if(i.containsRange(e))return!1;return!0}_updateLinkContent(e,t,i,n){const s=t.createText(n,{linkHref:n});return e.insertContent(s,i)}}function iy(e){if(e.isCollapsed){const t=e.getFirstPosition();return t.textNode&&t.textNode.data}{const t=Array.from(e.getFirstRange().getItems());if(t.length>1)return null;const i=t[0];return i.is("$text")||i.is("$textProxy")?i.data:null}}class ny extends so{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement();Rp(i,e.schema)?this.isEnabled=e.schema.checkAttribute(i,"linkHref"):this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref")}execute(){const e=this.editor,t=this.editor.model,i=t.document.selection,n=e.commands.get("link");t.change((e=>{const s=i.isCollapsed?[Ig(i.getFirstPosition(),"linkHref",i.getAttribute("linkHref"),t)]:t.schema.getValidRanges(i.getRanges(),"linkHref");for(const t of s)if(e.removeAttribute("linkHref",t),n)for(const i of n.manualDecorators)e.removeAttribute(i.id,t)}))}}class sy extends(W()){constructor({id:e,label:t,attributes:i,classes:n,styles:s,defaultValue:o}){super(),this.id=e,this.set("value",void 0),this.defaultValue=o,this.label=t,this.attributes=i,this.classes=n,this.styles=s}_createPattern(){return{attributes:this.attributes,classes:this.classes,styles:this.styles}}}const oy="automatic",ry=/^(https?:)?\/\//;class ay extends io{static get pluginName(){return"LinkEditing"}static get requires(){return[yg,lg,zg]}constructor(e){super(e),e.config.define("link",{addTargetToExternalLinks:!1})}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:"linkHref"}),e.conversion.for("dataDowncast").attributeToElement({model:"linkHref",view:Ip}),e.conversion.for("editingDowncast").attributeToElement({model:"linkHref",view:(e,t)=>Ip(Vp(e),t)}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{href:!0}},model:{key:"linkHref",value:e=>e.getAttribute("href")}}),e.commands.add("link",new ty(e)),e.commands.add("unlink",new ny(e));const t=function(e,t){const i={"Open in a new tab":e("Open in a new tab"),Downloadable:e("Downloadable")};return t.forEach((e=>("label"in e&&i[e.label]&&(e.label=i[e.label]),e))),t}(e.t,function(e){const t=[];if(e)for(const[i,n]of Object.entries(e)){const e=Object.assign({},n,{id:`link${Ap(i)}`});t.push(e)}return t}(e.config.get("link.decorators")));this._enableAutomaticDecorators(t.filter((e=>e.mode===oy))),this._enableManualDecorators(t.filter((e=>"manual"===e.mode))),e.plugins.get(yg).registerAttribute("linkHref"),Rg(e,"linkHref","a","ck-link_selected"),this._enableLinkOpen(),this._enableInsertContentSelectionAttributesFixer(),this._enableClickingAfterLink(),this._enableTypingOverLink(),this._handleDeleteContentAfterLink(),this._enableClipboardIntegration()}_enableAutomaticDecorators(e){const t=this.editor,i=t.commands.get("link").automaticDecorators;t.config.get("link.addTargetToExternalLinks")&&i.add({id:"linkIsExternal",mode:oy,callback:e=>!!e&&ry.test(e),attributes:{target:"_blank",rel:"noopener noreferrer"}}),i.add(e),i.length&&t.conversion.for("downcast").add(i.getDispatcher())}_enableManualDecorators(e){if(!e.length)return;const t=this.editor,i=t.commands.get("link").manualDecorators;e.forEach((e=>{t.model.schema.extend("$text",{allowAttributes:e.id});const n=new sy(e);i.add(n),t.conversion.for("downcast").attributeToElement({model:n.id,view:(e,{writer:t,schema:i},{item:s})=>{if((s.is("selection")||i.isInline(s))&&e){const e=t.createAttributeElement("a",n.attributes,{priority:5});n.classes&&t.addClass(n.classes,e);for(const i in n.styles)t.setStyle(i,n.styles[i],e);return t.setCustomProperty("link",!0,e),e}}}),t.conversion.for("upcast").elementToAttribute({view:{name:"a",...n._createPattern()},model:{key:n.id}})}))}_enableLinkOpen(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"click",((e,t)=>{if(!(l.isMac?t.domEvent.metaKey:t.domEvent.ctrlKey))return;let i=t.domTarget;if("a"!=i.tagName.toLowerCase()&&(i=i.closest("a")),!i)return;const n=i.getAttribute("href");n&&(e.stop(),t.preventDefault(),Bp(n))}),{context:"$capture"}),this.listenTo(t,"keydown",((t,i)=>{const n=e.commands.get("link").value;n&&i.keyCode===Cn.enter&&i.altKey&&(t.stop(),Bp(n))}))}_enableInsertContentSelectionAttributesFixer(){const e=this.editor.model,t=e.document.selection;this.listenTo(e,"insertContent",(()=>{const i=t.anchor.nodeBefore,n=t.anchor.nodeAfter;t.hasAttribute("linkHref")&&i&&i.hasAttribute("linkHref")&&(n&&n.hasAttribute("linkHref")||e.change((t=>{ly(t,dy(e.schema))})))}),{priority:"low"})}_enableClickingAfterLink(){const e=this.editor,t=e.model;e.editing.view.addObserver(Yd);let i=!1;this.listenTo(e.editing.view.document,"mousedown",(()=>{i=!0})),this.listenTo(e.editing.view.document,"selectionChange",(()=>{if(!i)return;i=!1;const e=t.document.selection;if(!e.isCollapsed)return;if(!e.hasAttribute("linkHref"))return;const n=e.getFirstPosition(),s=Ig(n,"linkHref",e.getAttribute("linkHref"),t);(n.isTouching(s.start)||n.isTouching(s.end))&&t.change((e=>{ly(e,dy(t.schema))}))}))}_enableTypingOverLink(){const e=this.editor,t=e.editing.view;let i=null,n=!1;this.listenTo(t.document,"delete",(()=>{n=!0}),{priority:"high"}),this.listenTo(e.model,"deleteContent",(()=>{const t=e.model.document.selection;t.isCollapsed||(n?n=!1:cy(e)&&function(e){const t=e.document.selection,i=t.getFirstPosition(),n=t.getLastPosition(),s=i.nodeAfter;if(!s)return!1;if(!s.is("$text"))return!1;if(!s.hasAttribute("linkHref"))return!1;return s===(n.textNode||n.nodeBefore)||Ig(i,"linkHref",s.getAttribute("linkHref"),e).containsRange(e.createRange(i,n),!0)}(e.model)&&(i=t.getAttributes()))}),{priority:"high"}),this.listenTo(e.model,"insertContent",((t,[s])=>{n=!1,cy(e)&&i&&(e.model.change((e=>{for(const[t,n]of i)e.setAttribute(t,n,s)})),i=null)}),{priority:"high"})}_handleDeleteContentAfterLink(){const e=this.editor,t=e.model,i=t.document.selection,n=e.editing.view;let s=!1,o=!1;this.listenTo(n.document,"delete",((e,t)=>{o="backward"===t.direction}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{s=!1;const e=i.getFirstPosition(),n=i.getAttribute("linkHref");if(!n)return;const o=Ig(e,"linkHref",n,t);s=o.containsPosition(e)||o.end.isEqual(e)}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{o&&(o=!1,s||e.model.enqueueChange((e=>{ly(e,dy(t.schema))})))}),{priority:"low"})}_enableClipboardIntegration(){const e=this.editor,t=e.model,i=this.editor.config.get("link.defaultProtocol");i&&this.listenTo(e.plugins.get("ClipboardPipeline"),"contentInsertion",((e,n)=>{t.change((e=>{const t=e.createRangeIn(n.content);for(const n of t.getItems())if(n.hasAttribute("linkHref")){const t=Lp(n.getAttribute("linkHref"),i);e.setAttribute("linkHref",t,n)}}))}))}}function ly(e,t){e.removeSelectionAttribute("linkHref");for(const i of t)e.removeSelectionAttribute(i)}function cy(e){return e.model.change((e=>e.batch)).isTyping}function dy(e){return e.getDefinition("$text").allowAttributes.filter((e=>e.startsWith("link")))}class hy extends Un{constructor(e,t){super(e),this.focusTracker=new Bn,this.keystrokes=new Mn,this._focusables=new Wn;const i=e.t;this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("Save"),Kh.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(i("Cancel"),Kh.cancel,"ck-button-cancel","cancel"),this._manualDecoratorSwitches=this._createManualDecoratorSwitches(t),this.children=this._createFormChildren(t.manualDecorators),this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}});const n=["ck","ck-link-form","ck-responsive-form"];t.manualDecorators.length&&n.push("ck-link-form_layout-vertical","ck-vertical-form"),this.setTemplate({tag:"form",attributes:{class:n,tabindex:"-1"},children:this.children})}getDecoratorSwitchesState(){return Array.from(this._manualDecoratorSwitches).reduce(((e,t)=>(e[t.name]=t.isOn,e)),{})}render(){super.render(),s({view:this}),[this.urlInputView,...this._manualDecoratorSwitches,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createUrlInput(){const e=this.locale.t,t=new $s(this.locale,mu);return t.label=e("Link URL"),t}_createButton(e,t,i,n){const s=new fs(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}_createManualDecoratorSwitches(e){const t=this.createCollection();for(const i of e.manualDecorators){const n=new ps(this.locale);n.set({name:i.id,label:i.label,withText:!0}),n.bind("isOn").toMany([i,e],"value",((e,t)=>void 0===t&&void 0===e?!!i.defaultValue:!!e)),n.on("execute",(()=>{i.set("value",!n.isOn)})),t.add(n)}return t}_createFormChildren(e){const t=this.createCollection();if(t.add(this.urlInputView),e.length){const e=new Un;e.setTemplate({tag:"ul",children:this._manualDecoratorSwitches.map((e=>({tag:"li",children:[e],attributes:{class:["ck","ck-list__item"]}}))),attributes:{class:["ck","ck-reset","ck-list"]}}),t.add(e)}return t.add(this.saveButtonView),t.add(this.cancelButtonView),t}}class uy extends Un{constructor(e){super(e),this.focusTracker=new Bn,this.keystrokes=new Mn,this._focusables=new Wn;const t=e.t;this.previewButtonView=this._createPreviewButton(),this.unlinkButtonView=this._createButton(t("Unlink"),'',"unlink"),this.editButtonView=this._createButton(t("Edit link"),Kh.pencil,"edit"),this.set("href",void 0),this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-link-actions","ck-responsive-form"],tabindex:"-1"},children:[this.previewButtonView,this.editButtonView,this.unlinkButtonView]})}render(){super.render(),[this.previewButtonView,this.editButtonView,this.unlinkButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createButton(e,t,i){const n=new fs(this.locale);return n.set({label:e,icon:t,tooltip:!0}),n.delegate("execute").to(this,i),n}_createPreviewButton(){const e=new fs(this.locale),t=this.bindTemplate,i=this.t;return e.set({withText:!0,tooltip:i("Open link in new tab")}),e.extendTemplate({attributes:{class:["ck","ck-link-actions__preview"],href:t.to("href",(e=>e&&Vp(e))),target:"_blank",rel:"noopener noreferrer"}}),e.bind("label").to(this,"href",(e=>e||i("This link has no URL"))),e.bind("isEnabled").to(this,"href",(e=>!!e)),e.template.tag="a",e.template.eventListeners={},e}}const my='',gy="link-ui";class fy extends io{constructor(){super(...arguments),this.actionsView=null,this.formView=null}static get requires(){return[Cm]}static get pluginName(){return"LinkUI"}init(){const e=this.editor;e.editing.view.addObserver(Zd),this._balloon=e.plugins.get(Cm),this._createToolbarLinkButton(),this._enableBalloonActivators(),e.conversion.for("editingDowncast").markerToHighlight({model:gy,view:{classes:["ck-fake-link-selection"]}}),e.conversion.for("editingDowncast").markerToElement({model:gy,view:{name:"span",classes:["ck-fake-link-selection","ck-fake-link-selection_collapsed"]}})}destroy(){super.destroy(),this.formView&&this.formView.destroy(),this.actionsView&&this.actionsView.destroy()}_createViews(){this.actionsView=this._createActionsView(),this.formView=this._createFormView(),this._enableUserBalloonInteractions()}_createActionsView(){const e=this.editor,t=new uy(e.locale),i=e.commands.get("link"),n=e.commands.get("unlink");return t.bind("href").to(i,"value"),t.editButtonView.bind("isEnabled").to(i),t.unlinkButtonView.bind("isEnabled").to(n),this.listenTo(t,"edit",(()=>{this._addFormView()})),this.listenTo(t,"unlink",(()=>{e.execute("unlink"),this._hideUI()})),t.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),t.keystrokes.set(Pp,((e,t)=>{this._addFormView(),t()})),t}_createFormView(){const e=this.editor,i=e.commands.get("link"),n=e.config.get("link.defaultProtocol"),s=new(t(hy))(e.locale,i);return s.urlInputView.fieldView.bind("value").to(i,"value"),s.urlInputView.bind("isEnabled").to(i,"isEnabled"),s.saveButtonView.bind("isEnabled").to(i),this.listenTo(s,"submit",(()=>{const{value:t}=s.urlInputView.fieldView.element,i=Lp(t,n);e.execute("link",i,s.getDecoratorSwitchesState()),this._closeFormView()})),this.listenTo(s,"cancel",(()=>{this._closeFormView()})),s.keystrokes.set("Esc",((e,t)=>{this._closeFormView(),t()})),s}_createToolbarLinkButton(){const e=this.editor,t=e.commands.get("link"),i=e.t;e.ui.componentFactory.add("link",(e=>{const n=new fs(e);return n.isEnabled=!0,n.label=i("Link"),n.icon=my,n.keystroke=Pp,n.tooltip=!0,n.isToggleable=!0,n.bind("isEnabled").to(t,"isEnabled"),n.bind("isOn").to(t,"value",(e=>!!e)),this.listenTo(n,"execute",(()=>this._showUI(!0))),n}))}_enableBalloonActivators(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"click",(()=>{this._getSelectedLinkElement()&&this._showUI()})),e.keystrokes.set(Pp,((t,i)=>{i(),e.commands.get("link").isEnabled&&this._showUI(!0)}))}_enableUserBalloonInteractions(){this.editor.keystrokes.set("Tab",((e,t)=>{this._areActionsVisible&&!this.actionsView.focusTracker.isFocused&&(this.actionsView.focus(),t())}),{priority:"high"}),this.editor.keystrokes.set("Esc",((e,t)=>{this._isUIVisible&&(this._hideUI(),t())})),e({emitter:this.formView,activator:()=>this._isUIInPanel,contextElements:()=>[this._balloon.view.element],callback:()=>this._hideUI()})}_addActionsView(){this.actionsView||this._createViews(),this._areActionsInPanel||this._balloon.add({view:this.actionsView,position:this._getBalloonPositionData()})}_addFormView(){if(this.formView||this._createViews(),this._isFormInPanel)return;const e=this.editor.commands.get("link");this.formView.disableCssTransitions(),this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),this._balloon.visibleView===this.formView&&this.formView.urlInputView.fieldView.select(),this.formView.enableCssTransitions(),this.formView.urlInputView.fieldView.element.value=e.value||""}_closeFormView(){const e=this.editor.commands.get("link");e.restoreManualDecoratorStates(),void 0!==e.value?this._removeFormView():this._hideUI()}_removeFormView(){this._isFormInPanel&&(this.formView.saveButtonView.focus(),this._balloon.remove(this.formView),this.editor.editing.view.focus(),this._hideFakeVisualSelection())}_showUI(e=!1){this.formView||this._createViews(),this._getSelectedLinkElement()?(this._areActionsVisible?this._addFormView():this._addActionsView(),e&&this._balloon.showStack("main")):(this._showFakeVisualSelection(),this._addActionsView(),e&&this._balloon.showStack("main"),this._addFormView()),this._startUpdatingUI()}_hideUI(){if(!this._isUIInPanel)return;const e=this.editor;this.stopListening(e.ui,"update"),this.stopListening(this._balloon,"change:visibleView"),e.editing.view.focus(),this._removeFormView(),this._balloon.remove(this.actionsView),this._hideFakeVisualSelection()}_startUpdatingUI(){const e=this.editor,t=e.editing.view.document;let i=this._getSelectedLinkElement(),n=o();const s=()=>{const e=this._getSelectedLinkElement(),t=o();i&&!e||!i&&t!==n?this._hideUI():this._isUIVisible&&this._balloon.updatePosition(this._getBalloonPositionData()),i=e,n=t};function o(){return t.selection.focus.getAncestors().reverse().find((e=>e.is("element")))}this.listenTo(e.ui,"update",s),this.listenTo(this._balloon,"change:visibleView",s)}get _isFormInPanel(){return!!this.formView&&this._balloon.hasView(this.formView)}get _areActionsInPanel(){return!!this.actionsView&&this._balloon.hasView(this.actionsView)}get _areActionsVisible(){return!!this.actionsView&&this._balloon.visibleView===this.actionsView}get _isUIInPanel(){return this._isFormInPanel||this._areActionsInPanel}get _isUIVisible(){const e=this._balloon.visibleView;return!!this.formView&&e==this.formView||this._areActionsVisible}_getBalloonPositionData(){const e=this.editor.editing.view,t=this.editor.model,i=e.document;let n;if(t.markers.has(gy)){const t=Array.from(this.editor.editing.mapper.markerNameToElements(gy)),i=e.createRange(e.createPositionBefore(t[0]),e.createPositionAfter(t[t.length-1]));n=e.domConverter.viewRangeToDom(i)}else n=()=>{const t=this._getSelectedLinkElement();return t?e.domConverter.mapViewToDom(t):e.domConverter.viewRangeToDom(i.selection.getFirstRange())};return{target:n}}_getSelectedLinkElement(){const e=this.editor.editing.view,t=e.document.selection,i=t.getSelectedElement();if(t.isCollapsed||i&&sf(i))return py(t.getFirstPosition());{const i=t.getFirstRange().getTrimmed(),n=py(i.start),s=py(i.end);return n&&n==s&&e.createRangeIn(n).getTrimmed().isEqual(i)?n:null}}_showFakeVisualSelection(){const e=this.editor.model;e.change((t=>{const i=e.document.selection.getFirstRange();if(e.markers.has(gy))t.updateMarker(gy,{range:i});else if(i.start.isAtEnd){const n=i.start.getLastMatchingPosition((({item:t})=>!e.schema.isContent(t)),{boundaries:i});t.addMarker(gy,{usingOperation:!1,affectsData:!1,range:t.createRange(n,i.end)})}else t.addMarker(gy,{usingOperation:!1,affectsData:!1,range:i})}))}_hideFakeVisualSelection(){const e=this.editor.model;e.markers.has(gy)&&e.change((e=>{e.removeMarker(gy)}))}}function py(e){return e.getAncestors().find((e=>{return(t=e).is("attributeElement")&&!!t.getCustomProperty("link");var t}))||null}class by extends io{static get requires(){return["ImageEditing","ImageUtils",ay]}static get pluginName(){return"LinkImageEditing"}init(){const e=this.editor,t=e.model.schema;e.plugins.has("ImageBlockEditing")&&t.extend("imageBlock",{allowAttributes:["linkHref"]}),e.conversion.for("upcast").add(function(e){const t=e.plugins.has("ImageInlineEditing"),i=e.plugins.get("ImageUtils");return e=>{e.on("element:a",((e,n,s)=>{const o=n.viewItem,r=i.findViewImgElement(o);if(!r)return;const a=r.findAncestor((e=>i.isBlockImageView(e)));if(t&&!a)return;if(!s.consumable.consume(o,{attributes:["href"]}))return;const l=o.getAttribute("href");if(!l)return;let c=n.modelCursor.parent;if(!c.is("element","imageBlock")){const e=s.convertItem(r,n.modelCursor);n.modelRange=e.modelRange,n.modelCursor=e.modelCursor,c=n.modelCursor.nodeBefore}c&&c.is("element","imageBlock")&&s.writer.setAttribute("linkHref",l,c)}),{priority:"high"})}}(e)),e.conversion.for("downcast").add(function(e){const t=e.plugins.get("ImageUtils");return e=>{e.on("attribute:linkHref:imageBlock",((e,i,n)=>{if(!n.consumable.consume(i.item,e.name))return;const s=n.mapper.toViewElement(i.item),o=n.writer,r=Array.from(s.getChildren()).find((e=>e.is("element","a"))),a=t.findViewImgElement(s),l=a.parent.is("element","picture")?a.parent:a;if(r)i.attributeNewValue?o.setAttribute("href",i.attributeNewValue,r):(o.move(o.createRangeOn(l),o.createPositionAt(s,0)),o.remove(r));else{const e=o.createContainerElement("a",{href:i.attributeNewValue});o.insert(o.createPositionAt(s,0),e),o.move(o.createRangeOn(l),o.createPositionAt(e,0))}}),{priority:"high"})}}(e)),this._enableAutomaticDecorators(),this._enableManualDecorators()}_enableAutomaticDecorators(){const e=this.editor,t=e.commands.get("link").automaticDecorators;t.length&&e.conversion.for("downcast").add(t.getDispatcherForLinkedImage())}_enableManualDecorators(){const e=this.editor,t=e.commands.get("link");for(const i of t.manualDecorators)e.plugins.has("ImageBlockEditing")&&e.model.schema.extend("imageBlock",{allowAttributes:i.id}),e.plugins.has("ImageInlineEditing")&&e.model.schema.extend("imageInline",{allowAttributes:i.id}),e.conversion.for("downcast").add(wy(i)),e.conversion.for("upcast").add(vy(e,i))}}function wy(e){return t=>{t.on(`attribute:${e.id}:imageBlock`,((t,i,n)=>{const s=n.mapper.toViewElement(i.item),o=Array.from(s.getChildren()).find((e=>e.is("element","a")));if(o){for(const[t,i]of Nn(e.attributes))n.writer.setAttribute(t,i,o);e.classes&&n.writer.addClass(e.classes,o);for(const t in e.styles)n.writer.setStyle(t,e.styles[t],o)}}))}}function vy(e,t){const i=e.plugins.has("ImageInlineEditing"),n=e.plugins.get("ImageUtils");return e=>{e.on("element:a",((e,s,o)=>{const r=s.viewItem,a=n.findViewImgElement(r);if(!a)return;const l=a.findAncestor((e=>n.isBlockImageView(e)));if(i&&!l)return;const c=new ko(t._createPattern()).match(r);if(!c)return;if(!o.consumable.consume(r,c.match))return;const d=s.modelCursor.nodeBefore||s.modelCursor.parent;o.writer.setAttribute(t.id,!0,d)}),{priority:"high"})}}class _y extends io{static get requires(){return[ay,fy,"ImageBlockEditing"]}static get pluginName(){return"LinkImageUI"}init(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"click",((t,i)=>{this._isSelectedLinkedImage(e.model.document.selection)&&(i.preventDefault(),t.stop())}),{priority:"high"}),this._createToolbarLinkImageButton()}_createToolbarLinkImageButton(){const e=this.editor,t=e.t;e.ui.componentFactory.add("linkImage",(i=>{const n=new fs(i),s=e.plugins.get("LinkUI"),o=e.commands.get("link");return n.set({isEnabled:!0,label:t("Link image"),icon:my,keystroke:Pp,tooltip:!0,isToggleable:!0}),n.bind("isEnabled").to(o,"isEnabled"),n.bind("isOn").to(o,"value",(e=>!!e)),this.listenTo(n,"execute",(()=>{this._isSelectedLinkedImage(e.model.document.selection)?s._addActionsView():s._showUI(!0)})),n}))}_isSelectedLinkedImage(e){const t=e.getSelectedElement();return this.editor.plugins.get("ImageUtils").isImage(t)&&t.hasAttribute("linkHref")}}class yy extends so{constructor(e,t){super(e),this.type=t}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){const t=this.editor.model,i=t.document,n=Array.from(i.selection.getSelectedBlocks()).filter((e=>Cy(e,t.schema))),s=void 0!==e.forceValue?!e.forceValue:this.value;t.change((e=>{if(s){let t=n[n.length-1].nextSibling,i=Number.POSITIVE_INFINITY,s=[];for(;t&&"listItem"==t.name&&0!==t.getAttribute("listIndent");){const e=t.getAttribute("listIndent");e=i;)o>s.getAttribute("listIndent")&&(o=s.getAttribute("listIndent")),s.getAttribute("listIndent")==o&&e[t?"unshift":"push"](s),s=s[t?"previousSibling":"nextSibling"]}}function Cy(e,t){return t.checkChild(e.parent,"listItem")&&!t.isObject(e)}class Ay extends so{constructor(e,t){super(e),this._indentBy="forward"==t?1:-1}refresh(){this.isEnabled=this._checkEnabled()}execute(){const e=this.editor.model,t=e.document;let i=Array.from(t.selection.getSelectedBlocks());e.change((e=>{const t=i[i.length-1];let n=t.nextSibling;for(;n&&"listItem"==n.name&&n.getAttribute("listIndent")>t.getAttribute("listIndent");)i.push(n),n=n.nextSibling;this._indentBy<0&&(i=i.reverse());for(const t of i){const i=t.getAttribute("listIndent")+this._indentBy;i<0?e.rename(t,"paragraph"):e.setAttribute("listIndent",i,t)}this.fire("_executeCleanup",i)}))}_checkEnabled(){const e=On(this.editor.model.document.selection.getSelectedBlocks());if(!e||!e.is("element","listItem"))return!1;if(this._indentBy>0){const t=e.getAttribute("listIndent"),i=e.getAttribute("listType");let n=e.previousSibling;for(;n&&n.is("element","listItem")&&n.getAttribute("listIndent")>=t;){if(n.getAttribute("listIndent")==t)return n.getAttribute("listType")==i;n=n.previousSibling}return!1}return!0}}function xy(e,t){const i=t.mapper,n=t.writer,s="numbered"==e.getAttribute("listType")?"ol":"ul",o=function(e){const t=e.createContainerElement("li");return t.getFillerOffset=Ny,t}(n),r=n.createContainerElement(s,null);return n.insert(n.createPositionAt(r,0),o),i.bindElements(e,o),o}function Ty(e,t,i,n){const s=t.parent,o=i.mapper,r=i.writer;let a=o.toViewPosition(n.createPositionBefore(e));const l=Py(e.previousSibling,{sameIndent:!0,smallerIndent:!0,listIndent:e.getAttribute("listIndent")}),c=e.previousSibling;if(l&&l.getAttribute("listIndent")==e.getAttribute("listIndent")){const e=o.toViewElement(l);a=r.breakContainer(r.createPositionAfter(e))}else if(c&&"listItem"==c.name){a=o.toViewPosition(n.createPositionAt(c,"end"));const e=o.findMappedViewAncestor(a),t=Vy(e);a=t?r.createPositionBefore(t):r.createPositionAt(e,"end")}else a=o.toViewPosition(n.createPositionBefore(e));if(a=Sy(a),r.insert(a,s),c&&"listItem"==c.name){const e=o.toViewElement(c),i=r.createRange(r.createPositionAt(e,0),a).getWalker({ignoreElementEnd:!0});for(const e of i)if(e.item.is("element","li")){const n=r.breakContainer(r.createPositionBefore(e.item)),s=e.item.parent,o=r.createPositionAt(t,"end");Ey(r,o.nodeBefore,o.nodeAfter),r.move(r.createRangeOn(s),o),i._position=n}}else{const i=s.nextSibling;if(i&&(i.is("element","ul")||i.is("element","ol"))){let n=null;for(const t of i.getChildren()){const i=o.toModelElement(t);if(!(i&&i.getAttribute("listIndent")>e.getAttribute("listIndent")))break;n=t}n&&(r.breakContainer(r.createPositionAfter(n)),r.move(r.createRangeOn(n.parent),r.createPositionAt(t,"end")))}}Ey(r,s,s.nextSibling),Ey(r,s.previousSibling,s)}function Ey(e,t,i){return!t||!i||"ul"!=t.name&&"ol"!=t.name||t.name!=i.name||t.getAttribute("class")!==i.getAttribute("class")?null:e.mergeContainers(e.createPositionAfter(t))}function Sy(e){return e.getLastMatchingPosition((e=>e.item.is("uiElement")))}function Py(e,t){const i=!!t.sameIndent,n=!!t.smallerIndent,s=t.listIndent;let o=e;for(;o&&"listItem"==o.name;){const e=o.getAttribute("listIndent");if(i&&s==e||n&&s>e)return o;o="forward"===t.direction?o.nextSibling:o.previousSibling}return null}function Iy(e,t,i,n){e.ui.componentFactory.add(t,(s=>{const o=e.commands.get(t),r=new fs(s);return r.set({label:i,icon:n,tooltip:!0,isToggleable:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),r.on("execute",(()=>{e.execute(t),e.editing.view.focus()})),r}))}function Vy(e){for(const t of e.getChildren())if("ul"==t.name||"ol"==t.name)return t;return null}function Ry(e,t){const i=[],n=e.parent,s={ignoreElementEnd:!1,startPosition:e,shallow:!0,direction:t},o=n.getAttribute("listIndent"),r=[...new rl(s)].filter((e=>e.item.is("element"))).map((e=>e.item));for(const e of r){if(!e.is("element","listItem"))break;if(e.getAttribute("listIndent")o)){if(e.getAttribute("listType")!==n.getAttribute("listType"))break;if(e.getAttribute("listStyle")!==n.getAttribute("listStyle"))break;if(e.getAttribute("listReversed")!==n.getAttribute("listReversed"))break;if(e.getAttribute("listStart")!==n.getAttribute("listStart"))break;"backward"===t?i.unshift(e):i.push(e)}}return i}function Ly(e){let t=[...e.document.selection.getSelectedBlocks()].filter((e=>e.is("element","listItem"))).map((t=>{const i=e.change((e=>e.createPositionAt(t,0)));return[...Ry(i,"backward"),...Ry(i,"forward")]})).flat();return t=[...new Set(t)],t}const Oy=["disc","circle","square"],By=["decimal","decimal-leading-zero","lower-roman","upper-roman","lower-latin","upper-latin"];function My(e){return Oy.includes(e)?"bulleted":By.includes(e)?"numbered":null}function Ny(){const e=!this.isEmpty&&("ul"==this.getChild(0).name||"ol"==this.getChild(0).name);return this.isEmpty||e?0:hr.call(this)}class Fy extends io{static get pluginName(){return"ListUtils"}getListTypeFromListStyleType(e){return My(e)}getSelectedListItems(e){return Ly(e)}getSiblingNodes(e,t){return Ry(e,t)}}function Dy(e){return(t,i,n)=>{const s=n.consumable;if(!s.test(i.item,"insert")||!s.test(i.item,"attribute:listType")||!s.test(i.item,"attribute:listIndent"))return;s.consume(i.item,"insert"),s.consume(i.item,"attribute:listType"),s.consume(i.item,"attribute:listIndent");const o=i.item;Ty(o,xy(o,n),n,e)}}const zy=(e,t,i)=>{if(!i.consumable.test(t.item,e.name))return;const n=i.mapper.toViewElement(t.item),s=i.writer;s.breakContainer(s.createPositionBefore(n)),s.breakContainer(s.createPositionAfter(n));const o=n.parent,r="numbered"==t.attributeNewValue?"ol":"ul";s.rename(r,o)},Hy=(e,t,i)=>{i.consumable.consume(t.item,e.name);const n=i.mapper.toViewElement(t.item).parent,s=i.writer;Ey(s,n,n.nextSibling),Ey(s,n.previousSibling,n)},$y=(e,t,i)=>{if(i.consumable.test(t.item,e.name)&&"listItem"!=t.item.name){let e=i.mapper.toViewPosition(t.range.start);const n=i.writer,s=[];for(;("ul"==e.parent.name||"ol"==e.parent.name)&&(e=n.breakContainer(e),"li"==e.parent.name);){const t=e,i=n.createPositionAt(e.parent,"end");if(!t.isEqual(i)){const e=n.remove(n.createRange(t,i));s.push(e)}e=n.createPositionAfter(e.parent)}if(s.length>0){for(let t=0;t0){const t=Ey(n,i,i.nextSibling);t&&t.parent==i&&e.offset--}}Ey(n,e.nodeBefore,e.nodeAfter)}}},Wy=(e,t,i)=>{const n=i.mapper.toViewPosition(t.position),s=n.nodeBefore,o=n.nodeAfter;Ey(i.writer,s,o)},Uy=(e,t,i)=>{if(i.consumable.consume(t.viewItem,{name:!0})){const e=i.writer,n=e.createElement("listItem"),s=function(e){let t=0,i=e.parent;for(;i;){if(i.is("element","li"))t++;else{const e=i.previousSibling;e&&e.is("element","li")&&t++}i=i.parent}return t}(t.viewItem);e.setAttribute("listIndent",s,n);const o=t.viewItem.parent&&"ol"==t.viewItem.parent.name?"numbered":"bulleted";if(e.setAttribute("listType",o,n),!i.safeInsert(n,t.modelCursor))return;const r=function(e,t,i){const{writer:n,schema:s}=i;let o=n.createPositionAfter(e);for(const r of t)if("ul"==r.name||"ol"==r.name)o=i.convertItem(r,o).modelCursor;else{const t=i.convertItem(r,n.createPositionAt(e,"end")),a=t.modelRange.start.nodeAfter;a&&a.is("element")&&!s.checkChild(e,a.name)&&(e=t.modelCursor.parent.is("element","listItem")?t.modelCursor.parent:Jy(t.modelCursor),o=n.createPositionAfter(e))}return o}(n,t.viewItem.getChildren(),i);t.modelRange=e.createRange(t.modelCursor,r),i.updateConversionResult(n,t)}},jy=(e,t,i)=>{if(i.consumable.test(t.viewItem,{name:!0})){const e=Array.from(t.viewItem.getChildren());for(const t of e)!t.is("element","li")&&!Zy(t)&&t._remove()}},qy=(e,t,i)=>{if(i.consumable.test(t.viewItem,{name:!0})){if(0===t.viewItem.childCount)return;const e=[...t.viewItem.getChildren()];let i=!1;for(const t of e)i&&!Zy(t)&&t._remove(),Zy(t)&&(i=!0)}};function Gy(e){return(t,i)=>{if(i.isPhantom)return;const n=i.modelPosition.nodeBefore;if(n&&n.is("element","listItem")){const t=i.mapper.toViewElement(n),s=t.getAncestors().find(Zy),o=e.createPositionAt(t,0).getWalker();for(const e of o){if("elementStart"==e.type&&e.item.is("element","li")){i.viewPosition=e.previousPosition;break}if("elementEnd"==e.type&&e.item==s){i.viewPosition=e.nextPosition;break}}}}}const Ky=function(e,[t,i]){let n,s=t.is("documentFragment")?t.getChild(0):t;if(n=i?this.createSelection(i):this.document.selection,s&&s.is("element","listItem")){const e=n.getFirstPosition();let t=null;if(e.parent.is("element","listItem")?t=e.parent:e.nodeBefore&&e.nodeBefore.is("element","listItem")&&(t=e.nodeBefore),t){const e=t.getAttribute("listIndent");if(e>0)for(;s&&s.is("element","listItem");)s._setAttribute("listIndent",s.getAttribute("listIndent")+e),s=s.nextSibling}}};function Jy(e){const t=new rl({startPosition:e});let i;do{i=t.next()}while(!i.value.item.is("element","listItem"));return i.value.item}function Qy(e,t,i,n,s,o){const r=Py(t.nodeBefore,{sameIndent:!0,smallerIndent:!0,listIndent:e}),a=s.mapper,l=s.writer,c=r?r.getAttribute("listIndent"):null;let d;if(r)if(c==e){const e=a.toViewElement(r).parent;d=l.createPositionAfter(e)}else{const e=o.createPositionAt(r,"end");d=a.toViewPosition(e)}else d=i;d=Sy(d);for(const e of[...n.getChildren()])Zy(e)&&(d=l.move(l.createRangeOn(e),d).end,Ey(l,e,e.nextSibling),Ey(l,e.previousSibling,e))}function Zy(e){return e.is("element","ol")||e.is("element","ul")}class Yy extends io{static get pluginName(){return"ListEditing"}static get requires(){return[qg,bg,Fy]}init(){const e=this.editor;e.model.schema.register("listItem",{inheritAllFrom:"$block",allowAttributes:["listType","listIndent"]});const t=e.data,i=e.editing;var n;e.model.document.registerPostFixer((t=>function(e,t){const i=e.document.differ.getChanges(),n=new Map;let s=!1;for(const n of i)if("insert"==n.type&&"listItem"==n.name)o(n.position);else if("insert"==n.type&&"listItem"!=n.name){if("$text"!=n.name){const i=n.position.nodeAfter;i.hasAttribute("listIndent")&&(t.removeAttribute("listIndent",i),s=!0),i.hasAttribute("listType")&&(t.removeAttribute("listType",i),s=!0),i.hasAttribute("listStyle")&&(t.removeAttribute("listStyle",i),s=!0),i.hasAttribute("listReversed")&&(t.removeAttribute("listReversed",i),s=!0),i.hasAttribute("listStart")&&(t.removeAttribute("listStart",i),s=!0);for(const t of Array.from(e.createRangeIn(i)).filter((e=>e.item.is("element","listItem"))))o(t.previousPosition)}o(n.position.getShiftedBy(n.length))}else"remove"==n.type&&"listItem"==n.name?o(n.position):("attribute"==n.type&&"listIndent"==n.attributeKey||"attribute"==n.type&&"listType"==n.attributeKey)&&o(n.range.start);for(const e of n.values())r(e),a(e);return s;function o(e){const t=e.nodeBefore;if(t&&t.is("element","listItem")){let e=t;if(n.has(e))return;for(let t=e.previousSibling;t&&t.is("element","listItem");t=e.previousSibling)if(e=t,n.has(e))return;n.set(t,e)}else{const t=e.nodeAfter;t&&t.is("element","listItem")&&n.set(t,t)}}function r(e){let i=0,n=null;for(;e&&e.is("element","listItem");){const o=e.getAttribute("listIndent");if(o>i){let r;null===n?(n=o-i,r=i):(n>o&&(n=o),r=o-n),t.setAttribute("listIndent",r,e),s=!0}else n=null,i=e.getAttribute("listIndent")+1;e=e.nextSibling}}function a(e){let i=[],n=null;for(;e&&e.is("element","listItem");){const o=e.getAttribute("listIndent");if(n&&n.getAttribute("listIndent")>o&&(i=i.slice(0,o+1)),0!=o)if(i[o]){const n=i[o];e.getAttribute("listType")!=n&&(t.setAttribute("listType",n,e),s=!0)}else i[o]=e.getAttribute("listType");n=e,e=e.nextSibling}}}(e.model,t))),i.mapper.registerViewToModelLength("li",Xy),t.mapper.registerViewToModelLength("li",Xy),i.mapper.on("modelToViewPosition",Gy(i.view)),i.mapper.on("viewToModelPosition",(n=e.model,(e,t)=>{const i=t.viewPosition,s=i.parent,o=t.mapper;if("ul"==s.name||"ol"==s.name){if(i.isAtEnd){const e=o.toModelElement(i.nodeBefore),s=o.getModelLength(i.nodeBefore);t.modelPosition=n.createPositionBefore(e).getShiftedBy(s)}else{const e=o.toModelElement(i.nodeAfter);t.modelPosition=n.createPositionBefore(e)}e.stop()}else if("li"==s.name&&i.nodeBefore&&("ul"==i.nodeBefore.name||"ol"==i.nodeBefore.name)){const r=o.toModelElement(s);let a=1,l=i.nodeBefore;for(;l&&Zy(l);)a+=o.getModelLength(l),l=l.previousSibling;t.modelPosition=n.createPositionBefore(r).getShiftedBy(a),e.stop()}})),t.mapper.on("modelToViewPosition",Gy(i.view)),e.conversion.for("editingDowncast").add((t=>{t.on("insert",$y,{priority:"high"}),t.on("insert:listItem",Dy(e.model)),t.on("attribute:listType:listItem",zy,{priority:"high"}),t.on("attribute:listType:listItem",Hy,{priority:"low"}),t.on("attribute:listIndent:listItem",function(e){return(t,i,n)=>{if(!n.consumable.consume(i.item,"attribute:listIndent"))return;const s=n.mapper.toViewElement(i.item),o=n.writer;o.breakContainer(o.createPositionBefore(s)),o.breakContainer(o.createPositionAfter(s));const r=s.parent,a=r.previousSibling,l=o.createRangeOn(r);o.remove(l),a&&a.nextSibling&&Ey(o,a,a.nextSibling),Qy(i.attributeOldValue+1,i.range.start,l.start,s,n,e),Ty(i.item,s,n,e);for(const e of i.item.getChildren())n.consumable.consume(e,"insert")}}(e.model)),t.on("remove:listItem",function(e){return(t,i,n)=>{const s=n.mapper.toViewPosition(i.position).getLastMatchingPosition((e=>!e.item.is("element","li"))).nodeAfter,o=n.writer;o.breakContainer(o.createPositionBefore(s)),o.breakContainer(o.createPositionAfter(s));const r=s.parent,a=r.previousSibling,l=o.createRangeOn(r),c=o.remove(l);a&&a.nextSibling&&Ey(o,a,a.nextSibling),Qy(n.mapper.toModelElement(s).getAttribute("listIndent")+1,i.position,l.start,s,n,e);for(const e of o.createRangeIn(c).getItems())n.mapper.unbindViewElement(e);t.stop()}}(e.model)),t.on("remove",Wy,{priority:"low"})})),e.conversion.for("dataDowncast").add((t=>{t.on("insert",$y,{priority:"high"}),t.on("insert:listItem",Dy(e.model))})),e.conversion.for("upcast").add((e=>{e.on("element:ul",jy,{priority:"high"}),e.on("element:ol",jy,{priority:"high"}),e.on("element:li",qy,{priority:"high"}),e.on("element:li",Uy)})),e.model.on("insertContent",Ky,{priority:"high"}),e.commands.add("numberedList",new yy(e,"numbered")),e.commands.add("bulletedList",new yy(e,"bulleted")),e.commands.add("indentList",new Ay(e,"forward")),e.commands.add("outdentList",new Ay(e,"backward"));const s=i.view.document;this.listenTo(s,"enter",((e,t)=>{const i=this.editor.model.document,n=i.selection.getLastPosition().parent;i.selection.isCollapsed&&"listItem"==n.name&&n.isEmpty&&(this.editor.execute("outdentList"),t.preventDefault(),e.stop())}),{context:"li"}),this.listenTo(s,"delete",((e,t)=>{if("backward"!==t.direction)return;const i=this.editor.model.document.selection;if(!i.isCollapsed)return;const n=i.getFirstPosition();if(!n.isAtStart)return;const s=n.parent;"listItem"===s.name&&(s.previousSibling&&"listItem"===s.previousSibling.name||(this.editor.execute("outdentList"),t.preventDefault(),e.stop()))}),{context:"li"}),this.listenTo(e.editing.view.document,"tab",((t,i)=>{const n=i.shiftKey?"outdentList":"indentList";this.editor.commands.get(n).isEnabled&&(e.execute(n),i.stopPropagation(),i.preventDefault(),t.stop())}),{context:"li"})}afterInit(){const e=this.editor.commands,t=e.get("indent"),i=e.get("outdent");t&&t.registerChildCommand(e.get("indentList")),i&&i.registerChildCommand(e.get("outdentList"))}}function Xy(e){let t=1;for(const i of e.getChildren())if("ul"==i.name||"ol"==i.name)for(const e of i.getChildren())t+=Xy(e);return t}const ek='',tk='';class ik extends io{static get pluginName(){return"ListUI"}init(){const e=this.editor.t;Iy(this.editor,"numberedList",e("Numbered List"),ek),Iy(this.editor,"bulletedList",e("Bulleted List"),tk)}}class nk extends so{constructor(e,t){super(e),this.defaultType=t}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(e={}){this._tryToConvertItemsToList(e);const t=this.editor.model,i=Ly(t);i.length&&t.change((t=>{for(const n of i)t.setAttribute("listStyle",e.type||this.defaultType,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")?e.getAttribute("listStyle"):null}_checkEnabled(){const e=this.editor,t=e.commands.get("numberedList"),i=e.commands.get("bulletedList");return t.isEnabled||i.isEnabled}_tryToConvertItemsToList(e){if(!e.type)return;const t=My(e.type);if(!t)return;const i=this.editor,n=`${t}List`;i.commands.get(n).value||i.execute(n)}}class sk extends so{refresh(){const e=this._getValue();this.value=e,this.isEnabled=null!=e}execute(e={}){const t=this.editor.model,i=Ly(t).filter((e=>"numbered"==e.getAttribute("listType")));t.change((t=>{for(const n of i)t.setAttribute("listReversed",!!e.reversed,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")&&"numbered"==e.getAttribute("listType")?e.getAttribute("listReversed"):null}}class ok extends so{refresh(){const e=this._getValue();this.value=e,this.isEnabled=null!=e}execute({startIndex:e=1}={}){const t=this.editor.model,i=Ly(t).filter((e=>"numbered"==e.getAttribute("listType")));t.change((t=>{for(const n of i)t.setAttribute("listStart",e>=0?e:1,n)}))}_getValue(){const e=this.editor.model.document.selection.getFirstPosition().parent;return e&&e.is("element","listItem")&&"numbered"==e.getAttribute("listType")?e.getAttribute("listStart"):null}}const rk="default";class ak extends io{static get requires(){return[Yy]}static get pluginName(){return"ListPropertiesEditing"}constructor(e){super(e),e.config.define("list",{properties:{styles:!0,startIndex:!1,reversed:!1}})}init(){const e=this.editor,t=e.model,i=function(e){const t=[];return e.styles&&t.push({attributeName:"listStyle",defaultValue:rk,addCommand(e){e.commands.add("listStyle",new nk(e,rk))},appliesToListItem:()=>!0,setAttributeOnDowncast(e,t,i){t&&t!==rk?e.setStyle("list-style-type",t,i):e.removeStyle("list-style-type",i)},getAttributeOnUpcast:e=>e.getStyle("list-style-type")||rk}),e.reversed&&t.push({attributeName:"listReversed",defaultValue:!1,addCommand(e){e.commands.add("listReversed",new sk(e))},appliesToListItem:e=>"numbered"==e.getAttribute("listType"),setAttributeOnDowncast(e,t,i){t?e.setAttribute("reversed","reversed",i):e.removeAttribute("reversed",i)},getAttributeOnUpcast:e=>e.hasAttribute("reversed")}),e.startIndex&&t.push({attributeName:"listStart",defaultValue:1,addCommand(e){e.commands.add("listStart",new ok(e))},appliesToListItem:e=>"numbered"==e.getAttribute("listType"),setAttributeOnDowncast(e,t,i){0==t||t>1?e.setAttribute("start",t,i):e.removeAttribute("start",i)},getAttributeOnUpcast(e){const t=e.getAttribute("start");return t>=0?t:1}}),t}(e.config.get("list.properties"));t.schema.extend("listItem",{allowAttributes:i.map((e=>e.attributeName))});for(const t of i)t.addCommand(e);var n;this.listenTo(e.commands.get("indentList"),"_executeCleanup",function(e,t){return(i,n)=>{const s=n[0],o=s.getAttribute("listIndent"),r=n.filter((e=>e.getAttribute("listIndent")===o));let a=null;s.previousSibling.getAttribute("listIndent")+1!==o&&(a=Py(s.previousSibling,{sameIndent:!0,direction:"backward",listIndent:o})),e.model.change((e=>{for(const i of r)for(const n of t)if(n.appliesToListItem(i)){const t=null==a?n.defaultValue:a.getAttribute(n.attributeName);e.setAttribute(n.attributeName,t,i)}}))}}(e,i)),this.listenTo(e.commands.get("outdentList"),"_executeCleanup",function(e,t){return(i,n)=>{if(!(n=n.reverse().filter((e=>e.is("element","listItem")))).length)return;const s=n[0].getAttribute("listIndent"),o=n[0].getAttribute("listType");let r=n[0].previousSibling;if(r.is("element","listItem"))for(;r.getAttribute("listIndent")!==s;)r=r.previousSibling;else r=null;r||(r=n[n.length-1].nextSibling),r&&r.is("element","listItem")&&r.getAttribute("listType")===o&&e.model.change((e=>{const i=n.filter((e=>e.getAttribute("listIndent")===s));for(const n of i)for(const i of t)if(i.appliesToListItem(n)){const t=i.attributeName,s=r.getAttribute(t);e.setAttribute(t,s,n)}}))}}(e,i)),this.listenTo(e.commands.get("bulletedList"),"_executeCleanup",dk(e)),this.listenTo(e.commands.get("numberedList"),"_executeCleanup",dk(e)),t.document.registerPostFixer(function(e,t){return i=>{let n=!1;const s=hk(e.model.document.differ.getChanges()).filter((e=>"todo"!==e.getAttribute("listType")));if(!s.length)return n;let o=s[s.length-1].nextSibling;if((!o||!o.is("element","listItem"))&&(o=s[0].previousSibling,o)){const e=s[0].getAttribute("listIndent");for(;o.is("element","listItem")&&o.getAttribute("listIndent")!==e&&(o=o.previousSibling,o););}for(const e of t){const t=e.attributeName;for(const r of s)if(e.appliesToListItem(r))if(r.hasAttribute(t)){const s=r.previousSibling;ck(s,r,e.attributeName)&&(i.setAttribute(t,s.getAttribute(t),r),n=!0)}else lk(o,r,e)?i.setAttribute(t,o.getAttribute(t),r):i.setAttribute(t,e.defaultValue,r),n=!0;else i.removeAttribute(t,r)}return n}}(e,i)),e.conversion.for("upcast").add((n=i,e=>{e.on("element:li",((e,t,i)=>{if(!t.modelRange)return;const s=t.viewItem.parent,o=t.modelRange.start.nodeAfter||t.modelRange.end.nodeBefore;for(const e of n)if(e.appliesToListItem(o)){const t=e.getAttributeOnUpcast(s);i.writer.setAttribute(e.attributeName,t,o)}}),{priority:"low"})})),e.conversion.for("downcast").add(function(e){return t=>{for(const i of e)t.on(`attribute:${i.attributeName}:listItem`,((e,t,n)=>{const s=n.writer,o=t.item,r=Py(o.previousSibling,{sameIndent:!0,listIndent:o.getAttribute("listIndent"),direction:"backward"}),a=n.mapper.toViewElement(o);var l,c;l=o,(c=r)&&l.getAttribute("listType")===c.getAttribute("listType")&&l.getAttribute("listIndent")===c.getAttribute("listIndent")&&l.getAttribute("listStyle")===c.getAttribute("listStyle")&&l.getAttribute("listReversed")===c.getAttribute("listReversed")&&l.getAttribute("listStart")===c.getAttribute("listStart")||s.breakContainer(s.createPositionBefore(a)),i.setAttributeOnDowncast(s,t.attributeNewValue,a.parent)}),{priority:"low"})}}(i)),this._mergeListAttributesWhileMergingLists(i)}afterInit(){const e=this.editor;e.commands.get("todoList")&&e.model.document.registerPostFixer(function(e){return t=>{const i=hk(e.model.document.differ.getChanges()).filter((e=>"todo"===e.getAttribute("listType")&&(e.hasAttribute("listStyle")||e.hasAttribute("listReversed")||e.hasAttribute("listStart"))));if(!i.length)return!1;for(const e of i)t.removeAttribute("listStyle",e),t.removeAttribute("listReversed",e),t.removeAttribute("listStart",e);return!0}}(e))}_mergeListAttributesWhileMergingLists(e){const t=this.editor.model;let i;this.listenTo(t,"deleteContent",((e,[t])=>{const n=t.getFirstPosition(),s=t.getLastPosition();if(n.parent===s.parent)return;if(!n.parent.is("element","listItem"))return;const o=s.parent.nextSibling;if(!o||!o.is("element","listItem"))return;const r=Py(n.parent,{sameIndent:!0,listIndent:o.getAttribute("listIndent")});r&&r.getAttribute("listType")===o.getAttribute("listType")&&(i=r)}),{priority:"high"}),this.listenTo(t,"deleteContent",(()=>{i&&(t.change((t=>{const n=Py(i.nextSibling,{sameIndent:!0,listIndent:i.getAttribute("listIndent"),direction:"forward"});if(!n)return void(i=null);const s=[n,...Ry(t.createPositionAt(n,0),"forward")];for(const n of s)for(const s of e)if(s.appliesToListItem(n)){const e=s.attributeName,o=i.getAttribute(e);t.setAttribute(e,o,n)}})),i=null)}),{priority:"low"})}}function lk(e,t,i){if(!e)return!1;const n=e.getAttribute(i.attributeName);return!!n&&n!=i.defaultValue&&e.getAttribute("listType")===t.getAttribute("listType")}function ck(e,t,i){if(!e||!e.is("element","listItem"))return!1;if(t.getAttribute("listType")!==e.getAttribute("listType"))return!1;const n=e.getAttribute("listIndent");if(n<1||n!==t.getAttribute("listIndent"))return!1;const s=e.getAttribute(i);return!(!s||s===t.getAttribute(i))}function dk(e){return(t,i)=>{i=i.filter((e=>e.is("element","listItem"))),e.model.change((e=>{for(const t of i)e.removeAttribute("listStyle",t)}))}}function hk(e){const t=[];for(const i of e){const e=uk(i);e&&e.is("element","listItem")&&t.push(e)}return t}function uk(e){return"attribute"===e.type?e.range.start.nodeAfter:"insert"===e.type?e.position.nodeAfter:null}class mk extends Un{constructor(e,t){super(e);const i=this.bindTemplate;this.set("isCollapsed",!1),this.set("label",""),this.buttonView=this._createButtonView(),this.children=this.createCollection(),this.set("_collapsibleAriaLabelUid",void 0),t&&this.children.addMany(t),this.setTemplate({tag:"div",attributes:{class:["ck","ck-collapsible",i.if("isCollapsed","ck-collapsible_collapsed")]},children:[this.buttonView,{tag:"div",attributes:{class:["ck","ck-collapsible__children"],role:"region",hidden:i.if("isCollapsed","hidden"),"aria-labelledby":i.to("_collapsibleAriaLabelUid")},children:this.children}]})}render(){super.render(),this._collapsibleAriaLabelUid=this.buttonView.labelView.element.id}_createButtonView(){const e=new fs(this.locale),t=e.bindTemplate;return e.set({withText:!0,icon:Js}),e.extendTemplate({attributes:{"aria-expanded":t.to("isOn",(e=>String(e)))}}),e.bind("label").to(this),e.bind("isOn").to(this,"isCollapsed",(e=>!e)),e.on("execute",(()=>{this.isCollapsed=!this.isCollapsed})),e}}class gk extends Un{constructor(e,{enabledProperties:t,styleButtonViews:i,styleGridAriaLabel:n}){super(e),this.stylesView=null,this.additionalPropertiesCollapsibleView=null,this.startIndexFieldView=null,this.reversedSwitchButtonView=null,this.focusTracker=new Bn,this.keystrokes=new Mn,this.focusables=new Wn;const s=["ck","ck-list-properties"];this.children=this.createCollection(),this.focusCycler=new Zs({focusables:this.focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),t.styles?(this.stylesView=this._createStylesView(i,n),this.children.add(this.stylesView)):s.push("ck-list-properties_without-styles"),(t.startIndex||t.reversed)&&(this._addNumberedListPropertyViews(t),s.push("ck-list-properties_with-numbered-properties")),this.setTemplate({tag:"div",attributes:{class:s},children:this.children})}render(){if(super.render(),this.stylesView){this.focusables.add(this.stylesView),this.focusTracker.add(this.stylesView.element),(this.startIndexFieldView||this.reversedSwitchButtonView)&&(this.focusables.add(this.children.last.buttonView),this.focusTracker.add(this.children.last.buttonView.element));for(const e of this.stylesView.children)this.stylesView.focusTracker.add(e.element);o({keystrokeHandler:this.stylesView.keystrokes,focusTracker:this.stylesView.focusTracker,gridItems:this.stylesView.children,numberOfColumns:()=>$i.window.getComputedStyle(this.stylesView.element).getPropertyValue("grid-template-columns").split(" ").length,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection})}if(this.startIndexFieldView){this.focusables.add(this.startIndexFieldView),this.focusTracker.add(this.startIndexFieldView.element);const e=e=>e.stopPropagation();this.keystrokes.set("arrowright",e),this.keystrokes.set("arrowleft",e),this.keystrokes.set("arrowup",e),this.keystrokes.set("arrowdown",e)}this.reversedSwitchButtonView&&(this.focusables.add(this.reversedSwitchButtonView),this.focusTracker.add(this.reversedSwitchButtonView.element)),this.keystrokes.listenTo(this.element)}focus(){this.focusCycler.focusFirst()}focusLast(){this.focusCycler.focusLast()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createStylesView(e,t){const i=new Un(this.locale);return i.children=i.createCollection(),i.children.addMany(e),i.setTemplate({tag:"div",attributes:{"aria-label":t,class:["ck","ck-list-styles-list"]},children:i.children}),i.children.delegate("execute").to(this),i.focus=function(){this.children.first.focus()},i.focusTracker=new Bn,i.keystrokes=new Mn,i.render(),i.keystrokes.listenTo(i.element),i}_addNumberedListPropertyViews(e){const t=this.locale.t,i=[];e.startIndex&&(this.startIndexFieldView=this._createStartIndexField(),i.push(this.startIndexFieldView)),e.reversed&&(this.reversedSwitchButtonView=this._createReversedSwitchButton(),i.push(this.reversedSwitchButtonView)),e.styles?(this.additionalPropertiesCollapsibleView=new mk(this.locale,i),this.additionalPropertiesCollapsibleView.set({label:t("List properties"),isCollapsed:!0}),this.additionalPropertiesCollapsibleView.buttonView.bind("isEnabled").toMany(i,"isEnabled",((...e)=>e.some((e=>e)))),this.additionalPropertiesCollapsibleView.buttonView.on("change:isEnabled",((e,t,i)=>{i||(this.additionalPropertiesCollapsibleView.isCollapsed=!0)})),this.children.add(this.additionalPropertiesCollapsibleView)):this.children.addMany(i)}_createStartIndexField(){const e=this.locale.t,t=new $s(this.locale,gu);return t.set({label:e("Start at"),class:"ck-numbered-list-properties__start-index"}),t.fieldView.set({min:0,step:1,value:1,inputMode:"numeric"}),t.fieldView.on("input",(()=>{const i=t.fieldView.element,n=i.valueAsNumber;Number.isNaN(n)||(i.checkValidity()?this.fire("listStart",{startIndex:n}):t.errorText=e("Start index must be greater than 0."))})),t}_createReversedSwitchButton(){const e=this.locale.t,t=new ps(this.locale);return t.set({withText:!0,label:e("Reversed order"),class:"ck-numbered-list-properties__reversed-order"}),t.delegate("execute").to(this,"listReversed"),t}}class fk extends io{static get pluginName(){return"ListPropertiesUI"}init(){const e=this.editor,t=e.locale.t,i=e.config.get("list.properties");i.styles&&e.ui.componentFactory.add("bulletedList",pk({editor:e,parentCommandName:"bulletedList",buttonLabel:t("Bulleted List"),buttonIcon:tk,styleGridAriaLabel:t("Bulleted list styles toolbar"),styleDefinitions:[{label:t("Toggle the disc list style"),tooltip:t("Disc"),type:"disc",icon:''},{label:t("Toggle the circle list style"),tooltip:t("Circle"),type:"circle",icon:''},{label:t("Toggle the square list style"),tooltip:t("Square"),type:"square",icon:''}]})),(i.styles||i.startIndex||i.reversed)&&e.ui.componentFactory.add("numberedList",pk({editor:e,parentCommandName:"numberedList",buttonLabel:t("Numbered List"),buttonIcon:ek,styleGridAriaLabel:t("Numbered list styles toolbar"),styleDefinitions:[{label:t("Toggle the decimal list style"),tooltip:t("Decimal"),type:"decimal",icon:''},{label:t("Toggle the decimal with leading zero list style"),tooltip:t("Decimal with leading zero"),type:"decimal-leading-zero",icon:''},{label:t("Toggle the lower–roman list style"),tooltip:t("Lower–roman"),type:"lower-roman",icon:''},{label:t("Toggle the upper–roman list style"),tooltip:t("Upper-roman"),type:"upper-roman",icon:''},{label:t("Toggle the lower–latin list style"),tooltip:t("Lower-latin"),type:"lower-latin",icon:''},{label:t("Toggle the upper–latin list style"),tooltip:t("Upper-latin"),type:"upper-latin",icon:''}]}))}}function pk({editor:e,parentCommandName:t,buttonLabel:i,buttonIcon:n,styleGridAriaLabel:s,styleDefinitions:o}){const r=e.commands.get(t);return a=>{const l=ru(a,ou),c=l.buttonView;return l.bind("isEnabled").to(r),l.class="ck-list-styles-dropdown",c.on("execute",(()=>{e.execute(t),e.editing.view.focus()})),c.set({label:i,icon:n,tooltip:!0,isToggleable:!0}),c.bind("isOn").to(r,"value",(e=>!!e)),l.once("change:isOpen",(()=>{const i=function({editor:e,dropdownView:t,parentCommandName:i,styleDefinitions:n,styleGridAriaLabel:s}){const o=e.locale,r=e.config.get("list.properties");let a=null;if("numberedList"!=i&&(r.startIndex=!1,r.reversed=!1),r.styles){const t=e.commands.get("listStyle"),s=function({editor:e,listStyleCommand:t,parentCommandName:i}){const n=e.locale,s=e.commands.get(i);return({label:i,type:o,icon:r,tooltip:a})=>{const l=new fs(n);return l.set({label:i,icon:r,tooltip:a}),t.on("change:value",(()=>{l.isOn=t.value===o})),l.on("execute",(()=>{s.value?t.value!==o?e.execute("listStyle",{type:o}):e.execute("listStyle",{type:t.defaultType}):e.model.change((()=>{e.execute("listStyle",{type:o})}))})),l}}({editor:e,parentCommandName:i,listStyleCommand:t}),o="function"==typeof t.isStyleTypeSupported?e=>t.isStyleTypeSupported(e.type):()=>!0;a=n.filter(o).map(s)}const l=new gk(o,{styleGridAriaLabel:s,enabledProperties:r,styleButtonViews:a});if(r.styles&&hu(t,(()=>l.stylesView.children.find((e=>e.isOn)))),r.startIndex){const t=e.commands.get("listStart");l.startIndexFieldView.bind("isEnabled").to(t),l.startIndexFieldView.fieldView.bind("value").to(t),l.on("listStart",((t,i)=>e.execute("listStart",i)))}if(r.reversed){const t=e.commands.get("listReversed");l.reversedSwitchButtonView.bind("isEnabled").to(t),l.reversedSwitchButtonView.bind("isOn").to(t,"value",(e=>!!e)),l.on("listReversed",(()=>{const i=t.value;e.execute("listReversed",{reversed:!i})}))}return l.delegate("execute").to(t),l}({editor:e,dropdownView:l,parentCommandName:t,styleGridAriaLabel:s,styleDefinitions:o});l.panelView.children.add(i)})),l.on("execute",(()=>{e.editing.view.focus()})),l}}function bk(e,t){const i=(i,n,s)=>{if(!s.consumable.consume(n.item,i.name))return;const o=n.attributeNewValue,r=s.writer,a=s.mapper.toViewElement(n.item),l=[...a.getChildren()].find((e=>e.getCustomProperty("media-content")));r.remove(l);const c=e.getMediaViewElement(r,o,t);r.insert(r.createPositionAt(a,0),c)};return e=>{e.on("attribute:url:media",i)}}function wk(e){const t=e.getSelectedElement();return t&&function(e){return!!e.getCustomProperty("media")&&sf(e)}(t)?t:null}function vk(e,t,i,n){return e.createContainerElement("figure",{class:"media"},[t.getMediaViewElement(e,i,n),e.createSlot()])}function _k(e){const t=e.getSelectedElement();return t&&t.is("element","media")?t:null}function yk(e,t,i,n){e.change((s=>{const o=s.createElement("media",{url:t});e.insertObject(o,i,null,{setSelection:"on",findOptimalPosition:n?"auto":void 0})}))}class kk extends so{refresh(){const e=this.editor.model,t=e.document.selection,i=_k(t);this.value=i?i.getAttribute("url"):void 0,this.isEnabled=function(e){const t=e.getSelectedElement();return!!t&&"media"===t.name}(t)||function(e,t){let i=df(e,t).start.parent;return i.isEmpty&&!t.schema.isLimit(i)&&(i=i.parent),t.schema.checkChild(i,"media")}(t,e)}execute(e){const t=this.editor.model,i=t.document.selection,n=_k(i);n?t.change((t=>{t.setAttribute("url",e,n)})):yk(t,e,i,!0)}}class Ck{constructor(e,t){const i=t.providers,n=t.extraProviders||[],s=new Set(t.removeProviders),o=i.concat(n).filter((e=>{const t=e.name;return t?!s.has(t):(y("media-embed-no-provider-name",{provider:e}),!1)}));this.locale=e,this.providerDefinitions=o}hasMedia(e){return!!this._getMedia(e)}getMediaViewElement(e,t,i){return this._getMedia(t).getViewElement(e,i)}_getMedia(e){if(!e)return new Ak(this.locale);e=e.trim();for(const t of this.providerDefinitions){const i=t.html,n=Pn(t.url);for(const t of n){const n=this._getUrlMatches(e,t);if(n)return new Ak(this.locale,e,n,i)}}return null}_getUrlMatches(e,t){let i=e.match(t);if(i)return i;let n=e.replace(/^https?:\/\//,"");return i=n.match(t),i||(n=n.replace(/^www\./,""),i=n.match(t),i||null)}}class Ak{constructor(e,t,i,n){this.url=this._getValidUrl(t),this._locale=e,this._match=i,this._previewRenderer=n}getViewElement(e,t){const i={};let n;if(t.renderForEditingView||t.renderMediaPreview&&this.url&&this._previewRenderer){this.url&&(i["data-oembed-url"]=this.url),t.renderForEditingView&&(i.class="ck-media__wrapper");const s=this._getPreviewHtml(t);n=e.createRawElement("div",i,((e,t)=>{t.setContentOf(e,s)}))}else this.url&&(i.url=this.url),n=e.createEmptyElement(t.elementName,i);return e.setCustomProperty("media-content",!0,n),n}_getPreviewHtml(e){return this._previewRenderer?this._previewRenderer(this._match):this.url&&e.renderForEditingView?this._getPlaceholderHtml():""}_getPlaceholderHtml(){const e=new ms,t=this._locale.t;return e.content='',e.viewBox="0 0 64 42",new jn({tag:"div",attributes:{class:"ck ck-reset_all ck-media__placeholder"},children:[{tag:"div",attributes:{class:"ck-media__placeholder__icon"},children:[e]},{tag:"a",attributes:{class:"ck-media__placeholder__url",target:"_blank",rel:"noopener noreferrer",href:this.url,"data-cke-tooltip-text":t("Open media in new tab")},children:[{tag:"span",attributes:{class:"ck-media__placeholder__url__text"},children:[this.url]}]}]}).render().outerHTML}_getValidUrl(e){return e?e.match(/^https?/)?e:"https://"+e:null}}class xk extends io{static get pluginName(){return"MediaEmbedEditing"}constructor(e){super(e),e.config.define("mediaEmbed",{elementName:"oembed",providers:[{name:"dailymotion",url:/^dailymotion\.com\/video\/(\w+)/,html:e=>`
    `},{name:"spotify",url:[/^open\.spotify\.com\/(artist\/\w+)/,/^open\.spotify\.com\/(album\/\w+)/,/^open\.spotify\.com\/(track\/\w+)/],html:e=>`
    `},{name:"youtube",url:[/^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)(?:&t=(\d+))?/,/^(?:m\.)?youtube\.com\/v\/([\w-]+)(?:\?t=(\d+))?/,/^youtube\.com\/embed\/([\w-]+)(?:\?start=(\d+))?/,/^youtu\.be\/([\w-]+)(?:\?t=(\d+))?/],html:e=>{const t=e[1],i=e[2];return`
    `}},{name:"vimeo",url:[/^vimeo\.com\/(\d+)/,/^vimeo\.com\/[^/]+\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/album\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/channels\/[^/]+\/(\d+)/,/^vimeo\.com\/groups\/[^/]+\/videos\/(\d+)/,/^vimeo\.com\/ondemand\/[^/]+\/(\d+)/,/^player\.vimeo\.com\/video\/(\d+)/],html:e=>`
    `},{name:"instagram",url:/^instagram\.com\/p\/(\w+)/},{name:"twitter",url:/^twitter\.com/},{name:"googleMaps",url:[/^google\.com\/maps/,/^goo\.gl\/maps/,/^maps\.google\.com/,/^maps\.app\.goo\.gl/]},{name:"flickr",url:/^flickr\.com/},{name:"facebook",url:/^facebook\.com/}]}),this.registry=new Ck(e.locale,e.config.get("mediaEmbed"))}init(){const e=this.editor,t=e.model.schema,i=e.t,n=e.conversion,s=e.config.get("mediaEmbed.previewsInData"),o=e.config.get("mediaEmbed.elementName"),r=this.registry;e.commands.add("mediaEmbed",new kk(e)),t.register("media",{inheritAllFrom:"$blockObject",allowAttributes:["url"]}),n.for("dataDowncast").elementToStructure({model:"media",view:(e,{writer:t})=>{const i=e.getAttribute("url");return vk(t,r,i,{elementName:o,renderMediaPreview:!!i&&s})}}),n.for("dataDowncast").add(bk(r,{elementName:o,renderMediaPreview:s})),n.for("editingDowncast").elementToStructure({model:"media",view:(e,{writer:t})=>{const n=e.getAttribute("url");return function(e,t,i){return t.setCustomProperty("media",!0,e),of(e,t,{label:i})}(vk(t,r,n,{elementName:o,renderForEditingView:!0}),t,i("media widget"))}}),n.for("editingDowncast").add(bk(r,{elementName:o,renderForEditingView:!0})),n.for("upcast").elementToElement({view:e=>["oembed",o].includes(e.name)&&e.getAttribute("url")?{name:!0}:null,model:(e,{writer:t})=>{const i=e.getAttribute("url");return r.hasMedia(i)?t.createElement("media",{url:i}):null}}).elementToElement({view:{name:"div",attributes:{"data-oembed-url":!0}},model:(e,{writer:t})=>{const i=e.getAttribute("data-oembed-url");return r.hasMedia(i)?t.createElement("media",{url:i}):null}}).add((e=>{e.on("element:figure",((e,t,i)=>{if(!i.consumable.consume(t.viewItem,{name:!0,classes:"media"}))return;const{modelRange:n,modelCursor:s}=i.convertChildren(t.viewItem,t.modelCursor);t.modelRange=n,t.modelCursor=s,On(n.getItems())||i.consumable.revert(t.viewItem,{name:!0,classes:"media"})}))}))}}const Tk=/^(?:http(s)?:\/\/)?[\w-]+\.[\w-.~:/?#[\]@!$&'()*+,;=%]+$/;class Ek extends io{static get requires(){return[Wf,bg,Xf]}static get pluginName(){return"AutoMediaEmbed"}constructor(e){super(e),this._timeoutId=null,this._positionToInsert=null}init(){const e=this.editor,t=e.model.document,i=e.plugins.get("ClipboardPipeline");this.listenTo(i,"inputTransformation",(()=>{const e=t.selection.getFirstRange(),i=ud.fromPosition(e.start);i.stickiness="toPrevious";const n=ud.fromPosition(e.end);n.stickiness="toNext",t.once("change:data",(()=>{this._embedMediaBetweenPositions(i,n),i.detach(),n.detach()}),{priority:"high"})})),e.commands.get("undo").on("execute",(()=>{this._timeoutId&&($i.window.clearTimeout(this._timeoutId),this._positionToInsert.detach(),this._timeoutId=null,this._positionToInsert=null)}),{priority:"high"})}_embedMediaBetweenPositions(e,t){const i=this.editor,n=i.plugins.get(xk).registry,s=new Sl(e,t),o=s.getWalker({ignoreElementEnd:!0});let r="";for(const e of o)e.item.is("$textProxy")&&(r+=e.item.data);r=r.trim(),r.match(Tk)&&n.hasMedia(r)&&i.commands.get("mediaEmbed").isEnabled?(this._positionToInsert=ud.fromPosition(e),this._timeoutId=$i.window.setTimeout((()=>{i.model.change((e=>{this._timeoutId=null,e.remove(s),s.detach();let t=null;"$graveyard"!==this._positionToInsert.root.rootName&&(t=this._positionToInsert),yk(i.model,r,t,!1),this._positionToInsert.detach(),this._positionToInsert=null})),i.plugins.get(bg).requestUndoOnBackspace()}),100)):s.detach()}}class Sk extends Un{constructor(e,t){super(t);const i=t.t;this.focusTracker=new Bn,this.keystrokes=new Mn,this.set("mediaURLInputValue",""),this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("Save"),Kh.check,"ck-button-save"),this.saveButtonView.type="submit",this.saveButtonView.bind("isEnabled").to(this,"mediaURLInputValue",(e=>!!e)),this.cancelButtonView=this._createButton(i("Cancel"),Kh.cancel,"ck-button-cancel","cancel"),this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this._validators=e,this.setTemplate({tag:"form",attributes:{class:["ck","ck-media-form","ck-responsive-form"],tabindex:"-1"},children:[this.urlInputView,this.saveButtonView,this.cancelButtonView]})}render(){super.render(),s({view:this}),[this.urlInputView,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element);const e=e=>e.stopPropagation();this.keystrokes.set("arrowright",e),this.keystrokes.set("arrowleft",e),this.keystrokes.set("arrowup",e),this.keystrokes.set("arrowdown",e)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}get url(){return this.urlInputView.fieldView.element.value.trim()}set url(e){this.urlInputView.fieldView.element.value=e.trim()}isValid(){this.resetFormStatus();for(const e of this._validators){const t=e(this);if(t)return this.urlInputView.errorText=t,!1}return!0}resetFormStatus(){this.urlInputView.errorText=null,this.urlInputView.infoText=this._urlInputViewInfoDefault}_createUrlInput(){const e=this.locale.t,t=new $s(this.locale,mu),i=t.fieldView;return this._urlInputViewInfoDefault=e("Paste the media URL in the input."),this._urlInputViewInfoTip=e("Tip: Paste the URL into the content to embed faster."),t.label=e("Media URL"),t.infoText=this._urlInputViewInfoDefault,i.on("input",(()=>{t.infoText=i.element.value?this._urlInputViewInfoTip:this._urlInputViewInfoDefault,this.mediaURLInputValue=i.element.value.trim()})),t}_createButton(e,t,i,n){const s=new fs(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),n&&s.delegate("execute").to(this,n),s}}class Pk extends io{static get requires(){return[xk]}static get pluginName(){return"MediaEmbedUI"}init(){const e=this.editor,t=e.commands.get("mediaEmbed");e.ui.componentFactory.add("mediaEmbed",(e=>{const i=ru(e);return this._setUpDropdown(i,t),i}))}_setUpDropdown(e,i){const n=this.editor,s=n.t,o=e.buttonView,r=n.plugins.get(xk).registry;e.once("change:isOpen",(()=>{const s=new(t(Sk))(function(e,t){return[t=>{if(!t.url.length)return e("The URL must not be empty.")},i=>{if(!t.hasMedia(i.url))return e("This media URL is not supported.")}]}(n.t,r),n.locale);e.panelView.children.add(s),o.on("open",(()=>{s.disableCssTransitions(),s.url=i.value||"",s.urlInputView.fieldView.select(),s.enableCssTransitions()}),{priority:"low"}),e.on("submit",(()=>{s.isValid()&&(n.execute("mediaEmbed",s.url),n.editing.view.focus())})),e.on("change:isOpen",(()=>s.resetFormStatus())),e.on("cancel",(()=>{n.editing.view.focus()})),s.delegate("submit","cancel").to(e),s.urlInputView.fieldView.bind("value").to(i,"value"),s.urlInputView.bind("isEnabled").to(i,"isEnabled")})),e.bind("isEnabled").to(i),o.set({label:s("Insert media"),icon:'',tooltip:!0})}}class Ik extends so{constructor(e){super(e),this._isEnabledBasedOnSelection=!1}refresh(){const e=this.editor.model,t=e.document;this.isEnabled=e.schema.checkAttributeInSelection(t.selection,"mention")}execute(e){const t=this.editor.model,i=t.document.selection,n="string"==typeof e.mention?{id:e.mention}:e.mention,s=n.id,o=e.range||i.getFirstRange();if(!t.canEditAt(o))return;const r=e.text||s,a=Rk({_text:r,id:s},n);if(1!=e.marker.length)throw new _("mentioncommand-incorrect-marker",this);if(s.charAt(0)!=e.marker)throw new _("mentioncommand-incorrect-id",this);t.change((e=>{const n=Nn(i.getAttributes()),s=new Map(n.entries());s.set("mention",a),t.insertContent(e.createText(r,s),o),t.insertContent(e.createText(" ",n),o.start.getShiftedBy(r.length))}))}}class Vk extends io{static get pluginName(){return"MentionEditing"}init(){const e=this.editor,t=e.model,i=t.document;t.schema.extend("$text",{allowAttributes:"mention"}),e.conversion.for("upcast").elementToAttribute({view:{name:"span",key:"data-mention",classes:"mention"},model:{key:"mention",value:e=>Lk(e)}}),e.conversion.for("downcast").attributeToElement({model:"mention",view:Bk}),e.conversion.for("downcast").add(Ok),i.registerPostFixer((e=>function(e,t,i){const n=t.differ.getChanges();let s=!1;for(const t of n){if("attribute"==t.type)continue;const n=t.position;if("$text"==t.name){const t=n.textNode&&n.textNode.nextSibling;s=Nk(n.textNode,e)||s,s=Nk(t,e)||s,s=Nk(n.nodeBefore,e)||s,s=Nk(n.nodeAfter,e)||s}if("$text"!=t.name&&"insert"==t.type){const t=n.nodeAfter;for(const i of e.createRangeIn(t).getItems())s=Nk(i,e)||s}if("insert"==t.type&&i.isInline(t.name)){const t=n.nodeAfter&&n.nodeAfter.nextSibling;s=Nk(n.nodeBefore,e)||s,s=Nk(t,e)||s}}return s}(e,i,t.schema))),i.registerPostFixer((e=>function(e,t){const i=t.differ.getChanges();let n=!1;for(const t of i)if("attribute"===t.type&&"mention"!=t.attributeKey){const i=t.range.start.nodeBefore,s=t.range.end.nodeAfter;for(const o of[i,s])Mk(o)&&o.getAttribute(t.attributeKey)!=t.attributeNewValue&&(e.setAttribute(t.attributeKey,t.attributeNewValue,o),n=!0)}return n}(e,i))),i.registerPostFixer((e=>function(e,t){const i=t.selection,n=i.focus;return!!(i.isCollapsed&&i.hasAttribute("mention")&&function(e){const t=e.isAtStart;return e.nodeBefore&&e.nodeBefore.is("$text")||t}(n))&&(e.removeSelectionAttribute("mention"),!0)}(e,i))),e.commands.add("mention",new Ik(e))}}function Rk(e,t){return Object.assign({uid:p()},e,t||{})}function Lk(e,t){const i=e.getAttribute("data-mention"),n=e.getChild(0);if(n)return Rk({id:i,_text:n.data},t)}function Ok(e){e.on("attribute:mention",((e,t,i)=>{const n=t.attributeNewValue;if(!t.item.is("$textProxy")||!n)return;const s=t.range.start;(s.textNode||s.nodeAfter).data!=n._text&&i.consumable.consume(t.item,e.name)}),{priority:"highest"})}function Bk(e,{writer:t}){if(!e)return;const i={class:"mention","data-mention":e.id},n={id:e.uid,priority:20};return t.createAttributeElement("span",i,n)}function Mk(e){return!(!e||!e.is("$text")&&!e.is("$textProxy")||!e.hasAttribute("mention"))&&e.data!=e.getAttribute("mention")._text}function Nk(e,t){return!!Mk(e)&&(t.removeAttribute("mention",e),!0)}class Fk extends iu{constructor(e){super(e),this.extendTemplate({attributes:{class:["ck-mentions"],tabindex:"-1"}})}selectFirst(){this.select(0)}selectNext(){const e=this.selected,t=this.items.getIndex(e);this.select(t+1)}selectPrevious(){const e=this.selected,t=this.items.getIndex(e);this.select(t-1)}select(e){let t=0;e>0&&e{i?(this.domElement.classList.add("ck-on"),this.domElement.classList.remove("ck-off")):(this.domElement.classList.add("ck-off"),this.domElement.classList.remove("ck-on"))})),this.listenTo(this.domElement,"click",(()=>{this.fire("execute")}))}render(){super.render(),this.element=this.domElement}focus(){this.domElement.focus()}}class zk extends nu{highlight(){this.children.first.isOn=!0}removeHighlight(){this.children.first.isOn=!1}}const Hk=[Cn.arrowup,Cn.arrowdown,Cn.esc],$k=[Cn.enter,Cn.tab];class Wk extends io{static get pluginName(){return"MentionUI"}static get requires(){return[Cm]}constructor(e){super(e),this._items=new Ln,this._mentionsView=this._createMentionView(),this._mentionsConfigurations=new Map,this._requestFeedDebounced=zs(this._requestFeed,100),e.config.define("mention",{feeds:[]})}init(){const t=this.editor,i=t.config.get("mention.commitKeys")||$k,n=Hk.concat(i);this._balloon=t.plugins.get(Cm),t.editing.view.document.on("keydown",((e,t)=>{var s;s=t.keyCode,n.includes(s)&&this._isUIVisible&&(t.preventDefault(),e.stop(),t.keyCode==Cn.arrowdown&&this._mentionsView.selectNext(),t.keyCode==Cn.arrowup&&this._mentionsView.selectPrevious(),i.includes(t.keyCode)&&this._mentionsView.executeSelected(),t.keyCode==Cn.esc&&this._hideUIAndRemoveMarker())}),{priority:"highest"}),e({emitter:this._mentionsView,activator:()=>this._isUIVisible,contextElements:()=>[this._balloon.view.element],callback:()=>this._hideUIAndRemoveMarker()});const s=t.config.get("mention.feeds");for(const e of s){const{feed:t,marker:i,dropdownLimit:n}=e;if(!Kk(i))throw new _("mentionconfig-incorrect-marker",null,{marker:i});const s={marker:i,feedCallback:"function"==typeof t?t.bind(this.editor):Gk(t),itemRenderer:e.itemRenderer,dropdownLimit:n};this._mentionsConfigurations.set(i,s)}this._setupTextWatcher(s),this.listenTo(t,"change:isReadOnly",(()=>{this._hideUIAndRemoveMarker()})),this.on("requestFeed:response",((e,t)=>this._handleFeedResponse(t))),this.on("requestFeed:error",(()=>this._hideUIAndRemoveMarker()))}destroy(){super.destroy(),this._mentionsView.destroy()}get _isUIVisible(){return this._balloon.visibleView===this._mentionsView}_createMentionView(){const e=this.editor.locale,t=new Fk(e);return t.items.bindTo(this._items).using((i=>{const{item:n,marker:s}=i,{dropdownLimit:o}=this._mentionsConfigurations.get(s),r=o||this.editor.config.get("mention.dropdownLimit")||10;if(t.items.length>=r)return null;const a=new zk(e),l=this._renderItem(n,s);return l.delegate("execute").to(a),a.children.add(l),a.item=n,a.marker=s,a.on("execute",(()=>{t.fire("execute",{item:n,marker:s})})),a})),t.on("execute",((e,t)=>{const i=this.editor,n=i.model,s=t.item,o=t.marker,r=i.model.markers.get("mention"),a=n.createPositionAt(n.document.selection.focus),l=n.createPositionAt(r.getStart()),c=n.createRange(l,a);this._hideUIAndRemoveMarker(),i.execute("mention",{mention:s,text:s.text,marker:o,range:c}),i.editing.view.focus()})),t}_getItemRenderer(e){const{itemRenderer:t}=this._mentionsConfigurations.get(e);return t}_requestFeed(e,t){this._lastRequested=t;const{feedCallback:i}=this._mentionsConfigurations.get(e),n=i(t);n instanceof Promise?n.then((i=>{this._lastRequested==t?this.fire("requestFeed:response",{feed:i,marker:e,feedText:t}):this.fire("requestFeed:discarded",{feed:i,marker:e,feedText:t})})).catch((t=>{this.fire("requestFeed:error",{error:t}),y("mention-feed-callback-error",{marker:e})})):this.fire("requestFeed:response",{feed:n,marker:e,feedText:t})}_setupTextWatcher(e){const t=this.editor,i=e.map((e=>({...e,pattern:qk(e.marker,e.minimumCharacters||0)}))),n=new _g(t.model,function(e){return t=>{const i=jk(e,t);if(!i)return!1;let n=0;0!==i.position&&(n=i.position-1);const s=t.substring(n);return i.pattern.test(s)}}(i));n.on("matched",((e,n)=>{const s=jk(i,n.text),o=t.model.document.selection.focus,r=t.model.createPositionAt(o.parent,s.position);if(function(e){const t=e.textNode&&e.textNode.hasAttribute("mention"),i=e.nodeBefore;return t||i&&i.is("$text")&&i.hasAttribute("mention")}(o)||function(e){const t=e.nodeAfter;return t&&t.is("$text")&&t.hasAttribute("mention")}(r))return void this._hideUIAndRemoveMarker();const a=function(e,t){let i=0;0!==e.position&&(i=e.position-1);const n=qk(e.marker,0);return t.substring(i).match(n)[2]}(s,n.text),l=s.marker.length+a.length,c=o.getShiftedBy(-l),d=o.getShiftedBy(-a.length),h=t.model.createRange(c,d);if(Jk(t)){const e=t.model.markers.get("mention");t.model.change((t=>{t.updateMarker(e,{range:h})}))}else t.model.change((e=>{e.addMarker("mention",{range:h,usingOperation:!1,affectsData:!1})}));this._requestFeedDebounced(s.marker,a)})),n.on("unmatched",(()=>{this._hideUIAndRemoveMarker()}));const s=t.commands.get("mention");return n.bind("isEnabled").to(s),n}_handleFeedResponse(e){const{feed:t,marker:i}=e;if(!Jk(this.editor))return;this._items.clear();for(const e of t){const t="object"!=typeof e?{id:e,text:e}:e;this._items.add({item:t,marker:i})}const n=this.editor.model.markers.get("mention");this._items.length?this._showOrUpdateUI(n):this._hideUIAndRemoveMarker()}_showOrUpdateUI(e){this._isUIVisible?this._balloon.updatePosition(this._getBalloonPanelPositionData(e,this._mentionsView.position)):this._balloon.add({view:this._mentionsView,position:this._getBalloonPanelPositionData(e,this._mentionsView.position),singleViewMode:!0}),this._mentionsView.position=this._balloon.view.position,this._mentionsView.selectFirst()}_hideUIAndRemoveMarker(){this._balloon.hasView(this._mentionsView)&&this._balloon.remove(this._mentionsView),Jk(this.editor)&&this.editor.model.change((e=>e.removeMarker("mention"))),this._mentionsView.position=void 0}_renderItem(e,t){const i=this.editor;let n,s=e.id;const o=this._getItemRenderer(t);if(o){const t=o(e);"string"!=typeof t?n=new Dk(i.locale,t):s=t}if(!n){const e=new fs(i.locale);e.label=s,e.withText=!0,n=e}return n}_getBalloonPanelPositionData(e,t){const i=this.editor,n=i.editing,s=n.view.domConverter,o=n.mapper;return{target:()=>{let t=e.getRange();"$graveyard"==t.start.root.rootName&&(t=i.model.document.selection.getFirstRange());const n=o.toViewRange(t);return Ki.getDomRangeRects(s.viewRangeToDom(n)).pop()},limiter:()=>{const e=this.editor.editing.view,t=e.document.selection.editableElement;return t?e.domConverter.mapViewToDom(t.root):null},positions:Uk(t,i.locale.uiLanguageDirection)}}}function Uk(e,t){const i={caret_se:e=>({top:e.bottom+3,left:e.right,name:"caret_se",config:{withArrow:!1}}),caret_ne:(e,t)=>({top:e.top-t.height-3,left:e.right,name:"caret_ne",config:{withArrow:!1}}),caret_sw:(e,t)=>({top:e.bottom+3,left:e.right-t.width,name:"caret_sw",config:{withArrow:!1}}),caret_nw:(e,t)=>({top:e.top-t.height-3,left:e.right-t.width,name:"caret_nw",config:{withArrow:!1}})};return Object.prototype.hasOwnProperty.call(i,e)?[i[e]]:"rtl"!==t?[i.caret_se,i.caret_sw,i.caret_ne,i.caret_nw]:[i.caret_sw,i.caret_se,i.caret_nw,i.caret_ne]}function jk(e,t){let i;for(const n of e){const e=t.lastIndexOf(n.marker);e>0&&!t.substring(e-1).match(n.pattern)||(!i||e>=i.position)&&(i={marker:n.marker,position:e,minimumCharacters:n.minimumCharacters,pattern:n.pattern})}return i}function qk(e,t){const i=0==t?"*":`{${t},}`,n=l.features.isRegExpUnicodePropertySupported?"\\p{Ps}\\p{Pi}\"'":"\\(\\[{\"'";return new RegExp(`(?:^|[ ${n}])([${e}])(.${i})$`,"u")}function Gk(e){return t=>e.filter((e=>("string"==typeof e?e:String(e.id)).toLowerCase().includes(t.toLowerCase())))}function Kk(e){return e&&1==e.length}function Jk(e){return e.model.markers.has("mention")}function Qk(e){if(e.startsWith("arabic-leading-zero"))return"decimal-leading-zero";switch(e){case"alpha-upper":return"upper-alpha";case"alpha-lower":return"lower-alpha";case"roman-upper":return"upper-roman";case"roman-lower":return"lower-roman";case"circle":case"disc":case"square":return e;default:return null}}function Zk(e,t,i){const n=t.parent,s=i.createElement(e.type),o=n.getChildIndex(t)+1;return i.insertChild(o,s,n),e.style&&i.setStyle("list-style-type",e.style,s),e.startIndex&&e.startIndex>1&&i.setAttribute("start",e.startIndex,s),s}function Yk(e){const t={},i=e.getStyle("mso-list");if(i){const e=i.match(/(^|\s{1,100})l(\d+)/i),n=i.match(/\s{0,100}lfo(\d+)/i),s=i.match(/\s{0,100}level(\d+)/i);e&&n&&s&&(t.id=e[2],t.order=n[1],t.indent=parseInt(s[1]))}return t}const Xk=//i,eC=/xmlns:o="urn:schemas-microsoft-com/i;class tC{constructor(e){this.document=e}isActive(e){return Xk.test(e)||eC.test(e)}execute(e){const{body:t,stylesString:i}=e._parsedData;(function(e,t){if(!e.childCount)return;const i=new Xd(e.document),n=function(e,t){const i=t.createRangeIn(e),n=new ko({name:/^p|h\d+$/,styles:{"mso-list":/.*/}}),s=[];for(const e of i)if("elementStart"===e.type&&n.match(e.item)){const t=Yk(e.item);s.push({element:e.item,id:t.id,order:t.order,indent:t.indent})}return s}(e,i);if(!n.length)return;let s=null,o=1;n.forEach(((e,r)=>{const a=function(e,t){if(!e)return!0;if(e.id!==t.id)return t.indent-e.indent!=1;const i=t.element.previousSibling;return!i||!((n=i).is("element","ol")||n.is("element","ul"));var n}(n[r-1],e),l=(d=e,(c=a?null:n[r-1])?d.indent-c.indent:d.indent-1);var c,d;if(a&&(s=null,o=1),!s||0!==l){const n=function(e,t){const i=/mso-level-number-format:([^;]{0,100});/gi,n=/mso-level-start-at:\s{0,100}([0-9]{0,10})\s{0,100};/gi,s=new RegExp(`@list l${e.id}:level${e.indent}\\s*({[^}]*)`,"gi").exec(t);let o="decimal",r="ol",a=null;if(s&&s[1]){const t=i.exec(s[1]);if(t&&t[1]&&(o=t[1].trim(),r="bullet"!==o&&"image"!==o?"ol":"ul"),"bullet"===o){const t=function(e){const t=function(e){if(e.getChild(0).is("$text"))return null;for(const t of e.getChildren()){if(!t.is("element","span"))continue;const e=t.getChild(0);if(e)return e.is("$text")?e:e.getChild(0)}return null}(e);if(!t)return null;const i=t._data;return"o"===i?"circle":"·"===i?"disc":"§"===i?"square":null}(e.element);t&&(o=t)}else{const e=n.exec(s[1]);e&&e[1]&&(a=parseInt(e[1]))}}return{type:r,startIndex:a,style:Qk(o)}}(e,t);if(s){if(e.indent>o){const e=s.getChild(s.childCount-1),t=e.getChild(e.childCount-1);s=Zk(n,t,i),o+=1}else if(e.indente.indexOf(t)>-1))?o.push(i):i.getAttribute("src")||o.push(i)}for(const e of o)i.remove(e)}(n,e,i),function(e,t,i){const n=i.createRangeIn(t),s=[];for(const t of n)if("elementStart"==t.type&&t.item.is("element","v:shape")){const i=t.item.getAttribute("id");if(e.includes(i))continue;o(t.item.parent.getChildren(),i)||s.push(t.item)}for(const e of s){const t={src:r(e)};e.hasAttribute("alt")&&(t.alt=e.getAttribute("alt"));const n=i.createElement("img",t);i.insertChild(e.index+1,n,e.parent)}function o(e,t){for(const i of e)if(i.is("element")){if("img"==i.name&&i.getAttribute("v:shapes")==t)return!0;if(o(i.getChildren(),t))return!0}return!1}function r(e){for(const t of e.getChildren())if(t.is("element")&&t.getAttribute("src"))return t.getAttribute("src")}}(n,e,i),function(e,t){const i=t.createRangeIn(e),n=new ko({name:/v:(.+)/}),s=[];for(const e of i)"elementStart"==e.type&&n.match(e.item)&&s.push(e.item);for(const e of s)t.remove(e)}(e,i);const s=function(e,t){const i=t.createRangeIn(e),n=new ko({name:"img"}),s=[];for(const e of i)e.item.is("element")&&n.match(e.item)&&e.item.getAttribute("src").startsWith("file://")&&s.push(e.item);return s}(e,i);s.length&&function(e,t,i){if(e.length===t.length)for(let s=0;sString.fromCharCode(parseInt(e,16)))).join(""))}`;i.setAttribute("src",o,e[s])}var n}(s,function(e){if(!e)return[];const t=/{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/,i=new RegExp("(?:("+t.source+"))([\\da-fA-F\\s]+)\\}","g"),n=e.match(i),s=[];if(n)for(const e of n){let i=!1;e.includes("\\pngblip")?i="image/png":e.includes("\\jpegblip")&&(i="image/jpeg"),i&&s.push({hex:e.replace(t,"").replace(/[^\da-fA-F]/g,""),type:i})}return s}(t),i)}(t,e.dataTransfer.getData("text/rtf")),e.content=t}}function iC(e,t,i,{blockElements:n,inlineObjectElements:s}){let o=i.createPositionAt(e,"forward"==t?"after":"before");return o=o.getLastMatchingPosition((({item:e})=>e.is("element")&&!n.includes(e.name)&&!s.includes(e.name)),{direction:t}),"forward"==t?o.nodeAfter:o.nodeBefore}function nC(e,t){return!!e&&e.is("element")&&t.includes(e.name)}const sC=/id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;class oC{constructor(e){this.document=e}isActive(e){return sC.test(e)}execute(e){const t=new Xd(this.document),{body:i}=e._parsedData;!function(e,t){for(const i of e.getChildren())if(i.is("element","b")&&"normal"===i.getStyle("font-weight")){const n=e.getChildIndex(i);t.remove(i),t.insertChild(n,i.getChildren(),e)}}(i,t),function(e,t){for(const i of t.createRangeIn(e)){const e=i.item;if(e.is("element","li")){const i=e.getChild(0);i&&i.is("element","p")&&t.unwrapElement(i)}}}(i,t),function(e,t){const i=new Sr(t.document.stylesProcessor),n=new fa(i,{renderingMode:"data"}),s=n.blockElements,o=n.inlineObjectElements,r=[];for(const i of t.createRangeIn(e)){const e=i.item;if(e.is("element","br")){const i=iC(e,"forward",t,{blockElements:s,inlineObjectElements:o}),n=iC(e,"backward",t,{blockElements:s,inlineObjectElements:o}),a=nC(i,s);(nC(n,s)||a)&&r.push(e)}}for(const e of r)e.hasClass("Apple-interchange-newline")?t.remove(e):t.replace(e,t.createElement("p"))}(i,t),e.content=i}}const rC=/(\s+)<\/span>/g,((e,t)=>1===t.length?" ":Array(t.length+1).join("  ").substr(0,t.length)))}const cC="removeFormat";class dC extends io{static get pluginName(){return"RemoveFormatUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(cC,(i=>{const n=e.commands.get(cC),s=new fs(i);return s.set({label:t("Remove Format"),icon:'',tooltip:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(cC),e.editing.view.focus()})),s}))}}class hC extends so{refresh(){const e=this.editor.model;this.isEnabled=!!On(this._getFormattingItems(e.document.selection,e.schema))}execute(){const e=this.editor.model,t=e.schema;e.change((i=>{for(const n of this._getFormattingItems(e.document.selection,t))if(n.is("selection"))for(const e of this._getFormattingAttributes(n,t))i.removeSelectionAttribute(e);else{const e=i.createRangeOn(n);for(const s of this._getFormattingAttributes(n,t))i.removeAttribute(s,e)}}))}*_getFormattingItems(e,t){const i=e=>!!On(this._getFormattingAttributes(e,t));for(const n of e.getRanges())for(const e of n.getItems())!t.isBlock(e)&&i(e)&&(yield e);for(const t of e.getSelectedBlocks())i(t)&&(yield t);i(e)&&(yield e)}*_getFormattingAttributes(e,t){for(const[i]of e.getAttributes()){const e=t.getAttributeProperties(i);e&&e.isFormatting&&(yield i)}}}class uC extends io{static get pluginName(){return"RemoveFormatEditing"}init(){const e=this.editor;e.commands.add("removeFormat",new hC(e))}}function mC(e,t,i=" "){return`${i.repeat(Math.max(0,t))}${e}`}const gC="SourceEditingMode";function fC(e){return function(e){return e.startsWith("<")}(e)?function(e){const t=[{name:"address",isVoid:!1},{name:"article",isVoid:!1},{name:"aside",isVoid:!1},{name:"blockquote",isVoid:!1},{name:"details",isVoid:!1},{name:"dialog",isVoid:!1},{name:"dd",isVoid:!1},{name:"div",isVoid:!1},{name:"dl",isVoid:!1},{name:"dt",isVoid:!1},{name:"fieldset",isVoid:!1},{name:"figcaption",isVoid:!1},{name:"figure",isVoid:!1},{name:"footer",isVoid:!1},{name:"form",isVoid:!1},{name:"h1",isVoid:!1},{name:"h2",isVoid:!1},{name:"h3",isVoid:!1},{name:"h4",isVoid:!1},{name:"h5",isVoid:!1},{name:"h6",isVoid:!1},{name:"header",isVoid:!1},{name:"hgroup",isVoid:!1},{name:"hr",isVoid:!0},{name:"li",isVoid:!1},{name:"main",isVoid:!1},{name:"nav",isVoid:!1},{name:"ol",isVoid:!1},{name:"p",isVoid:!1},{name:"section",isVoid:!1},{name:"table",isVoid:!1},{name:"tbody",isVoid:!1},{name:"td",isVoid:!1},{name:"th",isVoid:!1},{name:"thead",isVoid:!1},{name:"tr",isVoid:!1},{name:"ul",isVoid:!1}],i=t.map((e=>e.name)).join("|"),n=e.replace(new RegExp(``,"g"),"\n$&\n").replace(/]*>/g,"$&\n").split("\n");let s=0;return n.filter((e=>e.length)).map((e=>function(e,t){return t.some((t=>!t.isVoid&&!!new RegExp(`<${t.name}( .*?)?>`).test(e)))}(e,t)?mC(e,s++):function(e,t){return t.some((t=>new RegExp(``).test(e)))}(e,t)?mC(e,--s):mC(e,s))).join("\n")}(e):e}class pC extends wm{constructor(e,t){super(e);const i=e.t;this.set("class","ck-special-characters-navigation"),this.groupDropdownView=this._createGroupDropdown(t),this.groupDropdownView.panelPosition="rtl"===e.uiLanguageDirection?"se":"sw",this.label=i("Special characters"),this.children.add(this.groupDropdownView)}get currentGroupName(){return this.groupDropdownView.value}focus(){this.groupDropdownView.focus()}_createGroupDropdown(e){const t=this.locale,i=t.t,n=ru(t),s=this._getCharacterGroupListItemDefinitions(n,e),o=i("Character categories");return n.set("value",s.first.model.name),n.buttonView.bind("label").to(n,"value",(t=>e.get(t))),n.buttonView.set({isOn:!1,withText:!0,tooltip:o,class:["ck-dropdown__button_label-width_auto"],ariaLabel:o,ariaLabelledBy:void 0}),n.on("execute",(e=>{n.value=e.source.name})),n.delegate("execute").to(this),cu(n,s,{ariaLabel:o,role:"menu"}),n}_getCharacterGroupListItemDefinitions(e,t){const i=new Ln;for(const[n,s]of t){const t=new _m({name:n,label:s,withText:!0,role:"menuitemradio"});t.bind("isOn").to(e,"value",(e=>e===t.name)),i.add({type:"button",model:t})}return i}}class bC extends Un{constructor(e){super(e),this.tiles=this.createCollection(),this.setTemplate({tag:"div",children:[{tag:"div",attributes:{class:["ck","ck-character-grid__tiles"]},children:this.tiles}],attributes:{class:["ck","ck-character-grid"]}}),this.focusTracker=new Bn,this.keystrokes=new Mn,o({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.tiles,numberOfColumns:()=>$i.window.getComputedStyle(this.element.firstChild).getPropertyValue("grid-template-columns").split(" ").length,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection})}createTile(e,t){const i=new fs(this.locale);return i.set({label:e,withText:!0,class:"ck-character-grid__tile"}),i.extendTemplate({attributes:{title:t},on:{mouseover:i.bindTemplate.to("mouseover"),focus:i.bindTemplate.to("focus")}}),i.on("mouseover",(()=>{this.fire("tileHover",{name:t,character:e})})),i.on("focus",(()=>{this.fire("tileFocus",{name:t,character:e})})),i.on("execute",(()=>{this.fire("execute",{name:t,character:e})})),i}render(){super.render();for(const e of this.tiles)this.focusTracker.add(e.element);this.tiles.on("change",((e,{added:t,removed:i})=>{if(t.length>0)for(const e of t)this.focusTracker.add(e.element);if(i.length>0)for(const e of i)this.focusTracker.remove(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.keystrokes.destroy()}focus(){this.tiles.first.focus()}}class wC extends Un{constructor(e){super(e);const t=this.bindTemplate;this.set("character",null),this.set("name",null),this.bind("code").to(this,"character",vC),this.setTemplate({tag:"div",children:[{tag:"span",attributes:{class:["ck-character-info__name"]},children:[{text:t.to("name",(e=>e||"​"))}]},{tag:"span",attributes:{class:["ck-character-info__code"]},children:[{text:t.to("code")}]}],attributes:{class:["ck","ck-character-info"]}})}}function vC(e){return null===e?"":"U+"+("0000"+e.codePointAt(0).toString(16)).slice(-4)}class _C extends Un{constructor(e,t,i,n){super(e),this.navigationView=t,this.gridView=i,this.infoView=n,this.items=this.createCollection(),this.focusTracker=new Bn,this.keystrokes=new Mn,this._focusCycler=new Zs({focusables:this.items,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"div",children:[this.navigationView,this.gridView,this.infoView],attributes:{tabindex:"-1"}}),this.items.add(this.navigationView.groupDropdownView.buttonView),this.items.add(this.gridView)}render(){super.render(),this.focusTracker.add(this.navigationView.groupDropdownView.buttonView.element),this.focusTracker.add(this.gridView.element),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.navigationView.focus()}}const yC="All";class kC extends io{static get pluginName(){return"SpecialCharactersArrows"}init(){const e=this.editor,t=e.t;e.plugins.get("SpecialCharacters").addItems("Arrows",[{title:t("leftwards simple arrow"),character:"←"},{title:t("rightwards simple arrow"),character:"→"},{title:t("upwards simple arrow"),character:"↑"},{title:t("downwards simple arrow"),character:"↓"},{title:t("leftwards double arrow"),character:"⇐"},{title:t("rightwards double arrow"),character:"⇒"},{title:t("upwards double arrow"),character:"⇑"},{title:t("downwards double arrow"),character:"⇓"},{title:t("leftwards dashed arrow"),character:"⇠"},{title:t("rightwards dashed arrow"),character:"⇢"},{title:t("upwards dashed arrow"),character:"⇡"},{title:t("downwards dashed arrow"),character:"⇣"},{title:t("leftwards arrow to bar"),character:"⇤"},{title:t("rightwards arrow to bar"),character:"⇥"},{title:t("upwards arrow to bar"),character:"⤒"},{title:t("downwards arrow to bar"),character:"⤓"},{title:t("up down arrow with base"),character:"↨"},{title:t("back with leftwards arrow above"),character:"🔙"},{title:t("end with leftwards arrow above"),character:"🔚"},{title:t("on with exclamation mark with left right arrow above"),character:"🔛"},{title:t("soon with rightwards arrow above"),character:"🔜"},{title:t("top with upwards arrow above"),character:"🔝"}],{label:t("Arrows")})}}class CC extends io{static get pluginName(){return"SpecialCharactersCurrency"}init(){const e=this.editor,t=e.t;e.plugins.get("SpecialCharacters").addItems("Currency",[{character:"$",title:t("Dollar sign")},{character:"€",title:t("Euro sign")},{character:"¥",title:t("Yen sign")},{character:"£",title:t("Pound sign")},{character:"¢",title:t("Cent sign")},{character:"₠",title:t("Euro-currency sign")},{character:"₡",title:t("Colon sign")},{character:"₢",title:t("Cruzeiro sign")},{character:"₣",title:t("French franc sign")},{character:"₤",title:t("Lira sign")},{character:"¤",title:t("Currency sign")},{character:"₿",title:t("Bitcoin sign")},{character:"₥",title:t("Mill sign")},{character:"₦",title:t("Naira sign")},{character:"₧",title:t("Peseta sign")},{character:"₨",title:t("Rupee sign")},{character:"₩",title:t("Won sign")},{character:"₪",title:t("New sheqel sign")},{character:"₫",title:t("Dong sign")},{character:"₭",title:t("Kip sign")},{character:"₮",title:t("Tugrik sign")},{character:"₯",title:t("Drachma sign")},{character:"₰",title:t("German penny sign")},{character:"₱",title:t("Peso sign")},{character:"₲",title:t("Guarani sign")},{character:"₳",title:t("Austral sign")},{character:"₴",title:t("Hryvnia sign")},{character:"₵",title:t("Cedi sign")},{character:"₶",title:t("Livre tournois sign")},{character:"₷",title:t("Spesmilo sign")},{character:"₸",title:t("Tenge sign")},{character:"₹",title:t("Indian rupee sign")},{character:"₺",title:t("Turkish lira sign")},{character:"₻",title:t("Nordic mark sign")},{character:"₼",title:t("Manat sign")},{character:"₽",title:t("Ruble sign")}],{label:t("Currency")})}}class AC extends io{static get pluginName(){return"SpecialCharactersMathematical"}init(){const e=this.editor,t=e.t;e.plugins.get("SpecialCharacters").addItems("Mathematical",[{character:"<",title:t("Less-than sign")},{character:">",title:t("Greater-than sign")},{character:"≤",title:t("Less-than or equal to")},{character:"≥",title:t("Greater-than or equal to")},{character:"–",title:t("En dash")},{character:"—",title:t("Em dash")},{character:"¯",title:t("Macron")},{character:"‾",title:t("Overline")},{character:"°",title:t("Degree sign")},{character:"−",title:t("Minus sign")},{character:"±",title:t("Plus-minus sign")},{character:"÷",title:t("Division sign")},{character:"⁄",title:t("Fraction slash")},{character:"×",title:t("Multiplication sign")},{character:"ƒ",title:t("Latin small letter f with hook")},{character:"∫",title:t("Integral")},{character:"∑",title:t("N-ary summation")},{character:"∞",title:t("Infinity")},{character:"√",title:t("Square root")},{character:"∼",title:t("Tilde operator")},{character:"≅",title:t("Approximately equal to")},{character:"≈",title:t("Almost equal to")},{character:"≠",title:t("Not equal to")},{character:"≡",title:t("Identical to")},{character:"∈",title:t("Element of")},{character:"∉",title:t("Not an element of")},{character:"∋",title:t("Contains as member")},{character:"∏",title:t("N-ary product")},{character:"∧",title:t("Logical and")},{character:"∨",title:t("Logical or")},{character:"¬",title:t("Not sign")},{character:"∩",title:t("Intersection")},{character:"∪",title:t("Union")},{character:"∂",title:t("Partial differential")},{character:"∀",title:t("For all")},{character:"∃",title:t("There exists")},{character:"∅",title:t("Empty set")},{character:"∇",title:t("Nabla")},{character:"∗",title:t("Asterisk operator")},{character:"∝",title:t("Proportional to")},{character:"∠",title:t("Angle")},{character:"¼",title:t("Vulgar fraction one quarter")},{character:"½",title:t("Vulgar fraction one half")},{character:"¾",title:t("Vulgar fraction three quarters")}],{label:t("Mathematical")})}}class xC extends io{static get pluginName(){return"SpecialCharactersLatin"}init(){const e=this.editor,t=e.t;e.plugins.get("SpecialCharacters").addItems("Latin",[{character:"Ā",title:t("Latin capital letter a with macron")},{character:"ā",title:t("Latin small letter a with macron")},{character:"Ă",title:t("Latin capital letter a with breve")},{character:"ă",title:t("Latin small letter a with breve")},{character:"Ą",title:t("Latin capital letter a with ogonek")},{character:"ą",title:t("Latin small letter a with ogonek")},{character:"Ć",title:t("Latin capital letter c with acute")},{character:"ć",title:t("Latin small letter c with acute")},{character:"Ĉ",title:t("Latin capital letter c with circumflex")},{character:"ĉ",title:t("Latin small letter c with circumflex")},{character:"Ċ",title:t("Latin capital letter c with dot above")},{character:"ċ",title:t("Latin small letter c with dot above")},{character:"Č",title:t("Latin capital letter c with caron")},{character:"č",title:t("Latin small letter c with caron")},{character:"Ď",title:t("Latin capital letter d with caron")},{character:"ď",title:t("Latin small letter d with caron")},{character:"Đ",title:t("Latin capital letter d with stroke")},{character:"đ",title:t("Latin small letter d with stroke")},{character:"Ē",title:t("Latin capital letter e with macron")},{character:"ē",title:t("Latin small letter e with macron")},{character:"Ĕ",title:t("Latin capital letter e with breve")},{character:"ĕ",title:t("Latin small letter e with breve")},{character:"Ė",title:t("Latin capital letter e with dot above")},{character:"ė",title:t("Latin small letter e with dot above")},{character:"Ę",title:t("Latin capital letter e with ogonek")},{character:"ę",title:t("Latin small letter e with ogonek")},{character:"Ě",title:t("Latin capital letter e with caron")},{character:"ě",title:t("Latin small letter e with caron")},{character:"Ĝ",title:t("Latin capital letter g with circumflex")},{character:"ĝ",title:t("Latin small letter g with circumflex")},{character:"Ğ",title:t("Latin capital letter g with breve")},{character:"ğ",title:t("Latin small letter g with breve")},{character:"Ġ",title:t("Latin capital letter g with dot above")},{character:"ġ",title:t("Latin small letter g with dot above")},{character:"Ģ",title:t("Latin capital letter g with cedilla")},{character:"ģ",title:t("Latin small letter g with cedilla")},{character:"Ĥ",title:t("Latin capital letter h with circumflex")},{character:"ĥ",title:t("Latin small letter h with circumflex")},{character:"Ħ",title:t("Latin capital letter h with stroke")},{character:"ħ",title:t("Latin small letter h with stroke")},{character:"Ĩ",title:t("Latin capital letter i with tilde")},{character:"ĩ",title:t("Latin small letter i with tilde")},{character:"Ī",title:t("Latin capital letter i with macron")},{character:"ī",title:t("Latin small letter i with macron")},{character:"Ĭ",title:t("Latin capital letter i with breve")},{character:"ĭ",title:t("Latin small letter i with breve")},{character:"Į",title:t("Latin capital letter i with ogonek")},{character:"į",title:t("Latin small letter i with ogonek")},{character:"İ",title:t("Latin capital letter i with dot above")},{character:"ı",title:t("Latin small letter dotless i")},{character:"IJ",title:t("Latin capital ligature ij")},{character:"ij",title:t("Latin small ligature ij")},{character:"Ĵ",title:t("Latin capital letter j with circumflex")},{character:"ĵ",title:t("Latin small letter j with circumflex")},{character:"Ķ",title:t("Latin capital letter k with cedilla")},{character:"ķ",title:t("Latin small letter k with cedilla")},{character:"ĸ",title:t("Latin small letter kra")},{character:"Ĺ",title:t("Latin capital letter l with acute")},{character:"ĺ",title:t("Latin small letter l with acute")},{character:"Ļ",title:t("Latin capital letter l with cedilla")},{character:"ļ",title:t("Latin small letter l with cedilla")},{character:"Ľ",title:t("Latin capital letter l with caron")},{character:"ľ",title:t("Latin small letter l with caron")},{character:"Ŀ",title:t("Latin capital letter l with middle dot")},{character:"ŀ",title:t("Latin small letter l with middle dot")},{character:"Ł",title:t("Latin capital letter l with stroke")},{character:"ł",title:t("Latin small letter l with stroke")},{character:"Ń",title:t("Latin capital letter n with acute")},{character:"ń",title:t("Latin small letter n with acute")},{character:"Ņ",title:t("Latin capital letter n with cedilla")},{character:"ņ",title:t("Latin small letter n with cedilla")},{character:"Ň",title:t("Latin capital letter n with caron")},{character:"ň",title:t("Latin small letter n with caron")},{character:"ʼn",title:t("Latin small letter n preceded by apostrophe")},{character:"Ŋ",title:t("Latin capital letter eng")},{character:"ŋ",title:t("Latin small letter eng")},{character:"Ō",title:t("Latin capital letter o with macron")},{character:"ō",title:t("Latin small letter o with macron")},{character:"Ŏ",title:t("Latin capital letter o with breve")},{character:"ŏ",title:t("Latin small letter o with breve")},{character:"Ő",title:t("Latin capital letter o with double acute")},{character:"ő",title:t("Latin small letter o with double acute")},{character:"Œ",title:t("Latin capital ligature oe")},{character:"œ",title:t("Latin small ligature oe")},{character:"Ŕ",title:t("Latin capital letter r with acute")},{character:"ŕ",title:t("Latin small letter r with acute")},{character:"Ŗ",title:t("Latin capital letter r with cedilla")},{character:"ŗ",title:t("Latin small letter r with cedilla")},{character:"Ř",title:t("Latin capital letter r with caron")},{character:"ř",title:t("Latin small letter r with caron")},{character:"Ś",title:t("Latin capital letter s with acute")},{character:"ś",title:t("Latin small letter s with acute")},{character:"Ŝ",title:t("Latin capital letter s with circumflex")},{character:"ŝ",title:t("Latin small letter s with circumflex")},{character:"Ş",title:t("Latin capital letter s with cedilla")},{character:"ş",title:t("Latin small letter s with cedilla")},{character:"Š",title:t("Latin capital letter s with caron")},{character:"š",title:t("Latin small letter s with caron")},{character:"Ţ",title:t("Latin capital letter t with cedilla")},{character:"ţ",title:t("Latin small letter t with cedilla")},{character:"Ť",title:t("Latin capital letter t with caron")},{character:"ť",title:t("Latin small letter t with caron")},{character:"Ŧ",title:t("Latin capital letter t with stroke")},{character:"ŧ",title:t("Latin small letter t with stroke")},{character:"Ũ",title:t("Latin capital letter u with tilde")},{character:"ũ",title:t("Latin small letter u with tilde")},{character:"Ū",title:t("Latin capital letter u with macron")},{character:"ū",title:t("Latin small letter u with macron")},{character:"Ŭ",title:t("Latin capital letter u with breve")},{character:"ŭ",title:t("Latin small letter u with breve")},{character:"Ů",title:t("Latin capital letter u with ring above")},{character:"ů",title:t("Latin small letter u with ring above")},{character:"Ű",title:t("Latin capital letter u with double acute")},{character:"ű",title:t("Latin small letter u with double acute")},{character:"Ų",title:t("Latin capital letter u with ogonek")},{character:"ų",title:t("Latin small letter u with ogonek")},{character:"Ŵ",title:t("Latin capital letter w with circumflex")},{character:"ŵ",title:t("Latin small letter w with circumflex")},{character:"Ŷ",title:t("Latin capital letter y with circumflex")},{character:"ŷ",title:t("Latin small letter y with circumflex")},{character:"Ÿ",title:t("Latin capital letter y with diaeresis")},{character:"Ź",title:t("Latin capital letter z with acute")},{character:"ź",title:t("Latin small letter z with acute")},{character:"Ż",title:t("Latin capital letter z with dot above")},{character:"ż",title:t("Latin small letter z with dot above")},{character:"Ž",title:t("Latin capital letter z with caron")},{character:"ž",title:t("Latin small letter z with caron")},{character:"ſ",title:t("Latin small letter long s")}],{label:t("Latin")})}}class TC extends io{static get pluginName(){return"SpecialCharactersText"}init(){const e=this.editor,t=e.t;e.plugins.get("SpecialCharacters").addItems("Text",[{character:"‹",title:t("Single left-pointing angle quotation mark")},{character:"›",title:t("Single right-pointing angle quotation mark")},{character:"«",title:t("Left-pointing double angle quotation mark")},{character:"»",title:t("Right-pointing double angle quotation mark")},{character:"‘",title:t("Left single quotation mark")},{character:"’",title:t("Right single quotation mark")},{character:"“",title:t("Left double quotation mark")},{character:"”",title:t("Right double quotation mark")},{character:"‚",title:t("Single low-9 quotation mark")},{character:"„",title:t("Double low-9 quotation mark")},{character:"¡",title:t("Inverted exclamation mark")},{character:"¿",title:t("Inverted question mark")},{character:"‥",title:t("Two dot leader")},{character:"…",title:t("Horizontal ellipsis")},{character:"‡",title:t("Double dagger")},{character:"‰",title:t("Per mille sign")},{character:"‱",title:t("Per ten thousand sign")},{character:"‼",title:t("Double exclamation mark")},{character:"⁈",title:t("Question exclamation mark")},{character:"⁉",title:t("Exclamation question mark")},{character:"⁇",title:t("Double question mark")},{character:"©",title:t("Copyright sign")},{character:"®",title:t("Registered sign")},{character:"™",title:t("Trade mark sign")},{character:"§",title:t("Section sign")},{character:"¶",title:t("Paragraph sign")},{character:"⁋",title:t("Reversed paragraph sign")}],{label:t("Text")})}}const EC="strikethrough";class SC extends io{static get pluginName(){return"StrikethroughEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:EC}),e.model.schema.setAttributeProperties(EC,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:EC,view:"s",upcastAlso:["del","strike",{styles:{"text-decoration":"line-through"}}]}),e.commands.add(EC,new jp(e,EC)),e.keystrokes.set("CTRL+SHIFT+X","strikethrough")}}const PC="strikethrough";class IC extends io{static get pluginName(){return"StrikethroughUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(PC,(i=>{const n=e.commands.get(PC),s=new fs(i);return s.set({label:t("Strikethrough"),icon:'',keystroke:"CTRL+SHIFT+X",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(PC),e.editing.view.focus()})),s}))}}class VC extends fs{constructor(e,t){super(e),this.styleDefinition=t,this.previewView=this._createPreview(),this.set({label:t.name,class:"ck-style-grid__button",withText:!0}),this.extendTemplate({attributes:{role:"option"}}),this.children.add(this.previewView,0)}_createPreview(){const e=new Un(this.locale);return e.setTemplate({tag:"div",attributes:{class:["ck","ck-reset_all-excluded","ck-style-grid__button__preview","ck-content"],"aria-hidden":"true"},children:[this.styleDefinition.previewTemplate]}),e}}class RC extends Un{constructor(e,t){super(e),this.focusTracker=new Bn,this.keystrokes=new Mn,this.set("activeStyles",[]),this.set("enabledStyles",[]),this.children=this.createCollection(),this.children.delegate("execute").to(this);for(const i of t){const t=new VC(e,i);this.children.add(t)}this.on("change:activeStyles",(()=>{for(const e of this.children)e.isOn=this.activeStyles.includes(e.styleDefinition.name)})),this.on("change:enabledStyles",(()=>{for(const e of this.children)e.isEnabled=this.enabledStyles.includes(e.styleDefinition.name)})),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-grid"],role:"listbox"},children:this.children})}render(){super.render();for(const e of this.children)this.focusTracker.add(e.element);o({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.children,numberOfColumns:3,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection}),this.keystrokes.listenTo(this.element)}focus(){this.children.first.focus()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}}class LC extends Un{constructor(e,t,i){super(e),this.labelView=new Hs(e),this.labelView.text=t,this.gridView=new RC(e,i),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel__style-group"],role:"group","aria-labelledby":this.labelView.id},children:[this.labelView,this.gridView]})}}class OC extends Un{constructor(e,t){super(e);const i=e.t;this.focusTracker=new Bn,this.keystrokes=new Mn,this.children=this.createCollection(),this.blockStylesGroupView=new LC(e,i("Block styles"),t.block),this.inlineStylesGroupView=new LC(e,i("Text styles"),t.inline),this.set("activeStyles",[]),this.set("enabledStyles",[]),this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:["shift + tab"],focusNext:["tab"]}}),t.block.length&&this.children.add(this.blockStylesGroupView),t.inline.length&&this.children.add(this.inlineStylesGroupView),this.blockStylesGroupView.gridView.delegate("execute").to(this),this.inlineStylesGroupView.gridView.delegate("execute").to(this),this.blockStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this,"activeStyles","enabledStyles"),this.inlineStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this,"activeStyles","enabledStyles"),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel"]},children:this.children})}render(){super.render(),this._focusables.add(this.blockStylesGroupView.gridView),this._focusables.add(this.inlineStylesGroupView.gridView),this.focusTracker.add(this.blockStylesGroupView.gridView.element),this.focusTracker.add(this.inlineStylesGroupView.gridView.element),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}}const BC=["caption","colgroup","dd","dt","figcaption","legend","li","optgroup","option","rp","rt","summary","tbody","td","tfoot","th","thead","tr"];class MC extends io{static get pluginName(){return"StyleUtils"}constructor(e){super(e),this.decorate("isStyleEnabledForBlock"),this.decorate("isStyleActiveForBlock"),this.decorate("getAffectedBlocks"),this.decorate("isStyleEnabledForInlineSelection"),this.decorate("isStyleActiveForInlineSelection"),this.decorate("getAffectedInlineSelectable"),this.decorate("getStylePreview"),this.decorate("configureGHSDataFilter")}init(){this._htmlSupport=this.editor.plugins.get("GeneralHtmlSupport")}normalizeConfig(e,t=[]){const i={block:[],inline:[]};for(const n of t){const t=[],s=[];for(const i of e.getDefinitionsForView(n.element)){const e="appliesToBlock"in i&&i.appliesToBlock;if(i.isBlock||e){if("string"==typeof e)t.push(e);else if(i.isBlock){const e=i;t.push(i.model),e.paragraphLikeModel&&t.push(e.paragraphLikeModel)}}else s.push(i.model)}const o=this.getStylePreview(n,[{text:"AaBbCcDdEeFfGgHhIiJj"}]);t.length?i.block.push({...n,previewTemplate:o,modelElements:t,isBlock:!0}):i.inline.push({...n,previewTemplate:o,ghsAttributes:s})}return i}isStyleEnabledForBlock(e,t){const i=this.editor.model,n=this._htmlSupport.getGhsAttributeNameForElement(e.element);return!!i.schema.checkAttribute(t,n)&&e.modelElements.includes(t.name)}isStyleActiveForBlock(e,t){const i=this._htmlSupport.getGhsAttributeNameForElement(e.element),n=t.getAttribute(i);return this.hasAllClasses(n,e.classes)}getAffectedBlocks(e,t){return e.modelElements.includes(t.name)?[t]:null}isStyleEnabledForInlineSelection(e,t){const i=this.editor.model;for(const n of e.ghsAttributes)if(i.schema.checkAttributeInSelection(t,n))return!0;return!1}isStyleActiveForInlineSelection(e,t){for(const i of e.ghsAttributes){const n=this._getValueFromFirstAllowedNode(t,i);if(this.hasAllClasses(n,e.classes))return!0}return!1}getAffectedInlineSelectable(e,t){return t}getStylePreview(e,t){const{element:i,classes:n}=e;return{tag:(s=i,BC.includes(s)?"div":i),attributes:{class:n},children:t};var s}hasAllClasses(e,t){return M(e)&&(i=e,Boolean(i.classes)&&Array.isArray(i.classes))&&t.every((t=>e.classes.includes(t)));var i}configureGHSDataFilter({block:e,inline:t}){const i=this.editor.plugins.get("DataFilter");i.loadAllowedConfig(e.map(NC)),i.loadAllowedConfig(t.map(NC))}_getValueFromFirstAllowedNode(e,t){const i=this.editor.model.schema;if(e.isCollapsed)return e.getAttribute(t);for(const n of e.getRanges())for(const e of n.getItems())if(i.checkAttribute(e,t))return e.getAttribute(t);return null}}function NC({element:e,classes:t}){return{name:e,classes:t}}class FC extends io{static get pluginName(){return"StyleUI"}static get requires(){return[MC]}init(){const e=this.editor,t=e.plugins.get("DataSchema"),i=e.plugins.get("StyleUtils"),n=e.config.get("style.definitions"),s=i.normalizeConfig(t,n);e.ui.componentFactory.add("style",(t=>{const i=t.t,n=ru(t),o=e.commands.get("style");return n.once("change:isOpen",(()=>{const e=new OC(t,s);n.panelView.children.add(e),e.delegate("execute").to(n),e.bind("activeStyles").to(o,"value"),e.bind("enabledStyles").to(o,"enabledStyles")})),n.bind("isEnabled").to(o),n.buttonView.withText=!0,n.buttonView.bind("label").to(o,"value",(e=>e.length>1?i("Multiple styles"):1===e.length?e[0]:i("Styles"))),n.bind("class").to(o,"value",(e=>{const t=["ck-style-dropdown"];return e.length>1&&t.push("ck-style-dropdown_multiple-active"),t.join(" ")})),n.on("execute",(t=>{e.execute("style",{styleName:t.source.styleDefinition.name}),e.editing.view.focus()})),n}))}}class DC extends so{constructor(e,t){super(e),this.set("value",[]),this.set("enabledStyles",[]),this._styleDefinitions=t,this._styleUtils=this.editor.plugins.get(MC)}refresh(){const e=this.editor.model,t=e.document.selection,i=new Set,n=new Set;for(const e of this._styleDefinitions.inline)this._styleUtils.isStyleEnabledForInlineSelection(e,t)&&n.add(e.name),this._styleUtils.isStyleActiveForInlineSelection(e,t)&&i.add(e.name);const s=On(t.getSelectedBlocks())||t.getFirstPosition().parent;if(s){const t=s.getAncestors({includeSelf:!0,parentFirst:!0});for(const s of t){if(s.is("rootElement"))break;for(const e of this._styleDefinitions.block)this._styleUtils.isStyleEnabledForBlock(e,s)&&(n.add(e.name),this._styleUtils.isStyleActiveForBlock(e,s)&&i.add(e.name));if(e.schema.isObject(s))break}}this.enabledStyles=Array.from(n).sort(),this.isEnabled=this.enabledStyles.length>0,this.value=this.isEnabled?Array.from(i).sort():[]}execute({styleName:e,forceValue:t}){if(!this.enabledStyles.includes(e))return void y("style-command-executed-with-incorrect-style-name");const i=this.editor.model,n=i.document.selection,s=this.editor.plugins.get("GeneralHtmlSupport"),o=[...this._styleDefinitions.inline,...this._styleDefinitions.block],r=o.filter((({name:e})=>this.value.includes(e))),a=o.find((({name:t})=>t==e)),l=void 0===t?!this.value.includes(a.name):t;i.change((()=>{let e;e=function(e){return"isBlock"in e}(a)?this._findAffectedBlocks(function(e){const t=Array.from(e.getSelectedBlocks());return t.length?t:[e.getFirstPosition().parent]}(n),a):[this._styleUtils.getAffectedInlineSelectable(a,n)];for(const t of e)l?s.addModelHtmlClass(a.element,a.classes,t):s.removeModelHtmlClass(a.element,zC(r,a),t)}))}_findAffectedBlocks(e,t){const i=new Set;for(const n of e){const e=n.getAncestors({includeSelf:!0,parentFirst:!0});for(const n of e){if(n.is("rootElement"))break;const e=this._styleUtils.getAffectedBlocks(t,n);if(e){for(const t of e)i.add(t);break}}}return i}}function zC(e,t){return e.reduce(((e,i)=>i.name===t.name?e:e.filter((e=>!i.classes.includes(e)))),t.classes)}class HC extends io{static get pluginName(){return"DocumentListStyleSupport"}static get requires(){return[MC,"GeneralHtmlSupport"]}init(){const e=this.editor;e.plugins.has("DocumentListEditing")&&(this._styleUtils=e.plugins.get(MC),this._documentListUtils=this.editor.plugins.get("DocumentListUtils"),this._htmlSupport=this.editor.plugins.get("GeneralHtmlSupport"),this.listenTo(this._styleUtils,"isStyleEnabledForBlock",((e,[t,i])=>{this._isStyleEnabledForBlock(t,i)&&(e.return=!0,e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"isStyleActiveForBlock",((e,[t,i])=>{this._isStyleActiveForBlock(t,i)&&(e.return=!0,e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"getAffectedBlocks",((e,[t,i])=>{const n=this._getAffectedBlocks(t,i);n&&(e.return=n,e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"getStylePreview",((e,[t,i])=>{const n=this._getStylePreview(t,i);n&&(e.return=n,e.stop())}),{priority:"high"}))}_isStyleEnabledForBlock(e,t){const i=this.editor.model;if(!["ol","ul","li"].includes(e.element))return!1;if(!this._documentListUtils.isListItemBlock(t))return!1;const n=this._htmlSupport.getGhsAttributeNameForElement(e.element);if("ol"==e.element||"ul"==e.element){if(!i.schema.checkAttribute(t,n))return!1;const s="numbered"==t.getAttribute("listType")?"ol":"ul";return e.element==s}return i.schema.checkAttribute(t,n)}_isStyleActiveForBlock(e,t){const i=this._htmlSupport.getGhsAttributeNameForElement(e.element),n=t.getAttribute(i);return this._styleUtils.hasAllClasses(n,e.classes)}_getAffectedBlocks(e,t){return this._isStyleEnabledForBlock(e,t)?"li"==e.element?this._documentListUtils.expandListBlocksToCompleteItems(t,{withNested:!1}):this._documentListUtils.expandListBlocksToCompleteList(t):null}_getStylePreview(e,t){const{element:i,classes:n}=e;return"ol"==i||"ul"==i?{tag:i,attributes:{class:n},children:[{tag:"li",children:t}]}:"li"==i?{tag:"ol",children:[{tag:i,attributes:{class:n},children:t}]}:null}}class $C extends io{static get pluginName(){return"TableStyleSupport"}static get requires(){return[MC]}init(){const e=this.editor;e.plugins.has("TableEditing")&&(this._styleUtils=e.plugins.get(MC),this._tableUtils=this.editor.plugins.get("TableUtils"),this.listenTo(this._styleUtils,"isStyleEnabledForBlock",((e,[t,i])=>{this._isApplicable(t,i)&&(e.return=this._isStyleEnabledForBlock(t,i),e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"getAffectedBlocks",((e,[t,i])=>{this._isApplicable(t,i)&&(e.return=this._getAffectedBlocks(t,i),e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"configureGHSDataFilter",((e,[{block:t}])=>{this.editor.plugins.get("DataFilter").loadAllowedConfig(t.filter((e=>"figcaption"==e.element)).map((e=>({name:"caption",classes:e.classes}))))})))}_isApplicable(e,t){return["td","th"].includes(e.element)?"tableCell"==t.name:!!["thead","tbody"].includes(e.element)&&"table"==t.name}_isStyleEnabledForBlock(e,t){if(["td","th"].includes(e.element)){const i=this._tableUtils.getCellLocation(t),n=t.parent.parent,s=n.getAttribute("headingRows")||0,o=n.getAttribute("headingColumns")||0,r=i.row0:i{"a"==t.element&&(e.return=this._isStyleEnabled(t,i),e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"isStyleActiveForInlineSelection",((e,[t,i])=>{"a"==t.element&&(e.return=this._isStyleActive(t,i),e.stop())}),{priority:"high"}),this.listenTo(this._styleUtils,"getAffectedInlineSelectable",((e,[t,i])=>{if("a"!=t.element)return;const n=this._getAffectedSelectable(t,i);n&&(e.return=n,e.stop())}),{priority:"high"}))}_isStyleEnabled(e,t){const i=this.editor.model;if(t.isCollapsed)return t.hasAttribute("linkHref");for(const e of t.getRanges())for(const t of e.getItems())if((t.is("$textProxy")||i.schema.isInline(t))&&t.hasAttribute("linkHref"))return!0;return!1}_isStyleActive(e,t){const i=this.editor.model,n=this._htmlSupport.getGhsAttributeNameForElement(e.element);if(t.isCollapsed){if(t.hasAttribute("linkHref")){const i=t.getAttribute(n);if(this._styleUtils.hasAllClasses(i,e.classes))return!0}return!1}for(const s of t.getRanges())for(const t of s.getItems())if((t.is("$textProxy")||i.schema.isInline(t))&&t.hasAttribute("linkHref")){const i=t.getAttribute(n);return this._styleUtils.hasAllClasses(i,e.classes)}return!1}_getAffectedSelectable(e,t){const i=this.editor.model;if(t.isCollapsed){const e=t.getAttribute("linkHref");return Ig(t.getFirstPosition(),"linkHref",e,i)}const n=[];for(const e of t.getRanges()){const t=i.createRange(UC(e.start,"linkHref",!0,i),UC(e.end,"linkHref",!1,i));for(const e of t.getItems())(e.is("$textProxy")||i.schema.isInline(e))&&e.hasAttribute("linkHref")&&n.push(this.editor.model.createRangeOn(e))}return function(e){for(let t=1;t{const n=e.commands.get(KC),s=new fs(i);return s.set({label:t("Subscript"),icon:'',tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(KC),e.editing.view.focus()})),s}))}}const QC="superscript";class ZC extends io{static get pluginName(){return"SuperscriptEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:QC}),e.model.schema.setAttributeProperties(QC,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:QC,view:"sup",upcastAlso:[{styles:{"vertical-align":"super"}}]}),e.commands.add(QC,new jp(e,QC))}}const YC="superscript";class XC extends io{static get pluginName(){return"SuperscriptUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(YC,(i=>{const n=e.commands.get(YC),s=new fs(i);return s.set({label:t("Superscript"),icon:'',tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(YC),e.editing.view.focus()})),s}))}}function eA(e,t){const{modelAttribute:i,styleName:n,viewElement:s,defaultValue:o,reduceBoxSides:r=!1,shouldUpcast:a=(()=>!0)}=t;e.for("upcast").attributeToAttribute({view:{name:s,styles:{[n]:/[\s\S]+/}},model:{key:i,value:e=>{if(!a(e))return;const t=e.getNormalizedStyle(n),i=r?sA(t):t;return o!==i?i:void 0}}})}function tA(e,t,i,n){e.for("upcast").add((e=>e.on("element:"+t,((e,t,s)=>{if(!t.modelRange)return;const o=["border-top-width","border-top-color","border-top-style","border-bottom-width","border-bottom-color","border-bottom-style","border-right-width","border-right-color","border-right-style","border-left-width","border-left-color","border-left-style"].filter((e=>t.viewItem.hasStyle(e)));if(!o.length)return;const r={styles:o};if(!s.consumable.test(t.viewItem,r))return;const a=[...t.modelRange.getItems({shallow:!0})].pop();s.consumable.consume(t.viewItem,r);const l={style:t.viewItem.getNormalizedStyle("border-style"),color:t.viewItem.getNormalizedStyle("border-color"),width:t.viewItem.getNormalizedStyle("border-width")},c={style:sA(l.style),color:sA(l.color),width:sA(l.width)};c.style!==n.style&&s.writer.setAttribute(i.style,c.style,a),c.color!==n.color&&s.writer.setAttribute(i.color,c.color,a),c.width!==n.width&&s.writer.setAttribute(i.width,c.width,a)}))))}function iA(e,t){const{modelElement:i,modelAttribute:n,styleName:s}=t;e.for("downcast").attributeToAttribute({model:{name:i,key:n},view:e=>({key:"style",value:{[s]:e}})})}function nA(e,t){const{modelAttribute:i,styleName:n}=t;e.for("downcast").add((e=>e.on(`attribute:${i}:table`,((e,t,i)=>{const{item:s,attributeNewValue:o}=t,{mapper:r,writer:a}=i;if(!i.consumable.consume(t.item,e.name))return;const l=[...r.toViewElement(s).getChildren()].find((e=>e.is("element","table")));o?a.setStyle(n,o,l):a.removeStyle(n,l)}))))}function sA(e){if(!e)return;const t=["top","right","bottom","left"];if(!t.every((t=>e[t])))return e;const i=e.top;return t.every((t=>e[t]===i))?i:e}function oA(e,t,i,n,s=1){null!=t&&null!=s&&t>s?n.setAttribute(e,t,i):n.removeAttribute(e,i)}function rA(e,t,i={}){const n=e.createElement("tableCell",i);return e.insertElement("paragraph",n),e.insert(n,t),n}function aA(e,t){const i=t.parent.parent,n=parseInt(i.getAttribute("headingColumns")||"0"),{column:s}=e.getCellLocation(t);return!!n&&s{t.on(`element:${e}`,((e,t,{writer:i})=>{if(!t.modelRange)return;const n=t.modelRange.start.nodeAfter,s=i.createPositionAt(n,0);if(t.viewItem.isEmpty)return void i.insertElement("paragraph",s);const o=Array.from(n.getChildren());if(o.every((e=>e.is("element","$marker")))){const e=i.createElement("paragraph");i.insert(e,i.createPositionAt(n,0));for(const t of o)i.move(i.createRangeOn(t),i.createPositionAt(e,"end"))}}),{priority:"low"})}}function dA(e){let t=0,i=0;const n=Array.from(e.getChildren()).filter((e=>"th"===e.name||"td"===e.name));for(;i1||s>1)&&this._recordSpans(i,s,n),this._shouldSkipSlot()||(t=this._formatOutValue(i)),this._nextCellAtColumn=this._column+n}return this._column++,this._column==this._nextCellAtColumn&&this._cellIndex++,t||this.next()}skipRow(e){this._skipRows.add(e)}_advanceToNextRow(){return this._row++,this._rowIndex++,this._column=0,this._cellIndex=0,this._nextCellAtColumn=-1,this.next()}_isOverEndRow(){return void 0!==this._endRow&&this._row>this._endRow}_isOverEndColumn(){return void 0!==this._endColumn&&this._column>this._endColumn}_formatOutValue(e,t=this._row,i=this._column){return{done:!1,value:new uA(this,e,t,i)}}_shouldSkipSlot(){const e=this._skipRows.has(this._row),t=this._rowthis._endColumn;return e||t||i||n}_getSpanned(){const e=this._spannedCells.get(this._row);return e&&e.get(this._column)||null}_recordSpans(e,t,i){const n={cell:e,row:this._row,column:this._column};for(let e=this._row;e0&&!this._jumpedToStartRow}_jumpToNonSpannedRowClosestToStartRow(){const e=this._getRowLength(0);for(let t=this._startRow;!this._jumpedToStartRow;t--)e===this._getRowLength(t)&&(this._row=t,this._rowIndex=t,this._jumpedToStartRow=!0)}_getRowLength(e){return[...this._table.getChild(e).getChildren()].reduce(((e,t)=>e+parseInt(t.getAttribute("colspan")||"1")),0)}}class uA{constructor(e,t,i,n){this.cell=t,this.row=e._row,this.column=e._column,this.cellAnchorRow=i,this.cellAnchorColumn=n,this._cellIndex=e._cellIndex,this._rowIndex=e._rowIndex,this._table=e._table}get isAnchor(){return this.row===this.cellAnchorRow&&this.column===this.cellAnchorColumn}get cellWidth(){return parseInt(this.cell.getAttribute("colspan")||"1")}get cellHeight(){return parseInt(this.cell.getAttribute("rowspan")||"1")}get rowIndex(){return this._rowIndex}getPositionBefore(){return this._table.root.document.model.createPositionAt(this._table.getChild(this.row),this._cellIndex)}}function mA(e,t){return(i,{writer:n})=>{const s=i.getAttribute("headingRows")||0,o=n.createContainerElement("table",null,[]),r=n.createContainerElement("figure",{class:"table"},o);s>0&&n.insert(n.createPositionAt(o,"end"),n.createContainerElement("thead",null,n.createSlot((e=>e.is("element","tableRow")&&e.indexe.is("element","tableRow")&&e.index>=s))));for(const{positionOffset:e,filter:i}of t.additionalSlots)n.insert(n.createPositionAt(o,e),n.createSlot(i));return n.insert(n.createPositionAt(o,"after"),n.createSlot((e=>!e.is("element","tableRow")&&!t.additionalSlots.some((({filter:t})=>t(e)))))),t.asWidget?function(e,t){return t.setCustomProperty("table",!0,e),of(e,t,{hasSelectionHandle:!0})}(r,n):r}}function gA(e={}){return(t,{writer:i})=>{const n=t.parent,s=n.parent,o=s.getChildIndex(n),r=new hA(s,{row:o}),a=s.getAttribute("headingRows")||0,l=s.getAttribute("headingColumns")||0;let c=null;for(const n of r)if(n.cell==t){const t=n.row{if(!t.parent.is("element","tableCell"))return null;if(!pA(t))return null;if(e.asWidget)return i.createContainerElement("span",{class:"ck-table-bogus-paragraph"});{const e=i.createContainerElement("p");return i.setCustomProperty("dataPipeline:transparentRendering",!0,e),e}}}function pA(e){return 1==e.parent.childCount&&!!e.getAttributeKeys().next().done}class bA extends so{refresh(){const e=this.editor.model,t=e.document.selection,i=e.schema;this.isEnabled=function(e,t){const i=e.getFirstPosition().parent,n=i===i.root?i:i.parent;return t.checkChild(n,"table")}(t,i)}execute(e={}){const t=this.editor,i=t.model,n=t.plugins.get("TableUtils"),s=t.config.get("table.defaultHeadings.rows"),o=t.config.get("table.defaultHeadings.columns");void 0===e.headingRows&&s&&(e.headingRows=s),void 0===e.headingColumns&&o&&(e.headingColumns=o),i.change((t=>{const s=n.createTable(t,e);i.insertObject(s,null,null,{findOptimalPosition:"auto"}),t.setSelection(t.createPositionAt(s.getNodeByPath([0,0,0]),0))}))}}class wA extends so{constructor(e,t={}){super(e),this.order=t.order||"below"}refresh(){const e=this.editor.model.document.selection,t=!!this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(e).length;this.isEnabled=t}execute(){const e=this.editor,t=e.model.document.selection,i=e.plugins.get("TableUtils"),n="above"===this.order,s=i.getSelectionAffectedTableCells(t),o=i.getRowIndexes(s),r=n?o.first:o.last,a=s[0].findAncestor("table");i.insertRows(a,{at:n?r:r+1,copyStructureFromAbove:!n})}}class vA extends so{constructor(e,t={}){super(e),this.order=t.order||"right"}refresh(){const e=this.editor.model.document.selection,t=!!this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(e).length;this.isEnabled=t}execute(){const e=this.editor,t=e.model.document.selection,i=e.plugins.get("TableUtils"),n="left"===this.order,s=i.getSelectionAffectedTableCells(t),o=i.getColumnIndexes(s),r=n?o.first:o.last,a=s[0].findAncestor("table");i.insertColumns(a,{columns:1,at:n?r:r+1})}}class _A extends so{constructor(e,t={}){super(e),this.direction=t.direction||"horizontally"}refresh(){const e=this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(this.editor.model.document.selection);this.isEnabled=1===e.length}execute(){const e=this.editor.plugins.get("TableUtils"),t=e.getSelectionAffectedTableCells(this.editor.model.document.selection)[0];"horizontally"===this.direction?e.splitCellHorizontally(t,2):e.splitCellVertically(t,2)}}function yA(e,t,i){const{startRow:n,startColumn:s,endRow:o,endColumn:r}=t,a=i.createElement("table"),l=o-n+1;for(let e=0;e0&&oA("headingRows",o-i,e,s,0);const r=parseInt(t.getAttribute("headingColumns")||"0");r>0&&oA("headingColumns",r-n,e,s,0)}(a,e,n,s,i),a}function kA(e,t,i=0){const n=[],s=new hA(e,{startRow:i,endRow:t-1});for(const e of s){const{row:i,cellHeight:s}=e;i1&&(a.rowspan=l);const c=parseInt(e.getAttribute("colspan")||"1");c>1&&(a.colspan=c);const d=o+r,h=[...new hA(s,{startRow:o,endRow:d,includeAllSlots:!0})];let u,m=null;for(const t of h){const{row:n,column:s,cell:o}=t;o===e&&void 0===u&&(u=s),void 0!==u&&u===s&&n===d&&(m=rA(i,t.getPositionBefore(),a))}return oA("rowspan",r,e,i),m}function AA(e,t){const i=[],n=new hA(e);for(const e of n){const{column:n,cellWidth:s}=e;n1&&(o.colspan=r);const a=parseInt(e.getAttribute("rowspan")||"1");a>1&&(o.rowspan=a);const l=rA(n,n.createPositionAfter(e),o);return oA("colspan",s,e,n),l}function TA(e,t,i,n,s,o){const r=parseInt(e.getAttribute("colspan")||"1"),a=parseInt(e.getAttribute("rowspan")||"1");i+r-1>s&&oA("colspan",s-i+1,e,o,1),t+a-1>n&&oA("rowspan",n-t+1,e,o,1)}function EA(e,t){const i=t.getColumns(e),n=new Array(i).fill(0);for(const{column:t}of new hA(e))n[t]++;const s=n.reduce(((e,t,i)=>t?e:[...e,i]),[]);if(s.length>0){const i=s[s.length-1];return t.removeColumns(e,{at:i}),!0}return!1}function SA(e,t){const i=[],n=t.getRows(e);for(let t=0;t0){const n=i[i.length-1];return t.removeRows(e,{at:n}),!0}return!1}function PA(e,t){EA(e,t)||SA(e,t)}function IA(e,t){const i=Array.from(new hA(e,{startColumn:t.firstColumn,endColumn:t.lastColumn,row:t.lastRow}));if(i.every((({cellHeight:e})=>1===e)))return t.lastRow;const n=i[0].cellHeight-1;return t.lastRow+n}function VA(e,t){const i=Array.from(new hA(e,{startRow:t.firstRow,endRow:t.lastRow,column:t.lastColumn}));if(i.every((({cellWidth:e})=>1===e)))return t.lastColumn;const n=i[0].cellWidth-1;return t.lastColumn+n}class RA extends so{constructor(e,t){super(e),this.direction=t.direction,this.isHorizontal="right"==this.direction||"left"==this.direction}refresh(){const e=this._getMergeableCell();this.value=e,this.isEnabled=!!e}execute(){const e=this.editor.model,t=e.document,i=this.editor.plugins.get("TableUtils").getTableCellsContainingSelection(t.selection)[0],n=this.value,s=this.direction;e.change((e=>{const t="right"==s||"down"==s,o=t?i:n,r=t?n:i,a=r.parent;!function(e,t,i){LA(e)||(LA(t)&&i.remove(i.createRangeIn(t)),i.move(i.createRangeIn(e),i.createPositionAt(t,"end"))),i.remove(e)}(r,o,e);const l=this.isHorizontal?"colspan":"rowspan",c=parseInt(i.getAttribute(l)||"1"),d=parseInt(n.getAttribute(l)||"1");e.setAttribute(l,c+d,o),e.setSelection(e.createRangeIn(o));const h=this.editor.plugins.get("TableUtils");PA(a.findAncestor("table"),h)}))}_getMergeableCell(){const e=this.editor.model.document,t=this.editor.plugins.get("TableUtils"),i=t.getTableCellsContainingSelection(e.selection)[0];if(!i)return;const n=this.isHorizontal?function(e,t,i){const n=e.parent.parent,s="right"==t?e.nextSibling:e.previousSibling,o=(n.getAttribute("headingColumns")||0)>0;if(!s)return;const r="right"==t?e:s,a="right"==t?s:e,{column:l}=i.getCellLocation(r),{column:c}=i.getCellLocation(a),d=parseInt(r.getAttribute("colspan")||"1"),h=aA(i,r),u=aA(i,a);return o&&h!=u?void 0:l+d===c?s:void 0}(i,this.direction,t):function(e,t,i){const n=e.parent,s=n.parent,o=s.getChildIndex(n);if("down"==t&&o===i.getRows(s)-1||"up"==t&&0===o)return null;const r=parseInt(e.getAttribute("rowspan")||"1"),a=s.getAttribute("headingRows")||0;if(a&&("down"==t&&o+r===a||"up"==t&&o===a))return null;const l=parseInt(e.getAttribute("rowspan")||"1"),c="down"==t?o+l:o,d=[...new hA(s,{endRow:c})],h=d.find((t=>t.cell===e)).column,u=d.find((({row:e,cellHeight:i,column:n})=>n===h&&("down"==t?e===c:c===e+i)));return u&&u.cell?u.cell:null}(i,this.direction,t);if(!n)return;const s=this.isHorizontal?"rowspan":"colspan",o=parseInt(i.getAttribute(s)||"1");return parseInt(n.getAttribute(s)||"1")===o?n:void 0}}function LA(e){const t=e.getChild(0);return 1==e.childCount&&t.is("element","paragraph")&&t.isEmpty}class OA extends so{refresh(){const e=this.editor.plugins.get("TableUtils"),t=e.getSelectionAffectedTableCells(this.editor.model.document.selection),i=t[0];if(i){const n=i.findAncestor("table"),s=e.getRows(n)-1,o=e.getRowIndexes(t),r=0===o.first&&o.last===s;this.isEnabled=!r}else this.isEnabled=!1}execute(){const e=this.editor.model,t=this.editor.plugins.get("TableUtils"),i=t.getSelectionAffectedTableCells(e.document.selection),n=t.getRowIndexes(i),s=i[0],o=s.findAncestor("table"),r=t.getCellLocation(s).column;e.change((e=>{const i=n.last-n.first+1;t.removeRows(o,{at:n.first,rows:i});const s=function(e,t,i,n){const s=e.getChild(Math.min(t,n-1));let o=s.getChild(0),r=0;for(const e of s.getChildren()){if(r>i)return o;o=e,r+=parseInt(e.getAttribute("colspan")||"1")}return o}(o,n.first,r,t.getRows(o));e.setSelection(e.createPositionAt(s,0))}))}}class BA extends so{refresh(){const e=this.editor.plugins.get("TableUtils"),t=e.getSelectionAffectedTableCells(this.editor.model.document.selection),i=t[0];if(i){const n=i.findAncestor("table"),s=e.getColumns(n),{first:o,last:r}=e.getColumnIndexes(t);this.isEnabled=r-oe.cell===t)).column,last:s.find((e=>e.cell===i)).column},r=function(e,t,i,n){return parseInt(i.getAttribute("colspan")||"1")>1?i:t.previousSibling||i.nextSibling?i.nextSibling||t.previousSibling:n.first?e.reverse().find((({column:e})=>ee>n.last)).cell}(s,t,i,o);this.editor.model.change((t=>{const i=o.last-o.first+1;e.removeColumns(n,{at:o.first,columns:i}),t.setSelection(t.createPositionAt(r,0))}))}}class MA extends so{refresh(){const e=this.editor.plugins.get("TableUtils"),t=this.editor.model,i=e.getSelectionAffectedTableCells(t.document.selection),n=i.length>0;this.isEnabled=n,this.value=n&&i.every((e=>this._isInHeading(e,e.parent.parent)))}execute(e={}){if(e.forceValue===this.value)return;const t=this.editor.plugins.get("TableUtils"),i=this.editor.model,n=t.getSelectionAffectedTableCells(i.document.selection),s=n[0].findAncestor("table"),{first:o,last:r}=t.getRowIndexes(n),a=this.value?o:r+1,l=s.getAttribute("headingRows")||0;i.change((e=>{if(a){const t=kA(s,a,a>l?l:0);for(const{cell:i}of t)CA(i,a,e)}oA("headingRows",a,s,e,0)}))}_isInHeading(e,t){const i=parseInt(t.getAttribute("headingRows")||"0");return!!i&&e.parent.index0;this.isEnabled=n,this.value=n&&i.every((e=>aA(t,e)))}execute(e={}){if(e.forceValue===this.value)return;const t=this.editor.plugins.get("TableUtils"),i=this.editor.model,n=t.getSelectionAffectedTableCells(i.document.selection),s=n[0].findAncestor("table"),{first:o,last:r}=t.getColumnIndexes(n),a=this.value?o:r+1;i.change((e=>{if(a){const t=AA(s,a);for(const{cell:i,column:n}of t)xA(i,n,a,e)}oA("headingColumns",a,s,e,0)}))}}const FA=5,DA=2;function zA(e,t){const i=HA(e,"tbody",t)||HA(e,"thead",t);return $A(t.editing.view.domConverter.mapViewToDom(i))}function HA(e,t,i){return[...[...i.editing.mapper.toViewElement(e).getChildren()].find((e=>e.is("element","table"))).getChildren()].find((e=>e.is("element",t)))}function $A(e){const t=$i.window.getComputedStyle(e);return"border-box"===t.boxSizing?parseFloat(t.width)-parseFloat(t.paddingLeft)-parseFloat(t.paddingRight)-parseFloat(t.borderLeftWidth)-parseFloat(t.borderRightWidth):parseFloat(t.width)}function WA(e){const t=Math.pow(10,DA),i="number"==typeof e?e:parseFloat(e);return Math.round(i*t)/t}function UA(e){return e.map((e=>"number"==typeof e?e:parseFloat(e))).filter((e=>!Number.isNaN(e))).reduce(((e,t)=>e+t),0)}function jA(e){let t=function(e){const t=e.filter((e=>"auto"===e)).length;if(0===t)return e.map((e=>WA(e)));const i=UA(e),n=Math.max((100-i)/t,FA);return e.map((e=>"auto"===e?n:e)).map((e=>WA(e)))}(e.map((e=>"auto"===e?e:parseFloat(e.replace("%","")))));const i=UA(t);return 100!==i&&(t=t.map((e=>WA(100*e/i))).map(((e,t,i)=>t!==i.length-1?e:WA(e+100-UA(i))))),t.map((e=>e+"%"))}function qA(e){const t=$i.window.getComputedStyle(e);return"border-box"===t.boxSizing?parseInt(t.width):parseFloat(t.width)+parseFloat(t.paddingLeft)+parseFloat(t.paddingRight)+parseFloat(t.borderWidth)}function GA(e,t,i,n){for(let s=0;se.is("element","tableColumnGroup")))}function JA(e){const t=KA(e);return t?Array.from(t.getChildren()):[]}class QA extends io{static get pluginName(){return"TableUtils"}init(){this.decorate("insertColumns"),this.decorate("insertRows")}getCellLocation(e){const t=e.parent,i=t.parent,n=i.getChildIndex(t),s=new hA(i,{row:n});for(const{cell:t,row:i,column:n}of s)if(t===e)return{row:i,column:n}}createTable(e,t){const i=e.createElement("table"),n=t.rows||2,s=t.columns||2;return ZA(e,i,0,n,s),t.headingRows&&oA("headingRows",Math.min(t.headingRows,n),i,e,0),t.headingColumns&&oA("headingColumns",Math.min(t.headingColumns,s),i,e,0),i}insertRows(e,t={}){const i=this.editor.model,n=t.at||0,s=t.rows||1,o=void 0!==t.copyStructureFromAbove,r=t.copyStructureFromAbove?n-1:n,a=this.getRows(e),l=this.getColumns(e);if(n>a)throw new _("tableutils-insertrows-insert-out-of-range",this,{options:t});i.change((t=>{const i=e.getAttribute("headingRows")||0;if(i>n&&oA("headingRows",i+s,e,t,0),!o&&(0===n||n===a))return void ZA(t,e,n,s,l);const c=o?Math.max(n,r):n,d=new hA(e,{endRow:c}),h=new Array(l).fill(1);for(const{row:e,column:i,cellHeight:a,cellWidth:l,cell:c}of d){const d=e+a-1,u=e<=r&&r<=d;e0&&rA(t,s,n>1?{colspan:n}:void 0),e+=Math.abs(n)-1}}}))}insertColumns(e,t={}){const i=this.editor.model,n=t.at||0,s=t.columns||1;i.change((t=>{const i=e.getAttribute("headingColumns");ns-1)throw new _("tableutils-removerows-row-index-out-of-range",this,{table:e,options:t});i.change((t=>{const i={first:o,last:r},{cellsToMove:n,cellsToTrim:s}=function(e,{first:t,last:i}){const n=new Map,s=[];for(const{row:o,column:r,cellHeight:a,cell:l}of new hA(e,{endRow:i})){const e=o+a-1;if(o>=t&&o<=i&&e>i){const e=a-(i-o+1);n.set(r,{cell:l,rowspan:e})}if(o=t){let n;n=e>=i?i-t+1:e-t+1,s.push({cell:l,rowspan:a-n})}}return{cellsToMove:n,cellsToTrim:s}}(e,i);n.size&&function(e,t,i,n){const s=[...new hA(e,{includeAllSlots:!0,row:t})],o=e.getChild(t);let r;for(const{column:e,cell:t,isAnchor:a}of s)if(i.has(e)){const{cell:t,rowspan:s}=i.get(e),a=r?n.createPositionAfter(r):n.createPositionAt(o,0);n.move(n.createRangeOn(t),a),oA("rowspan",s,t,n),r=t}else a&&(r=t)}(e,r+1,n,t);for(let i=r;i>=o;i--)t.remove(e.getChild(i));for(const{rowspan:e,cell:i}of s)oA("rowspan",e,i,t);!function(e,{first:t,last:i},n){const s=e.getAttribute("headingRows")||0;t{!function(e,t,i){const n=e.getAttribute("headingColumns")||0;if(n&&t.first=n;s--){for(const{cell:i,column:n,cellWidth:o}of[...new hA(e)])n<=s&&o>1&&n+o>s?oA("colspan",o-1,i,t):n===s&&t.remove(i);if(i[s]){const e=0===s?i[1]:i[s-1],n=parseFloat(i[s].getAttribute("columnWidth")),o=parseFloat(e.getAttribute("columnWidth"));t.remove(i[s]),t.setAttribute("columnWidth",n+o+"%",e)}}SA(e,this)||EA(e,this)}))}splitCellVertically(e,t=2){const i=this.editor.model,n=e.parent.parent,s=parseInt(e.getAttribute("rowspan")||"1"),o=parseInt(e.getAttribute("colspan")||"1");i.change((i=>{if(o>1){const{newCellsSpan:n,updatedSpan:r}=XA(o,t);oA("colspan",r,e,i);const a={};n>1&&(a.colspan=n),s>1&&(a.rowspan=s),YA(o>t?t-1:o-1,i,i.createPositionAfter(e),a)}if(ot===e)),c=a.filter((({cell:t,cellWidth:i,column:n})=>t!==e&&n===l||nl));for(const{cell:e,cellWidth:t}of c)i.setAttribute("colspan",t+r,e);const d={};s>1&&(d.rowspan=s),YA(r,i,i.createPositionAfter(e),d);const h=n.getAttribute("headingColumns")||0;h>l&&oA("headingColumns",h+r,n,i)}}))}splitCellHorizontally(e,t=2){const i=this.editor.model,n=e.parent,s=n.parent,o=s.getChildIndex(n),r=parseInt(e.getAttribute("rowspan")||"1"),a=parseInt(e.getAttribute("colspan")||"1");i.change((i=>{if(r>1){const n=[...new hA(s,{startRow:o,endRow:o+r-1,includeAllSlots:!0})],{newCellsSpan:l,updatedSpan:c}=XA(r,t);oA("rowspan",c,e,i);const{column:d}=n.find((({cell:t})=>t===e)),h={};l>1&&(h.rowspan=l),a>1&&(h.colspan=a);for(const e of n){const{column:t,row:n}=e;n>=o+c&&t===d&&(n+o+c)%l==0&&YA(1,i,e.getPositionBefore(),h)}}if(ro){const e=s+n;i.setAttribute("rowspan",e,t)}const c={};a>1&&(c.colspan=a),ZA(i,s,o+1,n,1,c);const d=s.getAttribute("headingRows")||0;d>o&&oA("headingRows",d+n,s,i)}}))}getColumns(e){return[...e.getChild(0).getChildren()].reduce(((e,t)=>e+parseInt(t.getAttribute("colspan")||"1")),0)}getRows(e){return Array.from(e.getChildren()).reduce(((e,t)=>t.is("element","tableRow")?e+1:e),0)}createTableWalker(e,t={}){return new hA(e,t)}getSelectedTableCells(e){const t=[];for(const i of this.sortRanges(e.getRanges())){const e=i.getContainedElement();e&&e.is("element","tableCell")&&t.push(e)}return t}getTableCellsContainingSelection(e){const t=[];for(const i of e.getRanges()){const e=i.start.findAncestor("tableCell");e&&t.push(e)}return t}getSelectionAffectedTableCells(e){const t=this.getSelectedTableCells(e);return t.length?t:this.getTableCellsContainingSelection(e)}getRowIndexes(e){const t=e.map((e=>e.parent.index));return this._getFirstLastIndexesObject(t)}getColumnIndexes(e){const t=e[0].findAncestor("table"),i=[...new hA(t)].filter((t=>e.includes(t.cell))).map((e=>e.column));return this._getFirstLastIndexesObject(i)}isSelectionRectangular(e){if(e.length<2||!this._areCellInTheSameTableSection(e))return!1;const t=new Set,i=new Set;let n=0;for(const s of e){const{row:e,column:o}=this.getCellLocation(s),r=parseInt(s.getAttribute("rowspan"))||1,a=parseInt(s.getAttribute("colspan"))||1;t.add(e),i.add(o),r>1&&t.add(e+r-1),a>1&&i.add(o+a-1),n+=r*a}const s=function(e,t){const i=Array.from(e.values()),n=Array.from(t.values());return(Math.max(...i)-Math.min(...i)+1)*(Math.max(...n)-Math.min(...n)+1)}(t,i);return s==n}sortRanges(e){return Array.from(e).sort(ex)}_getFirstLastIndexesObject(e){const t=e.sort(((e,t)=>e-t));return{first:t[0],last:t[t.length-1]}}_areCellInTheSameTableSection(e){const t=e[0].findAncestor("table"),i=this.getRowIndexes(e),n=parseInt(t.getAttribute("headingRows"))||0;if(!this._areIndexesInSameSection(i,n))return!1;const s=this.getColumnIndexes(e),o=parseInt(t.getAttribute("headingColumns"))||0;return this._areIndexesInSameSection(s,o)}_areIndexesInSameSection({first:e,last:t},i){return e{const n=t.getSelectedTableCells(e.document.selection),s=n.shift(),{mergeWidth:o,mergeHeight:r}=function(e,t,i){let n=0,s=0;for(const e of t){const{row:t,column:o}=i.getCellLocation(e);n=sx(e,o,n,"colspan"),s=sx(e,t,s,"rowspan")}const{row:o,column:r}=i.getCellLocation(e);return{mergeWidth:n-r,mergeHeight:s-o}}(s,n,t);oA("colspan",o,s,i),oA("rowspan",r,s,i);for(const e of n)ix(e,s,i);PA(s.findAncestor("table"),t),i.setSelection(s,"in")}))}}function ix(e,t,i){nx(e)||(nx(t)&&i.remove(i.createRangeIn(t)),i.move(i.createRangeIn(e),i.createPositionAt(t,"end"))),i.remove(e)}function nx(e){const t=e.getChild(0);return 1==e.childCount&&t.is("element","paragraph")&&t.isEmpty}function sx(e,t,i,n){const s=parseInt(e.getAttribute(n)||"1");return Math.max(i,t+s)}class ox extends so{constructor(e){super(e),this.affectsData=!1}refresh(){const e=this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(this.editor.model.document.selection);this.isEnabled=e.length>0}execute(){const e=this.editor.model,t=this.editor.plugins.get("TableUtils"),i=t.getSelectionAffectedTableCells(e.document.selection),n=t.getRowIndexes(i),s=i[0].findAncestor("table"),o=[];for(let t=n.first;t<=n.last;t++)for(const i of s.getChild(t).getChildren())o.push(e.createRangeOn(i));e.change((e=>{e.setSelection(o)}))}}class rx extends so{constructor(e){super(e),this.affectsData=!1}refresh(){const e=this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(this.editor.model.document.selection);this.isEnabled=e.length>0}execute(){const e=this.editor.plugins.get("TableUtils"),t=this.editor.model,i=e.getSelectionAffectedTableCells(t.document.selection),n=i[0],s=i.pop(),o=n.findAncestor("table"),r=e.getCellLocation(n),a=e.getCellLocation(s),l=Math.min(r.column,a.column),c=Math.max(r.column,a.column),d=[];for(const e of new hA(o,{startColumn:l,endColumn:c}))d.push(t.createRangeOn(e.cell));t.change((e=>{e.setSelection(d)}))}}function ax(e,t){let i=!1;const n=function(e){const t=parseInt(e.getAttribute("headingRows")||"0"),i=Array.from(e.getChildren()).reduce(((e,t)=>t.is("element","tableRow")?e+1:e),0),n=[];for(const{row:s,cell:o,cellHeight:r}of new hA(e)){if(r<2)continue;const e=se){const t=e-s;n.push({cell:o,rowspan:t})}}return n}(e);if(n.length){i=!0;for(const e of n)oA("rowspan",e.rowspan,e.cell,t,1)}return i}function lx(e,t){let i=!1;const n=function(e){const t=new Array(e.childCount).fill(0);for(const{rowIndex:i}of new hA(e,{includeAllSlots:!0}))t[i]++;return t}(e),s=[];for(const[t,i]of n.entries())!i&&e.getChild(t).is("element","tableRow")&&s.push(t);if(s.length){i=!0;for(const i of s.reverse())t.remove(e.getChild(i)),n.splice(i,1)}const o=n.filter(((t,i)=>e.getChild(i).is("element","tableRow"))),r=o[0];if(!o.every((e=>e===r))){const n=o.reduce(((e,t)=>t>e?t:e),0);for(const[s,r]of o.entries()){const o=n-r;if(o){for(let i=0;ie.is("$text")));for(const e of i)t.wrap(t.createRangeOn(e),"paragraph");return!!i.length}function mx(e){return!!e.position.parent.is("element","tableCell")&&("insert"==e.type&&"$text"==e.name||"remove"==e.type)}function gx(e,t){if(!e.is("element","paragraph"))return!1;const i=t.toViewElement(e);return!!i&&pA(e)!==i.is("element","span")}class fx extends io{static get pluginName(){return"TableEditing"}static get requires(){return[QA]}constructor(e){super(e),this._additionalSlots=[]}init(){const e=this.editor,t=e.model,i=t.schema,n=e.conversion,s=e.plugins.get(QA);i.register("table",{inheritAllFrom:"$blockObject",allowAttributes:["headingRows","headingColumns"]}),i.register("tableRow",{allowIn:"table",isLimit:!0}),i.register("tableCell",{allowContentOf:"$container",allowIn:"tableRow",allowAttributes:["colspan","rowspan"],isLimit:!0,isSelectable:!0}),n.for("upcast").add((e=>{e.on("element:figure",((e,t,i)=>{if(!i.consumable.test(t.viewItem,{name:!0,classes:"table"}))return;const n=function(e){for(const t of e.getChildren())if(t.is("element","table"))return t}(t.viewItem);if(!n||!i.consumable.test(n,{name:!0}))return;i.consumable.consume(t.viewItem,{name:!0,classes:"table"});const s=On(i.convertItem(n,t.modelCursor).modelRange.getItems());s?(i.convertChildren(t.viewItem,i.writer.createPositionAt(s,"end")),i.updateConversionResult(s,t)):i.consumable.revert(t.viewItem,{name:!0,classes:"table"})}))})),n.for("upcast").add((e=>{e.on("element:table",((e,t,i)=>{const n=t.viewItem;if(!i.consumable.test(n,{name:!0}))return;const{rows:s,headingRows:o,headingColumns:r}=function(e){let t,i=0;const n=[],s=[];let o;for(const r of Array.from(e.getChildren())){if("tbody"!==r.name&&"thead"!==r.name&&"tfoot"!==r.name)continue;"thead"!==r.name||o||(o=r);const e=Array.from(r.getChildren()).filter((e=>e.is("element","tr")));for(const a of e)if(o&&r===o||"tbody"===r.name&&Array.from(a.getChildren()).length&&Array.from(a.getChildren()).every((e=>e.is("element","th"))))i++,n.push(a);else{s.push(a);const e=dA(a);(!t||ei.convertItem(e,i.writer.createPositionAt(l,"end")))),i.convertChildren(n,i.writer.createPositionAt(l,"end")),l.isEmpty){const e=i.writer.createElement("tableRow");i.writer.insert(e,i.writer.createPositionAt(l,"end")),rA(i.writer,i.writer.createPositionAt(e,"end"))}i.updateConversionResult(l,t)}}))})),n.for("editingDowncast").elementToStructure({model:{name:"table",attributes:["headingRows"]},view:mA(s,{asWidget:!0,additionalSlots:this._additionalSlots})}),n.for("dataDowncast").elementToStructure({model:{name:"table",attributes:["headingRows"]},view:mA(s,{additionalSlots:this._additionalSlots})}),n.for("upcast").elementToElement({model:"tableRow",view:"tr"}),n.for("upcast").add((e=>{e.on("element:tr",((e,t)=>{t.viewItem.isEmpty&&0==t.modelCursor.index&&e.stop()}),{priority:"high"})})),n.for("downcast").elementToElement({model:"tableRow",view:(e,{writer:t})=>e.isEmpty?t.createEmptyElement("tr"):t.createContainerElement("tr")}),n.for("upcast").elementToElement({model:"tableCell",view:"td"}),n.for("upcast").elementToElement({model:"tableCell",view:"th"}),n.for("upcast").add(cA("td")),n.for("upcast").add(cA("th")),n.for("editingDowncast").elementToElement({model:"tableCell",view:gA({asWidget:!0})}),n.for("dataDowncast").elementToElement({model:"tableCell",view:gA()}),n.for("editingDowncast").elementToElement({model:"paragraph",view:fA({asWidget:!0}),converterPriority:"high"}),n.for("dataDowncast").elementToElement({model:"paragraph",view:fA(),converterPriority:"high"}),n.for("downcast").attributeToAttribute({model:"colspan",view:"colspan"}),n.for("upcast").attributeToAttribute({model:{key:"colspan",value:px("colspan")},view:"colspan"}),n.for("downcast").attributeToAttribute({model:"rowspan",view:"rowspan"}),n.for("upcast").attributeToAttribute({model:{key:"rowspan",value:px("rowspan")},view:"rowspan"}),e.config.define("table.defaultHeadings.rows",0),e.config.define("table.defaultHeadings.columns",0),e.commands.add("insertTable",new bA(e)),e.commands.add("insertTableRowAbove",new wA(e,{order:"above"})),e.commands.add("insertTableRowBelow",new wA(e,{order:"below"})),e.commands.add("insertTableColumnLeft",new vA(e,{order:"left"})),e.commands.add("insertTableColumnRight",new vA(e,{order:"right"})),e.commands.add("removeTableRow",new OA(e)),e.commands.add("removeTableColumn",new BA(e)),e.commands.add("splitTableCellVertically",new _A(e,{direction:"vertically"})),e.commands.add("splitTableCellHorizontally",new _A(e,{direction:"horizontally"})),e.commands.add("mergeTableCells",new tx(e)),e.commands.add("mergeTableCellRight",new RA(e,{direction:"right"})),e.commands.add("mergeTableCellLeft",new RA(e,{direction:"left"})),e.commands.add("mergeTableCellDown",new RA(e,{direction:"down"})),e.commands.add("mergeTableCellUp",new RA(e,{direction:"up"})),e.commands.add("setTableColumnHeader",new NA(e)),e.commands.add("setTableRowHeader",new MA(e)),e.commands.add("selectTableRow",new ox(e)),e.commands.add("selectTableColumn",new rx(e)),function(e){e.document.registerPostFixer((t=>function(e,t){const i=t.document.differ.getChanges();let n=!1;const s=new Set;for(const t of i){let i=null;"insert"==t.type&&"table"==t.name&&(i=t.position.nodeAfter),"insert"!=t.type&&"remove"!=t.type||"tableRow"!=t.name&&"tableCell"!=t.name||(i=t.position.findAncestor("table")),cx(t)&&(i=t.range.start.findAncestor("table")),i&&!s.has(i)&&(n=ax(i,e)||n,n=lx(i,e)||n,s.add(i))}return n}(t,e)))}(t),function(e){e.document.registerPostFixer((t=>function(e,t){const i=t.document.differ.getChanges();let n=!1;for(const t of i)"insert"==t.type&&"table"==t.name&&(n=dx(t.position.nodeAfter,e)||n),"insert"==t.type&&"tableRow"==t.name&&(n=hx(t.position.nodeAfter,e)||n),"insert"==t.type&&"tableCell"==t.name&&(n=ux(t.position.nodeAfter,e)||n),"remove"!=t.type&&"insert"!=t.type||!mx(t)||(n=ux(t.position.parent,e)||n);return n}(t,e)))}(t),this.listenTo(t.document,"change:data",(()=>{!function(e,t){const i=e.document.differ;for(const e of i.getChanges()){let i,n=!1;if("attribute"==e.type){const t=e.range.start.nodeAfter;if(!t||!t.is("element","table"))continue;if("headingRows"!=e.attributeKey&&"headingColumns"!=e.attributeKey)continue;i=t,n="headingRows"==e.attributeKey}else"tableRow"!=e.name&&"tableCell"!=e.name||(i=e.position.findAncestor("table"),n="tableRow"==e.name);if(!i)continue;const s=i.getAttribute("headingRows")||0,o=i.getAttribute("headingColumns")||0,r=new hA(i);for(const e of r){const i=e.rowgx(e,t.mapper)));for(const e of i)t.reconvertItem(e)}}(t,e.editing)}))}registerAdditionalSlot(e){this._additionalSlots.push(e)}}function px(e){return t=>{const i=parseInt(t.getAttribute(e));return Number.isNaN(i)||i<=0?null:i}}class bx extends Un{constructor(e){super(e);const t=this.bindTemplate;this.items=this._createGridCollection(),this.keystrokes=new Mn,this.focusTracker=new Bn,this.set("rows",0),this.set("columns",0),this.bind("label").to(this,"columns",this,"rows",((e,t)=>`${t} × ${e}`)),this.setTemplate({tag:"div",attributes:{class:["ck"]},children:[{tag:"div",attributes:{class:["ck-insert-table-dropdown__grid"]},on:{"mouseover@.ck-insert-table-dropdown-grid-box":t.to("boxover")},children:this.items},{tag:"div",attributes:{class:["ck","ck-insert-table-dropdown__label"],"aria-hidden":!0},children:[{text:t.to("label")}]}],on:{mousedown:t.to((e=>{e.preventDefault()})),click:t.to((()=>{this.fire("execute")}))}}),this.on("boxover",((e,t)=>{const{row:i,column:n}=t.target.dataset;this.items.get(10*(parseInt(i,10)-1)+(parseInt(n,10)-1)).focus()})),this.focusTracker.on("change:focusedElement",((e,t,i)=>{if(!i)return;const{row:n,column:s}=i.dataset;this.set({rows:parseInt(n),columns:parseInt(s)})})),this.on("change:columns",(()=>this._highlightGridBoxes())),this.on("change:rows",(()=>this._highlightGridBoxes()))}render(){super.render(),o({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.items,numberOfColumns:10,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection});for(const e of this.items)this.focusTracker.add(e.element);this.keystrokes.listenTo(this.element)}focus(){this.items.get(0).focus()}focusLast(){this.items.get(0).focus()}_highlightGridBoxes(){const e=this.rows,t=this.columns;this.items.map(((i,n)=>{const s=Math.floor(n/10){const n=e.commands.get("insertTable"),s=ru(i);let o;return s.bind("isEnabled").to(n),s.buttonView.set({icon:'',label:t("Insert table"),tooltip:!0}),s.on("change:isOpen",(()=>{o||(o=new bx(i),s.panelView.children.add(o),o.delegate("execute").to(s),s.on("execute",(()=>{e.execute("insertTable",{rows:o.rows,columns:o.columns}),e.editing.view.focus()})))})),s})),e.ui.componentFactory.add("tableColumn",(e=>{const n=[{type:"switchbutton",model:{commandName:"setTableColumnHeader",label:t("Header column"),bindIsOn:!0}},{type:"separator"},{type:"button",model:{commandName:i?"insertTableColumnLeft":"insertTableColumnRight",label:t("Insert column left")}},{type:"button",model:{commandName:i?"insertTableColumnRight":"insertTableColumnLeft",label:t("Insert column right")}},{type:"button",model:{commandName:"removeTableColumn",label:t("Delete column")}},{type:"button",model:{commandName:"selectTableColumn",label:t("Select column")}}];return this._prepareDropdown(t("Column"),'',n,e)})),e.ui.componentFactory.add("tableRow",(e=>{const i=[{type:"switchbutton",model:{commandName:"setTableRowHeader",label:t("Header row"),bindIsOn:!0}},{type:"separator"},{type:"button",model:{commandName:"insertTableRowAbove",label:t("Insert row above")}},{type:"button",model:{commandName:"insertTableRowBelow",label:t("Insert row below")}},{type:"button",model:{commandName:"removeTableRow",label:t("Delete row")}},{type:"button",model:{commandName:"selectTableRow",label:t("Select row")}}];return this._prepareDropdown(t("Row"),'',i,e)})),e.ui.componentFactory.add("mergeTableCells",(e=>{const n=[{type:"button",model:{commandName:"mergeTableCellUp",label:t("Merge cell up")}},{type:"button",model:{commandName:i?"mergeTableCellRight":"mergeTableCellLeft",label:t("Merge cell right")}},{type:"button",model:{commandName:"mergeTableCellDown",label:t("Merge cell down")}},{type:"button",model:{commandName:i?"mergeTableCellLeft":"mergeTableCellRight",label:t("Merge cell left")}},{type:"separator"},{type:"button",model:{commandName:"splitTableCellVertically",label:t("Split cell vertically")}},{type:"button",model:{commandName:"splitTableCellHorizontally",label:t("Split cell horizontally")}}];return this._prepareMergeSplitButtonDropdown(t("Merge cells"),'',n,e)}))}_prepareDropdown(e,t,i,n){const s=this.editor,o=ru(n),r=this._fillDropdownWithListOptions(o,i);return o.buttonView.set({label:e,icon:t,tooltip:!0}),o.bind("isEnabled").toMany(r,"isEnabled",((...e)=>e.some((e=>e)))),this.listenTo(o,"execute",(e=>{s.execute(e.source.commandName),e.source instanceof ps||s.editing.view.focus()})),o}_prepareMergeSplitButtonDropdown(e,t,i,n){const s=this.editor,o=ru(n,ou),r="mergeTableCells",a=s.commands.get(r),l=this._fillDropdownWithListOptions(o,i);return o.buttonView.set({label:e,icon:t,tooltip:!0,isEnabled:!0}),o.bind("isEnabled").toMany([a,...l],"isEnabled",((...e)=>e.some((e=>e)))),this.listenTo(o.buttonView,"execute",(()=>{s.execute(r),s.editing.view.focus()})),this.listenTo(o,"execute",(e=>{s.execute(e.source.commandName),s.editing.view.focus()})),o}_fillDropdownWithListOptions(e,t){const i=this.editor,n=[],s=new Ln;for(const e of t)vx(e,i,n,s);return cu(e,s),n}}function vx(e,t,i,n){if("button"===e.type||"switchbutton"===e.type){const n=e.model=new _m(e.model),{commandName:s,bindIsOn:o}=e.model,r=t.commands.get(s);i.push(r),n.set({commandName:s}),n.bind("isEnabled").to(r),o&&n.bind("isOn").to(r,"value"),n.set({withText:!0})}n.add(e)}class _x extends io{static get pluginName(){return"TableSelection"}static get requires(){return[QA,QA]}init(){const e=this.editor,t=e.model,i=e.editing.view;this.listenTo(t,"deleteContent",((e,t)=>this._handleDeleteContent(e,t)),{priority:"high"}),this.listenTo(i.document,"insertText",((e,t)=>this._handleInsertTextEvent(e,t)),{priority:"high"}),this._defineSelectionConverter(),this._enablePluginDisabling()}getSelectedTableCells(){const e=this.editor.plugins.get(QA),t=this.editor.model.document.selection,i=e.getSelectedTableCells(t);return 0==i.length?null:i}getSelectionAsFragment(){const e=this.editor.plugins.get(QA),t=this.getSelectedTableCells();return t?this.editor.model.change((i=>{const n=i.createDocumentFragment(),{first:s,last:o}=e.getColumnIndexes(t),{first:r,last:a}=e.getRowIndexes(t),l=t[0].findAncestor("table");let c=a,d=o;if(e.isSelectionRectangular(t)){const e={firstColumn:s,lastColumn:o,firstRow:r,lastRow:a};c=IA(l,e),d=VA(l,e)}const h=yA(l,{startRow:r,startColumn:s,endRow:c,endColumn:d},i);return i.insert(h,n,0),n})):null}setCellSelection(e,t){const i=this._getCellsToSelect(e,t);this.editor.model.change((e=>{e.setSelection(i.cells.map((t=>e.createRangeOn(t))),{backward:i.backward})}))}getFocusCell(){const e=[...this.editor.model.document.selection.getRanges()].pop().getContainedElement();return e&&e.is("element","tableCell")?e:null}getAnchorCell(){const e=On(this.editor.model.document.selection.getRanges()).getContainedElement();return e&&e.is("element","tableCell")?e:null}_defineSelectionConverter(){const e=this.editor,t=new Set;e.conversion.for("editingDowncast").add((e=>e.on("selection",((e,i,n)=>{const s=n.writer;!function(e){for(const i of t)e.removeClass("ck-editor__editable_selected",i);t.clear()}(s);const o=this.getSelectedTableCells();if(!o)return;for(const e of o){const i=n.mapper.toViewElement(e);s.addClass("ck-editor__editable_selected",i),t.add(i)}const r=n.mapper.toViewElement(o[o.length-1]);s.setSelection(r,0)}),{priority:"lowest"})))}_enablePluginDisabling(){const e=this.editor;this.on("change:isEnabled",(()=>{if(!this.isEnabled){const t=this.getSelectedTableCells();if(!t)return;e.model.change((i=>{const n=i.createPositionAt(t[0],0),s=e.model.schema.getNearestSelectionRange(n);i.setSelection(s)}))}}))}_handleDeleteContent(e,t){const i=this.editor.plugins.get(QA),n=t[0],s=t[1],o=this.editor.model,r=!s||"backward"==s.direction,a=i.getSelectedTableCells(n);a.length&&(e.stop(),o.change((e=>{const t=a[r?a.length-1:0];o.change((e=>{for(const t of a)o.deleteContent(e.createSelection(t,"in"))}));const i=o.schema.getNearestSelectionRange(e.createPositionAt(t,0));n.is("documentSelection")?e.setSelection(i):n.setTo(i)})))}_handleInsertTextEvent(e,t){const i=this.editor,n=this.getSelectedTableCells();if(!n)return;const s=i.editing.view,o=i.editing.mapper,r=n.map((e=>s.createRangeOn(o.toViewElement(e))));t.selection=s.createSelection(r)}_getCellsToSelect(e,t){const i=this.editor.plugins.get("TableUtils"),n=i.getCellLocation(e),s=i.getCellLocation(t),o=Math.min(n.row,s.row),r=Math.max(n.row,s.row),a=Math.min(n.column,s.column),l=Math.max(n.column,s.column),c=new Array(r-o+1).fill(null).map((()=>[])),d={startRow:o,endRow:r,startColumn:a,endColumn:l};for(const{row:t,cell:i}of new hA(e.findAncestor("table"),d))c[t-o].push(i);const h=s.rowe.reverse())),{cells:c.flat(),backward:h||u}}}class yx extends io{static get pluginName(){return"TableClipboard"}static get requires(){return[_x,QA]}init(){const e=this.editor,t=e.editing.view.document;this.listenTo(t,"copy",((e,t)=>this._onCopyCut(e,t))),this.listenTo(t,"cut",((e,t)=>this._onCopyCut(e,t))),this.listenTo(e.model,"insertContent",((e,[t,i])=>this._onInsertContent(e,t,i)),{priority:"high"}),this.decorate("_replaceTableSlotCell")}_onCopyCut(e,t){const i=this.editor.plugins.get(_x);if(!i.getSelectedTableCells())return;if("cut"==e.name&&!this.editor.model.canEditAt(this.editor.model.document.selection))return;t.preventDefault(),e.stop();const n=this.editor.data,s=this.editor.editing.view.document,o=n.toView(i.getSelectionAsFragment());s.fire("clipboardOutput",{dataTransfer:t.dataTransfer,content:o,method:e.name})}_onInsertContent(e,t,i){if(i&&!i.is("documentSelection"))return;const n=this.editor.model,s=this.editor.plugins.get(QA);let o=this.getTableIfOnlyTableInContent(t,n);if(!o)return;const r=s.getSelectionAffectedTableCells(n.document.selection);r.length?(e.stop(),n.change((e=>{const t={width:s.getColumns(o),height:s.getRows(o)},i=function(e,t,i,n){const s=e[0].findAncestor("table"),o=n.getColumnIndexes(e),r=n.getRowIndexes(e),a={firstColumn:o.first,lastColumn:o.last,firstRow:r.first,lastRow:r.last},l=1===e.length;return l&&(a.lastRow+=t.height-1,a.lastColumn+=t.width-1,function(e,t,i,n){const s=n.getColumns(e),o=n.getRows(e);i>s&&n.insertColumns(e,{at:s,columns:i-s}),t>o&&n.insertRows(e,{at:o,rows:t-o})}(s,a.lastRow+1,a.lastColumn+1,n)),l||!n.isSelectionRectangular(e)?function(e,t,i){const{firstRow:n,lastRow:s,firstColumn:o,lastColumn:r}=t,a={first:n,last:s},l={first:o,last:r};Cx(e,o,a,i),Cx(e,r+1,a,i),kx(e,n,l,i),kx(e,s+1,l,i,n)}(s,a,i):(a.lastRow=IA(s,a),a.lastColumn=VA(s,a)),a}(r,t,e,s),n=i.lastRow-i.firstRow+1,a=i.lastColumn-i.firstColumn+1,l={startRow:0,startColumn:0,endRow:Math.min(n,t.height)-1,endColumn:Math.min(a,t.width)-1};o=yA(o,l,e);const c=r[0].findAncestor("table"),d=this._replaceSelectedCellsWithPasted(o,t,c,i,e);if(this.editor.plugins.get("TableSelection").isEnabled){const t=s.sortRanges(d.map((t=>e.createRangeOn(t))));e.setSelection(t)}else e.setSelection(d[0],0)}))):PA(o,s)}_replaceSelectedCellsWithPasted(e,t,i,n,s){const{width:o,height:r}=t,a=function(e,t,i){const n=new Array(i).fill(null).map((()=>new Array(t).fill(null)));for(const{column:t,row:i,cell:s}of new hA(e))n[i][t]=s;return n}(e,o,r),l=[...new hA(i,{startRow:n.firstRow,endRow:n.lastRow,startColumn:n.firstColumn,endColumn:n.lastColumn,includeAllSlots:!0})],c=[];let d;for(const e of l){const{row:t,column:i}=e;i===n.firstColumn&&(d=e.getPositionBefore());const l=t-n.firstRow,h=i-n.firstColumn,u=a[l%r][h%o],m=u?s.cloneElement(u):null,g=this._replaceTableSlotCell(e,m,d,s);g&&(TA(g,t,i,n.lastRow,n.lastColumn,s),c.push(g),d=s.createPositionAfter(g))}const h=parseInt(i.getAttribute("headingRows")||"0"),u=parseInt(i.getAttribute("headingColumns")||"0"),m=n.firstRowAx(e,t,i))).map((({cell:e})=>CA(e,t,n)))}function Cx(e,t,i,n){if(!(t<1))return AA(e,t).filter((({row:e,cellHeight:t})=>Ax(e,t,i))).map((({cell:e,column:i})=>xA(e,i,t,n)))}function Ax(e,t,i){const n=e+t-1,{first:s,last:o}=i;return e>=s&&e<=o||e=s}class xx extends io{static get pluginName(){return"TableKeyboard"}static get requires(){return[_x,QA]}init(){const e=this.editor.editing.view.document;this.listenTo(e,"arrowKey",((...e)=>this._onArrowKey(...e)),{context:"table"}),this.listenTo(e,"tab",((...e)=>this._handleTabOnSelectedTable(...e)),{context:"figure"}),this.listenTo(e,"tab",((...e)=>this._handleTab(...e)),{context:["th","td"]})}_handleTabOnSelectedTable(e,t){const i=this.editor,n=i.model.document.selection.getSelectedElement();n&&n.is("element","table")&&(t.preventDefault(),t.stopPropagation(),e.stop(),i.model.change((e=>{e.setSelection(e.createRangeIn(n.getChild(0).getChild(0)))})))}_handleTab(e,t){const i=this.editor,n=this.editor.plugins.get(QA),s=this.editor.plugins.get("TableSelection"),o=i.model.document.selection,r=!t.shiftKey;let a=n.getTableCellsContainingSelection(o)[0];if(a||(a=s.getFocusCell()),!a)return;t.preventDefault(),t.stopPropagation(),e.stop();const l=a.parent,c=l.parent,d=c.getChildIndex(l),h=l.getChildIndex(a),u=0===h;if(!r&&u&&0===d)return void i.model.change((e=>{e.setSelection(e.createRangeOn(c))}));const m=h===l.childCount-1,g=d===n.getRows(c)-1;if(r&&g&&m&&(i.execute("insertTableRowBelow"),d===n.getRows(c)-1))return void i.model.change((e=>{e.setSelection(e.createRangeOn(c))}));let f;if(r&&m){const e=c.getChild(d+1);f=e.getChild(0)}else if(!r&&u){const e=c.getChild(d-1);f=e.getChild(e.childCount-1)}else f=l.getChild(h+(r?1:-1));i.model.change((e=>{e.setSelection(e.createRangeIn(f))}))}_onArrowKey(e,t){const i=this.editor,n=Sn(t.keyCode,i.locale.contentLanguageDirection);this._handleArrowKeys(n,t.shiftKey)&&(t.preventDefault(),t.stopPropagation(),e.stop())}_handleArrowKeys(e,t){const i=this.editor.plugins.get(QA),n=this.editor.plugins.get("TableSelection"),s=this.editor.model,o=s.document.selection,r=["right","down"].includes(e),a=i.getSelectedTableCells(o);if(a.length){let i;return i=t?n.getFocusCell():r?a[a.length-1]:a[0],this._navigateFromCellInDirection(i,e,t),!0}const l=o.focus.findAncestor("tableCell");if(!l)return!1;if(!o.isCollapsed)if(t){if(o.isBackward==r&&!o.containsEntireContent(l))return!1}else{const e=o.getSelectedElement();if(!e||!s.schema.isObject(e))return!1}return!!this._isSelectionAtCellEdge(o,l,r)&&(this._navigateFromCellInDirection(l,e,t),!0)}_isSelectionAtCellEdge(e,t,i){const n=this.editor.model,s=this.editor.model.schema,o=i?e.getLastPosition():e.getFirstPosition();if(!s.getLimitElement(o).is("element","tableCell"))return n.createPositionAt(t,i?"end":0).isTouching(o);const r=n.createSelection(o);return n.modifySelection(r,{direction:i?"forward":"backward"}),o.isEqual(r.focus)}_navigateFromCellInDirection(e,t,i=!1){const n=this.editor.model,s=e.findAncestor("table"),o=[...new hA(s,{includeAllSlots:!0})],{row:r,column:a}=o[o.length-1],l=o.find((({cell:t})=>t==e));let{row:c,column:d}=l;switch(t){case"left":d--;break;case"up":c--;break;case"right":d+=l.cellWidth;break;case"down":c+=l.cellHeight}if(c<0||c>r||d<0&&c<=0||d>a&&c>=r)return void n.change((e=>{e.setSelection(e.createRangeOn(s))}));d<0?(d=i?0:a,c--):d>a&&(d=i?a:0,c++);const h=o.find((e=>e.row==c&&e.column==d)).cell,u=["right","down"].includes(t),m=this.editor.plugins.get("TableSelection");if(i&&m.isEnabled){const t=m.getAnchorCell()||e;m.setCellSelection(t,h)}else{const e=n.createPositionAt(h,u?0:"end");n.change((t=>{t.setSelection(e)}))}}}class Tx extends Ca{constructor(){super(...arguments),this.domEventType=["mousemove","mouseleave"]}onDomEvent(e){this.fire(e.type,e)}}class Ex extends io{static get pluginName(){return"TableMouse"}static get requires(){return[_x,QA]}init(){this.editor.editing.view.addObserver(Tx),this._enableShiftClickSelection(),this._enableMouseDragSelection()}_enableShiftClickSelection(){const e=this.editor,t=e.plugins.get(QA);let i=!1;const n=e.plugins.get(_x);this.listenTo(e.editing.view.document,"mousedown",((s,o)=>{const r=e.model.document.selection;if(!this.isEnabled||!n.isEnabled)return;if(!o.domEvent.shiftKey)return;const a=n.getAnchorCell()||t.getTableCellsContainingSelection(r)[0];if(!a)return;const l=this._getModelTableCellFromDomEvent(o);l&&Sx(a,l)&&(i=!0,n.setCellSelection(a,l),o.preventDefault())})),this.listenTo(e.editing.view.document,"mouseup",(()=>{i=!1})),this.listenTo(e.editing.view.document,"selectionChange",(e=>{i&&e.stop()}),{priority:"highest"})}_enableMouseDragSelection(){const e=this.editor;let t,i,n=!1,s=!1;const o=e.plugins.get(_x);this.listenTo(e.editing.view.document,"mousedown",((e,i)=>{this.isEnabled&&o.isEnabled&&(i.domEvent.shiftKey||i.domEvent.ctrlKey||i.domEvent.altKey||(t=this._getModelTableCellFromDomEvent(i)))})),this.listenTo(e.editing.view.document,"mousemove",((e,r)=>{if(!r.domEvent.buttons)return;if(!t)return;const a=this._getModelTableCellFromDomEvent(r);a&&Sx(t,a)&&(i=a,n||i==t||(n=!0)),n&&(s=!0,o.setCellSelection(t,i),r.preventDefault())})),this.listenTo(e.editing.view.document,"mouseup",(()=>{n=!1,s=!1,t=null,i=null})),this.listenTo(e.editing.view.document,"selectionChange",(e=>{s&&e.stop()}),{priority:"highest"})}_getModelTableCellFromDomEvent(e){const t=e.target,i=this.editor.editing.view.createPositionAt(t,0);return this.editor.editing.mapper.toModelPosition(i).parent.findAncestor("tableCell",{includeSelf:!0})}}function Sx(e,t){return e.parent.parent==t.parent.parent}function Px(e){return!!e&&e.is("element","table")}function Ix(e){for(const t of e.getChildren())if(t.is("element","caption"))return t;return null}function Vx(e){const t=e.parent;return"figcaption"==e.name&&t&&t.is("element","figure")&&t.hasClass("table")||"caption"==e.name&&t&&t.is("element","table")?{name:!0}:null}function Rx(e){const t=e.getSelectedElement();return t&&t.is("element","table")?t:e.getFirstPosition().findAncestor("table")}class Lx extends so{refresh(){const e=Rx(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled?this.value=!!Ix(e):this.value=!1}execute({focusCaptionOnShow:e=!1}={}){this.editor.model.change((t=>{this.value?this._hideTableCaption(t):this._showTableCaption(t,e)}))}_showTableCaption(e,t){const i=this.editor.model,n=Rx(i.document.selection),s=this.editor.plugins.get("TableCaptionEditing")._getSavedCaption(n)||e.createElement("caption");i.insertContent(s,n,"end"),t&&e.setSelection(s,"in")}_hideTableCaption(e){const t=this.editor.model,i=Rx(t.document.selection),n=this.editor.plugins.get("TableCaptionEditing"),s=Ix(i);n._saveCaption(i,s),t.deleteContent(e.createSelection(s,"on"))}}class Ox extends io{static get pluginName(){return"TableCaptionEditing"}constructor(e){super(e),this._savedCaptionsMap=new WeakMap}init(){const e=this.editor,t=e.model.schema,i=e.editing.view,n=e.t;var s;t.isRegistered("caption")?t.extend("caption",{allowIn:"table"}):t.register("caption",{allowIn:"table",allowContentOf:"$block",isLimit:!0}),e.commands.add("toggleTableCaption",new Lx(this.editor)),e.conversion.for("upcast").elementToElement({view:Vx,model:"caption"}),e.conversion.for("dataDowncast").elementToElement({model:"caption",view:(e,{writer:t})=>Px(e.parent)?t.createContainerElement("figcaption"):null}),e.conversion.for("editingDowncast").elementToElement({model:"caption",view:(e,{writer:t})=>{if(!Px(e.parent))return null;const s=t.createEditableElement("figcaption");return t.setCustomProperty("tableCaption",!0,s),s.placeholder=n("Enter table caption"),mo({view:i,element:s,keepOnFocus:!0}),cf(s,t)}}),(s=e.model).document.registerPostFixer((e=>function(e,t){const i=t.document.differ.getChanges();let n=!1;for(const t of i){if("insert"!=t.type)continue;const i=t.position.parent;if(i.is("element","table")||"table"==t.name){const s="table"==t.name?t.position.nodeAfter:i,o=Array.from(s.getChildren()).filter((e=>e.is("element","caption"))),r=o.shift();if(!r)continue;for(const t of o)e.move(e.createRangeIn(t),r,"end"),e.remove(t);r.nextSibling&&(e.move(e.createRangeOn(r),s,"end"),n=!0),n=!!o.length||n}}return n}(e,s)))}_getSavedCaption(e){const t=this._savedCaptionsMap.get(e);return t?ol.fromJSON(t):null}_saveCaption(e,t){this._savedCaptionsMap.set(e,t.toJSON())}}class Bx extends io{static get pluginName(){return"TableCaptionUI"}init(){const e=this.editor,t=e.editing.view,i=e.t;e.ui.componentFactory.add("toggleTableCaption",(n=>{const s=e.commands.get("toggleTableCaption"),o=new fs(n);return o.set({icon:Kh.caption,tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(s,"value","isEnabled"),o.bind("label").to(s,"value",(e=>i(e?"Toggle caption off":"Toggle caption on"))),this.listenTo(o,"execute",(()=>{if(e.execute("toggleTableCaption",{focusCaptionOnShow:!0}),s.value){const i=function(e){const t=Rx(e);return t?Ix(t):null}(e.model.document.selection),n=e.editing.mapper.toViewElement(i);if(!n)return;t.scrollToTheSelection(),t.change((e=>{e.addClass("table__caption_highlighted",n)}))}e.editing.view.focus()})),o}))}}class Mx extends Un{constructor(e,t){super(e),this.set("value",""),this.set("isReadOnly",!1),this.set("isFocused",!1),this.set("isEmpty",!0),this.options=t,this.focusTracker=new Bn,this._focusables=new Wn,this.dropdownView=this._createDropdownView(),this.inputView=this._createInputTextView(),this.keystrokes=new Mn,this._stillTyping=!1,this.focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-input-color"]},children:[this.dropdownView,this.inputView]}),this.on("change:value",((e,t,i)=>this._setInputValue(i)))}render(){super.render(),[this.inputView,this.dropdownView.buttonView].forEach((e=>{this.focusTracker.add(e.element),this._focusables.add(e)})),this.keystrokes.listenTo(this.element)}focus(e){-1===e?this.focusCycler.focusLast():this.focusCycler.focusFirst()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createDropdownView(){const e=this.locale,t=e.t,i=this.bindTemplate,n=this._createColorSelector(e),s=ru(e),o=new Un;return o.setTemplate({tag:"span",attributes:{class:["ck","ck-input-color__button__preview"],style:{backgroundColor:i.to("value")}},children:[{tag:"span",attributes:{class:["ck","ck-input-color__button__preview__no-color-indicator",i.if("value","ck-hidden",(e=>""!=e))]}}]}),s.buttonView.extendTemplate({attributes:{class:"ck-input-color__button"}}),s.buttonView.children.add(o),s.buttonView.label=t("Color picker"),s.buttonView.tooltip=!0,s.panelPosition="rtl"===e.uiLanguageDirection?"se":"sw",s.panelView.children.add(n),s.bind("isEnabled").to(this,"isReadOnly",(e=>!e)),s.on("change:isOpen",((e,t,i)=>{i&&(n.updateSelectedColors(),n.showColorGridsFragment())})),s}_createInputTextView(){const e=this.locale,t=new js(e);return t.extendTemplate({on:{blur:t.bindTemplate.to("blur")}}),t.value=this.value,t.bind("isReadOnly","hasError").to(this),this.bind("isFocused","isEmpty").to(t),t.on("input",(()=>{const e=t.element.value,i=this.options.colorDefinitions.find((t=>e===t.label));this._stillTyping=!0,this.value=i&&i.color||e})),t.on("blur",(()=>{this._stillTyping=!1,this._setInputValue(t.element.value)})),t.delegate("input").to(this),t}_createColorSelector(e){const t=e.t,i=this.options.defaultColorValue||"",n=t(i?"Restore default":"Remove color"),s=new Ju(e,{colors:this.options.colorDefinitions,columns:this.options.columns,removeButtonLabel:n,colorPickerLabel:t("Color picker"),colorPickerViewConfig:!1!==this.options.colorPickerConfig&&{...this.options.colorPickerConfig,hideInput:!0}});s.appendUI(),s.on("execute",((e,t)=>{"colorPickerSaveButton"!==t.source?(this.value=t.value||i,this.fire("input"),"colorPicker"!==t.source&&(this.dropdownView.isOpen=!1)):this.dropdownView.isOpen=!1}));let o=this.value;return s.on("colorPicker:cancel",(()=>{this.value=o,this.fire("input"),this.dropdownView.isOpen=!1})),s.colorGridsFragmentView.colorPickerButtonView.on("execute",(()=>{o=this.value})),s.bind("selectedColor").to(this,"value"),s}_setInputValue(e){if(!this._stillTyping){const t=Nx(e),i=this.options.colorDefinitions.find((e=>t===Nx(e.color)));this.inputView.value=i?i.label:e||""}}}function Nx(e){return e.replace(/([(,])\s+/g,"$1").replace(/^\s+|\s+(?=[),\s]|$)/g,"").replace(/,|\s/g," ")}const Fx=e=>""===e;function Dx(e){return{none:e("None"),solid:e("Solid"),dotted:e("Dotted"),dashed:e("Dashed"),double:e("Double"),groove:e("Groove"),ridge:e("Ridge"),inset:e("Inset"),outset:e("Outset")}}function zx(e){return e('The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".')}function Hx(e){return e('The value is invalid. Try "10px" or "2em" or simply "2".')}function $x(e){return e=e.trim().toLowerCase(),Fx(e)||ah(e)}function Wx(e){return e=e.trim(),Fx(e)||Jx(e)||hh(e)||mh(e)}function Ux(e){return e=e.trim(),Fx(e)||Jx(e)||hh(e)}function jx(e,t){const i=new Ln,n=Dx(e.t);for(const s in n){const o={type:"button",model:new _m({_borderStyleValue:s,label:n[s],role:"menuitemradio",withText:!0})};"none"===s?o.model.bind("isOn").to(e,"borderStyle",(e=>"none"===t?!e:e===s)):o.model.bind("isOn").to(e,"borderStyle",(e=>e===s)),i.add(o)}return i}function qx(e){const{view:t,icons:i,toolbar:n,labels:s,propertyName:o,nameToValue:r,defaultValue:a}=e;for(const e in s){const l=new fs(t.locale);l.set({label:s[e],icon:i[e],tooltip:s[e]});const c=r?r(e):e;l.bind("isOn").to(t,o,(e=>{let t=e;return""===e&&a&&(t=a),c===t})),l.on("execute",(()=>{t[o]=c})),n.items.add(l)}}const Gx=[{color:"hsl(0, 0%, 0%)",label:"Black"},{color:"hsl(0, 0%, 30%)",label:"Dim grey"},{color:"hsl(0, 0%, 60%)",label:"Grey"},{color:"hsl(0, 0%, 90%)",label:"Light grey"},{color:"hsl(0, 0%, 100%)",label:"White",hasBorder:!0},{color:"hsl(0, 75%, 60%)",label:"Red"},{color:"hsl(30, 75%, 60%)",label:"Orange"},{color:"hsl(60, 75%, 60%)",label:"Yellow"},{color:"hsl(90, 75%, 60%)",label:"Light green"},{color:"hsl(120, 75%, 60%)",label:"Green"},{color:"hsl(150, 75%, 60%)",label:"Aquamarine"},{color:"hsl(180, 75%, 60%)",label:"Turquoise"},{color:"hsl(210, 75%, 60%)",label:"Light blue"},{color:"hsl(240, 75%, 60%)",label:"Blue"},{color:"hsl(270, 75%, 60%)",label:"Purple"}];function Kx(e){return(t,i,n)=>{const s=new Mx(t.locale,{colorDefinitions:(o=e.colorConfig,o.map((e=>({color:e.model,label:e.label,options:{hasBorder:e.hasBorder}})))),columns:e.columns,defaultColorValue:e.defaultColorValue,colorPickerConfig:e.colorPickerConfig});var o;return s.inputView.set({id:i,ariaDescribedById:n}),s.bind("isReadOnly").to(t,"isEnabled",(e=>!e)),s.bind("hasError").to(t,"errorText",(e=>!!e)),s.on("input",(()=>{t.errorText=null})),t.bind("isEmpty","isFocused").to(s),s}}function Jx(e){const t=parseFloat(e);return!Number.isNaN(t)&&e===String(t)}class Qx extends Un{constructor(e,t={}){super(e);const i=this.bindTemplate;this.set("class",t.class||null),this.children=this.createCollection(),t.children&&t.children.forEach((e=>this.children.add(e))),this.set("_role",null),this.set("_ariaLabelledBy",null),t.labelView&&this.set({_role:"group",_ariaLabelledBy:t.labelView.id}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-form__row",i.to("class")],role:i.to("_role"),"aria-labelledby":i.to("_ariaLabelledBy")},children:this.children})}}const Zx={left:Kh.alignLeft,center:Kh.alignCenter,right:Kh.alignRight,justify:Kh.alignJustify,top:Kh.alignTop,middle:Kh.alignMiddle,bottom:Kh.alignBottom};class Yx extends Un{constructor(e,t){super(e),this.set({borderStyle:"",borderWidth:"",borderColor:"",padding:"",backgroundColor:"",width:"",height:"",horizontalAlignment:"",verticalAlignment:""}),this.options=t;const{borderStyleDropdown:i,borderWidthInput:n,borderColorInput:s,borderRowLabel:o}=this._createBorderFields(),{backgroundRowLabel:r,backgroundInput:a}=this._createBackgroundFields(),{widthInput:l,operatorLabel:c,heightInput:d,dimensionsLabel:h}=this._createDimensionFields(),{horizontalAlignmentToolbar:u,verticalAlignmentToolbar:m,alignmentLabel:g}=this._createAlignmentFields();this.focusTracker=new Bn,this.keystrokes=new Mn,this.children=this.createCollection(),this.borderStyleDropdown=i,this.borderWidthInput=n,this.borderColorInput=s,this.backgroundInput=a,this.paddingInput=this._createPaddingField(),this.widthInput=l,this.heightInput=d,this.horizontalAlignmentToolbar=u,this.verticalAlignmentToolbar=m;const{saveButtonView:f,cancelButtonView:p}=this._createActionButtons();this.saveButtonView=f,this.cancelButtonView=p,this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.children.add(new wm(e,{label:this.t("Cell properties")})),this.children.add(new Qx(e,{labelView:o,children:[o,i,s,n],class:"ck-table-form__border-row"})),this.children.add(new Qx(e,{labelView:r,children:[r,a],class:"ck-table-form__background-row"})),this.children.add(new Qx(e,{children:[new Qx(e,{labelView:h,children:[h,l,c,d],class:"ck-table-form__dimensions-row"}),new Qx(e,{children:[this.paddingInput],class:"ck-table-cell-properties-form__padding-row"})]})),this.children.add(new Qx(e,{labelView:g,children:[g,u,m],class:"ck-table-cell-properties-form__alignment-row"})),this.children.add(new Qx(e,{children:[this.saveButtonView,this.cancelButtonView],class:"ck-table-form__action-row"})),this.setTemplate({tag:"form",attributes:{class:["ck","ck-form","ck-table-form","ck-table-cell-properties-form"],tabindex:"-1"},children:this.children})}render(){super.render(),s({view:this}),[this.borderColorInput,this.backgroundInput].forEach((e=>{e.fieldView.focusCycler.on("forwardCycle",(e=>{this._focusCycler.focusNext(),e.stop()})),e.fieldView.focusCycler.on("backwardCycle",(e=>{this._focusCycler.focusPrevious(),e.stop()}))})),[this.borderStyleDropdown,this.borderColorInput,this.borderWidthInput,this.backgroundInput,this.widthInput,this.heightInput,this.paddingInput,this.horizontalAlignmentToolbar,this.verticalAlignmentToolbar,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createBorderFields(){const e=this.options.defaultTableCellProperties,t={style:e.borderStyle,width:e.borderWidth,color:e.borderColor},i=Kx({colorConfig:this.options.borderColors,columns:5,defaultColorValue:t.color,colorPickerConfig:this.options.colorPickerConfig}),n=this.locale,s=this.t,o=s("Style"),r=new Hs(n);r.text=s("Border");const a=Dx(s),l=new $s(n,fu);l.set({label:o,class:"ck-table-form__border-style"}),l.fieldView.buttonView.set({ariaLabel:o,ariaLabelledBy:void 0,isOn:!1,withText:!0,tooltip:o}),l.fieldView.buttonView.bind("label").to(this,"borderStyle",(e=>a[e||"none"])),l.fieldView.on("execute",(e=>{this.borderStyle=e.source._borderStyleValue})),l.bind("isEmpty").to(this,"borderStyle",(e=>!e)),cu(l.fieldView,jx(this,t.style),{role:"menu",ariaLabel:o});const c=new $s(n,mu);c.set({label:s("Width"),class:"ck-table-form__border-width"}),c.fieldView.bind("value").to(this,"borderWidth"),c.bind("isEnabled").to(this,"borderStyle",Xx),c.fieldView.on("input",(()=>{this.borderWidth=c.fieldView.element.value}));const d=new $s(n,i);return d.set({label:s("Color"),class:"ck-table-form__border-color"}),d.fieldView.bind("value").to(this,"borderColor"),d.bind("isEnabled").to(this,"borderStyle",Xx),d.fieldView.on("input",(()=>{this.borderColor=d.fieldView.value})),this.on("change:borderStyle",((e,i,n,s)=>{Xx(n)||(this.borderColor="",this.borderWidth=""),Xx(s)||(this.borderColor=t.color,this.borderWidth=t.width)})),{borderRowLabel:r,borderStyleDropdown:l,borderColorInput:d,borderWidthInput:c}}_createBackgroundFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Background");const n=Kx({colorConfig:this.options.backgroundColors,columns:5,defaultColorValue:this.options.defaultTableCellProperties.backgroundColor,colorPickerConfig:this.options.colorPickerConfig}),s=new $s(e,n);return s.set({label:t("Color"),class:"ck-table-cell-properties-form__background"}),s.fieldView.bind("value").to(this,"backgroundColor"),s.fieldView.on("input",(()=>{this.backgroundColor=s.fieldView.value})),{backgroundRowLabel:i,backgroundInput:s}}_createDimensionFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Dimensions");const n=new $s(e,mu);n.set({label:t("Width"),class:"ck-table-form__dimensions-row__width"}),n.fieldView.bind("value").to(this,"width"),n.fieldView.on("input",(()=>{this.width=n.fieldView.element.value}));const s=new Un(e);s.setTemplate({tag:"span",attributes:{class:["ck-table-form__dimension-operator"]},children:[{text:"×"}]});const o=new $s(e,mu);return o.set({label:t("Height"),class:"ck-table-form__dimensions-row__height"}),o.fieldView.bind("value").to(this,"height"),o.fieldView.on("input",(()=>{this.height=o.fieldView.element.value})),{dimensionsLabel:i,widthInput:n,operatorLabel:s,heightInput:o}}_createPaddingField(){const e=this.locale,t=this.t,i=new $s(e,mu);return i.set({label:t("Padding"),class:"ck-table-cell-properties-form__padding"}),i.fieldView.bind("value").to(this,"padding"),i.fieldView.on("input",(()=>{this.padding=i.fieldView.element.value})),i}_createAlignmentFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Table cell text alignment");const n=new Zh(e),s="rtl"===e.contentLanguageDirection;n.set({isCompact:!0,ariaLabel:t("Horizontal text alignment toolbar")}),qx({view:this,icons:Zx,toolbar:n,labels:this._horizontalAlignmentLabels,propertyName:"horizontalAlignment",nameToValue:e=>{if(s){if("left"===e)return"right";if("right"===e)return"left"}return e},defaultValue:this.options.defaultTableCellProperties.horizontalAlignment});const o=new Zh(e);return o.set({isCompact:!0,ariaLabel:t("Vertical text alignment toolbar")}),qx({view:this,icons:Zx,toolbar:o,labels:this._verticalAlignmentLabels,propertyName:"verticalAlignment",defaultValue:this.options.defaultTableCellProperties.verticalAlignment}),{horizontalAlignmentToolbar:n,verticalAlignmentToolbar:o,alignmentLabel:i}}_createActionButtons(){const e=this.locale,t=this.t,i=new fs(e),n=new fs(e),s=[this.borderWidthInput,this.borderColorInput,this.backgroundInput,this.paddingInput];return i.set({label:t("Save"),icon:Kh.check,class:"ck-button-save",type:"submit",withText:!0}),i.bind("isEnabled").toMany(s,"errorText",((...e)=>e.every((e=>!e)))),n.set({label:t("Cancel"),icon:Kh.cancel,class:"ck-button-cancel",withText:!0}),n.delegate("execute").to(this,"cancel"),{saveButtonView:i,cancelButtonView:n}}get _horizontalAlignmentLabels(){const e=this.locale,t=this.t,i=t("Align cell text to the left"),n=t("Align cell text to the center"),s=t("Align cell text to the right"),o=t("Justify cell text");return"rtl"===e.uiLanguageDirection?{right:s,center:n,left:i,justify:o}:{left:i,center:n,right:s,justify:o}}get _verticalAlignmentLabels(){const e=this.t;return{top:e("Align cell text to the top"),middle:e("Align cell text to the middle"),bottom:e("Align cell text to the bottom")}}}function Xx(e){return"none"!==e}function eT(e){const t=e.getSelectedElement();return t&&iT(t)?t:null}function tT(e){const t=e.getFirstPosition();if(!t)return null;let i=t.parent;for(;i;){if(i.is("element")&&iT(i))return i;i=i.parent}return null}function iT(e){return!!e.getCustomProperty("table")&&sf(e)}const nT=tm.defaultPositions,sT=[nT.northArrowSouth,nT.northArrowSouthWest,nT.northArrowSouthEast,nT.southArrowNorth,nT.southArrowNorthWest,nT.southArrowNorthEast,nT.viewportStickyNorth];function oT(e,t){const i=e.plugins.get("ContextualBalloon");if(tT(e.editing.view.document.selection)){let n;n="cell"===t?aT(e):rT(e),i.updatePosition(n)}}function rT(e){const t=e.model.document.selection.getFirstPosition().findAncestor("table"),i=e.editing.mapper.toViewElement(t);return{target:e.editing.view.domConverter.mapViewToDom(i),positions:sT}}function aT(e){const t=e.editing.mapper,i=e.editing.view.domConverter,n=e.model.document.selection;if(n.rangeCount>1)return{target:()=>function(e,t){const i=t.editing.mapper,n=t.editing.view.domConverter,s=Array.from(e).map((e=>{const t=lT(e.start),s=i.toViewElement(t);return new Ki(n.mapViewToDom(s))}));return Ki.getBoundingRect(s)}(n.getRanges(),e),positions:sT};const s=lT(n.getFirstPosition()),o=t.toViewElement(s);return{target:i.mapViewToDom(o),positions:sT}}function lT(e){return e.nodeAfter&&e.nodeAfter.is("element","tableCell")?e.nodeAfter:e.findAncestor("tableCell")}function cT(e){if(!e||!M(e))return e;const{top:t,right:i,bottom:n,left:s}=e;return t==i&&i==n&&n==s?t:void 0}function dT(e,t){const i=parseFloat(e);return Number.isNaN(i)||String(i)!==String(e)?e:`${i}${t}`}function hT(e,t={}){const i={borderStyle:"none",borderWidth:"",borderColor:"",backgroundColor:"",width:"",height:"",...e};return t.includeAlignmentProperty&&!i.alignment&&(i.alignment="center"),t.includePaddingProperty&&!i.padding&&(i.padding=""),t.includeVerticalAlignmentProperty&&!i.verticalAlignment&&(i.verticalAlignment="middle"),t.includeHorizontalAlignmentProperty&&!i.horizontalAlignment&&(i.horizontalAlignment=t.isRightToLeftContent?"right":"left"),i}const uT={borderStyle:"tableCellBorderStyle",borderColor:"tableCellBorderColor",borderWidth:"tableCellBorderWidth",height:"tableCellHeight",width:"tableCellWidth",padding:"tableCellPadding",backgroundColor:"tableCellBackgroundColor",horizontalAlignment:"tableCellHorizontalAlignment",verticalAlignment:"tableCellVerticalAlignment"};class mT extends io{static get requires(){return[Cm]}static get pluginName(){return"TableCellPropertiesUI"}constructor(e){super(e),e.config.define("table.tableCellProperties",{borderColors:Gx,backgroundColors:Gx})}init(){const e=this.editor,t=e.t;this._defaultTableCellProperties=hT(e.config.get("table.tableCellProperties.defaultProperties"),{includeVerticalAlignmentProperty:!0,includeHorizontalAlignmentProperty:!0,includePaddingProperty:!0,isRightToLeftContent:"rtl"===e.locale.contentLanguageDirection}),this._balloon=e.plugins.get(Cm),this.view=null,this._isReady=!1,e.ui.componentFactory.add("tableCellProperties",(i=>{const n=new fs(i);n.set({label:t("Cell properties"),icon:'',tooltip:!0}),this.listenTo(n,"execute",(()=>this._showView()));const s=Object.values(uT).map((t=>e.commands.get(t)));return n.bind("isEnabled").toMany(s,"isEnabled",((...e)=>e.some((e=>e)))),n}))}destroy(){super.destroy(),this.view&&this.view.destroy()}_createPropertiesView(){const t=this.editor,i=t.config.get("table.tableCellProperties"),n=ws(i.borderColors),s=bs(t.locale,n),o=ws(i.backgroundColors),r=bs(t.locale,o),a=!1!==i.colorPicker,l=new Yx(t.locale,{borderColors:s,backgroundColors:r,defaultTableCellProperties:this._defaultTableCellProperties,colorPickerConfig:!!a&&(i.colorPicker||{})}),c=t.t;l.render(),this.listenTo(l,"submit",(()=>{this._hideView()})),this.listenTo(l,"cancel",(()=>{this._undoStepBatch.operations.length&&t.execute("undo",this._undoStepBatch),this._hideView()})),l.keystrokes.set("Esc",((e,t)=>{this._hideView(),t()})),e({emitter:l,activator:()=>this._isViewInBalloon,contextElements:[this._balloon.view.element],callback:()=>this._hideView()});const d=zx(c),h=Hx(c);return l.on("change:borderStyle",this._getPropertyChangeCallback("tableCellBorderStyle")),l.on("change:borderColor",this._getValidatedPropertyChangeCallback({viewField:l.borderColorInput,commandName:"tableCellBorderColor",errorText:d,validator:$x})),l.on("change:borderWidth",this._getValidatedPropertyChangeCallback({viewField:l.borderWidthInput,commandName:"tableCellBorderWidth",errorText:h,validator:Ux})),l.on("change:padding",this._getValidatedPropertyChangeCallback({viewField:l.paddingInput,commandName:"tableCellPadding",errorText:h,validator:Wx})),l.on("change:width",this._getValidatedPropertyChangeCallback({viewField:l.widthInput,commandName:"tableCellWidth",errorText:h,validator:Wx})),l.on("change:height",this._getValidatedPropertyChangeCallback({viewField:l.heightInput,commandName:"tableCellHeight",errorText:h,validator:Wx})),l.on("change:backgroundColor",this._getValidatedPropertyChangeCallback({viewField:l.backgroundInput,commandName:"tableCellBackgroundColor",errorText:d,validator:$x})),l.on("change:horizontalAlignment",this._getPropertyChangeCallback("tableCellHorizontalAlignment")),l.on("change:verticalAlignment",this._getPropertyChangeCallback("tableCellVerticalAlignment")),l}_fillViewFormFromCommandValues(){const e=this.editor.commands,t=e.get("tableCellBorderStyle");Object.entries(uT).map((([t,i])=>{const n=this._defaultTableCellProperties[t]||"";return[t,e.get(i).value||n]})).forEach((([e,i])=>{("borderColor"!==e&&"borderWidth"!==e||"none"!==t.value)&&this.view.set(e,i)})),this._isReady=!0}_showView(){const e=this.editor;this.view||(this.view=this._createPropertiesView()),this.listenTo(e.ui,"update",(()=>{this._updateView()})),this._fillViewFormFromCommandValues(),this._balloon.add({view:this.view,position:aT(e)}),this._undoStepBatch=e.model.createBatch(),this.view.focus()}_hideView(){const e=this.editor;this.stopListening(e.ui,"update"),this._isReady=!1,this.view.saveButtonView.focus(),this._balloon.remove(this.view),this.editor.editing.view.focus()}_updateView(){const e=this.editor;tT(e.editing.view.document.selection)?this._isViewVisible&&oT(e,"cell"):this._hideView()}get _isViewVisible(){return!!this.view&&this._balloon.visibleView===this.view}get _isViewInBalloon(){return!!this.view&&this._balloon.hasView(this.view)}_getPropertyChangeCallback(e){return(t,i,n)=>{this._isReady&&this.editor.execute(e,{value:n,batch:this._undoStepBatch})}}_getValidatedPropertyChangeCallback(e){const{commandName:t,viewField:i,validator:n,errorText:s}=e,o=zs((()=>{i.errorText=s}),500);return(e,s,r)=>{o.cancel(),this._isReady&&(n(r)?(this.editor.execute(t,{value:r,batch:this._undoStepBatch}),i.errorText=null):o())}}}class gT extends so{constructor(e,t,i){super(e),this.attributeName=t,this._defaultValue=i}refresh(){const e=this.editor,t=this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(e.model.document.selection);this.isEnabled=!!t.length,this.value=this._getSingleValue(t)}execute(e={}){const{value:t,batch:i}=e,n=this.editor.model,s=this.editor.plugins.get("TableUtils").getSelectionAffectedTableCells(n.document.selection),o=this._getValueToSet(t);n.enqueueChange(i,(e=>{o?s.forEach((t=>e.setAttribute(this.attributeName,o,t))):s.forEach((t=>e.removeAttribute(this.attributeName,t)))}))}_getAttribute(e){if(!e)return;const t=e.getAttribute(this.attributeName);return t!==this._defaultValue?t:void 0}_getValueToSet(e){if(e!==this._defaultValue)return e}_getSingleValue(e){const t=this._getAttribute(e[0]);return e.every((e=>this._getAttribute(e)===t))?t:void 0}}class fT extends gT{constructor(e,t){super(e,"tableCellWidth",t)}_getValueToSet(e){if((e=dT(e,"px"))!==this._defaultValue)return e}}class pT extends io{static get pluginName(){return"TableCellWidthEditing"}static get requires(){return[fx]}init(){const e=this.editor,t=hT(e.config.get("table.tableCellProperties.defaultProperties"));lA(e.model.schema,e.conversion,{modelAttribute:"tableCellWidth",styleName:"width",defaultValue:t.width}),e.commands.add("tableCellWidth",new fT(e,t.width))}}class bT extends gT{constructor(e,t){super(e,"tableCellPadding",t)}_getAttribute(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}_getValueToSet(e){const t=dT(e,"px");if(t!==this._defaultValue)return t}}class wT extends gT{constructor(e,t){super(e,"tableCellHeight",t)}_getValueToSet(e){const t=dT(e,"px");if(t!==this._defaultValue)return t}}class vT extends gT{constructor(e,t){super(e,"tableCellBackgroundColor",t)}}class _T extends gT{constructor(e,t){super(e,"tableCellVerticalAlignment",t)}}class yT extends gT{constructor(e,t){super(e,"tableCellHorizontalAlignment",t)}}class kT extends gT{constructor(e,t){super(e,"tableCellBorderStyle",t)}_getAttribute(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}}class CT extends gT{constructor(e,t){super(e,"tableCellBorderColor",t)}_getAttribute(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}}class AT extends gT{constructor(e,t){super(e,"tableCellBorderWidth",t)}_getAttribute(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}_getValueToSet(e){const t=dT(e,"px");if(t!==this._defaultValue)return t}}const xT=/^(top|middle|bottom)$/,TT=/^(left|center|right|justify)$/;class ET extends io{static get pluginName(){return"TableCellPropertiesEditing"}static get requires(){return[fx,pT]}init(){const e=this.editor,t=e.model.schema,i=e.conversion;e.config.define("table.tableCellProperties.defaultProperties",{});const n=hT(e.config.get("table.tableCellProperties.defaultProperties"),{includeVerticalAlignmentProperty:!0,includeHorizontalAlignmentProperty:!0,includePaddingProperty:!0,isRightToLeftContent:"rtl"===e.locale.contentLanguageDirection});e.data.addStyleProcessorRules(Eh),function(e,t,i){const n={width:"tableCellBorderWidth",color:"tableCellBorderColor",style:"tableCellBorderStyle"};e.extend("tableCell",{allowAttributes:Object.values(n)}),tA(t,"td",n,i),tA(t,"th",n,i),iA(t,{modelElement:"tableCell",modelAttribute:n.style,styleName:"border-style"}),iA(t,{modelElement:"tableCell",modelAttribute:n.color,styleName:"border-color"}),iA(t,{modelElement:"tableCell",modelAttribute:n.width,styleName:"border-width"})}(t,i,{color:n.borderColor,style:n.borderStyle,width:n.borderWidth}),e.commands.add("tableCellBorderStyle",new kT(e,n.borderStyle)),e.commands.add("tableCellBorderColor",new CT(e,n.borderColor)),e.commands.add("tableCellBorderWidth",new AT(e,n.borderWidth)),lA(t,i,{modelAttribute:"tableCellHeight",styleName:"height",defaultValue:n.height}),e.commands.add("tableCellHeight",new wT(e,n.height)),e.data.addStyleProcessorRules(Fh),lA(t,i,{modelAttribute:"tableCellPadding",styleName:"padding",reduceBoxSides:!0,defaultValue:n.padding}),e.commands.add("tableCellPadding",new bT(e,n.padding)),e.data.addStyleProcessorRules(Th),lA(t,i,{modelAttribute:"tableCellBackgroundColor",styleName:"background-color",defaultValue:n.backgroundColor}),e.commands.add("tableCellBackgroundColor",new vT(e,n.backgroundColor)),function(e,t,i){e.extend("tableCell",{allowAttributes:["tableCellHorizontalAlignment"]}),t.for("downcast").attributeToAttribute({model:{name:"tableCell",key:"tableCellHorizontalAlignment"},view:e=>({key:"style",value:{"text-align":e}})}),t.for("upcast").attributeToAttribute({view:{name:/^(td|th)$/,styles:{"text-align":TT}},model:{key:"tableCellHorizontalAlignment",value:e=>{const t=e.getStyle("text-align");return t===i?null:t}}}).attributeToAttribute({view:{name:/^(td|th)$/,attributes:{align:TT}},model:{key:"tableCellHorizontalAlignment",value:e=>{const t=e.getAttribute("align");return t===i?null:t}}})}(t,i,n.horizontalAlignment),e.commands.add("tableCellHorizontalAlignment",new yT(e,n.horizontalAlignment)),function(e,t,i){e.extend("tableCell",{allowAttributes:["tableCellVerticalAlignment"]}),t.for("downcast").attributeToAttribute({model:{name:"tableCell",key:"tableCellVerticalAlignment"},view:e=>({key:"style",value:{"vertical-align":e}})}),t.for("upcast").attributeToAttribute({view:{name:/^(td|th)$/,styles:{"vertical-align":xT}},model:{key:"tableCellVerticalAlignment",value:e=>{const t=e.getStyle("vertical-align");return t===i?null:t}}}).attributeToAttribute({view:{name:/^(td|th)$/,attributes:{valign:xT}},model:{key:"tableCellVerticalAlignment",value:e=>{const t=e.getAttribute("valign");return t===i?null:t}}})}(t,i,n.verticalAlignment),e.commands.add("tableCellVerticalAlignment",new _T(e,n.verticalAlignment))}}class ST extends so{refresh(){this.isEnabled=!0}execute(e={}){const{model:t,plugins:i}=this.editor;let{table:n=t.document.selection.getSelectedElement(),columnWidths:s,tableWidth:o}=e;s&&(s=Array.isArray(s)?s:s.split(",")),t.change((e=>{o?e.setAttribute("tableWidth",o,n):e.removeAttribute("tableWidth",n);const t=i.get("TableColumnResizeEditing").getColumnGroupElement(n);if(!s&&!t)return;if(!s)return e.remove(t);const r=jA(s);if(t)Array.from(t.getChildren()).forEach(((t,i)=>e.setAttribute("columnWidth",r[i],t)));else{const t=e.createElement("tableColumnGroup");r.forEach((i=>e.appendElement("tableColumn",{columnWidth:i},t))),e.append(t,n)}}))}}class PT extends io{static get requires(){return[fx,QA]}static get pluginName(){return"TableColumnResizeEditing"}constructor(e){super(e),this._isResizingActive=!1,this.set("_isResizingAllowed",!0),this._resizingData=null,this._domEmitter=new(Fi()),this._tableUtilsPlugin=e.plugins.get("TableUtils"),this.on("change:_isResizingAllowed",((t,i,n)=>{const s=n?"removeClass":"addClass";e.editing.view.change((t=>{for(const i of e.editing.view.document.roots)t[s]("ck-column-resize_disabled",e.editing.view.document.getRoot(i.rootName))}))}))}init(){this._extendSchema(),this._registerPostFixer(),this._registerConverters(),this._registerResizingListeners(),this._registerResizerInserter();const e=this.editor,t=e.plugins.get("TableColumnResize");e.plugins.get("TableEditing").registerAdditionalSlot({filter:e=>e.is("element","tableColumnGroup"),positionOffset:0});const i=new ST(e);e.commands.add("resizeTableWidth",i),e.commands.add("resizeColumnWidths",i),this.bind("_isResizingAllowed").to(e,"isReadOnly",t,"isEnabled",i,"isEnabled",((e,t,i)=>!e&&t&&i))}destroy(){this._domEmitter.stopListening(),super.destroy()}getColumnGroupElement(e){return KA(e)}getTableColumnElements(e){return JA(e)}getTableColumnsWidths(e){return function(e){return JA(e).map((e=>e.getAttribute("columnWidth")))}(e)}_extendSchema(){this.editor.model.schema.extend("table",{allowAttributes:["tableWidth"]}),this.editor.model.schema.register("tableColumnGroup",{allowIn:"table",isLimit:!0}),this.editor.model.schema.register("tableColumn",{allowIn:"tableColumnGroup",allowAttributes:["columnWidth","colSpan"],isLimit:!0})}_registerPostFixer(){const e=this.editor.model;function t(e,t,i){const n=i._tableUtilsPlugin.getColumns(t);if(0==n-e.length)return e;const s=e.map((e=>Number(e.replace("%","")))),o=function(e,t){const i=new Set;for(const n of e.getChanges())if("insert"==n.type&&n.position.nodeAfter&&"tableCell"==n.position.nodeAfter.name&&n.position.nodeAfter.getAncestors().includes(t))i.add(n.position.nodeAfter);else if("remove"==n.type){const e=n.position.nodeBefore||n.position.nodeAfter;"tableCell"==e.name&&e.getAncestors().includes(t)&&i.add(e)}return i}(i.editor.model.document.differ,t);for(const e of o){const o=n-s.length;if(0===o)continue;const c=o>0,d=i._tableUtilsPlugin.getCellLocation(e).column;if(c){const e=(l=(r=t,a=i.editor,4e3/zA(r,a)),Array(o).fill(l));s.splice(d,0,...e)}else{const e=s.splice(d,Math.abs(o));s[d]+=UA(e)}}var r,a,l;return s.map((e=>e+"%"))}e.document.registerPostFixer((i=>{let n=!1;for(const s of function(e){const t=new Set;for(const i of e.document.differ.getChanges()){let n=null;switch(i.type){case"insert":n=["table","tableRow","tableCell"].includes(i.name)?i.position:null;break;case"remove":n=["tableRow","tableCell"].includes(i.name)?i.position:null;break;case"attribute":i.range.start.nodeAfter&&(n=["table","tableRow","tableCell"].includes(i.range.start.nodeAfter.name)?i.range.start:null)}if(!n)continue;const s=n.nodeAfter&&n.nodeAfter.is("element","table")?n.nodeAfter:n.findAncestor("table");for(const i of e.createRangeOn(s).getItems())i.is("element","table")&&KA(i)&&t.add(i)}return t}(e)){const e=this.getColumnGroupElement(s),o=this.getTableColumnElements(e),r=this.getTableColumnsWidths(e);let a=jA(r);a=t(a,s,this),Gc(r,a)||(GA(o,e,a,i),n=!0)}return n}))}_registerConverters(){const e=this.editor.conversion;var t;e.for("upcast").attributeToAttribute({view:{name:"figure",key:"style",value:{width:/[\s\S]+/}},model:{name:"table",key:"tableWidth",value:e=>e.getStyle("width")}}),e.for("downcast").attributeToAttribute({model:{name:"table",key:"tableWidth"},view:e=>({name:"figure",key:"style",value:{width:e}})}),e.elementToElement({model:"tableColumnGroup",view:"colgroup"}),e.elementToElement({model:"tableColumn",view:"col"}),e.for("downcast").add((e=>e.on("insert:table",((e,t,i)=>{const n=i.writer,s=t.item,o=i.mapper.toViewElement(s),r=o.is("element","table")?o:Array.from(o.getChildren()).find((e=>e.is("element","table")));KA(s)?n.addClass("ck-table-resized",r):n.removeClass("ck-table-resized",r)}),{priority:"low"}))),e.for("upcast").add((t=this._tableUtilsPlugin,e=>e.on("element:colgroup",((e,i,n)=>{const s=i.modelCursor.findAncestor("table"),o=KA(s);if(!o)return;const r=JA(o),a=t.getColumns(s);let l=(c=o,d=n.writer,JA(c).reduce(((e,t)=>{const i=t.getAttribute("columnWidth"),n=t.getAttribute("colSpan");if(!n)return e.push(i),e;for(let t=0;tl[t]||"auto")),(l.length!=r.length||l.includes("auto"))&&GA(r,o,jA(l),n.writer)}),{priority:"low"}))),e.for("upcast").attributeToAttribute({view:{name:"col",styles:{width:/.*/}},model:{key:"columnWidth",value:e=>{const t=e.getStyle("width");return t&&(t.endsWith("%")||t.endsWith("pt"))?t:"auto"}}}),e.for("upcast").attributeToAttribute({view:{name:"col",key:"span"},model:"colSpan"}),e.for("downcast").attributeToAttribute({model:{name:"tableColumn",key:"columnWidth"},view:e=>({key:"style",value:{width:e}})})}_registerResizingListeners(){const e=this.editor.editing.view;e.addObserver(Tx),e.document.on("mousedown",this._onMouseDownHandler.bind(this),{priority:"high"}),this._domEmitter.listenTo($i.window.document,"mousemove",am(this._onMouseMoveHandler.bind(this),50)),this._domEmitter.listenTo($i.window.document,"mouseup",this._onMouseUpHandler.bind(this))}_onMouseDownHandler(e,t){const i=t.target;if(!i.hasClass("ck-table-column-resizer"))return;if(!this._isResizingAllowed)return;const n=this.editor,s=n.editing.mapper.toModelElement(i.findAncestor("figure"));if(!n.model.canEditAt(s))return;t.preventDefault(),e.stop();const o=function(e,t,i){const n=Array(t.getColumns(e)),s=new hA(e);for(const e of s){const t=i.editing.mapper.toViewElement(e.cell),s=qA(i.editing.view.domConverter.mapViewToDom(t));(!n[e.column]||se.is("element","colgroup")))||a.change((e=>{!function(e,t,i){const n=e.createContainerElement("colgroup");for(let i=0;ifunction(e,t,i){const n=i.widths.viewFigureWidth/i.widths.viewFigureParentWidth;e.addClass("ck-table-resized",t),e.addClass("ck-table-column-resizer__active",i.elements.viewResizer),e.setStyle("width",`${WA(100*n)}%`,t.findAncestor("figure"))}(e,r,this._resizingData)))}_onMouseMoveHandler(e,t){if(!this._isResizingActive)return;if(!this._isResizingAllowed)return void this._onMouseUpHandler();const{columnPosition:i,flags:{isRightEdge:n,isTableCentered:s,isLtrContent:o},elements:{viewFigure:r,viewLeftColumn:a,viewRightColumn:l},widths:{viewFigureParentWidth:c,tableWidth:d,leftColumnWidth:h,rightColumnWidth:u}}=this._resizingData,m=40-h,g=n?c-d:u-40,f=(o?1:-1)*(n&&s?2:1),p=(b=(t.clientX-i)*f,w=Math.min(m,0),v=Math.max(g,0),WA(b<=w?w:b>=v?v:b));var b,w,v;0!==p&&this.editor.editing.view.change((e=>{const t=WA(100*(h+p)/d);if(e.setStyle("width",`${t}%`,a),n){const t=WA(100*(d+p)/c);e.setStyle("width",`${t}%`,r)}else{const t=WA(100*(u-p)/d);e.setStyle("width",`${t}%`,l)}}))}_onMouseUpHandler(){if(!this._isResizingActive)return;const{viewResizer:e,modelTable:t,viewFigure:i,viewColgroup:n}=this._resizingData.elements,s=this.editor,o=s.editing.view,r=this.getColumnGroupElement(t),a=Array.from(n.getChildren()).filter((e=>e.is("view:element"))),l=r?this.getTableColumnsWidths(r):null,c=a.map((e=>e.getStyle("width"))),d=!Gc(l,c),h=t.getAttribute("tableWidth"),u=i.getStyle("width"),m=h!==u;(d||m)&&(this._isResizingAllowed?s.execute("resizeTableWidth",{table:t,tableWidth:`${WA(u)}%`,columnWidths:c}):o.change((e=>{if(l)for(const t of a)e.setStyle("width",l.shift(),t);else e.remove(n);m&&(h?e.setStyle("width",h,i):e.removeStyle("width",i)),l||h||e.removeClass("ck-table-resized",[...i.getChildren()].find((e=>"table"===e.name)))}))),o.change((t=>{t.removeClass("ck-table-column-resizer__active",e)})),this._isResizingActive=!1,this._resizingData=null}_getResizingData(e,t){const i=this.editor,n=e.domEvent.clientX,s=e.target,o=s.findAncestor("td")||s.findAncestor("th"),r=i.editing.mapper.toModelElement(o),a=r.findAncestor("table"),l=function(e,t){const i=t.getCellLocation(e).column;return{leftEdge:i,rightEdge:i+(e.getAttribute("colspan")||1)-1}}(r,this._tableUtilsPlugin).rightEdge,c=l===this._tableUtilsPlugin.getColumns(a)-1,d=!a.hasAttribute("tableAlignment"),h="rtl"!==i.locale.contentLanguageDirection,u=o.findAncestor("table"),m=u.findAncestor("figure"),g=[...u.getChildren()].find((e=>e.is("element","colgroup"))),f=g.getChild(l),p=c?void 0:g.getChild(l+1);return{columnPosition:n,flags:{isRightEdge:c,isTableCentered:d,isLtrContent:h},elements:{viewResizer:s,modelTable:a,viewFigure:m,viewColgroup:g,viewLeftColumn:f,viewRightColumn:p},widths:{viewFigureParentWidth:$A(i.editing.view.domConverter.mapViewToDom(m.parent)),viewFigureWidth:$A(i.editing.view.domConverter.mapViewToDom(m)),tableWidth:zA(a,i),leftColumnWidth:t[l],rightColumnWidth:c?void 0:t[l+1]}}}_registerResizerInserter(){this.editor.conversion.for("editingDowncast").add((e=>{e.on("insert:tableCell",((e,t,i)=>{const n=t.item,s=i.mapper.toViewElement(n),o=i.writer;o.insert(o.createPositionAt(s,"end"),o.createUIElement("div",{class:"ck-table-column-resizer"}))}),{priority:"lowest"})}))}}class IT extends so{constructor(e,t,i){super(e),this.attributeName=t,this._defaultValue=i}refresh(){const e=this.editor.model.document.selection.getFirstPosition().findAncestor("table");this.isEnabled=!!e,this.value=this._getValue(e)}execute(e={}){const t=this.editor.model,i=t.document.selection,{value:n,batch:s}=e,o=i.getFirstPosition().findAncestor("table"),r=this._getValueToSet(n);t.enqueueChange(s,(e=>{r?e.setAttribute(this.attributeName,r,o):e.removeAttribute(this.attributeName,o)}))}_getValue(e){if(!e)return;const t=e.getAttribute(this.attributeName);return t!==this._defaultValue?t:void 0}_getValueToSet(e){if(e!==this._defaultValue)return e}}class VT extends IT{constructor(e,t){super(e,"tableBackgroundColor",t)}}class RT extends IT{constructor(e,t){super(e,"tableBorderColor",t)}_getValue(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}}class LT extends IT{constructor(e,t){super(e,"tableBorderStyle",t)}_getValue(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}}class OT extends IT{constructor(e,t){super(e,"tableBorderWidth",t)}_getValue(e){if(!e)return;const t=cT(e.getAttribute(this.attributeName));return t!==this._defaultValue?t:void 0}_getValueToSet(e){const t=dT(e,"px");if(t!==this._defaultValue)return t}}class BT extends IT{constructor(e,t){super(e,"tableWidth",t)}_getValueToSet(e){if((e=dT(e,"px"))!==this._defaultValue)return e}}class MT extends IT{constructor(e,t){super(e,"tableHeight",t)}_getValueToSet(e){if((e=dT(e,"px"))!==this._defaultValue)return e}}class NT extends IT{constructor(e,t){super(e,"tableAlignment",t)}}const FT=/^(left|center|right)$/,DT=/^(left|none|right)$/;class zT extends io{static get pluginName(){return"TablePropertiesEditing"}static get requires(){return[fx]}init(){const e=this.editor,t=e.model.schema,i=e.conversion;e.config.define("table.tableProperties.defaultProperties",{});const n=hT(e.config.get("table.tableProperties.defaultProperties"),{includeAlignmentProperty:!0});e.data.addStyleProcessorRules(Eh),function(e,t,i){const n={width:"tableBorderWidth",color:"tableBorderColor",style:"tableBorderStyle"};e.extend("table",{allowAttributes:Object.values(n)}),tA(t,"table",n,i),nA(t,{modelAttribute:n.color,styleName:"border-color"}),nA(t,{modelAttribute:n.style,styleName:"border-style"}),nA(t,{modelAttribute:n.width,styleName:"border-width"})}(t,i,{color:n.borderColor,style:n.borderStyle,width:n.borderWidth}),e.commands.add("tableBorderColor",new RT(e,n.borderColor)),e.commands.add("tableBorderStyle",new LT(e,n.borderStyle)),e.commands.add("tableBorderWidth",new OT(e,n.borderWidth)),function(e,t,i){e.extend("table",{allowAttributes:["tableAlignment"]}),t.for("downcast").attributeToAttribute({model:{name:"table",key:"tableAlignment"},view:e=>({key:"style",value:{float:"center"===e?"none":e}}),converterPriority:"high"}),t.for("upcast").attributeToAttribute({view:{name:/^(table|figure)$/,styles:{float:DT}},model:{key:"tableAlignment",value:e=>{let t=e.getStyle("float");return"none"===t&&(t="center"),t===i?null:t}}}).attributeToAttribute({view:{attributes:{align:FT}},model:{name:"table",key:"tableAlignment",value:e=>{const t=e.getAttribute("align");return t===i?null:t}}})}(t,i,n.alignment),e.commands.add("tableAlignment",new NT(e,n.alignment)),HT(t,i,{modelAttribute:"tableWidth",styleName:"width",defaultValue:n.width}),e.commands.add("tableWidth",new BT(e,n.width)),HT(t,i,{modelAttribute:"tableHeight",styleName:"height",defaultValue:n.height}),e.commands.add("tableHeight",new MT(e,n.height)),e.data.addStyleProcessorRules(Th),function(e,t,i){const{modelAttribute:n}=i;e.extend("table",{allowAttributes:[n]}),eA(t,{viewElement:"table",...i}),nA(t,i)}(t,i,{modelAttribute:"tableBackgroundColor",styleName:"background-color",defaultValue:n.backgroundColor}),e.commands.add("tableBackgroundColor",new VT(e,n.backgroundColor))}}function HT(e,t,i){const{modelAttribute:n}=i;e.extend("table",{allowAttributes:[n]}),eA(t,{viewElement:/^(table|figure)$/,shouldUpcast:e=>!("table"==e.name&&"figure"==e.parent.name),...i}),iA(t,{modelElement:"table",...i})}const $T={left:Kh.objectLeft,center:Kh.objectCenter,right:Kh.objectRight};class WT extends Un{constructor(e,t){super(e),this.set({borderStyle:"",borderWidth:"",borderColor:"",backgroundColor:"",width:"",height:"",alignment:""}),this.options=t;const{borderStyleDropdown:i,borderWidthInput:n,borderColorInput:s,borderRowLabel:o}=this._createBorderFields(),{backgroundRowLabel:r,backgroundInput:a}=this._createBackgroundFields(),{widthInput:l,operatorLabel:c,heightInput:d,dimensionsLabel:h}=this._createDimensionFields(),{alignmentToolbar:u,alignmentLabel:m}=this._createAlignmentFields();this.focusTracker=new Bn,this.keystrokes=new Mn,this.children=this.createCollection(),this.borderStyleDropdown=i,this.borderWidthInput=n,this.borderColorInput=s,this.backgroundInput=a,this.widthInput=l,this.heightInput=d,this.alignmentToolbar=u;const{saveButtonView:g,cancelButtonView:f}=this._createActionButtons();this.saveButtonView=g,this.cancelButtonView=f,this._focusables=new Wn,this._focusCycler=new Zs({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.children.add(new wm(e,{label:this.t("Table properties")})),this.children.add(new Qx(e,{labelView:o,children:[o,i,s,n],class:"ck-table-form__border-row"})),this.children.add(new Qx(e,{labelView:r,children:[r,a],class:"ck-table-form__background-row"})),this.children.add(new Qx(e,{children:[new Qx(e,{labelView:h,children:[h,l,c,d],class:"ck-table-form__dimensions-row"}),new Qx(e,{labelView:m,children:[m,u],class:"ck-table-properties-form__alignment-row"})]})),this.children.add(new Qx(e,{children:[this.saveButtonView,this.cancelButtonView],class:"ck-table-form__action-row"})),this.setTemplate({tag:"form",attributes:{class:["ck","ck-form","ck-table-form","ck-table-properties-form"],tabindex:"-1"},children:this.children})}render(){super.render(),s({view:this}),[this.borderColorInput,this.backgroundInput].forEach((e=>{e.fieldView.focusCycler.on("forwardCycle",(e=>{this._focusCycler.focusNext(),e.stop()})),e.fieldView.focusCycler.on("backwardCycle",(e=>{this._focusCycler.focusPrevious(),e.stop()}))})),[this.borderStyleDropdown,this.borderColorInput,this.borderWidthInput,this.backgroundInput,this.widthInput,this.heightInput,this.alignmentToolbar,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this._focusCycler.focusFirst()}_createBorderFields(){const e=this.options.defaultTableProperties,t={style:e.borderStyle,width:e.borderWidth,color:e.borderColor},i=Kx({colorConfig:this.options.borderColors,columns:5,defaultColorValue:t.color,colorPickerConfig:this.options.colorPickerConfig}),n=this.locale,s=this.t,o=s("Style"),r=new Hs(n);r.text=s("Border");const a=Dx(s),l=new $s(n,fu);l.set({label:o,class:"ck-table-form__border-style"}),l.fieldView.buttonView.set({ariaLabel:o,ariaLabelledBy:void 0,isOn:!1,withText:!0,tooltip:o}),l.fieldView.buttonView.bind("label").to(this,"borderStyle",(e=>a[e||"none"])),l.fieldView.on("execute",(e=>{this.borderStyle=e.source._borderStyleValue})),l.bind("isEmpty").to(this,"borderStyle",(e=>!e)),cu(l.fieldView,jx(this,t.style),{role:"menu",ariaLabel:o});const c=new $s(n,mu);c.set({label:s("Width"),class:"ck-table-form__border-width"}),c.fieldView.bind("value").to(this,"borderWidth"),c.bind("isEnabled").to(this,"borderStyle",UT),c.fieldView.on("input",(()=>{this.borderWidth=c.fieldView.element.value}));const d=new $s(n,i);return d.set({label:s("Color"),class:"ck-table-form__border-color"}),d.fieldView.bind("value").to(this,"borderColor"),d.bind("isEnabled").to(this,"borderStyle",UT),d.fieldView.on("input",(()=>{this.borderColor=d.fieldView.value})),this.on("change:borderStyle",((e,i,n,s)=>{UT(n)||(this.borderColor="",this.borderWidth=""),UT(s)||(this.borderColor=t.color,this.borderWidth=t.width)})),{borderRowLabel:r,borderStyleDropdown:l,borderColorInput:d,borderWidthInput:c}}_createBackgroundFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Background");const n=Kx({colorConfig:this.options.backgroundColors,columns:5,defaultColorValue:this.options.defaultTableProperties.backgroundColor,colorPickerConfig:this.options.colorPickerConfig}),s=new $s(e,n);return s.set({label:t("Color"),class:"ck-table-properties-form__background"}),s.fieldView.bind("value").to(this,"backgroundColor"),s.fieldView.on("input",(()=>{this.backgroundColor=s.fieldView.value})),{backgroundRowLabel:i,backgroundInput:s}}_createDimensionFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Dimensions");const n=new $s(e,mu);n.set({label:t("Width"),class:"ck-table-form__dimensions-row__width"}),n.fieldView.bind("value").to(this,"width"),n.fieldView.on("input",(()=>{this.width=n.fieldView.element.value}));const s=new Un(e);s.setTemplate({tag:"span",attributes:{class:["ck-table-form__dimension-operator"]},children:[{text:"×"}]});const o=new $s(e,mu);return o.set({label:t("Height"),class:"ck-table-form__dimensions-row__height"}),o.fieldView.bind("value").to(this,"height"),o.fieldView.on("input",(()=>{this.height=o.fieldView.element.value})),{dimensionsLabel:i,widthInput:n,operatorLabel:s,heightInput:o}}_createAlignmentFields(){const e=this.locale,t=this.t,i=new Hs(e);i.text=t("Alignment");const n=new Zh(e);return n.set({isCompact:!0,ariaLabel:t("Table alignment toolbar")}),qx({view:this,icons:$T,toolbar:n,labels:this._alignmentLabels,propertyName:"alignment",defaultValue:this.options.defaultTableProperties.alignment}),{alignmentLabel:i,alignmentToolbar:n}}_createActionButtons(){const e=this.locale,t=this.t,i=new fs(e),n=new fs(e),s=[this.borderWidthInput,this.borderColorInput,this.backgroundInput,this.widthInput,this.heightInput];return i.set({label:t("Save"),icon:Kh.check,class:"ck-button-save",type:"submit",withText:!0}),i.bind("isEnabled").toMany(s,"errorText",((...e)=>e.every((e=>!e)))),n.set({label:t("Cancel"),icon:Kh.cancel,class:"ck-button-cancel",withText:!0}),n.delegate("execute").to(this,"cancel"),{saveButtonView:i,cancelButtonView:n}}get _alignmentLabels(){const e=this.locale,t=this.t,i=t("Align table to the left"),n=t("Center table"),s=t("Align table to the right");return"rtl"===e.uiLanguageDirection?{right:s,center:n,left:i}:{left:i,center:n,right:s}}}function UT(e){return"none"!==e}const jT={borderStyle:"tableBorderStyle",borderColor:"tableBorderColor",borderWidth:"tableBorderWidth",backgroundColor:"tableBackgroundColor",width:"tableWidth",height:"tableHeight",alignment:"tableAlignment"};class qT extends io{static get requires(){return[Cm]}static get pluginName(){return"TablePropertiesUI"}constructor(e){super(e),this.view=null,e.config.define("table.tableProperties",{borderColors:Gx,backgroundColors:Gx})}init(){const e=this.editor,t=e.t;this._defaultTableProperties=hT(e.config.get("table.tableProperties.defaultProperties"),{includeAlignmentProperty:!0}),this._balloon=e.plugins.get(Cm),e.ui.componentFactory.add("tableProperties",(i=>{const n=new fs(i);n.set({label:t("Table properties"),icon:'',tooltip:!0}),this.listenTo(n,"execute",(()=>this._showView()));const s=Object.values(jT).map((t=>e.commands.get(t)));return n.bind("isEnabled").toMany(s,"isEnabled",((...e)=>e.some((e=>e)))),n}))}destroy(){super.destroy(),this.view&&this.view.destroy()}_createPropertiesView(){const t=this.editor,i=t.config.get("table.tableProperties"),n=ws(i.borderColors),s=bs(t.locale,n),o=ws(i.backgroundColors),r=bs(t.locale,o),a=!1!==i.colorPicker,l=new WT(t.locale,{borderColors:s,backgroundColors:r,defaultTableProperties:this._defaultTableProperties,colorPickerConfig:!!a&&(i.colorPicker||{})}),c=t.t;l.render(),this.listenTo(l,"submit",(()=>{this._hideView()})),this.listenTo(l,"cancel",(()=>{this._undoStepBatch.operations.length&&t.execute("undo",this._undoStepBatch),this._hideView()})),l.keystrokes.set("Esc",((e,t)=>{this._hideView(),t()})),e({emitter:l,activator:()=>this._isViewInBalloon,contextElements:[this._balloon.view.element],callback:()=>this._hideView()});const d=zx(c),h=Hx(c);return l.on("change:borderStyle",this._getPropertyChangeCallback("tableBorderStyle")),l.on("change:borderColor",this._getValidatedPropertyChangeCallback({viewField:l.borderColorInput,commandName:"tableBorderColor",errorText:d,validator:$x})),l.on("change:borderWidth",this._getValidatedPropertyChangeCallback({viewField:l.borderWidthInput,commandName:"tableBorderWidth",errorText:h,validator:Ux})),l.on("change:backgroundColor",this._getValidatedPropertyChangeCallback({viewField:l.backgroundInput,commandName:"tableBackgroundColor",errorText:d,validator:$x})),l.on("change:width",this._getValidatedPropertyChangeCallback({viewField:l.widthInput,commandName:"tableWidth",errorText:h,validator:Wx})),l.on("change:height",this._getValidatedPropertyChangeCallback({viewField:l.heightInput,commandName:"tableHeight",errorText:h,validator:Wx})),l.on("change:alignment",this._getPropertyChangeCallback("tableAlignment")),l}_fillViewFormFromCommandValues(){const e=this.editor.commands,t=e.get("tableBorderStyle");Object.entries(jT).map((([t,i])=>{const n=t,s=this._defaultTableProperties[n]||"";return[n,e.get(i).value||s]})).forEach((([e,i])=>{("borderColor"!==e&&"borderWidth"!==e||"none"!==t.value)&&this.view.set(e,i)})),this._isReady=!0}_showView(){const e=this.editor;this.view||(this.view=this._createPropertiesView()),this.listenTo(e.ui,"update",(()=>{this._updateView()})),this._fillViewFormFromCommandValues(),this._balloon.add({view:this.view,position:rT(e)}),this._undoStepBatch=e.model.createBatch(),this.view.focus()}_hideView(){const e=this.editor;this.stopListening(e.ui,"update"),this._isReady=!1,this.view.saveButtonView.focus(),this._balloon.remove(this.view),this.editor.editing.view.focus()}_updateView(){const e=this.editor;tT(e.editing.view.document.selection)?this._isViewVisible&&oT(e,"table"):this._hideView()}get _isViewVisible(){return!!this.view&&this._balloon.visibleView===this.view}get _isViewInBalloon(){return!!this.view&&this._balloon.hasView(this.view)}_getPropertyChangeCallback(e){return(t,i,n)=>{this._isReady&&this.editor.execute(e,{value:n,batch:this._undoStepBatch})}}_getValidatedPropertyChangeCallback(e){const{commandName:t,viewField:i,validator:n,errorText:s}=e,o=zs((()=>{i.errorText=s}),500);return(e,s,r)=>{o.cancel(),this._isReady&&(n(r)?(this.editor.execute(t,{value:r,batch:this._undoStepBatch}),i.errorText=null):o())}}}const GT="todoListChecked";class KT extends so{constructor(e){super(e),this._selectedElements=[],this.on("execute",(()=>{this.refresh()}),{priority:"highest"})}refresh(){this._selectedElements=this._getSelectedItems(),this.value=this._selectedElements.every((e=>!!e.getAttribute(GT))),this.isEnabled=!!this._selectedElements.length}_getSelectedItems(){const e=this.editor.model,t=e.schema,i=e.document.selection.getFirstRange(),n=i.start.parent,s=[];t.checkAttribute(n,GT)&&s.push(n);for(const e of i.getItems())t.checkAttribute(e,GT)&&!s.includes(e)&&s.push(e);return s}execute(e={}){this.editor.model.change((t=>{for(const i of this._selectedElements)(void 0===e.forceValue?!this.value:e.forceValue)?t.setAttribute(GT,!0,i):t.removeAttribute(GT,i)}))}}const JT=(e,t,i)=>{const n=t.modelCursor,s=n.parent,o=t.viewItem;if("checkbox"!=o.getAttribute("type")||"listItem"!=s.name||!n.isAtStart)return;if(!i.consumable.consume(o,{name:!0}))return;const r=i.writer;r.setAttribute("listType","todo",s),t.viewItem.hasAttribute("checked")&&r.setAttribute("todoListChecked",!0,s),t.modelRange=r.createRange(n)};function QT(e){return(t,i)=>{const n=i.modelPosition,s=n.parent;if(!s.is("element","listItem")||"todo"!=s.getAttribute("listType"))return;const o=YT(i.mapper.toViewElement(s),e);o&&(i.viewPosition=i.mapper.findPositionIn(o,n.offset))}}function ZT(e,t,i,n){return t.createUIElement("label",{class:"todo-list__label",contenteditable:!1},(function(t){const s=me(document,"input",{type:"checkbox",tabindex:"-1"});i&&s.setAttribute("checked","checked"),s.addEventListener("change",(()=>n(e)));const o=this.toDomElement(t);return o.appendChild(s),o}))}function YT(e,t){const i=t.createRangeIn(e);for(const e of i)if(e.item.is("containerElement","span")&&e.item.hasClass("todo-list__label__description"))return e.item}const XT=Tn("Ctrl+Enter");class eE extends io{static get pluginName(){return"TodoListEditing"}static get requires(){return[Yy]}init(){const e=this.editor,{editing:t,data:i,model:n}=e;n.schema.extend("listItem",{allowAttributes:["todoListChecked"]}),n.schema.addAttributeCheck(((e,t)=>{const i=e.last;if("todoListChecked"==t&&"listItem"==i.name&&"todo"!=i.getAttribute("listType"))return!1})),e.commands.add("todoList",new yy(e,"todo"));const s=new KT(e);var o,r;e.commands.add("checkTodoList",s),e.commands.add("todoListCheck",s),i.downcastDispatcher.on("insert:listItem",function(e){return(t,i,n)=>{const s=n.consumable;if(!s.test(i.item,"insert")||!s.test(i.item,"attribute:listType")||!s.test(i.item,"attribute:listIndent"))return;if("todo"!=i.item.getAttribute("listType"))return;const o=i.item;s.consume(o,"insert"),s.consume(o,"attribute:listType"),s.consume(o,"attribute:listIndent"),s.consume(o,"attribute:todoListChecked");const r=n.writer,a=xy(o,n);r.addClass("todo-list",a.parent);const l=r.createContainerElement("label",{class:"todo-list__label"}),c=r.createEmptyElement("input",{type:"checkbox",disabled:"disabled"}),d=r.createContainerElement("span",{class:"todo-list__label__description"});o.getAttribute("todoListChecked")&&r.setAttribute("checked","checked",c),r.insert(r.createPositionAt(a,0),l),r.insert(r.createPositionAt(l,0),c),r.insert(r.createPositionAfter(c),d),Ty(o,a,n,e)}}(n),{priority:"high"}),i.upcastDispatcher.on("element:input",JT,{priority:"high"}),t.downcastDispatcher.on("insert:listItem",function(e,t){return(i,n,s)=>{const o=s.consumable;if(!o.test(n.item,"insert")||!o.test(n.item,"attribute:listType")||!o.test(n.item,"attribute:listIndent"))return;if("todo"!=n.item.getAttribute("listType"))return;const r=n.item;o.consume(r,"insert"),o.consume(r,"attribute:listType"),o.consume(r,"attribute:listIndent"),o.consume(r,"attribute:todoListChecked");const a=s.writer,l=xy(r,s),c=!!r.getAttribute("todoListChecked"),d=ZT(r,a,c,t),h=a.createContainerElement("span",{class:"todo-list__label__description"});a.addClass("todo-list",l.parent),a.insert(a.createPositionAt(l,0),d),a.insert(a.createPositionAfter(d),h),Ty(r,l,s,e)}}(n,(e=>this._handleCheckmarkChange(e))),{priority:"high"}),t.downcastDispatcher.on("attribute:listType:listItem",(o=e=>this._handleCheckmarkChange(e),r=t.view,(e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.mapper.toViewElement(t.item),s=i.writer,a=function(e,t){const i=t.createRangeIn(e);for(const e of i)if(e.item.is("uiElement","label"))return e.item}(n,r);if("todo"==t.attributeNewValue){const e=!!t.item.getAttribute("todoListChecked"),i=ZT(t.item,s,e,o),r=s.createContainerElement("span",{class:"todo-list__label__description"}),a=s.createRangeIn(n),l=Vy(n),c=Sy(a.start),d=l?s.createPositionBefore(l):a.end,h=s.createRange(c,d);s.addClass("todo-list",n.parent),s.move(h,s.createPositionAt(r,0)),s.insert(s.createPositionAt(n,0),i),s.insert(s.createPositionAfter(i),r)}else if("todo"==t.attributeOldValue){const e=YT(n,r);s.removeClass("todo-list",n.parent),s.remove(a),s.move(s.createRangeIn(e),s.createPositionBefore(e)),s.remove(e)}})),t.downcastDispatcher.on("attribute:todoListChecked:listItem",function(e){return(t,i,n)=>{if("todo"!=i.item.getAttribute("listType"))return;if(!n.consumable.consume(i.item,"attribute:todoListChecked"))return;const{mapper:s,writer:o}=n,r=!!i.item.getAttribute("todoListChecked"),a=s.toViewElement(i.item).getChild(0),l=ZT(i.item,o,r,e);o.insert(o.createPositionAfter(a),l),o.remove(a)}}((e=>this._handleCheckmarkChange(e)))),t.mapper.on("modelToViewPosition",QT(t.view)),i.mapper.on("modelToViewPosition",QT(t.view)),this.listenTo(t.view.document,"arrowKey",function(e,t){return(i,n)=>{if("left"!=Sn(n.keyCode,t.contentLanguageDirection))return;const s=e.schema,o=e.document.selection;if(!o.isCollapsed)return;const r=o.getFirstPosition(),a=r.parent;if("listItem"===a.name&&"todo"==a.getAttribute("listType")&&r.isAtStart){const t=s.getNearestSelectionRange(e.createPositionBefore(a),"backward");t&&e.change((e=>e.setSelection(t))),n.preventDefault(),n.stopPropagation(),i.stop()}}}(n,e.locale),{context:"li"}),this.listenTo(t.view.document,"keydown",((t,i)=>{xn(i)===XT&&(e.execute("checkTodoList"),t.stop())}),{priority:"high"});const a=new Set;this.listenTo(n,"applyOperation",((e,t)=>{const i=t[0];if("rename"==i.type&&"listItem"==i.oldName){const e=i.position.nodeAfter;e.hasAttribute("todoListChecked")&&a.add(e)}else if("changeAttribute"==i.type&&"listType"==i.key&&"todo"===i.oldValue)for(const e of i.range.getItems())e.hasAttribute("todoListChecked")&&"todo"!==e.getAttribute("listType")&&a.add(e)})),n.document.registerPostFixer((e=>{let t=!1;for(const i of a)e.removeAttribute("todoListChecked",i),t=!0;return a.clear(),t}))}_handleCheckmarkChange(e){const t=this.editor,i=t.model,n=Array.from(i.document.selection.getRanges());i.change((i=>{i.setSelection(e,"end"),t.execute("checkTodoList"),i.setSelection(n)}))}}class tE extends io{static get pluginName(){return"TodoListUI"}init(){const e=this.editor.t;Iy(this.editor,"todoList",e("To-do List"),'')}}const iE="underline";class nE extends io{static get pluginName(){return"UnderlineEditing"}init(){const e=this.editor;e.model.schema.extend("$text",{allowAttributes:iE}),e.model.schema.setAttributeProperties(iE,{isFormatting:!0,copyOnEnter:!0}),e.conversion.attributeToElement({model:iE,view:"u",upcastAlso:{styles:{"text-decoration":"underline"}}}),e.commands.add(iE,new jp(e,iE)),e.keystrokes.set("CTRL+U","underline")}}const sE="underline";class oE extends io{static get pluginName(){return"UnderlineUI"}init(){const e=this.editor,t=e.t;e.ui.componentFactory.add(sE,(i=>{const n=e.commands.get(sE),s=new fs(i);return s.set({label:t("Underline"),icon:'',keystroke:"CTRL+U",tooltip:!0,isToggleable:!0}),s.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(s,"execute",(()=>{e.execute(sE),e.editing.view.focus()})),s}))}}function rE(e){if(e.is("$text")||e.is("$textProxy"))return e.data;const t=e;let i="",n=null;for(const e of t.getChildren()){const t=rE(e);n&&n.is("element")&&(i+="\n"),i+=t,n=e}return i}class aE extends io{init(){this.buttons=[],(this.editor.config.get("simpleButton")||[]).forEach((e=>this.createToolbarButton(e))),this.editor.on("change:isReadOnly",(()=>{this.buttons.forEach((e=>{e._syncDisabledState&&(e.isEnabled=!this.editor.isReadOnly)}))}))}createToolbarButton(e){this.editor.ui.componentFactory.add(e.name,(t=>{const i=this.createButton(e.label,e.icon,t);return i.isEnabled=!0,i._syncDisabledState="boolean"!=typeof e.syncDisabledState||e.syncDisabledState,this.listenTo(i,"execute",(()=>{this.enableButton(i,!1),Promise.resolve(e.onClick(i)).then((()=>this.enableButton(i,!0))).catch((()=>this.enableButton(i,!0)))})),this.buttons.push(i),i}))}enableButton(e,t){e._syncDisabledState?e.isEnabled=!this.editor.isReadOnly&&t:e.isEnabled=t}createButton(e,t,i){const n=new fs(i);return n.set({label:e,icon:t,tooltip:!0}),n}}class lE extends Gm{}lE.builtinPlugins=[class extends io{static get requires(){return[tg,ng]}static get pluginName(){return"Alignment"}},class extends io{static get requires(){return[bg]}static get pluginName(){return"Autoformat"}afterInit(){this._addListAutoformats(),this._addBasicStylesAutoformats(),this._addHeadingAutoformats(),this._addBlockQuoteAutoformats(),this._addCodeBlockAutoformats(),this._addHorizontalLineAutoformats()}_addListAutoformats(){const e=this.editor.commands;e.get("bulletedList")&&Lg(this.editor,this,/^[*-]\s$/,"bulletedList"),e.get("numberedList")&&Lg(this.editor,this,/^1[.|)]\s$/,"numberedList"),e.get("todoList")&&Lg(this.editor,this,/^\[\s?\]\s$/,"todoList"),e.get("checkTodoList")&&Lg(this.editor,this,/^\[\s?x\s?\]\s$/,(()=>{this.editor.execute("todoList"),this.editor.execute("checkTodoList")}))}_addBasicStylesAutoformats(){const e=this.editor.commands;if(e.get("bold")){const e=Mg(this.editor,"bold");Og(this.editor,this,/(?:^|\s)(\*\*)([^*]+)(\*\*)$/g,e),Og(this.editor,this,/(?:^|\s)(__)([^_]+)(__)$/g,e)}if(e.get("italic")){const e=Mg(this.editor,"italic");Og(this.editor,this,/(?:^|\s)(\*)([^*_]+)(\*)$/g,e),Og(this.editor,this,/(?:^|\s)(_)([^_]+)(_)$/g,e)}if(e.get("code")){const e=Mg(this.editor,"code");Og(this.editor,this,/(`)([^`]+)(`)$/g,e)}if(e.get("strikethrough")){const e=Mg(this.editor,"strikethrough");Og(this.editor,this,/(~~)([^~]+)(~~)$/g,e)}}_addHeadingAutoformats(){const e=this.editor.commands.get("heading");e&&e.modelElements.filter((e=>e.match(/^heading[1-6]$/))).forEach((t=>{const i=t[7],n=new RegExp(`^(#{${i}})\\s$`);Lg(this.editor,this,n,(()=>{if(!e.isEnabled||e.value===t)return!1;this.editor.execute("heading",{value:t})}))}))}_addBlockQuoteAutoformats(){this.editor.commands.get("blockQuote")&&Lg(this.editor,this,/^>\s$/,"blockQuote")}_addCodeBlockAutoformats(){const e=this.editor,t=e.model.document.selection;e.commands.get("codeBlock")&&Lg(e,this,/^```$/,(()=>{if(t.getFirstPosition().parent.is("element","listItem"))return!1;this.editor.execute("codeBlock",{usePreviousLanguageChoice:!0})}))}_addHorizontalLineAutoformats(){this.editor.commands.get("horizontalLine")&&Lg(this.editor,this,/^---$/,"horizontalLine")}},class extends io{static get requires(){return[Wf,rp,Xf,bg]}static get pluginName(){return"AutoImage"}constructor(e){super(e),this._timeoutId=null,this._positionToInsert=null}init(){const e=this.editor,t=e.model.document,i=e.plugins.get("ClipboardPipeline");this.listenTo(i,"inputTransformation",(()=>{const e=t.selection.getFirstRange(),i=ud.fromPosition(e.start);i.stickiness="toPrevious";const n=ud.fromPosition(e.end);n.stickiness="toNext",t.once("change:data",(()=>{this._embedImageBetweenPositions(i,n),i.detach(),n.detach()}),{priority:"high"})})),e.commands.get("undo").on("execute",(()=>{this._timeoutId&&($i.window.clearTimeout(this._timeoutId),this._positionToInsert.detach(),this._timeoutId=null,this._positionToInsert=null)}),{priority:"high"})}_embedImageBetweenPositions(e,t){const i=this.editor,n=new Sl(e,t),s=n.getWalker({ignoreElementEnd:!0}),o=Object.fromEntries(i.model.document.selection.getAttributes()),r=this.editor.plugins.get("ImageUtils");let a="";for(const e of s)e.item.is("$textProxy")&&(a+=e.item.data);a=a.trim(),a.match(lp)?(this._positionToInsert=ud.fromPosition(e),this._timeoutId=setTimeout((()=>{i.commands.get("insertImage").isEnabled?(i.model.change((e=>{let t;this._timeoutId=null,e.remove(n),n.detach(),"$graveyard"!==this._positionToInsert.root.rootName&&(t=this._positionToInsert.toPosition()),r.insertImage({...o,src:a},t),this._positionToInsert.detach(),this._positionToInsert=null})),i.plugins.get("Delete").requestUndoOnBackspace()):n.detach()}),100)):n.detach()}},Np,class extends io{static get requires(){return[Wp,Up]}static get pluginName(){return"BlockQuote"}},class extends io{static get requires(){return[Gp,Jp]}static get pluginName(){return"Bold"}},class extends io{static get requires(){return[Zp,Xp]}static get pluginName(){return"Code"}},class extends io{static get requires(){return[ub,fb]}static get pluginName(){return"CodeBlock"}},gw,lw,class extends io{static get requires(){return[Wf,qg,xw,Qg,wg,Xf]}static get pluginName(){return"Essentials"}},class extends io{static get requires(){return[Nw,Ew]}static get pluginName(){return"FindAndReplace"}init(){const e=this.editor.plugins.get("FindAndReplaceUI"),t=this.editor.plugins.get("FindAndReplaceEditing"),i=t.state;e.on("findNext",((e,t)=>{t?(i.searchText=t.searchText,this.editor.execute("find",t.searchText,t)):this.editor.execute("findNext")})),e.on("findPrevious",((e,t)=>{t&&i.searchText!==t.searchText?this.editor.execute("find",t.searchText):this.editor.execute("findPrevious")})),e.on("replace",((e,t)=>{i.searchText!==t.searchText&&this.editor.execute("find",t.searchText);const n=i.highlightedResult;n&&this.editor.execute("replace",t.replaceText,n)})),e.on("replaceAll",((e,t)=>{i.searchText!==t.searchText&&this.editor.execute("find",t.searchText),this.editor.execute("replaceAll",t.replaceText,i.results)})),e.on("searchReseted",(()=>{i.clear(this.editor.model),t.stop()}))}},class extends io{static get requires(){return[jw,qw]}static get pluginName(){return"FontSize"}normalizeSizeOptions(e){return Hw(e)}},class extends io{static get pluginName(){return"GeneralHtmlSupport"}static get requires(){return[gw,Gw,Kw,Jw,Zw,Yw,Xw,ev,tv,iv,ov]}init(){const e=this.editor,t=e.plugins.get(gw);t.loadAllowedEmptyElementsConfig(e.config.get("htmlSupport.allowEmpty")||[]),t.loadAllowedConfig(e.config.get("htmlSupport.allow")||[]),t.loadDisallowedConfig(e.config.get("htmlSupport.disallow")||[])}getGhsAttributeNameForElement(e){const t=this.editor.plugins.get("DataSchema"),i=Array.from(t.getDefinitionsForView(e,!1)),n=i.find((e=>e.isInline&&!i[0].isObject));return n?n.model:Zb(e)}addModelHtmlClass(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"classes",(e=>{for(const i of Pn(t))e.add(i)}))}))}removeModelHtmlClass(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"classes",(e=>{for(const i of Pn(t))e.delete(i)}))}))}setModelHtmlAttributes(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"attributes",(e=>{for(const[i,n]of Object.entries(t))e.set(i,n)}))}))}removeModelHtmlAttributes(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"attributes",(e=>{for(const i of Pn(t))e.delete(i)}))}))}setModelHtmlStyles(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"styles",(e=>{for(const[i,n]of Object.entries(t))e.set(i,n)}))}))}removeModelHtmlStyles(e,t,i){const n=this.editor.model,s=this.getGhsAttributeNameForElement(e);n.change((e=>{for(const o of rv(n,i,s))Qb(e,o,s,"styles",(e=>{for(const i of Pn(t))e.delete(i)}))}))}},class extends io{static get requires(){return[gv,fv]}static get pluginName(){return"Heading"}},class extends io{static get requires(){return[bv,wv,yf]}static get pluginName(){return"HorizontalLine"}},class extends io{static get requires(){return[yv,Cv,yf]}static get pluginName(){return"HtmlEmbed"}},class extends io{static get requires(){return[Dv,Hv]}static get pluginName(){return"Image"}},class extends io{static get requires(){return[Uv,jv]}static get pluginName(){return"ImageCaption"}},class extends io{static get pluginName(){return"ImageInsert"}static get requires(){return[d_,f_,g_]}},class extends io{static get requires(){return[b_,k_,v_]}static get pluginName(){return"ImageResize"}},class extends io{static get requires(){return[N_,F_]}static get pluginName(){return"ImageStyle"}},class extends io{static get requires(){return[kf,rp]}static get pluginName(){return"ImageToolbar"}afterInit(){const e=this.editor,t=e.t,i=e.plugins.get(kf),n=e.plugins.get("ImageUtils");var s;i.register("image",{ariaLabel:t("Image toolbar"),items:(s=e.config.get("image.toolbar")||[],s.map((e=>M(e)?e.name:e))),getRelatedElement:e=>n.getClosestSelectedImageWidget(e)})}},d_,class extends io{static get pluginName(){return"Indent"}static get requires(){return[$_,j_]}},class extends io{constructor(e){super(e),e.config.define("indentBlock",{offset:40,unit:"px"})}static get pluginName(){return"IndentBlock"}init(){const e=this.editor,t=e.config.get("indentBlock");t.classes&&t.classes.length?(this._setupConversionUsingClasses(t.classes),e.commands.add("indentBlock",new q_(e,new K_({direction:"forward",classes:t.classes}))),e.commands.add("outdentBlock",new q_(e,new K_({direction:"backward",classes:t.classes})))):(e.data.addStyleProcessorRules(Nh),this._setupConversionUsingOffset(),e.commands.add("indentBlock",new q_(e,new G_({direction:"forward",offset:t.offset,unit:t.unit}))),e.commands.add("outdentBlock",new q_(e,new G_({direction:"backward",offset:t.offset,unit:t.unit}))))}afterInit(){const e=this.editor,t=e.model.schema,i=e.commands.get("indent"),n=e.commands.get("outdent"),s=e.config.get("heading.options");(s&&s.map((e=>e.model))||J_).forEach((e=>{t.isRegistered(e)&&t.extend(e,{allowAttributes:"blockIndent"})})),t.setAttributeProperties("blockIndent",{isFormatting:!0}),i.registerChildCommand(e.commands.get("indentBlock")),n.registerChildCommand(e.commands.get("outdentBlock"))}_setupConversionUsingOffset(){const e=this.editor.conversion,t="rtl"===this.editor.locale.contentLanguageDirection?"margin-right":"margin-left";e.for("upcast").attributeToAttribute({view:{styles:{[t]:/[\s\S]+/}},model:{key:"blockIndent",value:e=>{if(!e.is("element","li"))return e.getStyle(t)}}}),e.for("downcast").attributeToAttribute({model:"blockIndent",view:e=>({key:"style",value:{[t]:e}})})}_setupConversionUsingClasses(e){const t={model:{key:"blockIndent",values:[]},view:{}};for(const i of e)t.model.values.push(i),t.view[i]={key:"class",value:[i]};this.editor.conversion.attributeToAttribute(t)}},class extends io{static get requires(){return[Z_,X_]}static get pluginName(){return"Italic"}},class extends io{static get requires(){return[ay,fy,Np]}static get pluginName(){return"Link"}},class extends io{static get requires(){return[by,_y]}static get pluginName(){return"LinkImage"}},class extends io{static get requires(){return[Yy,ik]}static get pluginName(){return"List"}},class extends io{static get requires(){return[ak,fk]}static get pluginName(){return"ListProperties"}},class extends io{static get requires(){return[xk,Pk,Ek,yf]}static get pluginName(){return"MediaEmbed"}},class extends io{static get requires(){return[kf]}static get pluginName(){return"MediaEmbedToolbar"}afterInit(){const e=this.editor,t=e.t;e.plugins.get(kf).register("mediaEmbed",{ariaLabel:t("Media toolbar"),items:e.config.get("mediaEmbed.toolbar")||[],getRelatedElement:wk})}},class extends io{toMentionAttribute(e,t){return Lk(e,t)}static get pluginName(){return"Mention"}static get requires(){return[Vk,Wk]}},dv,class extends io{static get pluginName(){return"PasteFromOffice"}static get requires(){return[zg]}init(){const e=this.editor,t=e.plugins.get("ClipboardPipeline"),i=e.editing.view.document,n=[];n.push(new tC(i)),n.push(new oC(i)),n.push(new aC(i)),t.on("inputTransformation",((t,s)=>{if(s._isTransformedWithPasteFromOffice)return;if(e.model.document.selection.getFirstPosition().parent.is("element","codeBlock"))return;const o=s.dataTransfer.getData("text/html"),r=n.find((e=>e.isActive(o)));r&&(s._parsedData||(s._parsedData=function(e,t){const i=new DOMParser,n=function(e){return lC(lC(e)).replace(/([^\S\r\n]*?)[\r\n]+([^\S\r\n]*<\/span>)/g,"$1$2").replace(/<\/span>/g,"").replace(/()[\r\n]+(<\/span>)/g,"$1 $2").replace(/ <\//g," <\/o:p>/g," ").replace(/( |\u00A0)<\/o:p>/g,"").replace(/>([^\S\r\n]*[\r\n]\s*)<")}(function(e){const t="",i=e.indexOf(t);if(i<0)return e;const n=e.indexOf("",i+7);return e.substring(0,i+7)+(n>=0?e.substring(n):"")}(e=e.replace(/

    abc

    \n //\n if (isAttribute && this._wrapAttributeElement(wrapElement, child)) {\n wrapPositions.push(new Position(parent, i));\n }\n //\n // Wrap the child if it is not an attribute element or if it is an attribute element that should be inside\n // `wrapElement` (due to priority).\n //\n //

    abc

    -->

    abc

    \n //

    abc

    -->

    abc

    \n else if (isText || !isAttribute || shouldABeOutsideB(wrapElement, child)) {\n // Clone attribute.\n const newAttribute = wrapElement._clone();\n // Wrap current node with new attribute.\n child._remove();\n newAttribute._appendChild(child);\n parent._insertChild(i, newAttribute);\n this._addToClonedElementsGroup(newAttribute);\n wrapPositions.push(new Position(parent, i));\n }\n //\n // If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.\n //\n //

    abc

    -->

    abc

    \n //\n else /* if ( isAttribute ) */ {\n this._wrapChildren(child, 0, child.childCount, wrapElement);\n }\n i++;\n }\n // Merge at each wrap.\n let offsetChange = 0;\n for (const position of wrapPositions) {\n position.offset -= offsetChange;\n // Do not merge with elements outside selected children.\n if (position.offset == startOffset) {\n continue;\n }\n const newPosition = this.mergeAttributes(position);\n // If nodes were merged - other merge offsets will change.\n if (!newPosition.isEqual(position)) {\n offsetChange++;\n endOffset--;\n }\n }\n return Range._createFromParentsAndOffsets(parent, startOffset, parent, endOffset);\n }\n /**\n * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between\n * `startOffset` and `endOffset` will be unwrapped.\n *\n * @private\n * @param {module:engine/view/element~Element} parent\n * @param {Number} startOffset\n * @param {Number} endOffset\n * @param {module:engine/view/element~Element} unwrapElement\n */\n _unwrapChildren(parent, startOffset, endOffset, unwrapElement) {\n let i = startOffset;\n const unwrapPositions = [];\n // Iterate over each element between provided offsets inside parent.\n // We don't use tree walker or range iterator because we will be removing and merging potentially multiple nodes,\n // so it could get messy. It is safer to it manually in this case.\n while (i < endOffset) {\n const child = parent.getChild(i);\n // Skip all text nodes. There should be no container element's here either.\n if (!child.is('attributeElement')) {\n i++;\n continue;\n }\n //\n // (In all examples, assume that `unwrapElement` is `` element.)\n //\n // If the child is similar to the given attribute element, unwrap it - it will be completely removed.\n //\n //

    abcxyz

    -->

    abcxyz

    \n //\n if (child.isSimilar(unwrapElement)) {\n const unwrapped = child.getChildren();\n const count = child.childCount;\n // Replace wrapper element with its children\n child._remove();\n parent._insertChild(i, unwrapped);\n this._removeFromClonedElementsGroup(child);\n // Save start and end position of moved items.\n unwrapPositions.push(new Position(parent, i), new Position(parent, i + count));\n // Skip elements that were unwrapped. Assuming there won't be another element to unwrap in child elements.\n i += count;\n endOffset += count - 1;\n continue;\n }\n //\n // If the child is not similar but is an attribute element, try partial unwrapping - remove the same attributes/styles/classes.\n // Partial unwrapping will happen only if the elements have the same name.\n //\n //

    abcxyz

    -->

    abcxyz

    \n //

    abcxyz

    -->

    abcxyz

    \n //\n if (this._unwrapAttributeElement(unwrapElement, child)) {\n unwrapPositions.push(new Position(parent, i), new Position(parent, i + 1));\n i++;\n continue;\n }\n //\n // If other nested attribute is found, look through it's children for elements to unwrap.\n //\n //

    abc

    -->

    abc

    \n //\n this._unwrapChildren(child, 0, child.childCount, unwrapElement);\n i++;\n }\n // Merge at each unwrap.\n let offsetChange = 0;\n for (const position of unwrapPositions) {\n position.offset -= offsetChange;\n // Do not merge with elements outside selected children.\n if (position.offset == startOffset || position.offset == endOffset) {\n continue;\n }\n const newPosition = this.mergeAttributes(position);\n // If nodes were merged - other merge offsets will change.\n if (!newPosition.isEqual(position)) {\n offsetChange++;\n endOffset--;\n }\n }\n return Range._createFromParentsAndOffsets(parent, startOffset, parent, endOffset);\n }\n /**\n * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.\n * This method will also merge newly added attribute element with its siblings whenever possible.\n *\n * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n *\n * @private\n * @param {module:engine/view/range~Range} range\n * @param {module:engine/view/attributeelement~AttributeElement} attribute\n * @returns {module:engine/view/range~Range} New range after wrapping, spanning over wrapping attribute element.\n */\n _wrapRange(range, attribute) {\n // Break attributes at range start and end.\n const { start: breakStart, end: breakEnd } = this._breakAttributesRange(range, true);\n const parentContainer = breakStart.parent;\n // Wrap all children with attribute.\n const newRange = this._wrapChildren(parentContainer, breakStart.offset, breakEnd.offset, attribute);\n // Merge attributes at the both ends and return a new range.\n const start = this.mergeAttributes(newRange.start);\n // If start position was merged - move end position back.\n if (!start.isEqual(newRange.start)) {\n newRange.end.offset--;\n }\n const end = this.mergeAttributes(newRange.end);\n return new Range(start, end);\n }\n /**\n * Helper function for {@link #wrap}. Wraps position with provided attribute element.\n * This method will also merge newly added attribute element with its siblings whenever possible.\n *\n * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n *\n * @private\n * @param {module:engine/view/position~Position} position\n * @param {module:engine/view/attributeelement~AttributeElement} attribute\n * @returns {module:engine/view/position~Position} New position after wrapping.\n */\n _wrapPosition(position, attribute) {\n // Return same position when trying to wrap with attribute similar to position parent.\n if (attribute.isSimilar(position.parent)) {\n return movePositionToTextNode(position.clone());\n }\n // When position is inside text node - break it and place new position between two text nodes.\n if (position.parent.is('$text')) {\n position = breakTextNode(position);\n }\n // Create fake element that will represent position, and will not be merged with other attributes.\n const fakeElement = this.createAttributeElement('_wrapPosition-fake-element');\n fakeElement._priority = Number.POSITIVE_INFINITY;\n fakeElement.isSimilar = () => false;\n // Insert fake element in position location.\n position.parent._insertChild(position.offset, fakeElement);\n // Range around inserted fake attribute element.\n const wrapRange = new Range(position, position.getShiftedBy(1));\n // Wrap fake element with attribute (it will also merge if possible).\n this.wrap(wrapRange, attribute);\n // Remove fake element and place new position there.\n const newPosition = new Position(fakeElement.parent, fakeElement.index);\n fakeElement._remove();\n // If position is placed between text nodes - merge them and return position inside.\n const nodeBefore = newPosition.nodeBefore;\n const nodeAfter = newPosition.nodeAfter;\n if (nodeBefore instanceof Text && nodeAfter instanceof Text) {\n return mergeTextNodes(nodeBefore, nodeAfter);\n }\n // If position is next to text node - move position inside.\n return movePositionToTextNode(newPosition);\n }\n /**\n * \tWraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n * \tmerging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n * \telement to element being wrapped.\n *\n * \t@private\n * \t@param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n * \t@param {module:engine/view/attributeelement~AttributeElement} toWrap AttributeElement to wrap using wrapper element.\n * \t@returns {Boolean} Returns `true` if elements are merged.\n */\n _wrapAttributeElement(wrapper, toWrap) {\n if (!canBeJoined(wrapper, toWrap)) {\n return false;\n }\n // Can't merge if name or priority differs.\n if (wrapper.name !== toWrap.name || wrapper.priority !== toWrap.priority) {\n return false;\n }\n // Check if attributes can be merged.\n for (const key of wrapper.getAttributeKeys()) {\n // Classes and styles should be checked separately.\n if (key === 'class' || key === 'style') {\n continue;\n }\n // If some attributes are different we cannot wrap.\n if (toWrap.hasAttribute(key) && toWrap.getAttribute(key) !== wrapper.getAttribute(key)) {\n return false;\n }\n }\n // Check if styles can be merged.\n for (const key of wrapper.getStyleNames()) {\n if (toWrap.hasStyle(key) && toWrap.getStyle(key) !== wrapper.getStyle(key)) {\n return false;\n }\n }\n // Move all attributes/classes/styles from wrapper to wrapped AttributeElement.\n for (const key of wrapper.getAttributeKeys()) {\n // Classes and styles should be checked separately.\n if (key === 'class' || key === 'style') {\n continue;\n }\n // Move only these attributes that are not present - other are similar.\n if (!toWrap.hasAttribute(key)) {\n this.setAttribute(key, wrapper.getAttribute(key), toWrap);\n }\n }\n for (const key of wrapper.getStyleNames()) {\n if (!toWrap.hasStyle(key)) {\n this.setStyle(key, wrapper.getStyle(key), toWrap);\n }\n }\n for (const key of wrapper.getClassNames()) {\n if (!toWrap.hasClass(key)) {\n this.addClass(key, toWrap);\n }\n }\n return true;\n }\n /**\n * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing\n * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present\n * inside element being unwrapped.\n *\n * @private\n * @param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n * @param {module:engine/view/attributeelement~AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.\n * @returns {Boolean} Returns `true` if elements are unwrapped.\n **/\n _unwrapAttributeElement(wrapper, toUnwrap) {\n if (!canBeJoined(wrapper, toUnwrap)) {\n return false;\n }\n // Can't unwrap if name or priority differs.\n if (wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority) {\n return false;\n }\n // Check if AttributeElement has all wrapper attributes.\n for (const key of wrapper.getAttributeKeys()) {\n // Classes and styles should be checked separately.\n if (key === 'class' || key === 'style') {\n continue;\n }\n // If some attributes are missing or different we cannot unwrap.\n if (!toUnwrap.hasAttribute(key) || toUnwrap.getAttribute(key) !== wrapper.getAttribute(key)) {\n return false;\n }\n }\n // Check if AttributeElement has all wrapper classes.\n if (!toUnwrap.hasClass(...wrapper.getClassNames())) {\n return false;\n }\n // Check if AttributeElement has all wrapper styles.\n for (const key of wrapper.getStyleNames()) {\n // If some styles are missing or different we cannot unwrap.\n if (!toUnwrap.hasStyle(key) || toUnwrap.getStyle(key) !== wrapper.getStyle(key)) {\n return false;\n }\n }\n // Remove all wrapper's attributes from unwrapped element.\n for (const key of wrapper.getAttributeKeys()) {\n // Classes and styles should be checked separately.\n if (key === 'class' || key === 'style') {\n continue;\n }\n this.removeAttribute(key, toUnwrap);\n }\n // Remove all wrapper's classes from unwrapped element.\n this.removeClass(Array.from(wrapper.getClassNames()), toUnwrap);\n // Remove all wrapper's styles from unwrapped element.\n this.removeStyle(Array.from(wrapper.getStyleNames()), toUnwrap);\n return true;\n }\n /**\n * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.\n *\n * @private\n * @param {module:engine/view/range~Range} range Range which `start` and `end` positions will be used to break attributes.\n * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n * @returns {module:engine/view/range~Range} New range with located at break positions.\n */\n _breakAttributesRange(range, forceSplitText = false) {\n const rangeStart = range.start;\n const rangeEnd = range.end;\n validateRangeContainer(range, this.document);\n // Break at the collapsed position. Return new collapsed range.\n if (range.isCollapsed) {\n const position = this._breakAttributes(range.start, forceSplitText);\n return new Range(position, position);\n }\n const breakEnd = this._breakAttributes(rangeEnd, forceSplitText);\n const count = breakEnd.parent.childCount;\n const breakStart = this._breakAttributes(rangeStart, forceSplitText);\n // Calculate new break end offset.\n breakEnd.offset += breakEnd.parent.childCount - count;\n return new Range(breakStart, breakEnd);\n }\n /**\n * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.\n *\n * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position\n * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n *\n * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position\n * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.\n *\n * @private\n * @param {module:engine/view/position~Position} position Position where to break attributes.\n * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n * @returns {module:engine/view/position~Position} New position after breaking the attributes.\n */\n _breakAttributes(position, forceSplitText = false) {\n const positionOffset = position.offset;\n const positionParent = position.parent;\n // If position is placed inside EmptyElement - throw an exception as we cannot break inside.\n if (position.parent.is('emptyElement')) {\n /**\n * Cannot break an `EmptyElement` instance.\n *\n * This error is thrown if\n * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n * was executed in an incorrect position.\n *\n * @error view-writer-cannot-break-empty-element\n */\n throw new CKEditorError('view-writer-cannot-break-empty-element', this.document);\n }\n // If position is placed inside UIElement - throw an exception as we cannot break inside.\n if (position.parent.is('uiElement')) {\n /**\n * Cannot break a `UIElement` instance.\n *\n * This error is thrown if\n * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n * was executed in an incorrect position.\n *\n * @error view-writer-cannot-break-ui-element\n */\n throw new CKEditorError('view-writer-cannot-break-ui-element', this.document);\n }\n // If position is placed inside RawElement - throw an exception as we cannot break inside.\n if (position.parent.is('rawElement')) {\n /**\n * Cannot break a `RawElement` instance.\n *\n * This error is thrown if\n * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n * was executed in an incorrect position.\n *\n * @error view-writer-cannot-break-raw-element\n */\n throw new CKEditorError('view-writer-cannot-break-raw-element', this.document);\n }\n // There are no attributes to break and text nodes breaking is not forced.\n if (!forceSplitText && positionParent.is('$text') && isContainerOrFragment(positionParent.parent)) {\n return position.clone();\n }\n // Position's parent is container, so no attributes to break.\n if (isContainerOrFragment(positionParent)) {\n return position.clone();\n }\n // Break text and start again in new position.\n if (positionParent.is('$text')) {\n return this._breakAttributes(breakTextNode(position), forceSplitText);\n }\n const length = positionParent.childCount;\n //

    foobar{}

    \n //

    foobar[]

    \n //

    foobar[]

    \n if (positionOffset == length) {\n const newPosition = new Position(positionParent.parent, positionParent.index + 1);\n return this._breakAttributes(newPosition, forceSplitText);\n }\n else {\n //

    foo{}bar

    \n //

    foo[]bar

    \n //

    foo{}bar

    \n if (positionOffset === 0) {\n const newPosition = new Position(positionParent.parent, positionParent.index);\n return this._breakAttributes(newPosition, forceSplitText);\n }\n //

    foob{}ar

    \n //

    foob[]ar

    \n //

    foob[]ar

    \n //

    foob[]ar

    \n else {\n const offsetAfter = positionParent.index + 1;\n // Break element.\n const clonedNode = positionParent._clone();\n // Insert cloned node to position's parent node.\n positionParent.parent._insertChild(offsetAfter, clonedNode);\n this._addToClonedElementsGroup(clonedNode);\n // Get nodes to move.\n const count = positionParent.childCount - positionOffset;\n const nodesToMove = positionParent._removeChildren(positionOffset, count);\n // Move nodes to cloned node.\n clonedNode._appendChild(nodesToMove);\n // Create new position to work on.\n const newPosition = new Position(positionParent.parent, offsetAfter);\n return this._breakAttributes(newPosition, forceSplitText);\n }\n }\n }\n /**\n * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was\n * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements\n * from the group now keep a reference to the given attribute element.\n *\n * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.\n *\n * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n *\n * @private\n * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to save.\n */\n _addToClonedElementsGroup(element) {\n // Add only if the element is in document tree.\n if (!element.root.is('rootElement')) {\n return;\n }\n // Traverse the element's children recursively to find other attribute elements that also might got inserted.\n // The loop is at the beginning so we can make fast returns later in the code.\n if (element.is('element')) {\n for (const child of element.getChildren()) {\n this._addToClonedElementsGroup(child);\n }\n }\n const id = element.id;\n if (!id) {\n return;\n }\n let group = this._cloneGroups.get(id);\n if (!group) {\n group = new Set();\n this._cloneGroups.set(id, group);\n }\n group.add(element);\n element._clonesGroup = group;\n }\n /**\n * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}\n * from its clones group.\n *\n * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).\n * This allows to reference the whole group even if the element was already removed from the tree.\n *\n * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n *\n * @private\n * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to remove.\n */\n _removeFromClonedElementsGroup(element) {\n // Traverse the element's children recursively to find other attribute elements that also got removed.\n // The loop is at the beginning so we can make fast returns later in the code.\n if (element.is('element')) {\n for (const child of element.getChildren()) {\n this._removeFromClonedElementsGroup(child);\n }\n }\n const id = element.id;\n if (!id) {\n return;\n }\n const group = this._cloneGroups.get(id);\n if (!group) {\n return;\n }\n group.delete(element);\n // Not removing group from element on purpose!\n // If other parts of code have reference to this element, they will be able to get references to other elements from the group.\n }\n}\n// Helper function for `view.writer.wrap`. Checks if given element has any children that are not ui elements.\nfunction _hasNonUiChildren(parent) {\n return Array.from(parent.getChildren()).some(child => !child.is('uiElement'));\n}\n/**\n * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`}\n * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n *\n * @error view-writer-wrap-invalid-attribute\n */\n// Returns first parent container of specified {@link module:engine/view/position~Position Position}.\n// Position's parent node is checked as first, then next parents are checked.\n// Note that {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n//\n// @param {module:engine/view/position~Position} position Position used as a start point to locate parent container.\n// @returns {module:engine/view/containerelement~ContainerElement|module:engine/view/documentfragment~DocumentFragment|undefined}\n// Parent container element or `undefined` if container is not found.\nfunction getParentContainer(position) {\n let parent = position.parent;\n while (!isContainerOrFragment(parent)) {\n if (!parent) {\n return undefined;\n }\n parent = parent.parent;\n }\n return parent;\n}\n// Checks if first {@link module:engine/view/attributeelement~AttributeElement AttributeElement} provided to the function\n// can be wrapped outside second element. It is done by comparing elements'\n// {@link module:engine/view/attributeelement~AttributeElement#priority priorities}, if both have same priority\n// {@link module:engine/view/element~Element#getIdentity identities} are compared.\n//\n// @param {module:engine/view/attributeelement~AttributeElement} a\n// @param {module:engine/view/attributeelement~AttributeElement} b\n// @returns {Boolean}\nfunction shouldABeOutsideB(a, b) {\n if (a.priority < b.priority) {\n return true;\n }\n else if (a.priority > b.priority) {\n return false;\n }\n // When priorities are equal and names are different - use identities.\n return a.getIdentity() < b.getIdentity();\n}\n// Returns new position that is moved to near text node. Returns same position if there is no text node before of after\n// specified position.\n//\n//\t\t

    foo[]

    ->

    foo{}

    \n//\t\t

    []foo

    ->

    {}foo

    \n//\n// @param {module:engine/view/position~Position} position\n// @returns {module:engine/view/position~Position} Position located inside text node or same position if there is no text nodes\n// before or after position location.\nfunction movePositionToTextNode(position) {\n const nodeBefore = position.nodeBefore;\n if (nodeBefore && nodeBefore.is('$text')) {\n return new Position(nodeBefore, nodeBefore.data.length);\n }\n const nodeAfter = position.nodeAfter;\n if (nodeAfter && nodeAfter.is('$text')) {\n return new Position(nodeAfter, 0);\n }\n return position;\n}\n// Breaks text node into two text nodes when possible.\n//\n//\t\t

    foo{}bar

    ->

    foo[]bar

    \n//\t\t

    {}foobar

    ->

    []foobar

    \n//\t\t

    foobar{}

    ->

    foobar[]

    \n//\n// @param {module:engine/view/position~Position} position Position that need to be placed inside text node.\n// @returns {module:engine/view/position~Position} New position after breaking text node.\nfunction breakTextNode(position) {\n if (position.offset == position.parent.data.length) {\n return new Position(position.parent.parent, position.parent.index + 1);\n }\n if (position.offset === 0) {\n return new Position(position.parent.parent, position.parent.index);\n }\n // Get part of the text that need to be moved.\n const textToMove = position.parent.data.slice(position.offset);\n // Leave rest of the text in position's parent.\n position.parent._data = position.parent.data.slice(0, position.offset);\n // Insert new text node after position's parent text node.\n position.parent.parent._insertChild(position.parent.index + 1, new Text(position.root.document, textToMove));\n // Return new position between two newly created text nodes.\n return new Position(position.parent.parent, position.parent.index + 1);\n}\n// Merges two text nodes into first node. Removes second node and returns merge position.\n//\n// @param {module:engine/view/text~Text} t1 First text node to merge. Data from second text node will be moved at the end of\n// this text node.\n// @param {module:engine/view/text~Text} t2 Second text node to merge. This node will be removed after merging.\n// @returns {module:engine/view/position~Position} Position after merging text nodes.\nfunction mergeTextNodes(t1, t2) {\n // Merge text data into first text node and remove second one.\n const nodeBeforeLength = t1.data.length;\n t1._data += t2.data;\n t2._remove();\n return new Position(t1, nodeBeforeLength);\n}\nconst validNodesToInsert = [Text, AttributeElement, ContainerElement, EmptyElement, RawElement, UIElement];\n// Checks if provided nodes are valid to insert.\n//\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n// contains instances that are not supported ones (see error description for valid ones.\n//\n// @param Iterable. nodes\n// @param {Object} errorContext\nfunction validateNodesToInsert(nodes, errorContext) {\n for (const node of nodes) {\n if (!validNodesToInsert.some((validNode => node instanceof validNode))) { // eslint-disable-line no-use-before-define\n /**\n * One of the nodes to be inserted is of an invalid type.\n *\n * Nodes to be inserted with {@link module:engine/view/downcastwriter~DowncastWriter#insert `DowncastWriter#insert()`} should be\n * of the following types:\n *\n * * {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n * * {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n * * {@link module:engine/view/emptyelement~EmptyElement EmptyElement},\n * * {@link module:engine/view/uielement~UIElement UIElement},\n * * {@link module:engine/view/rawelement~RawElement RawElement},\n * * {@link module:engine/view/text~Text Text}.\n *\n * @error view-writer-insert-invalid-node-type\n */\n throw new CKEditorError('view-writer-insert-invalid-node-type', errorContext);\n }\n if (!node.is('$text')) {\n validateNodesToInsert(node.getChildren(), errorContext);\n }\n }\n}\n// Checks if node is ContainerElement or DocumentFragment, because in most cases they should be treated the same way.\n//\n// @param {module:engine/view/node~Node} node\n// @returns {Boolean} Returns `true` if node is instance of ContainerElement or DocumentFragment.\nfunction isContainerOrFragment(node) {\n return node && (node.is('containerElement') || node.is('documentFragment'));\n}\n// Checks if {@link module:engine/view/range~Range#start range start} and {@link module:engine/view/range~Range#end range end} are placed\n// inside same {@link module:engine/view/containerelement~ContainerElement container element}.\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.\n//\n// @param {module:engine/view/range~Range} range\n// @param {Object} errorContext\nfunction validateRangeContainer(range, errorContext) {\n const startContainer = getParentContainer(range.start);\n const endContainer = getParentContainer(range.end);\n if (!startContainer || !endContainer || startContainer !== endContainer) {\n /**\n * The container of the given range is invalid.\n *\n * This may happen if {@link module:engine/view/range~Range#start range start} and\n * {@link module:engine/view/range~Range#end range end} positions are not placed inside the same container element or\n * a parent container for these positions cannot be found.\n *\n * Methods like {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#remove()`},\n * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#clean()`},\n * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`},\n * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#unwrap()`} need to be called\n * on a range that has its start and end positions located in the same container element. Both positions can be\n * nested within other elements (e.g. an attribute element) but the closest container ancestor must be the same.\n *\n * @error view-writer-invalid-range-container\n */\n throw new CKEditorError('view-writer-invalid-range-container', errorContext);\n }\n}\n// Checks if two attribute elements can be joined together. Elements can be joined together if, and only if\n// they do not have ids specified.\n//\n// @private\n// @param {module:engine/view/element~Element} a\n// @param {module:engine/view/element~Element} b\n// @returns {Boolean}\nfunction canBeJoined(a, b) {\n return a.id === null && b.id === null;\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\nimport { keyCodes, isText } from '@ckeditor/ckeditor5-utils';\n/**\n * Set of utilities related to handling block and inline fillers.\n *\n * Browsers do not allow to put caret in elements which does not have height. Because of it, we need to fill all\n * empty elements which should be selectable with elements or characters called \"fillers\". Unfortunately there is no one\n * universal filler, this is why two types are uses:\n *\n * * Block filler is an element which fill block elements, like `

    `. CKEditor uses `
    ` as a block filler during the editing,\n * as browsers do natively. So instead of an empty `

    ` there will be `


    `. The advantage of block filler is that\n * it is transparent for the selection, so when the caret is before the `
    ` and user presses right arrow he will be\n * moved to the next paragraph, not after the `
    `. The disadvantage is that it breaks a block, so it can not be used\n * in the middle of a line of text. The {@link module:engine/view/filler~BR_FILLER `
    ` filler} can be replaced with any other\n * character in the data output, for instance {@link module:engine/view/filler~NBSP_FILLER non-breaking space} or\n * {@link module:engine/view/filler~MARKED_NBSP_FILLER marked non-breaking space}.\n *\n * * Inline filler is a filler which does not break a line of text, so it can be used inside the text, for instance in the empty\n * `` surrendered by text: `foobar`, if we want to put the caret there. CKEditor uses a sequence of the zero-width\n * spaces as an {@link module:engine/view/filler~INLINE_FILLER inline filler} having the predetermined\n * {@link module:engine/view/filler~INLINE_FILLER_LENGTH length}. A sequence is used, instead of a single character to\n * avoid treating random zero-width spaces as the inline filler. Disadvantage of the inline filler is that it is not\n * transparent for the selection. The arrow key moves the caret between zero-width spaces characters, so the additional\n * code is needed to handle the caret.\n *\n * Both inline and block fillers are handled by the {@link module:engine/view/renderer~Renderer renderer} and are not present in the\n * view.\n *\n * @module engine/view/filler\n */\n/**\n * Non-breaking space filler creator. This function creates the ` ` text node.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~MARKED_NBSP_FILLER\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const NBSP_FILLER = (domDocument) => domDocument.createTextNode('\\u00A0');\n/**\n * Marked non-breaking space filler creator. This function creates the ` ` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const MARKED_NBSP_FILLER = (domDocument) => {\n const span = domDocument.createElement('span');\n span.dataset.ckeFiller = 'true';\n span.innerText = '\\u00A0';\n return span;\n};\n/**\n * `
    ` filler creator. This function creates the `
    ` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @see module:engine/view/filler~MARKED_NBSP_FILLER\n * @function\n */\nexport const BR_FILLER = (domDocument) => {\n const fillerBr = domDocument.createElement('br');\n fillerBr.dataset.ckeFiller = 'true';\n return fillerBr;\n};\n/**\n * Length of the {@link module:engine/view/filler~INLINE_FILLER INLINE_FILLER}.\n */\nexport const INLINE_FILLER_LENGTH = 7;\n/**\n * Inline filler which is a sequence of the word joiners.\n *\n * @type {String}\n */\nexport const INLINE_FILLER = '\\u2060'.repeat(INLINE_FILLER_LENGTH);\n/**\n * Checks if the node is a text node which starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( 'foo' ) ); // false\n *\t\tstartsWithFiller( document.createElement( 'p' ) ); // false\n *\n * @param {Node} domNode DOM node.\n * @returns {Boolean} True if the text node starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function startsWithFiller(domNode) {\n return isText(domNode) && (domNode.data.substr(0, INLINE_FILLER_LENGTH) === INLINE_FILLER);\n}\n/**\n * Checks if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // false\n *\n * @param {Text} domText DOM text node.\n * @returns {Boolean} True if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function isInlineFiller(domText) {\n return domText.data.length == INLINE_FILLER_LENGTH && startsWithFiller(domText);\n}\n/**\n * Get string data from the text node, removing an {@link module:engine/view/filler~INLINE_FILLER inline filler} from it,\n * if text node contains it.\n *\n *\t\tgetDataWithoutFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ) == 'foo' // true\n *\t\tgetDataWithoutFiller( document.createTextNode( 'foo' ) ) == 'foo' // true\n *\n * @param {Text} domText DOM text node, possible with inline filler.\n * @returns {String} Data without filler.\n */\nexport function getDataWithoutFiller(domText) {\n if (startsWithFiller(domText)) {\n return domText.data.slice(INLINE_FILLER_LENGTH);\n }\n else {\n return domText.data;\n }\n}\n/**\n * Assign key observer which move cursor from the end of the inline filler to the beginning of it when\n * the left arrow is pressed, so the filler does not break navigation.\n *\n * @param {module:engine/view/view~View} view View controller instance we should inject quirks handling on.\n */\nexport function injectQuirksHandling(view) {\n view.document.on('arrowKey', jumpOverInlineFiller, { priority: 'low' });\n}\n// Move cursor from the end of the inline filler to the beginning of it when, so the filler does not break navigation.\nfunction jumpOverInlineFiller(evt, data) {\n if (data.keyCode == keyCodes.arrowleft) {\n const domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n if (domSelection.rangeCount == 1 && domSelection.getRangeAt(0).collapsed) {\n const domParent = domSelection.getRangeAt(0).startContainer;\n const domOffset = domSelection.getRangeAt(0).startOffset;\n if (startsWithFiller(domParent) && domOffset <= INLINE_FILLER_LENGTH) {\n domSelection.collapse(domParent, 0);\n }\n }\n }\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module engine/view/renderer\n */\nimport ViewText from './text';\nimport ViewPosition from './position';\nimport { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller } from './filler';\nimport { CKEditorError, ObservableMixin, diff, env, fastDiff, insertAt, isComment, isNode, isText, remove } from '@ckeditor/ckeditor5-utils';\nimport '../../theme/renderer.css';\n/**\n * Renderer is responsible for updating the DOM structure and the DOM selection based on\n * the {@link module:engine/view/renderer~Renderer#markToSync information about updated view nodes}.\n * In other words, it renders the view to the DOM.\n *\n * Its main responsibility is to make only the necessary, minimal changes to the DOM. However, unlike in many\n * virtual DOM implementations, the primary reason for doing minimal changes is not the performance but ensuring\n * that native editing features such as text composition, autocompletion, spell checking, selection's x-index are\n * affected as little as possible.\n *\n * Renderer uses {@link module:engine/view/domconverter~DomConverter} to transform view nodes and positions\n * to and from the DOM.\n */\nexport default class Renderer extends ObservableMixin() {\n /**\n * Creates a renderer instance.\n *\n * @param {module:engine/view/domconverter~DomConverter} domConverter Converter instance.\n * @param {module:engine/view/documentselection~DocumentSelection} selection View selection.\n */\n constructor(domConverter, selection) {\n super();\n /**\n * Set of DOM Documents instances.\n *\n * @readonly\n * @member {Set.}\n */\n this.domDocuments = new Set();\n /**\n * Converter instance.\n *\n * @readonly\n * @member {module:engine/view/domconverter~DomConverter}\n */\n this.domConverter = domConverter;\n /**\n * Set of nodes which attributes changed and may need to be rendered.\n *\n * @readonly\n * @member {Set.}\n */\n this.markedAttributes = new Set();\n /**\n * Set of elements which child lists changed and may need to be rendered.\n *\n * @readonly\n * @member {Set.}\n */\n this.markedChildren = new Set();\n /**\n * Set of text nodes which text data changed and may need to be rendered.\n *\n * @readonly\n * @member {Set.}\n */\n this.markedTexts = new Set();\n /**\n * View selection. Renderer updates DOM selection based on the view selection.\n *\n * @readonly\n * @member {module:engine/view/documentselection~DocumentSelection}\n */\n this.selection = selection;\n /**\n * Indicates if the view document is focused and selection can be rendered. Selection will not be rendered if\n * this is set to `false`.\n *\n * @member {Boolean}\n * @observable\n */\n this.set('isFocused', false);\n /**\n * Indicates if the view document is changing the focus (`true`) and selection rendering should be prevented.\n *\n * @internal\n * @observable\n * @member {Boolean}\n */\n this.set('_isFocusChanging', false);\n /**\n * Indicates whether the user is making a selection in the document (e.g. holding the mouse button and moving the cursor).\n * When they stop selecting, the property goes back to `false`.\n *\n * Note: In some browsers, the renderer will stop rendering the selection and inline fillers while the user is making\n * a selection to avoid glitches in DOM selection\n * (https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723).\n *\n * @member {Boolean}\n * @observable\n */\n this.set('isSelecting', false);\n // Rendering the selection and inline filler manipulation should be postponed in (non-Android) Blink until the user finishes\n // creating the selection in DOM to avoid accidental selection collapsing\n // (https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723).\n // When the user stops selecting, all pending changes should be rendered ASAP, though.\n if (env.isBlink && !env.isAndroid) {\n this.on('change:isSelecting', () => {\n if (!this.isSelecting) {\n this.render();\n }\n });\n }\n /**\n * True if composition is in progress inside the document.\n *\n * This property is bound to the {@link module:engine/view/document~Document#isComposing `Document#isComposing`} property.\n *\n * @member {Boolean}\n * @observable\n */\n this.set('isComposing', false);\n this.on('change:isComposing', () => {\n if (!this.isComposing) {\n this.render();\n }\n });\n /**\n * The text node in which the inline filler was rendered.\n *\n * @private\n * @member {Text}\n */\n this._inlineFiller = null;\n /**\n * DOM element containing fake selection.\n *\n * @private\n * @type {null|HTMLElement}\n */\n this._fakeSelectionContainer = null;\n }\n /**\n * Marks a view node to be updated in the DOM by {@link #render `render()`}.\n *\n * Note that only view nodes whose parents have corresponding DOM elements need to be marked to be synchronized.\n *\n * @see #markedAttributes\n * @see #markedChildren\n * @see #markedTexts\n *\n * @param {module:engine/view/document~ChangeType} type Type of the change.\n * @param {module:engine/view/node~ViewNode} node ViewNode to be marked.\n */\n markToSync(type, node) {\n if (type === 'text') {\n if (this.domConverter.mapViewToDom(node.parent)) {\n this.markedTexts.add(node);\n }\n }\n else {\n // If the node has no DOM element it is not rendered yet,\n // its children/attributes do not need to be marked to be sync.\n if (!this.domConverter.mapViewToDom(node)) {\n return;\n }\n if (type === 'attributes') {\n this.markedAttributes.add(node);\n }\n else if (type === 'children') {\n this.markedChildren.add(node);\n }\n else {\n /**\n * Unknown type passed to Renderer.markToSync.\n *\n * @error view-renderer-unknown-type\n */\n throw new CKEditorError('view-renderer-unknown-type', this);\n }\n }\n }\n /**\n * Renders all buffered changes ({@link #markedAttributes}, {@link #markedChildren} and {@link #markedTexts}) and\n * the current view selection (if needed) to the DOM by applying a minimal set of changes to it.\n *\n * Renderer tries not to break the text composition (e.g. IME) and x-index of the selection,\n * so it does as little as it is needed to update the DOM.\n *\n * Renderer also handles {@link module:engine/view/filler fillers}. Especially, it checks if the inline filler is needed\n * at the selection position and adds or removes it. To prevent breaking text composition inline filler will not be\n * removed as long as the selection is in the text node which needed it at first.\n */\n render() {\n // Ignore rendering while in the composition mode. Composition events are not cancellable and browser will modify the DOM tree.\n // All marked elements, attributes, etc. will wait until next render after the composition ends.\n // On Android composition events are immediately applied to the model, so we don't need to skip rendering,\n // and we should not do it because the difference between view and DOM could lead to position mapping problems.\n if (this.isComposing && !env.isAndroid) {\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Rendering aborted while isComposing',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', ''\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n return;\n }\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.group( '%c[Renderer]%c Rendering',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', ''\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n let inlineFillerPosition = null;\n const isInlineFillerRenderingPossible = env.isBlink && !env.isAndroid ? !this.isSelecting : true;\n // Refresh mappings.\n for (const element of this.markedChildren) {\n this._updateChildrenMappings(element);\n }\n // Don't manipulate inline fillers while the selection is being made in (non-Android) Blink to prevent accidental\n // DOM selection collapsing\n // (https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723).\n if (isInlineFillerRenderingPossible) {\n // There was inline filler rendered in the DOM but it's not\n // at the selection position any more, so we can remove it\n // (cause even if it's needed, it must be placed in another location).\n if (this._inlineFiller && !this._isSelectionInInlineFiller()) {\n this._removeInlineFiller();\n }\n // If we've got the filler, let's try to guess its position in the view.\n if (this._inlineFiller) {\n inlineFillerPosition = this._getInlineFillerPosition();\n }\n // Otherwise, if it's needed, create it at the selection position.\n else if (this._needsInlineFillerAtSelection()) {\n inlineFillerPosition = this.selection.getFirstPosition();\n // Do not use `markToSync` so it will be added even if the parent is already added.\n this.markedChildren.add(inlineFillerPosition.parent);\n }\n }\n // Make sure the inline filler has any parent, so it can be mapped to view position by DomConverter.\n else if (this._inlineFiller && this._inlineFiller.parentNode) {\n // While the user is making selection, preserve the inline filler at its original position.\n inlineFillerPosition = this.domConverter.domPositionToView(this._inlineFiller);\n // While down-casting the document selection attributes, all existing empty\n // attribute elements (for selection position) are removed from the view and DOM,\n // so make sure that we were able to map filler position.\n // https://github.com/ckeditor/ckeditor5/issues/12026\n if (inlineFillerPosition && inlineFillerPosition.parent.is('$text')) {\n // The inline filler position is expected to be before the text node.\n inlineFillerPosition = ViewPosition._createBefore(inlineFillerPosition.parent);\n }\n }\n for (const element of this.markedAttributes) {\n this._updateAttrs(element);\n }\n for (const element of this.markedChildren) {\n this._updateChildren(element, { inlineFillerPosition });\n }\n for (const node of this.markedTexts) {\n if (!this.markedChildren.has(node.parent) && this.domConverter.mapViewToDom(node.parent)) {\n this._updateText(node, { inlineFillerPosition });\n }\n }\n // * Check whether the inline filler is required and where it really is in the DOM.\n // At this point in most cases it will be in the DOM, but there are exceptions.\n // For example, if the inline filler was deep in the created DOM structure, it will not be created.\n // Similarly, if it was removed at the beginning of this function and then neither text nor children were updated,\n // it will not be present. Fix those and similar scenarios.\n // * Don't manipulate inline fillers while the selection is being made in (non-Android) Blink to prevent accidental\n // DOM selection collapsing\n // (https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723).\n if (isInlineFillerRenderingPossible) {\n if (inlineFillerPosition) {\n const fillerDomPosition = this.domConverter.viewPositionToDom(inlineFillerPosition);\n const domDocument = fillerDomPosition.parent.ownerDocument;\n if (!startsWithFiller(fillerDomPosition.parent)) {\n // Filler has not been created at filler position. Create it now.\n this._inlineFiller = addInlineFiller(domDocument, fillerDomPosition.parent, fillerDomPosition.offset);\n }\n else {\n // Filler has been found, save it.\n this._inlineFiller = fillerDomPosition.parent;\n }\n }\n else {\n // There is no filler needed.\n this._inlineFiller = null;\n }\n }\n // First focus the new editing host, then update the selection.\n // Otherwise, FF may throw an error (https://github.com/ckeditor/ckeditor5/issues/721).\n this._updateFocus();\n this._updateSelection();\n this.markedTexts.clear();\n this.markedAttributes.clear();\n this.markedChildren.clear();\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.groupEnd();\n // @if CK_DEBUG_TYPING // }\n }\n /**\n * Updates mappings of view element's children.\n *\n * Children that were replaced in the view structure by similar elements (same tag name) are treated as 'replaced'.\n * This means that their mappings can be updated so the new view elements are mapped to the existing DOM elements.\n * Thanks to that these elements do not need to be re-rendered completely.\n *\n * @private\n * @param {module:engine/view/node~ViewNode} viewElement The view element whose children mappings will be updated.\n */\n _updateChildrenMappings(viewElement) {\n const domElement = this.domConverter.mapViewToDom(viewElement);\n if (!domElement) {\n // If there is no `domElement` it means that it was already removed from DOM and there is no need to process it.\n return;\n }\n // Removing nodes from the DOM as we iterate can cause `actualDomChildren`\n // (which is a live-updating `NodeList`) to get out of sync with the\n // indices that we compute as we iterate over `actions`.\n // This would produce incorrect element mappings.\n //\n // Converting live list to an array to make the list static.\n const actualDomChildren = Array.from(this.domConverter.mapViewToDom(viewElement).childNodes);\n const expectedDomChildren = Array.from(this.domConverter.viewChildrenToDom(viewElement, { withChildren: false }));\n const diff = this._diffNodeLists(actualDomChildren, expectedDomChildren);\n const actions = this._findReplaceActions(diff, actualDomChildren, expectedDomChildren);\n if (actions.indexOf('replace') !== -1) {\n const counter = { equal: 0, insert: 0, delete: 0 };\n for (const action of actions) {\n if (action === 'replace') {\n const insertIndex = counter.equal + counter.insert;\n const deleteIndex = counter.equal + counter.delete;\n const viewChild = viewElement.getChild(insertIndex);\n // UIElement and RawElement are special cases. Their children are not stored in a view (#799)\n // so we cannot use them with replacing flow (since they use view children during rendering\n // which will always result in rendering empty elements).\n if (viewChild && !(viewChild.is('uiElement') || viewChild.is('rawElement'))) {\n this._updateElementMappings(viewChild, actualDomChildren[deleteIndex]);\n }\n remove(expectedDomChildren[insertIndex]);\n counter.equal++;\n }\n else {\n counter[action]++;\n }\n }\n }\n }\n /**\n * Updates mappings of a given view element.\n *\n * @private\n * @param {module:engine/view/node~ViewNode} viewElement The view element whose mappings will be updated.\n * @param {ViewNode} domElement The DOM element representing the given view element.\n */\n _updateElementMappings(viewElement, domElement) {\n // Remap 'DomConverter' bindings.\n this.domConverter.unbindDomElement(domElement);\n this.domConverter.bindElements(domElement, viewElement);\n // View element may have children which needs to be updated, but are not marked, mark them to update.\n this.markedChildren.add(viewElement);\n // Because we replace new view element mapping with the existing one, the corresponding DOM element\n // will not be rerendered. The new view element may have different attributes than the previous one.\n // Since its corresponding DOM element will not be rerendered, new attributes will not be added\n // to the DOM, so we need to mark it here to make sure its attributes gets updated. See #1427 for more\n // detailed case study.\n // Also there are cases where replaced element is removed from the view structure and then has\n // its attributes changed or removed. In such cases the element will not be present in `markedAttributes`\n // and also may be the same (`element.isSimilar()`) as the reused element not having its attributes updated.\n // To prevent such situations we always mark reused element to have its attributes rerenderd (#1560).\n this.markedAttributes.add(viewElement);\n }\n /**\n * Gets the position of the inline filler based on the current selection.\n * Here, we assume that we know that the filler is needed and\n * {@link #_isSelectionInInlineFiller is at the selection position}, and, since it is needed,\n * it is somewhere at the selection position.\n *\n * Note: The filler position cannot be restored based on the filler's DOM text node, because\n * when this method is called (before rendering), the bindings will often be broken. View-to-DOM\n * bindings are only dependable after rendering.\n *\n * @private\n * @returns {module:engine/view/position~Position}\n */\n _getInlineFillerPosition() {\n const firstPos = this.selection.getFirstPosition();\n if (firstPos.parent.is('$text')) {\n return ViewPosition._createBefore(firstPos.parent);\n }\n else {\n return firstPos;\n }\n }\n /**\n * Returns `true` if the selection has not left the inline filler's text node.\n * If it is `true`, it means that the filler had been added for a reason and the selection did not\n * leave the filler's text node. For example, the user can be in the middle of a composition so it should not be touched.\n *\n * @private\n * @returns {Boolean} `true` if the inline filler and selection are in the same place.\n */\n _isSelectionInInlineFiller() {\n if (this.selection.rangeCount != 1 || !this.selection.isCollapsed) {\n return false;\n }\n // Note, we can't check if selection's position equals position of the\n // this._inlineFiller node, because of #663. We may not be able to calculate\n // the filler's position in the view at this stage.\n // Instead, we check it the other way – whether selection is anchored in\n // that text node or next to it.\n // Possible options are:\n // \"FILLER{}\"\n // \"FILLERadded-text{}\"\n const selectionPosition = this.selection.getFirstPosition();\n const position = this.domConverter.viewPositionToDom(selectionPosition);\n if (position && isText(position.parent) && startsWithFiller(position.parent)) {\n return true;\n }\n return false;\n }\n /**\n * Removes the inline filler.\n *\n * @private\n */\n _removeInlineFiller() {\n const domFillerNode = this._inlineFiller;\n // Something weird happened and the stored node doesn't contain the filler's text.\n if (!startsWithFiller(domFillerNode)) {\n /**\n * The inline filler node was lost. Most likely, something overwrote the filler text node\n * in the DOM.\n *\n * @error view-renderer-filler-was-lost\n */\n throw new CKEditorError('view-renderer-filler-was-lost', this);\n }\n if (isInlineFiller(domFillerNode)) {\n domFillerNode.remove();\n }\n else {\n domFillerNode.data = domFillerNode.data.substr(INLINE_FILLER_LENGTH);\n }\n this._inlineFiller = null;\n }\n /**\n * Checks if the inline {@link module:engine/view/filler filler} should be added.\n *\n * @private\n * @returns {Boolean} `true` if the inline filler should be added.\n */\n _needsInlineFillerAtSelection() {\n if (this.selection.rangeCount != 1 || !this.selection.isCollapsed) {\n return false;\n }\n const selectionPosition = this.selection.getFirstPosition();\n const selectionParent = selectionPosition.parent;\n const selectionOffset = selectionPosition.offset;\n // If there is no DOM root we do not care about fillers.\n if (!this.domConverter.mapViewToDom(selectionParent.root)) {\n return false;\n }\n if (!(selectionParent.is('element'))) {\n return false;\n }\n // Prevent adding inline filler inside elements with contenteditable=false.\n // https://github.com/ckeditor/ckeditor5-engine/issues/1170\n if (!isEditable(selectionParent)) {\n return false;\n }\n // We have block filler, we do not need inline one.\n if (selectionOffset === selectionParent.getFillerOffset()) {\n return false;\n }\n const nodeBefore = selectionPosition.nodeBefore;\n const nodeAfter = selectionPosition.nodeAfter;\n if (nodeBefore instanceof ViewText || nodeAfter instanceof ViewText) {\n return false;\n }\n // Do not use inline filler while typing outside inline elements on Android.\n // The deleteContentBackward would remove part of the inline filler instead of removing last letter in a link.\n if (env.isAndroid && (nodeBefore || nodeAfter)) {\n return false;\n }\n return true;\n }\n /**\n * Checks if text needs to be updated and possibly updates it.\n *\n * @private\n * @param {module:engine/view/text~Text} viewText View text to update.\n * @param {Object} options\n * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n * filler should be rendered.\n */\n _updateText(viewText, options) {\n const domText = this.domConverter.findCorrespondingDomText(viewText);\n const newDomText = this.domConverter.viewToDom(viewText);\n let expectedText = newDomText.data;\n const filler = options.inlineFillerPosition;\n if (filler && filler.parent == viewText.parent && filler.offset == viewText.index) {\n expectedText = INLINE_FILLER + expectedText;\n }\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.group( '%c[Renderer]%c Update text',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', ''\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n updateTextNode(domText, expectedText);\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.groupEnd();\n // @if CK_DEBUG_TYPING // }\n }\n /**\n * Checks if attribute list needs to be updated and possibly updates it.\n *\n * @private\n * @param {module:engine/view/element~Element} viewElement The view element to update.\n */\n _updateAttrs(viewElement) {\n const domElement = this.domConverter.mapViewToDom(viewElement);\n if (!domElement) {\n // If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated\n // in 'this._updateChildrenMappings()'. There is no need to process it as new view element which\n // replaced old 'viewElement' mapping was also added to 'this.markedAttributes'\n // in 'this._updateChildrenMappings()' so it will be processed separately.\n return;\n }\n const domAttrKeys = Array.from(domElement.attributes).map(attr => attr.name);\n const viewAttrKeys = viewElement.getAttributeKeys();\n // Add or overwrite attributes.\n for (const key of viewAttrKeys) {\n this.domConverter.setDomElementAttribute(domElement, key, viewElement.getAttribute(key), viewElement);\n }\n // Remove from DOM attributes which do not exists in the view.\n for (const key of domAttrKeys) {\n // All other attributes not present in the DOM should be removed.\n if (!viewElement.hasAttribute(key)) {\n this.domConverter.removeDomElementAttribute(domElement, key);\n }\n }\n }\n /**\n * Checks if elements child list needs to be updated and possibly updates it.\n *\n * Note that on Android, to reduce the risk of composition breaks, it tries to update data of an existing\n * child text nodes instead of replacing them completely.\n *\n * @private\n * @param {module:engine/view/element~Element} viewElement View element to update.\n * @param {Object} options\n * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n * filler should be rendered.\n */\n _updateChildren(viewElement, options) {\n const domElement = this.domConverter.mapViewToDom(viewElement);\n if (!domElement) {\n // If there is no `domElement` it means that it was already removed from DOM.\n // There is no need to process it. It will be processed when re-inserted.\n return;\n }\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.group( '%c[Renderer]%c Update children',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', ''\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n // IME on Android inserts a new text node while typing after a link\n // instead of updating an existing text node that follows the link.\n // We must normalize those text nodes so the diff won't get confused.\n // https://github.com/ckeditor/ckeditor5/issues/12574.\n if (env.isAndroid) {\n let previousDomNode = null;\n for (const domNode of Array.from(domElement.childNodes)) {\n if (previousDomNode && isText(previousDomNode) && isText(domNode)) {\n domElement.normalize();\n break;\n }\n previousDomNode = domNode;\n }\n }\n const inlineFillerPosition = options.inlineFillerPosition;\n const actualDomChildren = domElement.childNodes;\n const expectedDomChildren = Array.from(this.domConverter.viewChildrenToDom(viewElement, { bind: true }));\n // Inline filler element has to be created as it is present in the DOM, but not in the view. It is required\n // during diffing so text nodes could be compared correctly and also during rendering to maintain\n // proper order and indexes while updating the DOM.\n if (inlineFillerPosition && inlineFillerPosition.parent === viewElement) {\n addInlineFiller(domElement.ownerDocument, expectedDomChildren, inlineFillerPosition.offset);\n }\n const diff = this._diffNodeLists(actualDomChildren, expectedDomChildren);\n // The rendering is not disabled on Android in the composition mode.\n // Composition events are not cancellable and browser will modify the DOM tree.\n // On Android composition events are immediately applied to the model, so we don't need to skip rendering,\n // and we should not do it because the difference between view and DOM could lead to position mapping problems.\n // Since the composition is fragile and often breaks if the composed text node is replaced while composing\n // we need to make sure that we update the existing text node and not replace it with another one.\n // We don't want to change the behavior on other browsers for safety, but maybe one day cause it seems to make sense.\n // https://github.com/ckeditor/ckeditor5/issues/12455.\n const actions = env.isAndroid ?\n this._findReplaceActions(diff, actualDomChildren, expectedDomChildren, { replaceText: true }) :\n diff;\n let i = 0;\n const nodesToUnbind = new Set();\n // Handle deletions first.\n // This is to prevent a situation where an element that already exists in `actualDomChildren` is inserted at a different\n // index in `actualDomChildren`. Since `actualDomChildren` is a `NodeList`, this works like move, not like an insert,\n // and it disrupts the whole algorithm. See https://github.com/ckeditor/ckeditor5/issues/6367.\n //\n // It doesn't matter in what order we remove or add nodes, as long as we remove and add correct nodes at correct indexes.\n for (const action of actions) {\n if (action === 'delete') {\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Remove node',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', '', actualDomChildren[ i ]\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n nodesToUnbind.add(actualDomChildren[i]);\n remove(actualDomChildren[i]);\n }\n else if (action === 'equal' || action === 'replace') {\n i++;\n }\n }\n i = 0;\n for (const action of actions) {\n if (action === 'insert') {\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Insert node',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', '', expectedDomChildren[ i ]\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n insertAt(domElement, i, expectedDomChildren[i]);\n i++;\n }\n // Update the existing text node data. Note that replace action is generated only for Android for now.\n else if (action === 'replace') {\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.group( '%c[Renderer]%c Update text node',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', ''\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n updateTextNode(actualDomChildren[i], expectedDomChildren[i].data);\n i++;\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.groupEnd();\n // @if CK_DEBUG_TYPING // }\n }\n else if (action === 'equal') {\n // Force updating text nodes inside elements which did not change and do not need to be re-rendered (#1125).\n // Do it here (not in the loop above) because only after insertions the `i` index is correct.\n this._markDescendantTextToSync(this.domConverter.domToView(expectedDomChildren[i]));\n i++;\n }\n }\n // Unbind removed nodes. When node does not have a parent it means that it was removed from DOM tree during\n // comparison with the expected DOM. We don't need to check child nodes, because if child node was reinserted,\n // it was moved to DOM tree out of the removed node.\n for (const node of nodesToUnbind) {\n if (!node.parentNode) {\n this.domConverter.unbindDomElement(node);\n }\n }\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.groupEnd();\n // @if CK_DEBUG_TYPING // }\n }\n /**\n * Shorthand for diffing two arrays or node lists of DOM nodes.\n *\n * @private\n * @param {Array.|NodeList} actualDomChildren Actual DOM children\n * @param {Array.|NodeList} expectedDomChildren Expected DOM children.\n * @returns {Array.} The list of actions based on the {@link module:utils/diff~diff} function.\n */\n _diffNodeLists(actualDomChildren, expectedDomChildren) {\n actualDomChildren = filterOutFakeSelectionContainer(actualDomChildren, this._fakeSelectionContainer);\n return diff(actualDomChildren, expectedDomChildren, sameNodes.bind(null, this.domConverter));\n }\n /**\n * Finds DOM nodes that were replaced with the similar nodes (same tag name) in the view. All nodes are compared\n * within one `insert`/`delete` action group, for example:\n *\n * \t\tActual DOM:\t\t

    FooBarBazBax

    \n * \t\tExpected DOM:\t

    Bar123Baz456

    \n * \t\tInput actions:\t[ insert, insert, delete, delete, equal, insert, delete ]\n * \t\tOutput actions:\t[ insert, replace, delete, equal, replace ]\n *\n * @private\n * @param {Array.} actions Actions array which is a result of the {@link module:utils/diff~diff} function.\n * @param {Array.|NodeList} actualDom Actual DOM children\n * @param {Array.} expectedDom Expected DOM children.\n * @param {Object} [options] Options\n * @param {Boolean} [options.replaceText] Mark text nodes replacement.\n * @returns {Array.} Actions array modified with the `replace` actions.\n */\n _findReplaceActions(actions, actualDom, expectedDom, options = {}) {\n // If there is no both 'insert' and 'delete' actions, no need to check for replaced elements.\n if (actions.indexOf('insert') === -1 || actions.indexOf('delete') === -1) {\n return actions;\n }\n let newActions = [];\n let actualSlice = [];\n let expectedSlice = [];\n const counter = { equal: 0, insert: 0, delete: 0 };\n for (const action of actions) {\n if (action === 'insert') {\n expectedSlice.push(expectedDom[counter.equal + counter.insert]);\n }\n else if (action === 'delete') {\n actualSlice.push(actualDom[counter.equal + counter.delete]);\n }\n else { // equal\n newActions = newActions.concat(diff(actualSlice, expectedSlice, options.replaceText ? areTextNodes : areSimilar)\n .map(x => x === 'equal' ? 'replace' : x));\n newActions.push('equal');\n // Reset stored elements on 'equal'.\n actualSlice = [];\n expectedSlice = [];\n }\n counter[action]++;\n }\n return newActions.concat(diff(actualSlice, expectedSlice, options.replaceText ? areTextNodes : areSimilar)\n .map(x => x === 'equal' ? 'replace' : x));\n }\n /**\n * Marks text nodes to be synchronized.\n *\n * If a text node is passed, it will be marked. If an element is passed, all descendant text nodes inside it will be marked.\n *\n * @private\n * @param {module:engine/view/node~ViewNode} viewNode View node to sync.\n */\n _markDescendantTextToSync(viewNode) {\n if (!viewNode) {\n return;\n }\n if (viewNode.is('$text')) {\n this.markedTexts.add(viewNode);\n }\n else if (viewNode.is('element')) {\n for (const child of viewNode.getChildren()) {\n this._markDescendantTextToSync(child);\n }\n }\n }\n /**\n * Checks if the selection needs to be updated and possibly updates it.\n *\n * @private\n */\n _updateSelection() {\n // Block updating DOM selection in (non-Android) Blink while the user is selecting to prevent accidental selection collapsing.\n // Note: Structural changes in DOM must trigger selection rendering, though. Nodes the selection was anchored\n // to, may disappear in DOM which would break the selection (e.g. in real-time collaboration scenarios).\n // https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723\n if (env.isBlink && !env.isAndroid && this.isSelecting && !this.markedChildren.size) {\n return;\n }\n // The focus is still in progress and we are waiting for new values from `selectionchange` event.\n // In that case, we need to prevent update selection since it would be updated using old values.\n if (this._isFocusChanging) {\n return;\n }\n // If there is no selection - remove DOM and fake selections.\n if (this.selection.rangeCount === 0) {\n this._removeDomSelection();\n this._removeFakeSelection();\n return;\n }\n const domRoot = this.domConverter.mapViewToDom(this.selection.editableElement);\n // Do nothing if there is no focus, or there is no DOM element corresponding to selection's editable element.\n if (!this.isFocused || !domRoot) {\n return;\n }\n // Render fake selection - create the fake selection container (if needed) and move DOM selection to it.\n if (this.selection.isFake) {\n this._updateFakeSelection(domRoot);\n }\n // There was a fake selection so remove it and update the DOM selection.\n // This is especially important on Android because otherwise IME will try to compose over the fake selection container.\n else if (this._fakeSelectionContainer && this._fakeSelectionContainer.isConnected) {\n this._removeFakeSelection();\n this._updateDomSelection(domRoot);\n }\n // Update the DOM selection in case of a plain selection change (no fake selection is involved).\n // On non-Android the whole rendering is disabled in composition mode (including DOM selection update),\n // but updating DOM selection should be also disabled on Android if in the middle of the composition\n // (to not interrupt it).\n else if (!(this.isComposing && env.isAndroid)) {\n this._updateDomSelection(domRoot);\n }\n }\n /**\n * Updates the fake selection.\n *\n * @private\n * @param {HTMLElement} domRoot A valid DOM root where the fake selection container should be added.\n */\n _updateFakeSelection(domRoot) {\n const domDocument = domRoot.ownerDocument;\n if (!this._fakeSelectionContainer) {\n this._fakeSelectionContainer = createFakeSelectionContainer(domDocument);\n }\n const container = this._fakeSelectionContainer;\n // Bind fake selection container with the current selection *position*.\n this.domConverter.bindFakeSelection(container, this.selection);\n if (!this._fakeSelectionNeedsUpdate(domRoot)) {\n return;\n }\n if (!container.parentElement || container.parentElement != domRoot) {\n domRoot.appendChild(container);\n }\n container.textContent = this.selection.fakeSelectionLabel || '\\u00A0';\n const domSelection = domDocument.getSelection();\n const domRange = domDocument.createRange();\n domSelection.removeAllRanges();\n domRange.selectNodeContents(container);\n domSelection.addRange(domRange);\n }\n /**\n * Updates the DOM selection.\n *\n * @private\n * @param {HTMLElement} domRoot A valid DOM root where the DOM selection should be rendered.\n */\n _updateDomSelection(domRoot) {\n const domSelection = domRoot.ownerDocument.defaultView.getSelection();\n // Let's check whether DOM selection needs updating at all.\n if (!this._domSelectionNeedsUpdate(domSelection)) {\n return;\n }\n // Multi-range selection is not available in most browsers, and, at least in Chrome, trying to\n // set such selection, that is not continuous, throws an error. Because of that, we will just use anchor\n // and focus of view selection.\n // Since we are not supporting multi-range selection, we also do not need to check if proper editable is\n // selected. If there is any editable selected, it is okay (editable is taken from selection anchor).\n const anchor = this.domConverter.viewPositionToDom(this.selection.anchor);\n const focus = this.domConverter.viewPositionToDom(this.selection.focus);\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Update DOM selection:',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', '', anchor, focus\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n domSelection.collapse(anchor.parent, anchor.offset);\n domSelection.extend(focus.parent, focus.offset);\n // Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n if (env.isGecko) {\n fixGeckoSelectionAfterBr(focus, domSelection);\n }\n }\n /**\n * Checks whether a given DOM selection needs to be updated.\n *\n * @private\n * @param {Selection} domSelection The DOM selection to check.\n * @returns {Boolean}\n */\n _domSelectionNeedsUpdate(domSelection) {\n if (!this.domConverter.isDomSelectionCorrect(domSelection)) {\n // Current DOM selection is in incorrect position. We need to update it.\n return true;\n }\n const oldViewSelection = domSelection && this.domConverter.domSelectionToView(domSelection);\n if (oldViewSelection && this.selection.isEqual(oldViewSelection)) {\n return false;\n }\n // If selection is not collapsed, it does not need to be updated if it is similar.\n if (!this.selection.isCollapsed && this.selection.isSimilar(oldViewSelection)) {\n // Selection did not changed and is correct, do not update.\n return false;\n }\n // Selections are not similar.\n return true;\n }\n /**\n * Checks whether the fake selection needs to be updated.\n *\n * @private\n * @param {HTMLElement} domRoot A valid DOM root where a new fake selection container should be added.\n * @returns {Boolean}\n */\n _fakeSelectionNeedsUpdate(domRoot) {\n const container = this._fakeSelectionContainer;\n const domSelection = domRoot.ownerDocument.getSelection();\n // Fake selection needs to be updated if there's no fake selection container, or the container currently sits\n // in a different root.\n if (!container || container.parentElement !== domRoot) {\n return true;\n }\n // Make sure that the selection actually is within the fake selection.\n if (domSelection.anchorNode !== container && !container.contains(domSelection.anchorNode)) {\n return true;\n }\n return container.textContent !== this.selection.fakeSelectionLabel;\n }\n /**\n * Removes the DOM selection.\n *\n * @private\n */\n _removeDomSelection() {\n for (const doc of this.domDocuments) {\n const domSelection = doc.getSelection();\n if (domSelection.rangeCount) {\n const activeDomElement = doc.activeElement;\n const viewElement = this.domConverter.mapDomToView(activeDomElement);\n if (activeDomElement && viewElement) {\n domSelection.removeAllRanges();\n }\n }\n }\n }\n /**\n * Removes the fake selection.\n *\n * @private\n */\n _removeFakeSelection() {\n const container = this._fakeSelectionContainer;\n if (container) {\n container.remove();\n }\n }\n /**\n * Checks if focus needs to be updated and possibly updates it.\n *\n * @private\n */\n _updateFocus() {\n if (this.isFocused) {\n const editable = this.selection.editableElement;\n if (editable) {\n this.domConverter.focus(editable);\n }\n }\n }\n}\n// Checks if provided element is editable.\n//\n// @private\n// @param {module:engine/view/element~Element} element\n// @returns {Boolean}\nfunction isEditable(element) {\n if (element.getAttribute('contenteditable') == 'false') {\n return false;\n }\n const parent = element.findAncestor(element => element.hasAttribute('contenteditable'));\n return !parent || parent.getAttribute('contenteditable') == 'true';\n}\n// Adds inline filler at a given position.\n//\n// The position can be given as an array of DOM nodes and an offset in that array,\n// or a DOM parent element and an offset in that element.\n//\n// @private\n// @param {Document} domDocument\n// @param {Element|Array.} domParentOrArray\n// @param {Number} offset\n// @returns {Text} The DOM text node that contains an inline filler.\nfunction addInlineFiller(domDocument, domParentOrArray, offset) {\n const childNodes = domParentOrArray instanceof Array ? domParentOrArray : domParentOrArray.childNodes;\n const nodeAfterFiller = childNodes[offset];\n if (isText(nodeAfterFiller)) {\n nodeAfterFiller.data = INLINE_FILLER + nodeAfterFiller.data;\n return nodeAfterFiller;\n }\n else {\n const fillerNode = domDocument.createTextNode(INLINE_FILLER);\n if (Array.isArray(domParentOrArray)) {\n childNodes.splice(offset, 0, fillerNode);\n }\n else {\n insertAt(domParentOrArray, offset, fillerNode);\n }\n return fillerNode;\n }\n}\n// Whether two DOM nodes should be considered as similar.\n// Nodes are considered similar if they have the same tag name.\n//\n// @private\n// @param {ViewNode} node1\n// @param {ViewNode} node2\n// @returns {Boolean}\nfunction areSimilar(node1, node2) {\n return isNode(node1) && isNode(node2) &&\n !isText(node1) && !isText(node2) &&\n !isComment(node1) && !isComment(node2) &&\n node1.tagName.toLowerCase() === node2.tagName.toLowerCase();\n}\n// Whether two DOM nodes are text nodes.\nfunction areTextNodes(node1, node2) {\n return isNode(node1) && isNode(node2) &&\n isText(node1) && isText(node2);\n}\n// Whether two dom nodes should be considered as the same.\n// Two nodes which are considered the same are:\n//\n//\t\t* Text nodes with the same text.\n//\t\t* Element nodes represented by the same object.\n//\t\t* Two block filler elements.\n//\n// @private\n// @param {String} blockFillerMode Block filler mode, see {@link module:engine/view/domconverter~DomConverter#blockFillerMode}.\n// @param {ViewNode} node1\n// @param {ViewNode} node2\n// @returns {Boolean}\nfunction sameNodes(domConverter, actualDomChild, expectedDomChild) {\n // Elements.\n if (actualDomChild === expectedDomChild) {\n return true;\n }\n // Texts.\n else if (isText(actualDomChild) && isText(expectedDomChild)) {\n return actualDomChild.data === expectedDomChild.data;\n }\n // Block fillers.\n else if (domConverter.isBlockFiller(actualDomChild) &&\n domConverter.isBlockFiller(expectedDomChild)) {\n return true;\n }\n // Not matching types.\n return false;\n}\n// The following is a Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n// When the native DOM selection is at the end of the block and preceded by
    e.g.\n//\n//\t\t

    foo
    []

    \n//\n// which happens a lot when using the soft line break, the browser fails to (visually) move the\n// caret to the new line. A quick fix is as simple as force–refreshing the selection with the same range.\nfunction fixGeckoSelectionAfterBr(focus, domSelection) {\n const parent = focus.parent;\n // This fix works only when the focus point is at the very end of an element.\n // There is no point in running it in cases unrelated to the browser bug.\n if (parent.nodeType != Node.ELEMENT_NODE || focus.offset != parent.childNodes.length - 1) {\n return;\n }\n const childAtOffset = parent.childNodes[focus.offset];\n // To stay on the safe side, the fix being as specific as possible, it targets only the\n // selection which is at the very end of the element and preceded by
    .\n if (childAtOffset && childAtOffset.tagName == 'BR') {\n domSelection.addRange(domSelection.getRangeAt(0));\n }\n}\nfunction filterOutFakeSelectionContainer(domChildList, fakeSelectionContainer) {\n const childList = Array.from(domChildList);\n if (childList.length == 0 || !fakeSelectionContainer) {\n return childList;\n }\n const last = childList[childList.length - 1];\n if (last == fakeSelectionContainer) {\n childList.pop();\n }\n return childList;\n}\n// Creates a fake selection container for a given document.\n//\n// @private\n// @param {Document} domDocument\n// @returns {HTMLElement}\nfunction createFakeSelectionContainer(domDocument) {\n const container = domDocument.createElement('div');\n container.className = 'ck-fake-selection-container';\n Object.assign(container.style, {\n position: 'fixed',\n top: 0,\n left: '-9999px',\n // See https://github.com/ckeditor/ckeditor5/issues/752.\n width: '42px'\n });\n // Fill it with a text node so we can update it later.\n container.textContent = '\\u00A0';\n return container;\n}\n// Checks if text needs to be updated and possibly updates it by removing and inserting only parts\n// of the data from the existing text node to reduce impact on the IME composition.\n//\n// @param {Text} domText DOM text node to update.\n// @param {String} expectedText The expected data of a text node.\nfunction updateTextNode(domText, expectedText) {\n const actualText = domText.data;\n if (actualText == expectedText) {\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Text node does not need update:',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', '',\n // @if CK_DEBUG_TYPING // \t\t`\"${ domText.data }\" (${ domText.data.length })`\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n return;\n }\n // @if CK_DEBUG_TYPING // if ( window.logCKETyping ) {\n // @if CK_DEBUG_TYPING // \tconsole.info( '%c[Renderer]%c Update text node:',\n // @if CK_DEBUG_TYPING // \t\t'color: green;font-weight: bold', '',\n // @if CK_DEBUG_TYPING // \t\t`\"${ domText.data }\" (${ domText.data.length }) -> \"${ expectedText }\" (${ expectedText.length })`\n // @if CK_DEBUG_TYPING // \t);\n // @if CK_DEBUG_TYPING // }\n const actions = fastDiff(actualText, expectedText);\n for (const action of actions) {\n if (action.type === 'insert') {\n domText.insertData(action.index, action.values.join(''));\n }\n else { // 'delete'\n domText.deleteData(action.index, action.howMany);\n }\n }\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module engine/view/domconverter\n */\n/* globals Node, NodeFilter, DOMParser, Text */\nimport ViewText from './text';\nimport ViewElement from './element';\nimport ViewUIElement from './uielement';\nimport ViewPosition from './position';\nimport ViewRange from './range';\nimport ViewSelection from './selection';\nimport ViewDocumentFragment from './documentfragment';\nimport ViewTreeWalker from './treewalker';\nimport { default as Matcher } from './matcher';\nimport { BR_FILLER, INLINE_FILLER_LENGTH, NBSP_FILLER, MARKED_NBSP_FILLER, getDataWithoutFiller, isInlineFiller, startsWithFiller } from './filler';\nimport { global, logWarning, indexOf, getAncestors, isText, isComment } from '@ckeditor/ckeditor5-utils';\nconst BR_FILLER_REF = BR_FILLER(global.document); // eslint-disable-line new-cap\nconst NBSP_FILLER_REF = NBSP_FILLER(global.document); // eslint-disable-line new-cap\nconst MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER(global.document); // eslint-disable-line new-cap\nconst UNSAFE_ATTRIBUTE_NAME_PREFIX = 'data-ck-unsafe-attribute-';\nconst UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';\n/**\n * `DomConverter` is a set of tools to do transformations between DOM nodes and view nodes. It also handles\n * {@link module:engine/view/domconverter~DomConverter#bindElements bindings} between these nodes.\n *\n * An instance of the DOM converter is available under\n * {@link module:engine/view/view~View#domConverter `editor.editing.view.domConverter`}.\n *\n * The DOM converter does not check which nodes should be rendered (use {@link module:engine/view/renderer~Renderer}), does not keep the\n * state of a tree nor keeps the synchronization between the tree view and the DOM tree (use {@link module:engine/view/document~Document}).\n *\n * The DOM converter keeps DOM elements to view element bindings, so when the converter gets destroyed, the bindings are lost.\n * Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.\n */\nexport default class DomConverter {\n /**\n * Creates a DOM converter.\n *\n * @param {module:engine/view/document~Document} document The view document instance.\n * @param {Object} options An object with configuration options.\n * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode] The type of the block filler to use.\n * Default value depends on the options.renderingMode:\n * 'nbsp' when options.renderingMode == 'data',\n * 'br' when options.renderingMode == 'editing'.\n * @param {'data'|'editing'} [options.renderingMode='editing'] Whether to leave the View-to-DOM conversion result unchanged\n * or improve editing experience by filtering out interactive data.\n */\n constructor(document, options = {}) {\n /**\n * @readonly\n * @type {module:engine/view/document~Document}\n */\n this.document = document;\n /**\n * Whether to leave the View-to-DOM conversion result unchanged or improve editing experience by filtering out interactive data.\n *\n * @member {'data'|'editing'} module:engine/view/domconverter~DomConverter#renderingMode\n */\n this.renderingMode = options.renderingMode || 'editing';\n /**\n * The mode of a block filler used by the DOM converter.\n *\n * @member {'br'|'nbsp'|'markedNbsp'} module:engine/view/domconverter~DomConverter#blockFillerMode\n */\n this.blockFillerMode = options.blockFillerMode || (this.renderingMode === 'editing' ? 'br' : 'nbsp');\n /**\n * Elements which are considered pre-formatted elements.\n *\n * @readonly\n * @member {Array.} module:engine/view/domconverter~DomConverter#preElements\n */\n this.preElements = ['pre'];\n /**\n * Elements which are considered block elements (and hence should be filled with a\n * {@link #isBlockFiller block filler}).\n *\n * Whether an element is considered a block element also affects handling of trailing whitespaces.\n *\n * You can extend this array if you introduce support for block elements which are not yet recognized here.\n *\n * @readonly\n * @member {Array.} module:engine/view/domconverter~DomConverter#blockElements\n */\n this.blockElements = [\n 'address', 'article', 'aside', 'blockquote', 'caption', 'center', 'dd', 'details', 'dir', 'div',\n 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header',\n 'hgroup', 'legend', 'li', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'summary', 'table', 'tbody',\n 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'\n ];\n /**\n * A list of elements that exist inline (in text) but their inner structure cannot be edited because\n * of the way they are rendered by the browser. They are mostly HTML form elements but there are other\n * elements such as `` or `' +\n\t\t\t\t\t\t\t'
    '\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'spotify',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(artist\\/\\w+)/,\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(album\\/\\w+)/,\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(track\\/\\w+)/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'
    ' +\n\t\t\t\t\t\t\t\t`' +\n\t\t\t\t\t\t\t'
    '\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'youtube',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^(?:m\\.)?youtube\\.com\\/watch\\?v=([\\w-]+)(?:&t=(\\d+))?/,\n\t\t\t\t\t\t/^(?:m\\.)?youtube\\.com\\/v\\/([\\w-]+)(?:\\?t=(\\d+))?/,\n\t\t\t\t\t\t/^youtube\\.com\\/embed\\/([\\w-]+)(?:\\?start=(\\d+))?/,\n\t\t\t\t\t\t/^youtu\\.be\\/([\\w-]+)(?:\\?t=(\\d+))?/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\t\t\t\t\t\tconst time = match[ 2 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'
    ' +\n\t\t\t\t\t\t\t\t`' +\n\t\t\t\t\t\t\t'
    '\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'vimeo',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^vimeo\\.com\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/[^/]+\\/[^/]+\\/video\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/album\\/[^/]+\\/video\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/channels\\/[^/]+\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/groups\\/[^/]+\\/videos\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/ondemand\\/[^/]+\\/(\\d+)/,\n\t\t\t\t\t\t/^player\\.vimeo\\.com\\/video\\/(\\d+)/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'
    ' +\n\t\t\t\t\t\t\t\t`' +\n\t\t\t\t\t\t\t'
    '\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'instagram',\n\t\t\t\t\turl: /^instagram\\.com\\/p\\/(\\w+)/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'twitter',\n\t\t\t\t\turl: /^twitter\\.com/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'googleMaps',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^google\\.com\\/maps/,\n\t\t\t\t\t\t/^goo\\.gl\\/maps/,\n\t\t\t\t\t\t/^maps\\.google\\.com/,\n\t\t\t\t\t\t/^maps\\.app\\.goo\\.gl/\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'flickr',\n\t\t\t\t\turl: /^flickr\\.com/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'facebook',\n\t\t\t\t\turl: /^facebook\\.com/\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t/**\n\t\t * The media registry managing the media providers in the editor.\n\t\t *\n\t\t * @member {module:media-embed/mediaregistry~MediaRegistry} #registry\n\t\t */\n\t\tthis.registry = new MediaRegistry( editor.locale, editor.config.get( 'mediaEmbed' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.t;\n\t\tconst conversion = editor.conversion;\n\t\tconst renderMediaPreview = editor.config.get( 'mediaEmbed.previewsInData' );\n\t\tconst elementName = editor.config.get( 'mediaEmbed.elementName' );\n\n\t\tconst registry = this.registry;\n\n\t\teditor.commands.add( 'mediaEmbed', new MediaEmbedCommand( editor ) );\n\n\t\t// Configure the schema.\n\t\tschema.register( 'media', {\n\t\t\tinheritAllFrom: '$blockObject',\n\t\t\tallowAttributes: [ 'url' ]\n\t\t} );\n\n\t\t// Model -> Data\n\t\tconversion.for( 'dataDowncast' ).elementToStructure( {\n\t\t\tmodel: 'media',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\tconst url = modelElement.getAttribute( 'url' );\n\n\t\t\t\treturn createMediaFigureElement( writer, registry, url, {\n\t\t\t\t\telementName,\n\t\t\t\t\trenderMediaPreview: url && renderMediaPreview\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Model -> Data (url -> data-oembed-url)\n\t\tconversion.for( 'dataDowncast' ).add(\n\t\t\tmodelToViewUrlAttributeConverter( registry, {\n\t\t\t\telementName,\n\t\t\t\trenderMediaPreview\n\t\t\t} ) );\n\n\t\t// Model -> View (element)\n\t\tconversion.for( 'editingDowncast' ).elementToStructure( {\n\t\t\tmodel: 'media',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\tconst url = modelElement.getAttribute( 'url' );\n\t\t\t\tconst figure = createMediaFigureElement( writer, registry, url, {\n\t\t\t\t\telementName,\n\t\t\t\t\trenderForEditingView: true\n\t\t\t\t} );\n\n\t\t\t\treturn toMediaWidget( figure, writer, t( 'media widget' ) );\n\t\t\t}\n\t\t} );\n\n\t\t// Model -> View (url -> data-oembed-url)\n\t\tconversion.for( 'editingDowncast' ).add(\n\t\t\tmodelToViewUrlAttributeConverter( registry, {\n\t\t\t\telementName,\n\t\t\t\trenderForEditingView: true\n\t\t\t} ) );\n\n\t\t// View -> Model (data-oembed-url -> url)\n\t\tconversion.for( 'upcast' )\n\t\t\t// Upcast semantic media.\n\t\t\t.elementToElement( {\n\t\t\t\tview: element => [ 'oembed', elementName ].includes( element.name ) && element.getAttribute( 'url' ) ?\n\t\t\t\t\t{ name: true } :\n\t\t\t\t\tnull,\n\t\t\t\tmodel: ( viewMedia, { writer } ) => {\n\t\t\t\t\tconst url = viewMedia.getAttribute( 'url' );\n\n\t\t\t\t\tif ( registry.hasMedia( url ) ) {\n\t\t\t\t\t\treturn writer.createElement( 'media', { url } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// Upcast non-semantic media.\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'data-oembed-url': true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewMedia, { writer } ) => {\n\t\t\t\t\tconst url = viewMedia.getAttribute( 'data-oembed-url' );\n\n\t\t\t\t\tif ( registry.hasMedia( url ) ) {\n\t\t\t\t\t\treturn writer.createElement( 'media', { url } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// Consume `
    ` elements, that were left after upcast.\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'element:figure', converter );\n\n\t\t\t\tfunction converter( evt, data, conversionApi ) {\n\t\t\t\t\tif ( !conversionApi.consumable.consume( data.viewItem, { name: true, classes: 'media' } ) ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { modelRange, modelCursor } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n\n\t\t\t\t\tdata.modelRange = modelRange;\n\t\t\t\t\tdata.modelCursor = modelCursor;\n\n\t\t\t\t\tconst modelElement = first( modelRange.getItems() );\n\n\t\t\t\t\tif ( !modelElement ) {\n\t\t\t\t\t\t// Revert consumed figure so other features can convert it.\n\t\t\t\t\t\tconversionApi.consumable.revert( data.viewItem, { name: true, classes: 'media' } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/automediaembed\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { LiveRange, LivePosition } from 'ckeditor5/src/engine';\nimport { Clipboard } from 'ckeditor5/src/clipboard';\nimport { Delete } from 'ckeditor5/src/typing';\nimport { Undo } from 'ckeditor5/src/undo';\nimport { global } from 'ckeditor5/src/utils';\n\nimport MediaEmbedEditing from './mediaembedediting';\nimport { insertMedia } from './utils';\n\nconst URL_REGEXP = /^(?:http(s)?:\\/\\/)?[\\w-]+\\.[\\w-.~:/?#[\\]@!$&'()*+,;=%]+$/;\n\n/**\n * The auto-media embed plugin. It recognizes media links in the pasted content and embeds\n * them shortly after they are injected into the document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AutoMediaEmbed extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard, Delete, Undo ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AutoMediaEmbed';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The paste–to–embed `setTimeout` ID. Stored as a property to allow\n\t\t * cleaning of the timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_timeoutId\n\t\t */\n\t\tthis._timeoutId = null;\n\n\t\t/**\n\t\t * The position where the `` element will be inserted after the timeout,\n\t\t * determined each time the new content is pasted into the document.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition} #_positionToInsert\n\t\t */\n\t\tthis._positionToInsert = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\n\t\t// We need to listen on `Clipboard#inputTransformation` because we need to save positions of selection.\n\t\t// After pasting, the content between those positions will be checked for a URL that could be transformed\n\t\t// into media.\n\t\tthis.listenTo( editor.plugins.get( 'ClipboardPipeline' ), 'inputTransformation', () => {\n\t\t\tconst firstRange = modelDocument.selection.getFirstRange();\n\n\t\t\tconst leftLivePosition = LivePosition.fromPosition( firstRange.start );\n\t\t\tleftLivePosition.stickiness = 'toPrevious';\n\n\t\t\tconst rightLivePosition = LivePosition.fromPosition( firstRange.end );\n\t\t\trightLivePosition.stickiness = 'toNext';\n\n\t\t\tmodelDocument.once( 'change:data', () => {\n\t\t\t\tthis._embedMediaBetweenPositions( leftLivePosition, rightLivePosition );\n\n\t\t\t\tleftLivePosition.detach();\n\t\t\t\trightLivePosition.detach();\n\t\t\t}, { priority: 'high' } );\n\t\t} );\n\n\t\teditor.commands.get( 'undo' ).on( 'execute', () => {\n\t\t\tif ( this._timeoutId ) {\n\t\t\t\tglobal.window.clearTimeout( this._timeoutId );\n\t\t\t\tthis._positionToInsert.detach();\n\n\t\t\t\tthis._timeoutId = null;\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Analyzes the part of the document between provided positions in search for a URL representing media.\n\t * When the URL is found, it is automatically converted into media.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liveposition~LivePosition} leftPosition Left position of the selection.\n\t * @param {module:engine/model/liveposition~LivePosition} rightPosition Right position of the selection.\n\t */\n\t_embedMediaBetweenPositions( leftPosition, rightPosition ) {\n\t\tconst editor = this.editor;\n\t\tconst mediaRegistry = editor.plugins.get( MediaEmbedEditing ).registry;\n\t\t// TODO: Use marker instead of LiveRange & LivePositions.\n\t\tconst urlRange = new LiveRange( leftPosition, rightPosition );\n\t\tconst walker = urlRange.getWalker( { ignoreElementEnd: true } );\n\n\t\tlet url = '';\n\n\t\tfor ( const node of walker ) {\n\t\t\tif ( node.item.is( '$textProxy' ) ) {\n\t\t\t\turl += node.item.data;\n\t\t\t}\n\t\t}\n\n\t\turl = url.trim();\n\n\t\t// If the URL does not match to universal URL regexp, let's skip that.\n\t\tif ( !url.match( URL_REGEXP ) ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If the URL represents a media, let's use it.\n\t\tif ( !mediaRegistry.hasMedia( url ) ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst mediaEmbedCommand = editor.commands.get( 'mediaEmbed' );\n\n\t\t// Do not anything if media element cannot be inserted at the current position (#47).\n\t\tif ( !mediaEmbedCommand.isEnabled ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Position won't be available in the `setTimeout` function so let's clone it.\n\t\tthis._positionToInsert = LivePosition.fromPosition( leftPosition );\n\n\t\t// This action mustn't be executed if undo was called between pasting and auto-embedding.\n\t\tthis._timeoutId = global.window.setTimeout( () => {\n\t\t\teditor.model.change( writer => {\n\t\t\t\tthis._timeoutId = null;\n\n\t\t\t\twriter.remove( urlRange );\n\t\t\t\turlRange.detach();\n\n\t\t\t\tlet insertionPosition;\n\n\t\t\t\t// Check if position where the media element should be inserted is still valid.\n\t\t\t\t// Otherwise leave it as undefined to use document.selection - default behavior of model.insertContent().\n\t\t\t\tif ( this._positionToInsert.root.rootName !== '$graveyard' ) {\n\t\t\t\t\tinsertionPosition = this._positionToInsert;\n\t\t\t\t}\n\n\t\t\t\tinsertMedia( editor.model, url, insertionPosition, false );\n\n\t\t\t\tthis._positionToInsert.detach();\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t} );\n\n\t\t\teditor.plugins.get( 'Delete' ).requestUndoOnBackspace();\n\t\t}, 100 );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/ui/mediaformview\n */\n\nimport {\n\tButtonView,\n\tFocusCycler,\n\tLabeledFieldView,\n\tView,\n\tViewCollection,\n\tcreateLabeledInputText,\n\tinjectCssTransitionDisabler,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\n// See: #8833.\n// eslint-disable-next-line ckeditor5-rules/ckeditor-imports\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\nimport '../../theme/mediaform.css';\n\n/**\n * The media form view controller class.\n *\n * See {@link module:media-embed/ui/mediaformview~MediaFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class MediaFormView extends View {\n\t/**\n\t * @param {Array.} validators Form validators used by {@link #isValid}.\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n\tconstructor( validators, locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The value of the URL input.\n\t\t *\n\t\t * @member {String} #mediaURLInputValue\n\t\t * @observable\n\t\t */\n\t\tthis.set( 'mediaURLInputValue', '' );\n\n\t\t/**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t\t */\n\t\tthis.urlInputView = this._createUrlInput();\n\n\t\t/**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), icons.check, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\t\tthis.saveButtonView.bind( 'isEnabled' ).to( this, 'mediaURLInputValue', value => !!value );\n\n\t\t/**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), icons.cancel, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * An array of form validators used by {@link #isValid}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Array.}\n\t\t */\n\t\tthis._validators = validators;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-media-form',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.urlInputView,\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t]\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\n\t\t/**\n\t\t * The default info text for the {@link #urlInputView}.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoDefault\n\t\t */\n\n\t\t/**\n\t\t * The info text with an additional tip for the {@link #urlInputView},\n\t\t * displayed when the input has some value.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoTip\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\tconst childViews = [\n\t\t\tthis.urlInputView,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tconst stopPropagation = data => data.stopPropagation();\n\n\t\t// Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's\n\t\t// keystroke handler would take over the key management in the URL input. We need to prevent\n\t\t// this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.\n\t\tthis.keystrokes.set( 'arrowright', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowleft', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowup', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowdown', stopPropagation );\n\n\t\t// Intercept the `selectstart` event, which is blocked by default because of the default behavior\n\t\t// of the DropdownView#panelView.\n\t\t// TODO: blocking `selectstart` in the #panelView should be configurable per–drop–down instance.\n\t\tthis.listenTo( this.urlInputView.element, 'selectstart', ( evt, domEvt ) => {\n\t\t\tdomEvt.stopPropagation();\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis.focusTracker.destroy();\n\t\tthis.keystrokes.destroy();\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * The native DOM `value` of the {@link #urlInputView} element.\n\t *\n\t * **Note**: Do not confuse it with the {@link module:ui/inputtext/inputtextview~InputTextView#value}\n\t * which works one way only and may not represent the actual state of the component in the DOM.\n\t *\n\t * @type {String}\n\t */\n\tget url() {\n\t\treturn this.urlInputView.fieldView.element.value.trim();\n\t}\n\n\tset url( url ) {\n\t\tthis.urlInputView.fieldView.element.value = url.trim();\n\t}\n\n\t/**\n\t * Validates the form and returns `false` when some fields are invalid.\n\t *\n\t * @returns {Boolean}\n\t */\n\tisValid() {\n\t\tthis.resetFormStatus();\n\n\t\tfor ( const validator of this._validators ) {\n\t\t\tconst errorText = validator( this );\n\n\t\t\t// One error per field is enough.\n\t\t\tif ( errorText ) {\n\t\t\t\t// Apply updated error.\n\t\t\t\tthis.urlInputView.errorText = errorText;\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Cleans up the supplementary error and information text of the {@link #urlInputView}\n\t * bringing them back to the state when the form has been displayed for the first time.\n\t *\n\t * See {@link #isValid}.\n\t */\n\tresetFormStatus() {\n\t\tthis.urlInputView.errorText = null;\n\t\tthis.urlInputView.infoText = this._urlInputViewInfoDefault;\n\t}\n\n\t/**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled input view instance.\n\t */\n\t_createUrlInput() {\n\t\tconst t = this.locale.t;\n\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\t\tconst inputField = labeledInput.fieldView;\n\n\t\tthis._urlInputViewInfoDefault = t( 'Paste the media URL in the input.' );\n\t\tthis._urlInputViewInfoTip = t( 'Tip: Paste the URL into the content to embed faster.' );\n\n\t\tlabeledInput.label = t( 'Media URL' );\n\t\tlabeledInput.infoText = this._urlInputViewInfoDefault;\n\n\t\tinputField.on( 'input', () => {\n\t\t\t// Display the tip text only when there is some value. Otherwise fall back to the default info text.\n\t\t\tlabeledInput.infoText = inputField.element.value ? this._urlInputViewInfoTip : this._urlInputViewInfoDefault;\n\t\t\tthis.mediaURLInputValue = inputField.element.value.trim();\n\t\t} );\n\n\t\treturn labeledInput;\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n}\n\n/**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * e.g. click on {@link #saveButtonView}.\n *\n * @event submit\n */\n\n/**\n * Fired when the form view is canceled, e.g. by a click on {@link #cancelButtonView}.\n *\n * @event cancel\n */\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaembedui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { createDropdown } from 'ckeditor5/src/ui';\n\nimport MediaFormView from './ui/mediaformview';\nimport MediaEmbedEditing from './mediaembedediting';\nimport mediaIcon from '../theme/icons/media.svg';\n\n/**\n * The media embed UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbedUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ MediaEmbedEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MediaEmbedUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'mediaEmbed' );\n\t\tconst registry = editor.plugins.get( MediaEmbedEditing ).registry;\n\n\t\teditor.ui.componentFactory.add( 'mediaEmbed', locale => {\n\t\t\tconst dropdown = createDropdown( locale );\n\n\t\t\tconst mediaForm = new MediaFormView( getFormValidators( editor.t, registry ), editor.locale );\n\n\t\t\tthis._setUpDropdown( dropdown, mediaForm, command, editor );\n\t\t\tthis._setUpForm( dropdown, mediaForm, command );\n\n\t\t\treturn dropdown;\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdown\n\t * @param {module:ui/view~View} form\n\t * @param {module:media-embed/mediaembedcommand~MediaEmbedCommand} command\n\t */\n\t_setUpDropdown( dropdown, form, command ) {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst button = dropdown.buttonView;\n\n\t\tdropdown.bind( 'isEnabled' ).to( command );\n\t\tdropdown.panelView.children.add( form );\n\n\t\tbutton.set( {\n\t\t\tlabel: t( 'Insert media' ),\n\t\t\ticon: mediaIcon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\t// Note: Use the low priority to make sure the following listener starts working after the\n\t\t// default action of the drop-down is executed (i.e. the panel showed up). Otherwise, the\n\t\t// invisible form/input cannot be focused/selected.\n\t\tbutton.on( 'open', () => {\n\t\t\tform.disableCssTransitions();\n\n\t\t\t// Make sure that each time the panel shows up, the URL field remains in sync with the value of\n\t\t\t// the command. If the user typed in the input, then canceled (`urlInputView#fieldView#value` stays\n\t\t\t// unaltered) and re-opened it without changing the value of the media command (e.g. because they\n\t\t\t// didn't change the selection), they would see the old value instead of the actual value of the\n\t\t\t// command.\n\t\t\tform.url = command.value || '';\n\t\t\tform.urlInputView.fieldView.select();\n\t\t\tform.enableCssTransitions();\n\t\t}, { priority: 'low' } );\n\n\t\tdropdown.on( 'submit', () => {\n\t\t\tif ( form.isValid() ) {\n\t\t\t\teditor.execute( 'mediaEmbed', form.url );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t}\n\t\t} );\n\n\t\tdropdown.on( 'change:isOpen', () => form.resetFormStatus() );\n\t\tdropdown.on( 'cancel', () => {\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdown\n\t * @param {module:ui/view~View} form\n\t * @param {module:media-embed/mediaembedcommand~MediaEmbedCommand} command\n\t */\n\t_setUpForm( dropdown, form, command ) {\n\t\tform.delegate( 'submit', 'cancel' ).to( dropdown );\n\t\tform.urlInputView.bind( 'value' ).to( command, 'value' );\n\n\t\t// Form elements should be read-only when corresponding commands are disabled.\n\t\tform.urlInputView.bind( 'isReadOnly' ).to( command, 'isEnabled', value => !value );\n\t}\n}\n\nfunction getFormValidators( t, registry ) {\n\treturn [\n\t\tform => {\n\t\t\tif ( !form.url.length ) {\n\t\t\t\treturn t( 'The URL must not be empty.' );\n\t\t\t}\n\t\t},\n\t\tform => {\n\t\t\tif ( !registry.hasMedia( form.url ) ) {\n\t\t\t\treturn t( 'This media URL is not supported.' );\n\t\t\t}\n\t\t}\n\t];\n}\n","export default \"\";","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mentioncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { CKEditorError, toMap } from 'ckeditor5/src/utils';\n\nimport { _addMentionAttributes } from './mentionediting';\n\n/**\n * The mention command.\n *\n * The command is registered by {@link module:mention/mentionediting~MentionEditing} as `'mention'`.\n *\n * To insert a mention onto a range, execute the command and specify a mention object with a range to replace:\n *\n *\t\tconst focus = editor.model.document.selection.focus;\n *\n *\t\t// It will replace one character before the selection focus with the '#1234' text\n *\t\t// with the mention attribute filled with passed attributes.\n *\t\teditor.execute( 'mention', {\n *\t\t\tmarker: '#',\n *\t\t\tmention: {\n *\t\t\t\tid: '#1234',\n *\t\t\t\tname: 'Foo',\n *\t\t\t\ttitle: 'Big Foo'\n *\t\t\t},\n *\t\t\trange: editor.model.createRange( focus.getShiftedBy( -1 ), focus )\n *\t\t} );\n *\n *\t\t// It will replace one character before the selection focus with the 'The \"Big Foo\"' text\n *\t\t// with the mention attribute filled with passed attributes.\n *\t\teditor.execute( 'mention', {\n *\t\t\tmarker: '#',\n *\t\t\tmention: {\n *\t\t\t\tid: '#1234',\n *\t\t\t\tname: 'Foo',\n *\t\t\t\ttitle: 'Big Foo'\n *\t\t\t},\n *\t\t\ttext: 'The \"Big Foo\"',\n *\t\t\trange: editor.model.createRange( focus.getShiftedBy( -1 ), focus )\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class MentionCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'mention' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {Object|String} options.mention The mention object to insert. When a string is passed, it will be used to create a plain\n\t * object with the name attribute that equals the passed string.\n\t * @param {String} options.marker The marker character (e.g. `'@'`).\n\t * @param {String} [options.text] The text of the inserted mention. Defaults to the full mention string composed from `marker` and\n\t * `mention` string or `mention.id` if an object is passed.\n\t * @param {module:engine/model/range~Range} [options.range] The range to replace.\n\t * Note that the replaced range might be shorter than the inserted text with the mention attribute.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst mentionData = typeof options.mention == 'string' ? { id: options.mention } : options.mention;\n\t\tconst mentionID = mentionData.id;\n\n\t\tconst range = options.range || selection.getFirstRange();\n\n\t\tconst mentionText = options.text || mentionID;\n\n\t\tconst mention = _addMentionAttributes( { _text: mentionText, id: mentionID }, mentionData );\n\n\t\tif ( options.marker.length != 1 ) {\n\t\t\t/**\n\t\t\t * The marker must be a single character.\n\t\t\t *\n\t\t\t * Correct markers: `'@'`, `'#'`.\n\t\t\t *\n\t\t\t * Incorrect markers: `'$$'`, `'[@'`.\n\t\t\t *\n\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t *\n\t\t\t * @error mentioncommand-incorrect-marker\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'mentioncommand-incorrect-marker',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( mentionID.charAt( 0 ) != options.marker ) {\n\t\t\t/**\n\t\t\t * The feed item ID must start with the marker character.\n\t\t\t *\n\t\t\t * Correct mention feed setting:\n\t\t\t *\n\t\t\t *\t\tmentions: [\n\t\t\t *\t\t\t{\n\t\t\t *\t\t\t\tmarker: '@',\n\t\t\t *\t\t\t\tfeed: [ '@Ann', '@Barney', ... ]\n\t\t\t *\t\t\t}\n\t\t\t *\t\t]\n\t\t\t *\n\t\t\t * Incorrect mention feed setting:\n\t\t\t *\n\t\t\t *\t\tmentions: [\n\t\t\t *\t\t\t{\n\t\t\t *\t\t\t\tmarker: '@',\n\t\t\t *\t\t\t\tfeed: [ 'Ann', 'Barney', ... ]\n\t\t\t *\t\t\t}\n\t\t\t *\t\t]\n\t\t\t *\n\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t *\n\t\t\t * @error mentioncommand-incorrect-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'mentioncommand-incorrect-id',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\tconst currentAttributes = toMap( selection.getAttributes() );\n\t\t\tconst attributesWithMention = new Map( currentAttributes.entries() );\n\n\t\t\tattributesWithMention.set( 'mention', mention );\n\n\t\t\t// Replace a range with the text with a mention.\n\t\t\tmodel.insertContent( writer.createText( mentionText, attributesWithMention ), range );\n\t\t\tmodel.insertContent( writer.createText( ' ', currentAttributes ), range.start.getShiftedBy( mentionText.length ) );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mentionediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { uid } from 'ckeditor5/src/utils';\n\nimport MentionCommand from './mentioncommand';\n\n/**\n * The mention editing feature.\n *\n * It introduces the {@link module:mention/mentioncommand~MentionCommand command} and the `mention`\n * attribute in the {@link module:engine/model/model~Model model} which renders in the {@link module:engine/view/view view}\n * as a ``.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MentionEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MentionEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst doc = model.document;\n\n\t\t// Allow the mention attribute on all text nodes.\n\t\tmodel.schema.extend( '$text', { allowAttributes: 'mention' } );\n\n\t\t// Upcast conversion.\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tkey: 'data-mention',\n\t\t\t\tclasses: 'mention'\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: 'mention',\n\t\t\t\tvalue: viewElement => _toMentionAttribute( viewElement )\n\t\t\t}\n\t\t} );\n\n\t\t// Downcast conversion.\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: 'mention',\n\t\t\tview: createViewMentionElement\n\t\t} );\n\t\teditor.conversion.for( 'downcast' ).add( preventPartialMentionDowncast );\n\n\t\tdoc.registerPostFixer( writer => removePartialMentionPostFixer( writer, doc, model.schema ) );\n\t\tdoc.registerPostFixer( writer => extendAttributeOnMentionPostFixer( writer, doc ) );\n\t\tdoc.registerPostFixer( writer => selectionMentionAttributePostFixer( writer, doc ) );\n\n\t\teditor.commands.add( 'mention', new MentionCommand( editor ) );\n\t}\n}\n\nexport function _addMentionAttributes( baseMentionData, data ) {\n\treturn Object.assign( { uid: uid() }, baseMentionData, data || {} );\n}\n\n/**\n * Creates a mention attribute value from the provided view element and optional data.\n *\n * This function is exposed as\n * {@link module:mention/mention~Mention#toMentionAttribute `editor.plugins.get( 'Mention' ).toMentionAttribute()`}.\n *\n * @protected\n * @param {module:engine/view/element~Element} viewElementOrMention\n * @param {String|Object} [data] Mention data to be extended.\n * @returns {module:mention/mention~MentionAttribute}\n */\nexport function _toMentionAttribute( viewElementOrMention, data ) {\n\tconst dataMention = viewElementOrMention.getAttribute( 'data-mention' );\n\n\tconst textNode = viewElementOrMention.getChild( 0 );\n\n\t// Do not convert empty mentions.\n\tif ( !textNode ) {\n\t\treturn;\n\t}\n\n\tconst baseMentionData = {\n\t\tid: dataMention,\n\t\t_text: textNode.data\n\t};\n\n\treturn _addMentionAttributes( baseMentionData, data );\n}\n\n// A converter that blocks partial mention from being converted.\n//\n// This converter is registered with 'highest' priority in order to consume mention attribute before it is converted by\n// any other converters. This converter only consumes partial mention - those whose `_text` attribute is not equal to text with mention\n// attribute. This may happen when copying part of mention text.\n//\n// @param {module:engine/conversion/dwoncastdispatcher~DowncastDispatcher}\nfunction preventPartialMentionDowncast( dispatcher ) {\n\tdispatcher.on( 'attribute:mention', ( evt, data, conversionApi ) => {\n\t\tconst mention = data.attributeNewValue;\n\n\t\tif ( !data.item.is( '$textProxy' ) || !mention ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst start = data.range.start;\n\t\tconst textNode = start.textNode || start.nodeAfter;\n\n\t\tif ( textNode.data != mention._text ) {\n\t\t\t// Consume item to prevent partial mention conversion.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\t\t}\n\t}, { priority: 'highest' } );\n}\n\n// Creates a mention element from the mention data.\n//\n// @param {Object} mention\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/attributeelement~AttributeElement}\nfunction createViewMentionElement( mention, { writer } ) {\n\tif ( !mention ) {\n\t\treturn;\n\t}\n\n\tconst attributes = {\n\t\tclass: 'mention',\n\t\t'data-mention': mention.id\n\t};\n\n\tconst options = {\n\t\tid: mention.uid,\n\t\tpriority: 20\n\t};\n\n\treturn writer.createAttributeElement( 'span', attributes, options );\n}\n\n// Model post-fixer that disallows typing with selection when the selection is placed after the text node with the mention attribute or\n// before a text node with mention attribute.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction selectionMentionAttributePostFixer( writer, doc ) {\n\tconst selection = doc.selection;\n\tconst focus = selection.focus;\n\n\tif ( selection.isCollapsed && selection.hasAttribute( 'mention' ) && shouldNotTypeWithMentionAt( focus ) ) {\n\t\twriter.removeSelectionAttribute( 'mention' );\n\n\t\treturn true;\n\t}\n}\n\n// Helper function to detect if mention attribute should be removed from selection.\n// This check makes only sense if the selection has mention attribute.\n//\n// The mention attribute should be removed from a selection when selection focus is placed:\n// a) after a text node\n// b) the position is at parents start - the selection will set attributes from node after.\nfunction shouldNotTypeWithMentionAt( position ) {\n\tconst isAtStart = position.isAtStart;\n\tconst isAfterAMention = position.nodeBefore && position.nodeBefore.is( '$text' );\n\n\treturn isAfterAMention || isAtStart;\n}\n\n// Model post-fixer that removes the mention attribute from the modified text node.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction removePartialMentionPostFixer( writer, doc, schema ) {\n\tconst changes = doc.differ.getChanges();\n\n\tlet wasChanged = false;\n\n\tfor ( const change of changes ) {\n\t\t// Checks the text node on the current position.\n\t\tconst position = change.position;\n\n\t\tif ( change.name == '$text' ) {\n\t\t\tconst nodeAfterInsertedTextNode = position.textNode && position.textNode.nextSibling;\n\n\t\t\t// Checks the text node where the change occurred.\n\t\t\twasChanged = checkAndFix( position.textNode, writer ) || wasChanged;\n\n\t\t\t// Occurs on paste inside a text node with mention.\n\t\t\twasChanged = checkAndFix( nodeAfterInsertedTextNode, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( position.nodeBefore, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( position.nodeAfter, writer ) || wasChanged;\n\t\t}\n\n\t\t// Checks text nodes in inserted elements (might occur when splitting a paragraph or pasting content inside text with mention).\n\t\tif ( change.name != '$text' && change.type == 'insert' ) {\n\t\t\tconst insertedNode = position.nodeAfter;\n\n\t\t\tfor ( const item of writer.createRangeIn( insertedNode ).getItems() ) {\n\t\t\t\twasChanged = checkAndFix( item, writer ) || wasChanged;\n\t\t\t}\n\t\t}\n\n\t\t// Inserted inline elements might break mention.\n\t\tif ( change.type == 'insert' && schema.isInline( change.name ) ) {\n\t\t\tconst nodeAfterInserted = position.nodeAfter && position.nodeAfter.nextSibling;\n\n\t\t\twasChanged = checkAndFix( position.nodeBefore, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( nodeAfterInserted, writer ) || wasChanged;\n\t\t}\n\t}\n\n\treturn wasChanged;\n}\n\n// This post-fixer will extend the attribute applied on the part of the mention so the whole text node of the mention will have\n// the added attribute.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction extendAttributeOnMentionPostFixer( writer, doc ) {\n\tconst changes = doc.differ.getChanges();\n\n\tlet wasChanged = false;\n\n\tfor ( const change of changes ) {\n\t\tif ( change.type === 'attribute' && change.attributeKey != 'mention' ) {\n\t\t\t// Checks the node on the left side of the range...\n\t\t\tconst nodeBefore = change.range.start.nodeBefore;\n\t\t\t// ... and on the right side of the range.\n\t\t\tconst nodeAfter = change.range.end.nodeAfter;\n\n\t\t\tfor ( const node of [ nodeBefore, nodeAfter ] ) {\n\t\t\t\tif ( isBrokenMentionNode( node ) && node.getAttribute( change.attributeKey ) != change.attributeNewValue ) {\n\t\t\t\t\twriter.setAttribute( change.attributeKey, change.attributeNewValue, node );\n\n\t\t\t\t\twasChanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wasChanged;\n}\n\n// Checks if a node has a correct mention attribute if present.\n// Returns `true` if the node is text and has a mention attribute whose text does not match the expected mention text.\n//\n// @param {module:engine/model/node~Node} node The node to check.\n// @returns {Boolean}\nfunction isBrokenMentionNode( node ) {\n\tif ( !node || !( node.is( '$text' ) || node.is( '$textProxy' ) ) || !node.hasAttribute( 'mention' ) ) {\n\t\treturn false;\n\t}\n\n\tconst text = node.data;\n\tconst mention = node.getAttribute( 'mention' );\n\n\tconst expectedText = mention._text;\n\n\treturn text != expectedText;\n}\n\n// Fixes a mention on a text node if it needs a fix.\n//\n// @param {module:engine/model/text~Text} textNode\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean}\nfunction checkAndFix( textNode, writer ) {\n\tif ( isBrokenMentionNode( textNode ) ) {\n\t\twriter.removeAttribute( 'mention', textNode );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/mentionsview\n */\n\nimport { ListView } from 'ckeditor5/src/ui';\nimport { Rect } from 'ckeditor5/src/utils';\n\nimport '../../theme/mentionui.css';\n\n/**\n * The mention ui view.\n *\n * @extends module:ui/list/listview~ListView\n */\nexport default class MentionsView extends ListView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-mentions'\n\t\t\t\t],\n\n\t\t\t\ttabindex: '-1'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * {@link #select Selects} the first item.\n\t */\n\tselectFirst() {\n\t\tthis.select( 0 );\n\t}\n\n\t/**\n\t * Selects next item to the currently {@link #select selected}.\n\t *\n\t * If the last item is already selected, it will select the first item.\n\t */\n\tselectNext() {\n\t\tconst item = this.selected;\n\t\tconst index = this.items.getIndex( item );\n\n\t\tthis.select( index + 1 );\n\t}\n\n\t/**\n\t * Selects previous item to the currently {@link #select selected}.\n\t *\n\t * If the first item is already selected, it will select the last item.\n\t */\n\tselectPrevious() {\n\t\tconst item = this.selected;\n\t\tconst index = this.items.getIndex( item );\n\n\t\tthis.select( index - 1 );\n\t}\n\n\t/**\n\t * Marks item at a given index as selected.\n\t *\n\t * Handles selection cycling when passed index is out of bounds:\n\t * - if the index is lower than 0, it will select the last item,\n\t * - if the index is higher than the last item index, it will select the first item.\n\t *\n\t * @param {Number} index Index of an item to be marked as selected.\n\t */\n\tselect( index ) {\n\t\tlet indexToGet = 0;\n\n\t\tif ( index > 0 && index < this.items.length ) {\n\t\t\tindexToGet = index;\n\t\t} else if ( index < 0 ) {\n\t\t\tindexToGet = this.items.length - 1;\n\t\t}\n\n\t\tconst item = this.items.get( indexToGet );\n\n\t\t// Return early if item is already selected.\n\t\tif ( this.selected === item ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove highlight of previously selected item.\n\t\tif ( this.selected ) {\n\t\t\tthis.selected.removeHighlight();\n\t\t}\n\n\t\titem.highlight();\n\t\tthis.selected = item;\n\n\t\t// Scroll the mentions view to the selected element.\n\t\tif ( !this._isItemVisibleInScrolledArea( item ) ) {\n\t\t\tthis.element.scrollTop = item.element.offsetTop;\n\t\t}\n\t}\n\n\t/**\n\t * Triggers the `execute` event on the {@link #select selected} item.\n\t */\n\texecuteSelected() {\n\t\tthis.selected.fire( 'execute' );\n\t}\n\n\t// Checks if an item is visible in the scrollable area.\n\t//\n\t// The item is considered visible when:\n\t// - its top boundary is inside the scrollable rect\n\t// - its bottom boundary is inside the scrollable rect (the whole item must be visible)\n\t_isItemVisibleInScrolledArea( item ) {\n\t\treturn new Rect( this.element ).contains( new Rect( item.element ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/domwrapperview\n */\n\nimport { View } from 'ckeditor5/src/ui';\n\n/**\n * This class wraps DOM element as a CKEditor5 UI View.\n *\n * It allows to render any DOM element and use it in mentions list.\n *\n * @extends {module:ui/view~View}\n */\nexport default class DomWrapperView extends View {\n\t/**\n\t * Creates an instance of {@link module:mention/ui/domwrapperview~DomWrapperView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Element} domElement\n\t */\n\tconstructor( locale, domElement ) {\n\t\tsuper( locale );\n\n\t\t// Disable template rendering on this view.\n\t\tthis.template = false;\n\n\t\t/**\n\t\t * The DOM element for which wrapper was created.\n\t\t *\n\t\t * @type {Element}\n\t\t */\n\t\tthis.domElement = domElement;\n\n\t\t// Render dom wrapper as a button.\n\t\tthis.domElement.classList.add( 'ck-button' );\n\n\t\t/**\n\t\t * Controls whether the dom wrapper view is \"on\". This is in line with {@link module:ui/button/button~Button#isOn} property.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #isOn\n\t\t */\n\t\tthis.set( 'isOn', false );\n\n\t\t// Handle isOn state as in buttons.\n\t\tthis.on( 'change:isOn', ( evt, name, isOn ) => {\n\t\t\tif ( isOn ) {\n\t\t\t\tthis.domElement.classList.add( 'ck-on' );\n\t\t\t\tthis.domElement.classList.remove( 'ck-off' );\n\t\t\t} else {\n\t\t\t\tthis.domElement.classList.add( 'ck-off' );\n\t\t\t\tthis.domElement.classList.remove( 'ck-on' );\n\t\t\t}\n\t\t} );\n\n\t\t// Pass click event as execute event.\n\t\tthis.listenTo( this.domElement, 'click', () => {\n\t\t\tthis.fire( 'execute' );\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.element = this.domElement;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/mentionlistitemview\n */\n\nimport { ListItemView } from 'ckeditor5/src/ui';\n\nexport default class MentionListItemView extends ListItemView {\n\thighlight() {\n\t\tconst child = this.children.first;\n\n\t\tchild.isOn = true;\n\t}\n\n\tremoveHighlight() {\n\t\tconst child = this.children.first;\n\n\t\tchild.isOn = false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mentionui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui';\nimport { Collection, keyCodes, env, Rect, CKEditorError, logWarning } from 'ckeditor5/src/utils';\nimport { TextWatcher } from 'ckeditor5/src/typing';\n\nimport { debounce } from 'lodash-es';\n\nimport MentionsView from './ui/mentionsview';\nimport DomWrapperView from './ui/domwrapperview';\nimport MentionListItemView from './ui/mentionlistitemview';\n\nconst VERTICAL_SPACING = 3;\n\n// The key codes that mention UI handles when it is open (without commit keys).\nconst defaultHandledKeyCodes = [\n\tkeyCodes.arrowup,\n\tkeyCodes.arrowdown,\n\tkeyCodes.esc\n];\n\n// Dropdown commit key codes.\nconst defaultCommitKeyCodes = [\n\tkeyCodes.enter,\n\tkeyCodes.tab\n];\n\n/**\n * The mention UI feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MentionUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MentionUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The mention view.\n\t\t *\n\t\t * @type {module:mention/ui/mentionsview~MentionsView}\n\t\t * @private\n\t\t */\n\t\tthis._mentionsView = this._createMentionView();\n\n\t\t/**\n\t\t * Stores mention feeds configurations.\n\t\t *\n\t\t * @type {Map}\n\t\t * @private\n\t\t */\n\t\tthis._mentionsConfigurations = new Map();\n\n\t\t/**\n\t\t * Debounced feed requester. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {String} marker\n\t\t * @param {String} feedText\n\t\t * @method\n\t\t */\n\t\tthis._requestFeedDebounced = debounce( this._requestFeed, 100 );\n\n\t\teditor.config.define( 'mention', { feeds: [] } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\tconst commitKeys = editor.config.get( 'mention.commitKeys' ) || defaultCommitKeyCodes;\n\t\tconst handledKeyCodes = defaultHandledKeyCodes.concat( commitKeys );\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t// Key listener that handles navigation in mention view.\n\t\teditor.editing.view.document.on( 'keydown', ( evt, data ) => {\n\t\t\tif ( isHandledKey( data.keyCode ) && this._isUIVisible ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop(); // Required for Enter key overriding.\n\n\t\t\t\tif ( data.keyCode == keyCodes.arrowdown ) {\n\t\t\t\t\tthis._mentionsView.selectNext();\n\t\t\t\t}\n\n\t\t\t\tif ( data.keyCode == keyCodes.arrowup ) {\n\t\t\t\t\tthis._mentionsView.selectPrevious();\n\t\t\t\t}\n\n\t\t\t\tif ( commitKeys.includes( data.keyCode ) ) {\n\t\t\t\t\tthis._mentionsView.executeSelected();\n\t\t\t\t}\n\n\t\t\t\tif ( data.keyCode == keyCodes.esc ) {\n\t\t\t\t\tthis._hideUIAndRemoveMarker();\n\t\t\t\t}\n\t\t\t}\n\t\t}, { priority: 'highest' } ); // Required to override the Enter key.\n\n\t\t// Close the dropdown upon clicking outside of the plugin UI.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this._mentionsView,\n\t\t\tactivator: () => this._isUIVisible,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideUIAndRemoveMarker()\n\t\t} );\n\n\t\tconst feeds = editor.config.get( 'mention.feeds' );\n\n\t\tfor ( const mentionDescription of feeds ) {\n\t\t\tconst feed = mentionDescription.feed;\n\n\t\t\tconst marker = mentionDescription.marker;\n\n\t\t\tif ( !isValidMentionMarker( marker ) ) {\n\t\t\t\t/**\n\t\t\t\t * The marker must be a single character.\n\t\t\t\t *\n\t\t\t\t * Correct markers: `'@'`, `'#'`.\n\t\t\t\t *\n\t\t\t\t * Incorrect markers: `'$$'`, `'[@'`.\n\t\t\t\t *\n\t\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t\t *\n\t\t\t\t * @error mentionconfig-incorrect-marker\n\t\t\t\t * @param {String} marker Configured marker\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'mentionconfig-incorrect-marker', null, { marker } );\n\t\t\t}\n\n\t\t\tconst feedCallback = typeof feed == 'function' ? feed.bind( this.editor ) : createFeedCallback( feed );\n\t\t\tconst itemRenderer = mentionDescription.itemRenderer;\n\t\t\tconst definition = { marker, feedCallback, itemRenderer };\n\n\t\t\tthis._mentionsConfigurations.set( marker, definition );\n\t\t}\n\n\t\tthis._setupTextWatcher( feeds );\n\t\tthis.listenTo( editor, 'change:isReadOnly', () => {\n\t\t\tthis._hideUIAndRemoveMarker();\n\t\t} );\n\t\tthis.on( 'requestFeed:response', ( evt, data ) => this._handleFeedResponse( data ) );\n\t\tthis.on( 'requestFeed:error', () => this._hideUIAndRemoveMarker() );\n\n\t\t// Checks if a given key code is handled by the mention UI.\n\t\t//\n\t\t// @param {Number}\n\t\t// @returns {Boolean}\n\t\tfunction isHandledKey( keyCode ) {\n\t\t\treturn handledKeyCodes.includes( keyCode );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis._mentionsView.destroy();\n\t}\n\n\t/**\n\t * Returns true when {@link #_mentionsView} is in the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIVisible() {\n\t\treturn this._balloon.visibleView === this._mentionsView;\n\t}\n\n\t/**\n\t * Creates the {@link #_mentionsView}.\n\t *\n\t * @private\n\t * @returns {module:mention/ui/mentionsview~MentionsView}\n\t */\n\t_createMentionView() {\n\t\tconst locale = this.editor.locale;\n\n\t\tconst mentionsView = new MentionsView( locale );\n\n\t\tthis._items = new Collection();\n\n\t\tmentionsView.items.bindTo( this._items ).using( data => {\n\t\t\tconst { item, marker } = data;\n\n\t\t\t// Set to 10 by default for backwards compatibility. See: #10479\n\t\t\tconst dropdownLimit = this.editor.config.get( 'mention.dropdownLimit' ) || 10;\n\n\t\t\tif ( mentionsView.items.length >= dropdownLimit ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst listItemView = new MentionListItemView( locale );\n\n\t\t\tconst view = this._renderItem( item, marker );\n\t\t\tview.delegate( 'execute' ).to( listItemView );\n\n\t\t\tlistItemView.children.add( view );\n\t\t\tlistItemView.item = item;\n\t\t\tlistItemView.marker = marker;\n\n\t\t\tlistItemView.on( 'execute', () => {\n\t\t\t\tmentionsView.fire( 'execute', {\n\t\t\t\t\titem,\n\t\t\t\t\tmarker\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn listItemView;\n\t\t} );\n\n\t\tmentionsView.on( 'execute', ( evt, data ) => {\n\t\t\tconst editor = this.editor;\n\t\t\tconst model = editor.model;\n\n\t\t\tconst item = data.item;\n\t\t\tconst marker = data.marker;\n\n\t\t\tconst mentionMarker = editor.model.markers.get( 'mention' );\n\n\t\t\t// Create a range on matched text.\n\t\t\tconst end = model.createPositionAt( model.document.selection.focus );\n\t\t\tconst start = model.createPositionAt( mentionMarker.getStart() );\n\t\t\tconst range = model.createRange( start, end );\n\n\t\t\tthis._hideUIAndRemoveMarker();\n\n\t\t\teditor.execute( 'mention', {\n\t\t\t\tmention: item,\n\t\t\t\ttext: item.text,\n\t\t\t\tmarker,\n\t\t\t\trange\n\t\t\t} );\n\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn mentionsView;\n\t}\n\n\t/**\n\t * Returns item renderer for the marker.\n\t *\n\t * @private\n\t * @param {String} marker\n\t * @returns {Function|null}\n\t */\n\t_getItemRenderer( marker ) {\n\t\tconst { itemRenderer } = this._mentionsConfigurations.get( marker );\n\n\t\treturn itemRenderer;\n\t}\n\n\t/**\n\t * Requests a feed from a configured callbacks.\n\t *\n\t * @private\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:response\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:discarded\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:error\n\t * @param {String} marker\n\t * @param {String} feedText\n\t */\n\t_requestFeed( marker, feedText ) {\n\t\t// @if CK_DEBUG_MENTION // console.log( '%c[Feed]%c Requesting for', 'color: blue', 'color: black', `\"${ feedText }\"` );\n\n\t\t// Store the last requested feed - it is used to discard any out-of order requests.\n\t\tthis._lastRequested = feedText;\n\n\t\tconst { feedCallback } = this._mentionsConfigurations.get( marker );\n\t\tconst feedResponse = feedCallback( feedText );\n\n\t\tconst isAsynchronous = feedResponse instanceof Promise;\n\n\t\t// For synchronous feeds (e.g. callbacks, arrays) fire the response event immediately.\n\t\tif ( !isAsynchronous ) {\n\t\t\t/**\n\t\t\t * Fired whenever requested feed has a response.\n\t\t\t *\n\t\t\t * @event requestFeed:response\n\t\t\t * @param {Object} data Event data.\n\t\t\t * @param {Array.} data.feed Autocomplete items.\n\t\t\t * @param {String} data.marker The character which triggers autocompletion for mention.\n\t\t\t * @param {String} data.feedText The text for which feed items were requested.\n\t\t\t */\n\t\t\tthis.fire( 'requestFeed:response', { feed: feedResponse, marker, feedText } );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle the asynchronous responses.\n\t\tfeedResponse\n\t\t\t.then( response => {\n\t\t\t\t// Check the feed text of this response with the last requested one so either:\n\t\t\t\tif ( this._lastRequested == feedText ) {\n\t\t\t\t\t// It is the same and fire the response event.\n\t\t\t\t\tthis.fire( 'requestFeed:response', { feed: response, marker, feedText } );\n\t\t\t\t} else {\n\t\t\t\t\t// It is different - most probably out-of-order one, so fire the discarded event.\n\t\t\t\t\t/**\n\t\t\t\t\t * Fired whenever the requested feed was discarded. This happens when the response was delayed and\n\t\t\t\t\t * other feed was already requested.\n\t\t\t\t\t *\n\t\t\t\t\t * @event requestFeed:discarded\n\t\t\t\t\t * @param {Object} data Event data.\n\t\t\t\t\t * @param {Array.} data.feed Autocomplete items.\n\t\t\t\t\t * @param {String} data.marker The character which triggers autocompletion for mention.\n\t\t\t\t\t * @param {String} data.feedText The text for which feed items were requested.\n\t\t\t\t\t */\n\t\t\t\t\tthis.fire( 'requestFeed:discarded', { feed: response, marker, feedText } );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( error => {\n\t\t\t\t/**\n\t\t\t\t * Fired whenever the requested {@link module:mention/mention~MentionFeed#feed} promise fails with error.\n\t\t\t\t *\n\t\t\t\t * @event requestFeed:error\n\t\t\t\t * @param {Object} data Event data.\n\t\t\t\t * @param {Error} data.error The error that was caught.\n\t\t\t\t */\n\t\t\t\tthis.fire( 'requestFeed:error', { error } );\n\n\t\t\t\t/**\n\t\t\t\t * The callback used for obtaining mention autocomplete feed thrown and error and the mention UI was hidden or\n\t\t\t\t * not displayed at all.\n\t\t\t\t *\n\t\t\t\t * @error mention-feed-callback-error\n\t\t\t\t * @param {String} marker Configured marker for which error occurred.\n\t\t\t\t */\n\t\t\t\tlogWarning( 'mention-feed-callback-error', { marker } );\n\t\t\t} );\n\t}\n\n\t/**\n\t * Registers a text watcher for the marker.\n\t *\n\t * @private\n\t * @param {Array.} feeds Feeds of mention plugin configured in editor\n\t * @returns {module:typing/textwatcher~TextWatcher}\n\t */\n\t_setupTextWatcher( feeds ) {\n\t\tconst editor = this.editor;\n\n\t\tconst feedsWithPattern = feeds.map( feed => ( {\n\t\t\t...feed,\n\t\t\tpattern: createRegExp( feed.marker, feed.minimumCharacters || 0 )\n\t\t} ) );\n\n\t\tconst watcher = new TextWatcher( editor.model, createTestCallback( feedsWithPattern ) );\n\n\t\twatcher.on( 'matched', ( evt, data ) => {\n\t\t\tconst markerDefinition = getLastValidMarkerInText( feedsWithPattern, data.text );\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tconst focus = selection.focus;\n\t\t\tconst markerPosition = editor.model.createPositionAt( focus.parent, markerDefinition.position );\n\n\t\t\tif ( isPositionInExistingMention( focus ) || isMarkerInExistingMention( markerPosition ) ) {\n\t\t\t\tthis._hideUIAndRemoveMarker();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst feedText = requestFeedText( markerDefinition, data.text );\n\t\t\tconst matchedTextLength = markerDefinition.marker.length + feedText.length;\n\n\t\t\t// Create a marker range.\n\t\t\tconst start = focus.getShiftedBy( -matchedTextLength );\n\t\t\tconst end = focus.getShiftedBy( -feedText.length );\n\n\t\t\tconst markerRange = editor.model.createRange( start, end );\n\n\t\t\t// @if CK_DEBUG_MENTION // console.group( '%c[TextWatcher]%c matched', 'color: red', 'color: black', `\"${ feedText }\"` );\n\t\t\t// @if CK_DEBUG_MENTION // console.log( 'data#text', `\"${ data.text }\"` );\n\t\t\t// @if CK_DEBUG_MENTION // console.log( 'data#range', data.range.start.path, data.range.end.path );\n\t\t\t// @if CK_DEBUG_MENTION // console.log( 'marker definition', markerDefinition );\n\t\t\t// @if CK_DEBUG_MENTION // console.log( 'marker range', markerRange.start.path, markerRange.end.path );\n\n\t\t\tif ( checkIfStillInCompletionMode( editor ) ) {\n\t\t\t\tconst mentionMarker = editor.model.markers.get( 'mention' );\n\n\t\t\t\t// Update the marker - user might've moved the selection to other mention trigger.\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[Editing]%c Updating the marker.', 'color: purple', 'color: black' );\n\n\t\t\t\t\twriter.updateMarker( mentionMarker, { range: markerRange } );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[Editing]%c Adding the marker.', 'color: purple', 'color: black' );\n\n\t\t\t\t\twriter.addMarker( 'mention', { range: markerRange, usingOperation: false, affectsData: false } );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis._requestFeedDebounced( markerDefinition.marker, feedText );\n\n\t\t\t// @if CK_DEBUG_MENTION // console.groupEnd( '[TextWatcher] matched' );\n\t\t} );\n\n\t\twatcher.on( 'unmatched', () => {\n\t\t\tthis._hideUIAndRemoveMarker();\n\t\t} );\n\n\t\tconst mentionCommand = editor.commands.get( 'mention' );\n\t\twatcher.bind( 'isEnabled' ).to( mentionCommand );\n\n\t\treturn watcher;\n\t}\n\n\t/**\n\t * Handles the feed response event data.\n\t *\n\t * @param data\n\t * @private\n\t */\n\t_handleFeedResponse( data ) {\n\t\tconst { feed, marker } = data;\n\n\t\t// eslint-disable-next-line max-len\n\t\t// @if CK_DEBUG_MENTION // console.log( `%c[Feed]%c Response for \"${ data.feedText }\" (${ feed.length })`, 'color: blue', 'color: black', feed );\n\n\t\t// If the marker is not in the document happens when the selection had changed and the 'mention' marker was removed.\n\t\tif ( !checkIfStillInCompletionMode( this.editor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Reset the view.\n\t\tthis._items.clear();\n\n\t\tfor ( const feedItem of feed ) {\n\t\t\tconst item = typeof feedItem != 'object' ? { id: feedItem, text: feedItem } : feedItem;\n\n\t\t\tthis._items.add( { item, marker } );\n\t\t}\n\n\t\tconst mentionMarker = this.editor.model.markers.get( 'mention' );\n\n\t\tif ( this._items.length ) {\n\t\t\tthis._showOrUpdateUI( mentionMarker );\n\t\t} else {\n\t\t\t// Do not show empty mention UI.\n\t\t\tthis._hideUIAndRemoveMarker();\n\t\t}\n\t}\n\n\t/**\n\t * Shows the mentions balloon. If the panel is already visible, it will reposition it.\n\t *\n\t * @private\n\t */\n\t_showOrUpdateUI( markerMarker ) {\n\t\tif ( this._isUIVisible ) {\n\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[UI]%c Updating position.', 'color: green', 'color: black' );\n\n\t\t\t// Update balloon position as the mention list view may change its size.\n\t\t\tthis._balloon.updatePosition( this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ) );\n\t\t} else {\n\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[UI]%c Showing the UI.', 'color: green', 'color: black' );\n\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: this._mentionsView,\n\t\t\t\tposition: this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ),\n\t\t\t\tsingleViewMode: true\n\t\t\t} );\n\t\t}\n\n\t\tthis._mentionsView.position = this._balloon.view.position;\n\t\tthis._mentionsView.selectFirst();\n\t}\n\n\t/**\n\t * Hides the mentions balloon and removes the 'mention' marker from the markers collection.\n\t *\n\t * @private\n\t */\n\t_hideUIAndRemoveMarker() {\n\t\t// Remove the mention view from balloon before removing marker - it is used by balloon position target().\n\t\tif ( this._balloon.hasView( this._mentionsView ) ) {\n\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[UI]%c Hiding the UI.', 'color: green', 'color: black' );\n\n\t\t\tthis._balloon.remove( this._mentionsView );\n\t\t}\n\n\t\tif ( checkIfStillInCompletionMode( this.editor ) ) {\n\t\t\t// @if CK_DEBUG_MENTION // console.log( '%c[Editing]%c Removing marker.', 'color: purple', 'color: black' );\n\n\t\t\tthis.editor.model.change( writer => writer.removeMarker( 'mention' ) );\n\t\t}\n\n\t\t// Make the last matched position on panel view undefined so the #_getBalloonPanelPositionData() method will return all positions\n\t\t// on the next call.\n\t\tthis._mentionsView.position = undefined;\n\t}\n\n\t/**\n\t * Renders a single item in the autocomplete list.\n\t *\n\t * @private\n\t * @param {module:mention/mention~MentionFeedItem} item\n\t * @param {String} marker\n\t * @returns {module:ui/button/buttonview~ButtonView|module:mention/ui/domwrapperview~DomWrapperView}\n\t */\n\t_renderItem( item, marker ) {\n\t\tconst editor = this.editor;\n\n\t\tlet view;\n\t\tlet label = item.id;\n\n\t\tconst renderer = this._getItemRenderer( marker );\n\n\t\tif ( renderer ) {\n\t\t\tconst renderResult = renderer( item );\n\n\t\t\tif ( typeof renderResult != 'string' ) {\n\t\t\t\tview = new DomWrapperView( editor.locale, renderResult );\n\t\t\t} else {\n\t\t\t\tlabel = renderResult;\n\t\t\t}\n\t\t}\n\n\t\tif ( !view ) {\n\t\t\tconst buttonView = new ButtonView( editor.locale );\n\n\t\t\tbuttonView.label = label;\n\t\t\tbuttonView.withText = true;\n\n\t\t\tview = buttonView;\n\t\t}\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * Creates a position options object used to position the balloon panel.\n\t *\n\t * @param {module:engine/model/markercollection~Marker} mentionMarker\n\t * @param {String|undefined} preferredPosition The name of the last matched position name.\n\t * @returns {module:utils/dom/position~Options}\n\t * @private\n\t */\n\t_getBalloonPanelPositionData( mentionMarker, preferredPosition ) {\n\t\tconst editor = this.editor;\n\t\tconst editing = editor.editing;\n\t\tconst domConverter = editing.view.domConverter;\n\t\tconst mapper = editing.mapper;\n\n\t\treturn {\n\t\t\ttarget: () => {\n\t\t\t\tlet modelRange = mentionMarker.getRange();\n\n\t\t\t\t// Target the UI to the model selection range - the marker has been removed so probably the UI will not be shown anyway.\n\t\t\t\t// The logic is used by ContextualBalloon to display another panel in the same place.\n\t\t\t\tif ( modelRange.start.root.rootName == '$graveyard' ) {\n\t\t\t\t\tmodelRange = editor.model.document.selection.getFirstRange();\n\t\t\t\t}\n\n\t\t\t\tconst viewRange = mapper.toViewRange( modelRange );\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( domConverter.viewRangeToDom( viewRange ) );\n\n\t\t\t\treturn rangeRects.pop();\n\t\t\t},\n\t\t\tlimiter: () => {\n\t\t\t\tconst view = this.editor.editing.view;\n\t\t\t\tconst viewDocument = view.document;\n\t\t\t\tconst editableElement = viewDocument.selection.editableElement;\n\n\t\t\t\tif ( editableElement ) {\n\t\t\t\t\treturn view.domConverter.mapViewToDom( editableElement.root );\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tpositions: getBalloonPanelPositions( preferredPosition )\n\t\t};\n\t}\n}\n\n// Returns the balloon positions data callbacks.\n//\n// @param {String} preferredPosition\n// @returns {Array.}\nfunction getBalloonPanelPositions( preferredPosition ) {\n\tconst positions = {\n\t\t// Positions the panel to the southeast of the caret rectangle.\n\t\t'caret_se': targetRect => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.bottom + VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right,\n\t\t\t\tname: 'caret_se',\n\t\t\t\tconfig: {\n\t\t\t\t\twithArrow: false\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the northeast of the caret rectangle.\n\t\t'caret_ne': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.top - balloonRect.height - VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right,\n\t\t\t\tname: 'caret_ne',\n\t\t\t\tconfig: {\n\t\t\t\t\twithArrow: false\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the southwest of the caret rectangle.\n\t\t'caret_sw': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.bottom + VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right - balloonRect.width,\n\t\t\t\tname: 'caret_sw',\n\t\t\t\tconfig: {\n\t\t\t\t\twithArrow: false\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the northwest of the caret rect.\n\t\t'caret_nw': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.top - balloonRect.height - VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right - balloonRect.width,\n\t\t\t\tname: 'caret_nw',\n\t\t\t\tconfig: {\n\t\t\t\t\twithArrow: false\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n\n\t// Returns only the last position if it was matched to prevent the panel from jumping after the first match.\n\tif ( Object.prototype.hasOwnProperty.call( positions, preferredPosition ) ) {\n\t\treturn [\n\t\t\tpositions[ preferredPosition ]\n\t\t];\n\t}\n\n\t// By default return all position callbacks.\n\treturn [\n\t\tpositions.caret_se,\n\t\tpositions.caret_sw,\n\t\tpositions.caret_ne,\n\t\tpositions.caret_nw\n\t];\n}\n\n// Returns a marker definition of the last valid occurring marker in a given string.\n// If there is no valid marker in a string, it returns undefined.\n//\n// Example of returned object:\n//\n//\t\t{\n//\t\t\tmarker: '@',\n//\t\t\tposition: 4,\n//\t\t\tminimumCharacters: 0\n//\t\t}\n//\n// @param {Array.} feedsWithPattern Registered feeds in editor for mention plugin with created RegExp for matching marker.\n// @param {String} text String to find the marker in\n// @returns {Object} Matched marker's definition\nfunction getLastValidMarkerInText( feedsWithPattern, text ) {\n\tlet lastValidMarker;\n\n\tfor ( const feed of feedsWithPattern ) {\n\t\tconst currentMarkerLastIndex = text.lastIndexOf( feed.marker );\n\n\t\tif ( currentMarkerLastIndex > 0 && !text.substring( currentMarkerLastIndex - 1 ).match( feed.pattern ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( !lastValidMarker || currentMarkerLastIndex >= lastValidMarker.position ) {\n\t\t\tlastValidMarker = {\n\t\t\t\tmarker: feed.marker,\n\t\t\t\tposition: currentMarkerLastIndex,\n\t\t\t\tminimumCharacters: feed.minimumCharacters,\n\t\t\t\tpattern: feed.pattern\n\t\t\t};\n\t\t}\n\t}\n\n\treturn lastValidMarker;\n}\n\n// Creates a RegExp pattern for the marker.\n//\n// Function has to be exported to achieve 100% code coverage.\n//\n// @param {String} marker\n// @param {Number} minimumCharacters\n// @returns {RegExp}\nexport function createRegExp( marker, minimumCharacters ) {\n\tconst numberOfCharacters = minimumCharacters == 0 ? '*' : `{${ minimumCharacters },}`;\n\n\tconst openAfterCharacters = env.features.isRegExpUnicodePropertySupported ? '\\\\p{Ps}\\\\p{Pi}\"\\'' : '\\\\(\\\\[{\"\\'';\n\tconst mentionCharacters = '.';\n\n\t// The pattern consists of 3 groups:\n\t// - 0 (non-capturing): Opening sequence - start of the line, space or an opening punctuation character like \"(\" or \"\\\"\",\n\t// - 1: The marker character,\n\t// - 2: Mention input (taking the minimal length into consideration to trigger the UI),\n\t//\n\t// The pattern matches up to the caret (end of string switch - $).\n\t// (0: opening sequence )(1: marker )(2: typed mention )$\n\tconst pattern = `(?:^|[ ${ openAfterCharacters }])([${ marker }])(${ mentionCharacters }${ numberOfCharacters })$`;\n\treturn new RegExp( pattern, 'u' );\n}\n\n// Creates a test callback for the marker to be used in the text watcher instance.\n//\n// @param {Array.} feedsWithPattern Feeds of mention plugin configured in editor with RegExp to match marker in text\n// @returns {Function}\nfunction createTestCallback( feedsWithPattern ) {\n\tconst textMatcher = text => {\n\t\tconst markerDefinition = getLastValidMarkerInText( feedsWithPattern, text );\n\n\t\tif ( !markerDefinition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet splitStringFrom = 0;\n\n\t\tif ( markerDefinition.position !== 0 ) {\n\t\t\tsplitStringFrom = markerDefinition.position - 1;\n\t\t}\n\n\t\tconst textToTest = text.substring( splitStringFrom );\n\n\t\treturn markerDefinition.pattern.test( textToTest );\n\t};\n\n\treturn textMatcher;\n}\n\n// Creates a text matcher from the marker.\n//\n// @param {Object} markerDefinition\n// @param {String} text\n// @returns {Function}\nfunction requestFeedText( markerDefinition, text ) {\n\tlet splitStringFrom = 0;\n\n\tif ( markerDefinition.position !== 0 ) {\n\t\tsplitStringFrom = markerDefinition.position - 1;\n\t}\n\n\tconst regExp = createRegExp( markerDefinition.marker, 0 );\n\tconst textToMatch = text.substring( splitStringFrom );\n\tconst match = textToMatch.match( regExp );\n\n\treturn match[ 2 ];\n}\n\n// The default feed callback.\nfunction createFeedCallback( feedItems ) {\n\treturn feedText => {\n\t\tconst filteredItems = feedItems\n\t\t// Make the default mention feed case-insensitive.\n\t\t\t.filter( item => {\n\t\t\t\t// Item might be defined as object.\n\t\t\t\tconst itemId = typeof item == 'string' ? item : String( item.id );\n\n\t\t\t\t// The default feed is case insensitive.\n\t\t\t\treturn itemId.toLowerCase().includes( feedText.toLowerCase() );\n\t\t\t} );\n\t\treturn filteredItems;\n\t};\n}\n\n// Checks if position in inside or right after a text with a mention.\n//\n// @param {module:engine/model/position~Position} position.\n// @returns {Boolean}\nfunction isPositionInExistingMention( position ) {\n\t// The text watcher listens only to changed range in selection - so the selection attributes are not yet available\n\t// and you cannot use selection.hasAttribute( 'mention' ) just yet.\n\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1723.\n\tconst hasMention = position.textNode && position.textNode.hasAttribute( 'mention' );\n\n\tconst nodeBefore = position.nodeBefore;\n\n\treturn hasMention || nodeBefore && nodeBefore.is( '$text' ) && nodeBefore.hasAttribute( 'mention' );\n}\n\n// Checks if the closest marker offset is at the beginning of a mention.\n//\n// See https://github.com/ckeditor/ckeditor5/issues/11400.\n//\n// @param {module:engine/model/position~Position} markerPosition\n// @returns {Boolean}\nfunction isMarkerInExistingMention( markerPosition ) {\n\tconst nodeAfter = markerPosition.nodeAfter;\n\n\treturn nodeAfter && nodeAfter.is( '$text' ) && nodeAfter.hasAttribute( 'mention' );\n}\n\n// Checks if string is a valid mention marker.\n//\n// @param {String} marker\n// @returns {Boolean}\nfunction isValidMentionMarker( marker ) {\n\treturn marker && marker.length == 1;\n}\n\n// Checks the mention plugins is in completion mode (e.g. when typing is after a valid mention string like @foo).\n//\n// @returns {Boolean}\nfunction checkIfStillInCompletionMode( editor ) {\n\treturn editor.model.markers.has( 'mention' );\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/br\n */\n\nimport { DomConverter, ViewDocument } from 'ckeditor5/src/engine';\n\n/**\n * Transforms `
    ` elements that are siblings to some block element into a paragraphs.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment The view structure to be transformed.\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport default function transformBlockBrsToParagraphs( documentFragment, writer ) {\n\tconst viewDocument = new ViewDocument( writer.document.stylesProcessor );\n\tconst domConverter = new DomConverter( viewDocument, { renderingMode: 'data' } );\n\n\tconst blockElements = domConverter.blockElements;\n\tconst inlineObjectElements = domConverter.inlineObjectElements;\n\n\tconst elementsToReplace = [];\n\n\tfor ( const value of writer.createRangeIn( documentFragment ) ) {\n\t\tconst element = value.item;\n\n\t\tif ( element.is( 'element', 'br' ) ) {\n\t\t\tconst nextSibling = findSibling( element, 'forward', writer, { blockElements, inlineObjectElements } );\n\t\t\tconst previousSibling = findSibling( element, 'backward', writer, { blockElements, inlineObjectElements } );\n\n\t\t\tconst nextSiblingIsBlock = isBlockViewElement( nextSibling, blockElements );\n\t\t\tconst previousSiblingIsBlock = isBlockViewElement( previousSibling, blockElements );\n\n\t\t\t// If the
    is surrounded by blocks then convert it to a paragraph:\n\t\t\t// *

    foo

    [
    ]

    bar

    ->

    foo

    [

    ]

    bar

    \n\t\t\t// *

    foo

    [
    ] ->

    foo

    [

    ]\n\t\t\t// * [
    ]

    foo

    -> [

    ]

    foo

    \n\t\t\tif ( previousSiblingIsBlock || nextSiblingIsBlock ) {\n\t\t\t\telementsToReplace.push( element );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( const element of elementsToReplace ) {\n\t\tif ( element.hasClass( 'Apple-interchange-newline' ) ) {\n\t\t\twriter.remove( element );\n\t\t} else {\n\t\t\twriter.replace( element, writer.createElement( 'p' ) );\n\t\t}\n\t}\n}\n\n// Returns sibling node, threats inline elements as transparent (but should stop on an inline objects).\nfunction findSibling( viewElement, direction, writer, { blockElements, inlineObjectElements } ) {\n\tlet position = writer.createPositionAt( viewElement, direction == 'forward' ? 'after' : 'before' );\n\n\t// Find first position that is just before a first:\n\t// * text node,\n\t// * block element,\n\t// * inline object element.\n\t// It's ignoring any inline (non-object) elements like span, strong, etc.\n\tposition = position.getLastMatchingPosition( ( { item } ) => (\n\t\titem.is( 'element' ) &&\n\t\t!blockElements.includes( item.name ) &&\n\t\t!inlineObjectElements.includes( item.name )\n\t), { direction } );\n\n\treturn direction == 'forward' ? position.nodeAfter : position.nodeBefore;\n}\n\n// Returns true for view elements that are listed as block view elements.\nfunction isBlockViewElement( node, blockElements ) {\n\treturn !!node && node.is( 'element' ) && blockElements.includes( node.name );\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/list\n */\n\nimport { Matcher, UpcastWriter } from 'ckeditor5/src/engine';\n\n/**\n * Transforms Word specific list-like elements to the semantic HTML lists.\n *\n * Lists in Word are represented by block elements with special attributes like:\n *\n *\t\t

    ...

    // Paragraph based list.\n *\t\t

    ...

    // Heading 1 based list.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment The view structure to be transformed.\n * @param {String} stylesString Styles from which list-like elements styling will be extracted.\n */\nexport function transformListItemLikeElementsIntoLists( documentFragment, stylesString ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst writer = new UpcastWriter( documentFragment.document );\n\tconst itemLikeElements = findAllItemLikeElements( documentFragment, writer );\n\n\tif ( !itemLikeElements.length ) {\n\t\treturn;\n\t}\n\n\tlet currentList = null;\n\tlet currentIndentation = 1;\n\n\titemLikeElements.forEach( ( itemLikeElement, i ) => {\n\t\tconst isDifferentList = isNewListNeeded( itemLikeElements[ i - 1 ], itemLikeElement );\n\t\tconst previousItemLikeElement = isDifferentList ? null : itemLikeElements[ i - 1 ];\n\t\tconst indentationDifference = getIndentationDifference( previousItemLikeElement, itemLikeElement );\n\n\t\tif ( isDifferentList ) {\n\t\t\tcurrentList = null;\n\t\t\tcurrentIndentation = 1;\n\t\t}\n\n\t\tif ( !currentList || indentationDifference !== 0 ) {\n\t\t\tconst listStyle = detectListStyle( itemLikeElement, stylesString );\n\n\t\t\tif ( !currentList ) {\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, itemLikeElement.element, writer );\n\t\t\t} else if ( itemLikeElement.indent > currentIndentation ) {\n\t\t\t\tconst lastListItem = currentList.getChild( currentList.childCount - 1 );\n\t\t\t\tconst lastListItemChild = lastListItem.getChild( lastListItem.childCount - 1 );\n\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, lastListItemChild, writer );\n\t\t\t\tcurrentIndentation += 1;\n\t\t\t} else if ( itemLikeElement.indent < currentIndentation ) {\n\t\t\t\tconst differentIndentation = currentIndentation - itemLikeElement.indent;\n\n\t\t\t\tcurrentList = findParentListAtLevel( currentList, differentIndentation );\n\t\t\t\tcurrentIndentation = parseInt( itemLikeElement.indent );\n\t\t\t}\n\n\t\t\tif ( itemLikeElement.indent <= currentIndentation ) {\n\t\t\t\tif ( !currentList.is( 'element', listStyle.type ) ) {\n\t\t\t\t\tcurrentList = writer.rename( listStyle.type, currentList );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst listItem = transformElementIntoListItem( itemLikeElement.element, writer );\n\n\t\twriter.appendChild( listItem, currentList );\n\t} );\n}\n\n/**\n * Removes paragraph wrapping content inside a list item.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport function unwrapParagraphInListItem( documentFragment, writer ) {\n\tfor ( const value of writer.createRangeIn( documentFragment ) ) {\n\t\tconst element = value.item;\n\n\t\tif ( element.is( 'element', 'li' ) ) {\n\t\t\t// Google Docs allows for single paragraph inside LI.\n\t\t\tconst firstChild = element.getChild( 0 );\n\n\t\t\tif ( firstChild && firstChild.is( 'element', 'p' ) ) {\n\t\t\t\twriter.unwrapElement( firstChild );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Finds all list-like elements in a given document fragment.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// in which to look for list-like nodes.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.} Array of found list-like items. Each item is an object containing:\n//\n//\t\t* {module:engine/src/view/element~Element} element List-like element.\n//\t\t* {Number} id List item id parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} order List item creation order parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} indent List item indentation level parsed from `mso-list` style (see `getListItemData()` function).\nfunction findAllItemLikeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\t// Matcher for finding list-like elements.\n\tconst itemLikeElementsMatcher = new Matcher( {\n\t\tname: /^p|h\\d+$/,\n\t\tstyles: {\n\t\t\t'mso-list': /.*/\n\t\t}\n\t} );\n\n\tconst itemLikeElements = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && itemLikeElementsMatcher.match( value.item ) ) {\n\t\t\tconst itemData = getListItemData( value.item );\n\n\t\t\titemLikeElements.push( {\n\t\t\t\telement: value.item,\n\t\t\t\tid: itemData.id,\n\t\t\t\torder: itemData.order,\n\t\t\t\tindent: itemData.indent\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn itemLikeElements;\n}\n\n// Extracts list item style from the provided CSS.\n//\n// List item style is extracted from the CSS stylesheet. Each list with its specific style attribute\n// value (`mso-list:l1 level1 lfo1`) has its dedicated properties in a CSS stylesheet defined with a selector like:\n//\n// \t\t@list l1:level1 { ... }\n//\n// It contains `mso-level-number-format` property which defines list numbering/bullet style. If this property\n// is not defined it means default `decimal` numbering.\n//\n// Here CSS string representation is used as `mso-level-number-format` property is an invalid CSS property\n// and will be removed during CSS parsing.\n//\n// @param {Object} listLikeItem List-like item for which list style will be searched for. Usually\n// a result of `findAllItemLikeElements()` function.\n// @param {String} stylesString CSS stylesheet.\n// @returns {Object} result\n// @returns {String} result.type List type, could be `ul` or `ol`.\n// @returns {Number} result.startIndex List start index, valid only for ordered lists.\n// @returns {String|null} result.style List style, for example: `decimal`, `lower-roman`, etc. It is extracted\n// directly from Word stylesheet and adjusted to represent proper values for the CSS `list-style-type` property.\n// If it cannot be adjusted, the `null` value is returned.\nfunction detectListStyle( listLikeItem, stylesString ) {\n\tconst listStyleRegexp = new RegExp( `@list l${ listLikeItem.id }:level${ listLikeItem.indent }\\\\s*({[^}]*)`, 'gi' );\n\tconst listStyleTypeRegex = /mso-level-number-format:([^;]{0,100});/gi;\n\tconst listStartIndexRegex = /mso-level-start-at:\\s{0,100}([0-9]{0,10})\\s{0,100};/gi;\n\n\tconst listStyleMatch = listStyleRegexp.exec( stylesString );\n\n\tlet listStyleType = 'decimal'; // Decimal is default one.\n\tlet type = 'ol'; //
      is default list.\n\tlet startIndex = null;\n\n\tif ( listStyleMatch && listStyleMatch[ 1 ] ) {\n\t\tconst listStyleTypeMatch = listStyleTypeRegex.exec( listStyleMatch[ 1 ] );\n\n\t\tif ( listStyleTypeMatch && listStyleTypeMatch[ 1 ] ) {\n\t\t\tlistStyleType = listStyleTypeMatch[ 1 ].trim();\n\t\t\ttype = listStyleType !== 'bullet' && listStyleType !== 'image' ? 'ol' : 'ul';\n\t\t}\n\n\t\t// Styles for the numbered lists are always defined in the Word CSS stylesheet.\n\t\t// Unordered lists MAY contain a value for the Word CSS definition `mso-level-text` but sometimes\n\t\t// this tag is missing. And because of that, we cannot depend on that. We need to predict the list style value\n\t\t// based on the list style marker element.\n\t\tif ( listStyleType === 'bullet' ) {\n\t\t\tconst bulletedStyle = findBulletedListStyle( listLikeItem.element );\n\n\t\t\tif ( bulletedStyle ) {\n\t\t\t\tlistStyleType = bulletedStyle;\n\t\t\t}\n\t\t} else {\n\t\t\tconst listStartIndexMatch = listStartIndexRegex.exec( listStyleMatch[ 1 ] );\n\n\t\t\tif ( listStartIndexMatch && listStartIndexMatch[ 1 ] ) {\n\t\t\t\tstartIndex = parseInt( listStartIndexMatch[ 1 ] );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttype,\n\t\tstartIndex,\n\t\tstyle: mapListStyleDefinition( listStyleType )\n\t};\n}\n\n// Tries to extract the `list-style-type` value based on the marker element for bulleted list.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {String|null}\nfunction findBulletedListStyle( element ) {\n\tconst listMarkerElement = findListMarkerNode( element );\n\n\tif ( !listMarkerElement ) {\n\t\treturn null;\n\t}\n\n\tconst listMarker = listMarkerElement._data;\n\n\tif ( listMarker === 'o' ) {\n\t\treturn 'circle';\n\t} else if ( listMarker === '·' ) {\n\t\treturn 'disc';\n\t}\n\t// Word returns '§' instead of '■' for the square list style.\n\telse if ( listMarker === '§' ) {\n\t\treturn 'square';\n\t}\n\n\treturn null;\n}\n\n// Tries to find a text node that represents the marker element (list-style-type).\n//\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/view/text~Text|null}\nfunction findListMarkerNode( element ) {\n\t// If the first child is a text node, it is the data for the element.\n\t// The list-style marker is not present here.\n\tif ( element.getChild( 0 ).is( '$text' ) ) {\n\t\treturn null;\n\t}\n\n\tfor ( const childNode of element.getChildren() ) {\n\t\t// The list-style marker will be inside the `` element. Let's ignore all non-span elements.\n\t\t// It may happen that the `` element is added as the first child. Most probably, it's an anchor element.\n\t\tif ( !childNode.is( 'element', 'span' ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst textNodeOrElement = childNode.getChild( 0 );\n\n\t\t// If already found the marker element, use it.\n\t\tif ( textNodeOrElement.is( '$text' ) ) {\n\t\t\treturn textNodeOrElement;\n\t\t}\n\n\t\treturn textNodeOrElement.getChild( 0 );\n\t}\n}\n\n// Parses the `list-style-type` value extracted directly from the Word CSS stylesheet and returns proper CSS definition.\n//\n// @param {String|null} value\n// @returns {String|null}\nfunction mapListStyleDefinition( value ) {\n\tif ( value.startsWith( 'arabic-leading-zero' ) ) {\n\t\treturn 'decimal-leading-zero';\n\t}\n\n\tswitch ( value ) {\n\t\tcase 'alpha-upper':\n\t\t\treturn 'upper-alpha';\n\t\tcase 'alpha-lower':\n\t\t\treturn 'lower-alpha';\n\t\tcase 'roman-upper':\n\t\t\treturn 'upper-roman';\n\t\tcase 'roman-lower':\n\t\t\treturn 'lower-roman';\n\t\tcase 'circle':\n\t\tcase 'disc':\n\t\tcase 'square':\n\t\t\treturn value;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n// Creates an empty list of a given type and inserts it after a specified element.\n//\n// @param {Object} listStyle List style object which determines the type of newly created list.\n// Usually a result of `detectListStyle()` function.\n// @param {module:engine/view/element~Element} element Element after which list is inserted.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} Newly created list element.\n\nfunction insertNewEmptyList( listStyle, element, writer ) {\n\tconst parent = element.parent;\n\tconst list = writer.createElement( listStyle.type );\n\tconst position = parent.getChildIndex( element ) + 1;\n\n\twriter.insertChild( position, list, parent );\n\n\t// We do not support modifying the marker for a particular list item.\n\t// Set the value for the `list-style-type` property directly to the list container.\n\tif ( listStyle.style ) {\n\t\twriter.setStyle( 'list-style-type', listStyle.style, list );\n\t}\n\n\tif ( listStyle.startIndex && listStyle.startIndex > 1 ) {\n\t\twriter.setAttribute( 'start', listStyle.startIndex, list );\n\t}\n\n\treturn list;\n}\n\n// Transforms a given element into a semantic list item. As the function operates on a provided\n// {module:engine/src/view/element~Element element} it will modify the view structure to which this element belongs.\n//\n// @param {module:engine/view/element~Element} element Element which will be transformed into a list item.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} New element to which the given one was transformed. It is\n// inserted in place of the old element (the reference to the old element is lost due to renaming).\nfunction transformElementIntoListItem( element, writer ) {\n\tremoveBulletElement( element, writer );\n\n\treturn writer.rename( 'li', element );\n}\n\n// Extracts list item information from Word specific list-like element style:\n//\n//\t\t`style=\"mso-list:l1 level1 lfo1\"`\n//\n// where:\n//\n//\t\t* `l1` is a list id (however it does not mean this is a continuous list - see #43),\n//\t\t* `level1` is a list item indentation level,\n//\t\t* `lfo1` is a list insertion order in a document.\n//\n// @param {module:engine/view/element~Element} element Element from which style data is extracted.\n// @returns {Object} result\n// @returns {Number} result.id Parent list id.\n// @returns {Number} result.order List item creation order.\n// @returns {Number} result.indent List item indentation level.\nfunction getListItemData( element ) {\n\tconst data = {};\n\tconst listStyle = element.getStyle( 'mso-list' );\n\n\tif ( listStyle ) {\n\t\tconst idMatch = listStyle.match( /(^|\\s{1,100})l(\\d+)/i );\n\t\tconst orderMatch = listStyle.match( /\\s{0,100}lfo(\\d+)/i );\n\t\tconst indentMatch = listStyle.match( /\\s{0,100}level(\\d+)/i );\n\n\t\tif ( idMatch && orderMatch && indentMatch ) {\n\t\t\tdata.id = idMatch[ 2 ];\n\t\t\tdata.order = orderMatch[ 1 ];\n\t\t\tdata.indent = indentMatch[ 1 ];\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// Removes span with a numbering/bullet from a given element.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeBulletElement( element, writer ) {\n\t// Matcher for finding `span` elements holding lists numbering/bullets.\n\tconst bulletMatcher = new Matcher( {\n\t\tname: 'span',\n\t\tstyles: {\n\t\t\t'mso-list': 'Ignore'\n\t\t}\n\t} );\n\n\tconst range = writer.createRangeIn( element );\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && bulletMatcher.match( value.item ) ) {\n\t\t\twriter.remove( value.item );\n\t\t}\n\t}\n}\n\n// Whether the previous and current items belong to the same list. It is determined based on `item.id`\n// (extracted from `mso-list` style, see #getListItemData) and a previous sibling of the current item.\n//\n// However, it's quite easy to change the `id` attribute for nested lists in Word. It will break the list feature while pasting.\n// Let's check also the `indent` attribute. If the difference between those two elements is equal to 1, we can assume that\n// the `currentItem` is a beginning of the nested list because lists in CKEditor 5 always start with the `indent=0` attribute.\n// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Boolean}\nfunction isNewListNeeded( previousItem, currentItem ) {\n\tif ( !previousItem ) {\n\t\treturn true;\n\t}\n\n\tif ( previousItem.id !== currentItem.id ) {\n\t\t// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n\t\t//\n\t\t// * List item 1.\n\t\t// - Nested list item 1.\n\t\tif ( currentItem.indent - previousItem.indent === 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tconst previousSibling = currentItem.element.previousSibling;\n\n\tif ( !previousSibling ) {\n\t\treturn true;\n\t}\n\n\t// Even with the same id the list does not have to be continuous (#43).\n\treturn !isList( previousSibling );\n}\n\nfunction isList( element ) {\n\treturn element.is( 'element', 'ol' ) || element.is( 'element', 'ul' );\n}\n\n// Calculates the indentation difference between two given list items (based on the indent attribute\n// extracted from the `mso-list` style, see #getListItemData).\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Number}\nfunction getIndentationDifference( previousItem, currentItem ) {\n\treturn previousItem ? currentItem.indent - previousItem.indent : currentItem.indent - 1;\n}\n\n// Finds the parent list element (ul/ol) of a given list element with indentation level lower by a given value.\n//\n// @param {module:engine/view/element~Element} listElement List element from which to start looking for a parent list.\n// @param {Number} indentationDifference Indentation difference between lists.\n// @returns {module:engine/view/element~Element} Found list element with indentation level lower by a given value.\nfunction findParentListAtLevel( listElement, indentationDifference ) {\n\tconst ancestors = listElement.getAncestors( { parentFirst: true } );\n\n\tlet parentList = null;\n\tlet levelChange = 0;\n\n\tfor ( const ancestor of ancestors ) {\n\t\tif ( ancestor.name === 'ul' || ancestor.name === 'ol' ) {\n\t\t\tlevelChange++;\n\t\t}\n\n\t\tif ( levelChange === indentationDifference ) {\n\t\t\tparentList = ancestor;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn parentList;\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/normalizers/googledocsnormalizer\n */\n\nimport { UpcastWriter } from 'ckeditor5/src/engine';\n\nimport removeBoldWrapper from '../filters/removeboldwrapper';\nimport transformBlockBrsToParagraphs from '../filters/br';\nimport { unwrapParagraphInListItem } from '../filters/list';\n\nconst googleDocsMatch = /id=(\"|')docs-internal-guid-[-0-9a-f]+(\"|')/i;\n\n/**\n * Normalizer for the content pasted from Google Docs.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class GoogleDocsNormalizer {\n\t/**\n\t * Creates a new `GoogleDocsNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn googleDocsMatch.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst writer = new UpcastWriter( this.document );\n\t\tconst { body: documentFragment } = data._parsedData;\n\n\t\tremoveBoldWrapper( documentFragment, writer );\n\t\tunwrapParagraphInListItem( documentFragment, writer );\n\t\ttransformBlockBrsToParagraphs( documentFragment, writer );\n\n\t\tdata.content = documentFragment;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/removeboldwrapper\n */\n\n/**\n * Removes `` tag wrapper added by Google Docs to a copied content.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment element `data.content` obtained from clipboard\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport default function removeBoldWrapper( documentFragment, writer ) {\n\tfor ( const child of documentFragment.getChildren() ) {\n\t\tif ( child.is( 'element', 'b' ) && child.getStyle( 'font-weight' ) === 'normal' ) {\n\t\t\tconst childIndex = documentFragment.getChildIndex( child );\n\n\t\t\twriter.remove( child );\n\t\t\twriter.insertChild( childIndex, child.getChildren(), documentFragment );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/image\n */\n\n/* globals btoa */\n\nimport { Matcher, UpcastWriter } from 'ckeditor5/src/engine';\n\n/**\n * Replaces source attribute of all `` elements representing regular\n * images (not the Word shapes) with inlined base64 image representation extracted from RTF or Blob data.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment on which transform images.\n * @param {String} rtfData The RTF data from which images representation will be used.\n */\nexport function replaceImagesSourceWithBase64( documentFragment, rtfData ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst upcastWriter = new UpcastWriter();\n\tconst shapesIds = findAllShapesIds( documentFragment, upcastWriter );\n\n\tremoveAllImgElementsRepresentingShapes( shapesIds, documentFragment, upcastWriter );\n\tremoveAllShapeElements( documentFragment, upcastWriter );\n\n\tconst images = findAllImageElementsWithLocalSource( documentFragment, upcastWriter );\n\n\tif ( images.length ) {\n\t\treplaceImagesFileSourceWithInlineRepresentation( images, extractImageDataFromRtf( rtfData ), upcastWriter );\n\t}\n}\n\n/**\n * Converts given HEX string to base64 representation.\n *\n * @protected\n * @param {String} hexString The HEX string to be converted.\n * @returns {String} Base64 representation of a given HEX string.\n */\nexport function _convertHexToBase64( hexString ) {\n\treturn btoa( hexString.match( /\\w{2}/g ).map( char => {\n\t\treturn String.fromCharCode( parseInt( char, 16 ) );\n\t} ).join( '' ) );\n}\n\n// Finds all shapes (`...`) ids. Shapes can represent images (canvas)\n// or Word shapes (which does not have RTF or Blob representation).\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// from which to extract shape ids.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.} Array of shape ids.\nfunction findAllShapesIds( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new Matcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapesIds = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type != 'elementStart' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst el = value.item;\n\t\tconst prevSiblingName = el.previousSibling && el.previousSibling.name || null;\n\n\t\t// If shape element have 'o:gfxdata' attribute and is not directly before `` element it means it represent Word shape.\n\t\tif ( shapeElementsMatcher.match( el ) && el.getAttribute( 'o:gfxdata' ) && prevSiblingName !== 'v:shapetype' ) {\n\t\t\tshapesIds.push( value.item.getAttribute( 'id' ) );\n\t\t}\n\t}\n\n\treturn shapesIds;\n}\n\n// Removes all `` elements which represents Word shapes and not regular images.\n//\n// @param {Array.} shapesIds Shape ids which will be checked against `` elements.\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove `` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllImgElementsRepresentingShapes( shapesIds, documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new Matcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tconst el = value.item;\n\t\t\tconst shapes = el.getAttribute( 'v:shapes' ) ? el.getAttribute( 'v:shapes' ).split( ' ' ) : [];\n\n\t\t\tif ( shapes.length && shapes.every( shape => shapesIds.indexOf( shape ) > -1 ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t// Shapes may also have empty source while content is paste in some browsers (Safari).\n\t\t\t} else if ( !el.getAttribute( 'src' ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( const img of imgs ) {\n\t\twriter.remove( img );\n\t}\n}\n\n// Removes all shape elements (`...`) so they do not pollute the output structure.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove shape elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllShapeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new Matcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapes = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type == 'elementStart' && shapeElementsMatcher.match( value.item ) ) {\n\t\t\tshapes.push( value.item );\n\t\t}\n\t}\n\n\tfor ( const shape of shapes ) {\n\t\twriter.remove( shape );\n\t}\n}\n\n// Finds all `` elements in a given document fragment which have source pointing to local `file://` resource.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment in which to look for `` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Object} result All found images grouped by source type.\n// @returns {Array.} result.file Array of found `` elements with `file://` source.\n// @returns {Array.} result.blob Array of found `` elements with `blob:` source.\nfunction findAllImageElementsWithLocalSource( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new Matcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tif ( value.item.getAttribute( 'src' ).startsWith( 'file://' ) ) {\n\t\t\t\timgs.push( value.item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn imgs;\n}\n\n// Extracts all images HEX representations from a given RTF data.\n//\n// @param {String} rtfData The RTF data from which to extract images HEX representation.\n// @returns {Array.} Array of found HEX representations. Each array item is an object containing:\n//\n// \t\t* {String} hex Image representation in HEX format.\n// \t\t* {string} type Type of image, `image/png` or `image/jpeg`.\nfunction extractImageDataFromRtf( rtfData ) {\n\tif ( !rtfData ) {\n\t\treturn [];\n\t}\n\n\tconst regexPictureHeader = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/;\n\tconst regexPicture = new RegExp( '(?:(' + regexPictureHeader.source + '))([\\\\da-fA-F\\\\s]+)\\\\}', 'g' );\n\tconst images = rtfData.match( regexPicture );\n\tconst result = [];\n\n\tif ( images ) {\n\t\tfor ( const image of images ) {\n\t\t\tlet imageType = false;\n\n\t\t\tif ( image.includes( '\\\\pngblip' ) ) {\n\t\t\t\timageType = 'image/png';\n\t\t\t} else if ( image.includes( '\\\\jpegblip' ) ) {\n\t\t\t\timageType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tif ( imageType ) {\n\t\t\t\tresult.push( {\n\t\t\t\t\thex: image.replace( regexPictureHeader, '' ).replace( /[^\\da-fA-F]/g, '' ),\n\t\t\t\t\ttype: imageType\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Replaces `src` attribute value of all given images with the corresponding base64 image representation.\n//\n// @param {Array.} imageElements Array of image elements which will have its source replaced.\n// @param {Array.} imagesHexSources Array of images hex sources (usually the result of `extractImageDataFromRtf()` function).\n// The array should be the same length as `imageElements` parameter.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction replaceImagesFileSourceWithInlineRepresentation( imageElements, imagesHexSources, writer ) {\n\t// Assume there is an equal amount of image elements and images HEX sources so they can be matched accordingly based on existing order.\n\tif ( imageElements.length === imagesHexSources.length ) {\n\t\tfor ( let i = 0; i < imageElements.length; i++ ) {\n\t\t\tconst newSrc = `data:${ imagesHexSources[ i ].type };base64,${ _convertHexToBase64( imagesHexSources[ i ].hex ) }`;\n\t\t\twriter.setAttribute( 'src', newSrc, imageElements[ i ] );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/normalizers/mswordnormalizer\n */\n\nimport { transformListItemLikeElementsIntoLists } from '../filters/list';\nimport { replaceImagesSourceWithBase64 } from '../filters/image';\n\nconst msWordMatch1 = //i;\nconst msWordMatch2 = /xmlns:o=\"urn:schemas-microsoft-com/i;\n\n/**\n * Normalizer for the content pasted from Microsoft Word.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class MSWordNormalizer {\n\t/**\n\t * Creates a new `MSWordNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn msWordMatch1.test( htmlString ) || msWordMatch2.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst { body: documentFragment, stylesString } = data._parsedData;\n\n\t\ttransformListItemLikeElementsIntoLists( documentFragment, stylesString );\n\t\treplaceImagesSourceWithBase64( documentFragment, data.dataTransfer.getData( 'text/rtf' ) );\n\n\t\tdata.content = documentFragment;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/space\n */\n\n/**\n * Replaces last space preceding elements closing tag with ` `. Such operation prevents spaces from being removed\n * during further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n * This method also takes into account Word specific `` empty tags.\n * Additionally multiline sequences of spaces and new lines between tags are removed (see #39 and #40).\n *\n * @param {String} htmlString HTML string in which spacing should be normalized.\n * @returns {String} Input HTML with spaces normalized.\n */\nexport function normalizeSpacing( htmlString ) {\n\t// Run normalizeSafariSpaceSpans() two times to cover nested spans.\n\treturn normalizeSafariSpaceSpans( normalizeSafariSpaceSpans( htmlString ) )\n\t\t// Remove all \\r\\n from \"spacerun spans\" so the last replace line doesn't strip all whitespaces.\n\t\t.replace( /([^\\S\\r\\n]*?)[\\r\\n]+([^\\S\\r\\n]*<\\/span>)/g, '$1$2' )\n\t\t.replace( /<\\/span>/g, '' )\n\t\t.replace( / <\\//g, '\\u00A0<\\/o:p>/g, '\\u00A0' )\n\t\t// Remove block filler from empty paragraph. Safari uses \\u00A0 instead of  .\n\t\t.replace( /( |\\u00A0)<\\/o:p>/g, '' )\n\t\t// Remove all whitespaces when they contain any \\r or \\n.\n\t\t.replace( />([^\\S\\r\\n]*[\\r\\n]\\s*)<' );\n}\n\n/**\n * Normalizes spacing in special Word `spacerun spans` (`\\s+`) by replacing\n * all spaces with `  ` pairs. This prevents spaces from being removed during further DOM/View processing\n * (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n *\n * @param {Document} htmlDocument Native `Document` object in which spacing should be normalized.\n */\nexport function normalizeSpacerunSpans( htmlDocument ) {\n\thtmlDocument.querySelectorAll( 'span[style*=spacerun]' ).forEach( el => {\n\t\tconst innerTextLength = el.innerText.length || 0;\n\n\t\tel.innerText = Array( innerTextLength + 1 ).join( '\\u00A0 ' ).substr( 0, innerTextLength );\n\t} );\n}\n\n// Normalizes specific spacing generated by Safari when content pasted from Word (` `)\n// by replacing all spaces sequences longer than 1 space with `  ` pairs. This prevents spaces from being removed during\n// further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n//\n// This function is similar to {@link module:clipboard/utils/normalizeclipboarddata normalizeClipboardData util} but uses\n// regular spaces /   sequence for replacement.\n//\n// @param {String} htmlString HTML string in which spacing should be normalized\n// @returns {String} Input HTML with spaces normalized.\nfunction normalizeSafariSpaceSpans( htmlString ) {\n\treturn htmlString.replace( /(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\treturn spaces.length === 1 ? ' ' : Array( spaces.length + 1 ).join( '\\u00A0 ' ).substr( 0, spaces.length );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/parse\n */\n\n/* globals DOMParser */\n\nimport { DomConverter, ViewDocument } from 'ckeditor5/src/engine';\n\nimport { normalizeSpacing, normalizeSpacerunSpans } from './space';\n\n/**\n * Parses provided HTML extracting contents of `` and ``);\n const root = this.attachShadow({ mode: 'open' });\n root.appendChild(template.content.cloneNode(true));\n root.addEventListener('move', this);\n this[$parts] = this[$sliders].map((slider) => new slider(root));\n }\n connectedCallback() {\n // A user may set a property on an _instance_ of an element,\n // before its prototype has been connected to this class.\n // If so, we need to run it through the proper class setter.\n if (this.hasOwnProperty('color')) {\n const value = this.color;\n delete this['color'];\n this.color = value;\n }\n else if (!this.color) {\n this.color = this.colorModel.defaultColor;\n }\n }\n attributeChangedCallback(_attr, _oldVal, newVal) {\n const color = this.colorModel.fromAttr(newVal);\n if (!this[$isSame](color)) {\n this.color = color;\n }\n }\n handleEvent(event) {\n // Merge the current HSV color object with updated params.\n const oldHsva = this[$hsva];\n const newHsva = { ...oldHsva, ...event.detail };\n this[$update](newHsva);\n let newColor;\n if (!equalColorObjects(newHsva, oldHsva) &&\n !this[$isSame]((newColor = this.colorModel.fromHsva(newHsva)))) {\n this[$color] = newColor;\n fire(this, 'color-changed', { value: newColor });\n }\n }\n [$isSame](color) {\n return this.color && this.colorModel.equal(color, this.color);\n }\n [$update](hsva) {\n this[$hsva] = hsva;\n this[$parts].forEach((part) => part.update(hsva));\n }\n}\n//# sourceMappingURL=color-picker.js.map","export default `[part=hue]{flex:0 0 24px;background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}[part=hue-pointer]{top:50%;z-index:2}`;\n//# sourceMappingURL=hue.js.map","export default `[part=saturation]{flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,rgba(255,255,255,0));box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}[part=saturation-pointer]{z-index:3}`;\n//# sourceMappingURL=saturation.js.map","import { ColorPicker } from '../components/color-picker.js';\nimport { hexToHsva, hsvaToHex } from '../utils/convert.js';\nimport { equalHex } from '../utils/compare.js';\nconst colorModel = {\n defaultColor: '#000',\n toHsva: hexToHsva,\n fromHsva: ({ h, s, v }) => hsvaToHex({ h, s, v, a: 1 }),\n equal: equalHex,\n fromAttr: (color) => color\n};\nexport class HexBase extends ColorPicker {\n get colorModel() {\n return colorModel;\n }\n}\n//# sourceMappingURL=hex.js.map","import { HexBase } from './lib/entrypoints/hex.js';\n/**\n * A color picker custom element that uses HEX format.\n *\n * @element hex-color-picker\n *\n * @prop {string} color - Selected color in HEX format.\n * @attr {string} color - Selected color in HEX format.\n *\n * @fires color-changed - Event fired when color property changes.\n *\n * @csspart hue - A hue selector container.\n * @csspart saturation - A saturation selector container\n * @csspart hue-pointer - A hue pointer element.\n * @csspart saturation-pointer - A saturation pointer element.\n */\nexport class HexColorPicker extends HexBase {\n}\ncustomElements.define('hex-color-picker', HexColorPicker);\n//# sourceMappingURL=hex-color-picker.js.map","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/colorpicker/colorpickerview\r\n */\r\nimport { convertColor, convertToHex } from './utils';\r\nimport { global, env } from '@ckeditor/ckeditor5-utils';\r\nimport { debounce } from 'lodash-es';\r\nimport View from '../view';\r\nimport LabeledFieldView from '../labeledfield/labeledfieldview';\r\nimport { createLabeledInputText } from '../labeledfield/utils';\r\nimport 'vanilla-colorful/hex-color-picker.js';\r\nimport '../../theme/components/colorpicker/colorpicker.css';\r\nconst waitingTime = 150;\r\n/**\r\n * A class which represents a color picker with an input field for defining custom colors.\r\n */\r\nexport default class ColorPickerView extends View {\r\n /**\r\n * Creates a view of color picker.\r\n *\r\n * @param locale\r\n * @param config\r\n */\r\n constructor(locale, config = {}) {\r\n super(locale);\r\n this.set({\r\n color: '',\r\n _hexColor: ''\r\n });\r\n this.hexInputRow = this._createInputRow();\r\n const children = this.createCollection();\r\n if (!config.hideInput) {\r\n children.add(this.hexInputRow);\r\n }\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: ['ck', 'ck-color-picker'],\r\n tabindex: -1\r\n },\r\n children\r\n });\r\n this._config = config;\r\n this._debounceColorPickerEvent = debounce((color) => {\r\n // At first, set the color internally in the component. It's converted to the configured output format.\r\n this.set('color', color);\r\n // Then let the outside world know that the user changed the color.\r\n this.fire('colorSelected', { color: this.color });\r\n }, waitingTime, {\r\n leading: true\r\n });\r\n // The `color` property holds the color in the configured output format.\r\n // Ensure it before actually setting the value.\r\n this.on('set:color', (evt, propertyName, newValue) => {\r\n evt.return = convertColor(newValue, this._config.format || 'hsl');\r\n });\r\n // The `_hexColor` property is bound to the `color` one, but requires conversion.\r\n this.on('change:color', () => {\r\n this._hexColor = convertColorToCommonHexFormat(this.color);\r\n });\r\n this.on('change:_hexColor', () => {\r\n // Update the selected color in the color picker palette when it's not focused.\r\n // It means the user typed the color in the input.\r\n if (document.activeElement !== this.picker) {\r\n this.picker.setAttribute('color', this._hexColor);\r\n }\r\n // There has to be two way binding between properties.\r\n // Extra precaution has to be taken to trigger change back only when the color really changes.\r\n if (convertColorToCommonHexFormat(this.color) != convertColorToCommonHexFormat(this._hexColor)) {\r\n this.color = this._hexColor;\r\n }\r\n });\r\n }\r\n /**\r\n * Renders color picker in the view.\r\n */\r\n render() {\r\n super.render();\r\n this.picker = global.document.createElement('hex-color-picker');\r\n this.picker.setAttribute('class', 'hex-color-picker');\r\n this.picker.setAttribute('tabindex', '-1');\r\n this._createSlidersView();\r\n if (this.element) {\r\n if (this.hexInputRow.element) {\r\n this.element.insertBefore(this.picker, this.hexInputRow.element);\r\n }\r\n else {\r\n this.element.appendChild(this.picker);\r\n }\r\n // Create custom stylesheet with a look of focused pointer in color picker and append it into the color picker shadowDom\r\n const styleSheetForFocusedColorPicker = document.createElement('style');\r\n styleSheetForFocusedColorPicker.textContent = '[role=\"slider\"]:focus [part$=\"pointer\"] {' +\r\n 'border: 1px solid #fff;' +\r\n 'outline: 1px solid var(--ck-color-focus-border);' +\r\n 'box-shadow: 0 0 0 2px #fff;' +\r\n '}';\r\n this.picker.shadowRoot.appendChild(styleSheetForFocusedColorPicker);\r\n }\r\n this.picker.addEventListener('color-changed', event => {\r\n const customEvent = event;\r\n const color = customEvent.detail.value;\r\n this._debounceColorPickerEvent(color);\r\n });\r\n }\r\n /**\r\n * Focuses the first pointer in color picker.\r\n *\r\n */\r\n focus() {\r\n // In some browsers we need to move the focus to the input first.\r\n // Otherwise, the color picker doesn't behave as expected.\r\n // In FF, after selecting the color via slider, it instantly moves back to the previous color.\r\n // In all iOS browsers and desktop Safari, once the saturation slider is moved for the first time,\r\n // editor collapses the selection and doesn't apply the color change.\r\n // See: https://github.com/cksource/ckeditor5-internal/issues/3245, https://github.com/ckeditor/ckeditor5/issues/14119,\r\n // https://github.com/cksource/ckeditor5-internal/issues/3268.\r\n /* istanbul ignore next -- @preserve */\r\n if (!this._config.hideInput && (env.isGecko || env.isiOS || env.isSafari)) {\r\n const input = this.hexInputRow.children.get(1);\r\n input.focus();\r\n }\r\n const firstSlider = this.slidersView.first;\r\n firstSlider.focus();\r\n }\r\n /**\r\n * Creates collection of sliders in color picker.\r\n *\r\n * @private\r\n */\r\n _createSlidersView() {\r\n const colorPickersChildren = [...this.picker.shadowRoot.children];\r\n const sliders = colorPickersChildren.filter(item => item.getAttribute('role') === 'slider');\r\n const slidersView = sliders.map(slider => {\r\n const view = new SliderView(slider);\r\n return view;\r\n });\r\n this.slidersView = this.createCollection();\r\n slidersView.forEach(item => {\r\n this.slidersView.add(item);\r\n });\r\n }\r\n /**\r\n * Creates input row for defining custom colors in color picker.\r\n *\r\n * @private\r\n */\r\n _createInputRow() {\r\n const hashView = new HashView();\r\n const colorInput = this._createColorInput();\r\n return new ColorPickerInputRowView(this.locale, [hashView, colorInput]);\r\n }\r\n /**\r\n * Creates the input where user can type or paste the color in hex format.\r\n *\r\n * @private\r\n */\r\n _createColorInput() {\r\n const labeledInput = new LabeledFieldView(this.locale, createLabeledInputText);\r\n const { t } = this.locale;\r\n labeledInput.set({\r\n label: t('HEX'),\r\n class: 'color-picker-hex-input'\r\n });\r\n labeledInput.fieldView.bind('value').to(this, '_hexColor', pickerColor => {\r\n if (labeledInput.isFocused) {\r\n // Text field shouldn't be updated with color change if the text field is focused.\r\n // Imagine user typing hex code and getting the value of field changed.\r\n return labeledInput.fieldView.value;\r\n }\r\n else {\r\n return pickerColor.startsWith('#') ? pickerColor.substring(1) : pickerColor;\r\n }\r\n });\r\n // Only accept valid hex colors as input.\r\n labeledInput.fieldView.on('input', () => {\r\n const inputValue = labeledInput.fieldView.element.value;\r\n if (inputValue) {\r\n // Trim the whitespace.\r\n const trimmedValue = inputValue.trim();\r\n // Drop the `#` from the beginning if present.\r\n const hashlessInput = trimmedValue.startsWith('#') ? trimmedValue.substring(1) : trimmedValue;\r\n // Check if it's a hex color (3,4,6 or 8 chars long and with proper characters).\r\n const isValidHexColor = [3, 4, 6, 8].includes(hashlessInput.length) &&\r\n /(([0-9a-fA-F]{2}){3,4}|([0-9a-fA-F]){3,4})/.test(hashlessInput);\r\n if (isValidHexColor) {\r\n // If so, set the color.\r\n // Otherwise, do nothing.\r\n this._debounceColorPickerEvent('#' + hashlessInput);\r\n }\r\n }\r\n });\r\n return labeledInput;\r\n }\r\n}\r\n// Converts any color format to a unified hex format.\r\n//\r\n// @param inputColor\r\n// @returns An unified hex string.\r\nfunction convertColorToCommonHexFormat(inputColor) {\r\n let ret = convertToHex(inputColor);\r\n if (!ret) {\r\n ret = '#000';\r\n }\r\n if (ret.length === 4) {\r\n // Unfold shortcut format.\r\n ret = '#' + [ret[1], ret[1], ret[2], ret[2], ret[3], ret[3]].join('');\r\n }\r\n return ret.toLowerCase();\r\n}\r\n// View abstraction over pointer in color picker.\r\nclass SliderView extends View {\r\n /**\r\n * @param element HTML elemnt of slider in color picker.\r\n */\r\n constructor(element) {\r\n super();\r\n this.element = element;\r\n }\r\n /**\r\n * Focuses element.\r\n */\r\n focus() {\r\n this.element.focus();\r\n }\r\n}\r\n// View abstraction over the `#` character before color input.\r\nclass HashView extends View {\r\n constructor(locale) {\r\n super(locale);\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-color-picker__hash-view'\r\n ]\r\n },\r\n children: '#'\r\n });\r\n }\r\n}\r\n// The class representing a row containing hex color input field.\r\n// **Note**: For now this class is private. When more use cases appear (beyond `ckeditor5-table` and `ckeditor5-image`),\r\n// it will become a component in `ckeditor5-ui`.\r\n//\r\n// @private\r\nclass ColorPickerInputRowView extends View {\r\n /**\r\n * Creates an instance of the form row class.\r\n *\r\n * @param locale The locale instance.\r\n */\r\n constructor(locale, children) {\r\n super(locale);\r\n this.children = this.createCollection(children);\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-color-picker__row'\r\n ]\r\n },\r\n children: this.children\r\n });\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\nimport { Collection, ObservableMixin } from '@ckeditor/ckeditor5-utils';\r\n/**\r\n * A collection to store document colors. It enforces colors to be unique.\r\n */\r\nexport default class DocumentColorCollection extends ObservableMixin((Collection)) {\r\n constructor(options) {\r\n super(options);\r\n this.set('isEmpty', true);\r\n this.on('change', () => {\r\n this.set('isEmpty', this.length === 0);\r\n });\r\n }\r\n /**\r\n * Adds a color to the document color collection.\r\n *\r\n * This method ensures that no color duplicates are inserted (compared using\r\n * the color value of the {@link module:ui/colorgrid/colorgridview~ColorDefinition}).\r\n *\r\n * If the item does not have an ID, it will be automatically generated and set on the item.\r\n *\r\n * @param index The position of the item in the collection. The item is pushed to the collection when `index` is not specified.\r\n * @fires add\r\n * @fires change\r\n */\r\n add(item, index) {\r\n if (this.find(element => element.color === item.color)) {\r\n // No duplicates are allowed.\r\n return this;\r\n }\r\n return super.add(item, index);\r\n }\r\n /**\r\n * Checks if an object with given colors is present in the document color collection.\r\n */\r\n hasColor(color) {\r\n return !!this.find(item => item.color === color);\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/colorselector/colorgridsfragmentview\r\n */\r\nimport View from '../view';\r\nimport ButtonView from '../button/buttonview';\r\nimport ColorGridView from '../colorgrid/colorgridview';\r\nimport ColorTileView from '../colorgrid/colortileview';\r\nimport LabelView from '../label/labelview';\r\nimport Template from '../template';\r\nimport DocumentColorCollection from './documentcolorcollection';\r\nimport removeButtonIcon from '@ckeditor/ckeditor5-core/theme/icons/eraser.svg';\r\nimport colorPaletteIcon from '../../theme/icons/color-palette.svg';\r\n/**\r\n * One of the fragments of {@link module:ui/colorselector/colorselectorview~ColorSelectorView}.\r\n *\r\n * It provides a UI that allows users to select colors from the a predefined set and from existing document colors.\r\n *\r\n * It consists of the following sub–components:\r\n *\r\n * * A \"Remove color\" button,\r\n * * A static {@link module:ui/colorgrid/colorgridview~ColorGridView} of colors defined in the configuration,\r\n * * A dynamic {@link module:ui/colorgrid/colorgridview~ColorGridView} of colors used in the document.\r\n * * If color picker is configured, the \"Color Picker\" button is visible too.\r\n */\r\nexport default class ColorGridsFragmentView extends View {\r\n /**\r\n * Creates an instance of the view.\r\n *\r\n * @param locale The localization services instance.\r\n * @param colors An array with definitions of colors to be displayed in the table.\r\n * @param columns The number of columns in the color grid.\r\n * @param removeButtonLabel The label of the button responsible for removing the color.\r\n * @param colorPickerLabel The label of the button responsible for color picker appearing.\r\n * @param documentColorsLabel The label for the section with the document colors.\r\n * @param documentColorsCount The number of colors in the document colors section inside the color dropdown.\r\n * @param focusTracker Tracks information about the DOM focus in the list.\r\n * @param focusables A collection of views that can be focused in the view.\r\n */\r\n constructor(locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount, colorPickerLabel, focusTracker, focusables }) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n this.set('isVisible', true);\r\n this.focusTracker = focusTracker;\r\n this.items = this.createCollection();\r\n this.colorDefinitions = colors;\r\n this.columns = columns;\r\n this.documentColors = new DocumentColorCollection();\r\n this.documentColorsCount = documentColorsCount;\r\n this._focusables = focusables;\r\n this._removeButtonLabel = removeButtonLabel;\r\n this._colorPickerLabel = colorPickerLabel;\r\n this._documentColorsLabel = documentColorsLabel;\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck-color-grids-fragment',\r\n bind.if('isVisible', 'ck-hidden', value => !value)\r\n ]\r\n },\r\n children: this.items\r\n });\r\n this.removeColorButtonView = this._createRemoveColorButton();\r\n this.items.add(this.removeColorButtonView);\r\n }\r\n /**\r\n * Scans through the editor model and searches for text node attributes with the given attribute name.\r\n * Found entries are set as document colors.\r\n *\r\n * All the previously stored document colors will be lost in the process.\r\n *\r\n * @param model The model used as a source to obtain the document colors.\r\n * @param attributeName Determines the name of the related model's attribute for a given dropdown.\r\n */\r\n updateDocumentColors(model, attributeName) {\r\n const document = model.document;\r\n const maxCount = this.documentColorsCount;\r\n this.documentColors.clear();\r\n for (const root of document.getRoots()) {\r\n const range = model.createRangeIn(root);\r\n for (const node of range.getItems()) {\r\n if (node.is('$textProxy') && node.hasAttribute(attributeName)) {\r\n this._addColorToDocumentColors(node.getAttribute(attributeName));\r\n if (this.documentColors.length >= maxCount) {\r\n return;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n /**\r\n * Refreshes the state of the selected color in one or both {@link module:ui/colorgrid/colorgridview~ColorGridView}s\r\n * available in the {@link module:ui/colorselector/colorselectorview~ColorSelectorView}. It guarantees that the selection will\r\n * occur only in one of them.\r\n */\r\n updateSelectedColors() {\r\n const documentColorsGrid = this.documentColorsGrid;\r\n const staticColorsGrid = this.staticColorsGrid;\r\n const selectedColor = this.selectedColor;\r\n staticColorsGrid.selectedColor = selectedColor;\r\n if (documentColorsGrid) {\r\n documentColorsGrid.selectedColor = selectedColor;\r\n }\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n this.staticColorsGrid = this._createStaticColorsGrid();\r\n this.items.add(this.staticColorsGrid);\r\n if (this.documentColorsCount) {\r\n // Create a label for document colors.\r\n const bind = Template.bind(this.documentColors, this.documentColors);\r\n const label = new LabelView(this.locale);\r\n label.text = this._documentColorsLabel;\r\n label.extendTemplate({\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-color-grid__label',\r\n bind.if('isEmpty', 'ck-hidden')\r\n ]\r\n }\r\n });\r\n this.items.add(label);\r\n this.documentColorsGrid = this._createDocumentColorsGrid();\r\n this.items.add(this.documentColorsGrid);\r\n }\r\n this._createColorPickerButton();\r\n this._addColorSelectorElementsToFocusTracker();\r\n this.focus();\r\n }\r\n /**\r\n * Focuses the component.\r\n */\r\n focus() {\r\n this.removeColorButtonView.focus();\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n }\r\n /**\r\n * Handles displaying the color picker button (if it was previously created) and making it focusable.\r\n */\r\n addColorPickerButton() {\r\n if (this.colorPickerButtonView) {\r\n this.items.add(this.colorPickerButtonView);\r\n this.focusTracker.add(this.colorPickerButtonView.element);\r\n this._focusables.add(this.colorPickerButtonView);\r\n }\r\n }\r\n /**\r\n * Adds color selector elements to focus tracker.\r\n */\r\n _addColorSelectorElementsToFocusTracker() {\r\n this.focusTracker.add(this.removeColorButtonView.element);\r\n this._focusables.add(this.removeColorButtonView);\r\n if (this.staticColorsGrid) {\r\n this.focusTracker.add(this.staticColorsGrid.element);\r\n this._focusables.add(this.staticColorsGrid);\r\n }\r\n if (this.documentColorsGrid) {\r\n this.focusTracker.add(this.documentColorsGrid.element);\r\n this._focusables.add(this.documentColorsGrid);\r\n }\r\n }\r\n /**\r\n * Creates the button responsible for displaying the color picker component.\r\n */\r\n _createColorPickerButton() {\r\n this.colorPickerButtonView = new ButtonView();\r\n this.colorPickerButtonView.set({\r\n label: this._colorPickerLabel,\r\n withText: true,\r\n icon: colorPaletteIcon,\r\n class: 'ck-color-selector__color-picker'\r\n });\r\n this.colorPickerButtonView.on('execute', () => {\r\n this.fire('colorPicker:show');\r\n });\r\n }\r\n /**\r\n * Adds the remove color button as a child of the current view.\r\n */\r\n _createRemoveColorButton() {\r\n const buttonView = new ButtonView();\r\n buttonView.set({\r\n withText: true,\r\n icon: removeButtonIcon,\r\n label: this._removeButtonLabel\r\n });\r\n buttonView.class = 'ck-color-selector__remove-color';\r\n buttonView.on('execute', () => {\r\n this.fire('execute', {\r\n value: null,\r\n source: 'removeColorButton'\r\n });\r\n });\r\n buttonView.render();\r\n return buttonView;\r\n }\r\n /**\r\n * Creates a static color grid based on the editor configuration.\r\n */\r\n _createStaticColorsGrid() {\r\n const colorGrid = new ColorGridView(this.locale, {\r\n colorDefinitions: this.colorDefinitions,\r\n columns: this.columns\r\n });\r\n colorGrid.on('execute', (evt, data) => {\r\n this.fire('execute', {\r\n value: data.value,\r\n source: 'staticColorsGrid'\r\n });\r\n });\r\n return colorGrid;\r\n }\r\n /**\r\n * Creates the document colors section view and binds it to {@link #documentColors}.\r\n */\r\n _createDocumentColorsGrid() {\r\n const bind = Template.bind(this.documentColors, this.documentColors);\r\n const documentColorsGrid = new ColorGridView(this.locale, {\r\n columns: this.columns\r\n });\r\n documentColorsGrid.extendTemplate({\r\n attributes: {\r\n class: bind.if('isEmpty', 'ck-hidden')\r\n }\r\n });\r\n documentColorsGrid.items.bindTo(this.documentColors).using(colorObj => {\r\n const colorTile = new ColorTileView();\r\n colorTile.set({\r\n color: colorObj.color,\r\n hasBorder: colorObj.options && colorObj.options.hasBorder\r\n });\r\n if (colorObj.label) {\r\n colorTile.set({\r\n label: colorObj.label,\r\n tooltip: true\r\n });\r\n }\r\n colorTile.on('execute', () => {\r\n this.fire('execute', {\r\n value: colorObj.color,\r\n source: 'documentColorsGrid'\r\n });\r\n });\r\n return colorTile;\r\n });\r\n // Selected color should be cleared when document colors became empty.\r\n this.documentColors.on('change:isEmpty', (evt, name, val) => {\r\n if (val) {\r\n documentColorsGrid.selectedColor = null;\r\n }\r\n });\r\n return documentColorsGrid;\r\n }\r\n /**\r\n * Adds a given color to the document colors list. If possible, the method will attempt to use\r\n * data from the {@link #colorDefinitions} (label, color options).\r\n *\r\n * @param color A string that stores the value of the recently applied color.\r\n */\r\n _addColorToDocumentColors(color) {\r\n const predefinedColor = this.colorDefinitions\r\n .find(definition => definition.color === color);\r\n if (!predefinedColor) {\r\n this.documentColors.add({\r\n color,\r\n label: color,\r\n options: {\r\n hasBorder: false\r\n }\r\n });\r\n }\r\n else {\r\n this.documentColors.add(Object.assign({}, predefinedColor));\r\n }\r\n }\r\n}\r\n","export default \"\";","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/colorselector/colorpickerfragmentview\r\n */\r\nimport View from '../view';\r\nimport ButtonView from '../button/buttonview';\r\nimport { default as ColorPickerView } from '../colorpicker/colorpickerview';\r\nimport checkButtonIcon from '@ckeditor/ckeditor5-core/theme/icons/check.svg';\r\nimport cancelButtonIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';\r\n/**\r\n * One of the fragments of {@link module:ui/colorselector/colorselectorview~ColorSelectorView}.\r\n *\r\n * It allows users to select a color from a color picker.\r\n *\r\n * It consists of the following sub–components:\r\n *\r\n * * A color picker saturation and hue sliders,\r\n * * A text input accepting colors in HEX format,\r\n * * \"Save\" and \"Cancel\" action buttons.\r\n */\r\nexport default class ColorPickerFragmentView extends View {\r\n /**\r\n * Creates an instance of the view.\r\n *\r\n * @param locale The localization services instance.\r\n * @param focusTracker Tracks information about the DOM focus in the list.\r\n * @param focusables A collection of views that can be focused in the view..\r\n * @param keystrokes An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\r\n * @param colorPickerViewConfig The configuration of color picker feature. If set to `false`, the color picker\r\n * will not be rendered.\r\n */\r\n constructor(locale, { focusTracker, focusables, keystrokes, colorPickerViewConfig }) {\r\n super(locale);\r\n this.items = this.createCollection();\r\n this.focusTracker = focusTracker;\r\n this.keystrokes = keystrokes;\r\n this.set('isVisible', false);\r\n this.set('selectedColor', undefined);\r\n this._focusables = focusables;\r\n this._colorPickerViewConfig = colorPickerViewConfig;\r\n const bind = this.bindTemplate;\r\n const { saveButtonView, cancelButtonView } = this._createActionButtons();\r\n this.saveButtonView = saveButtonView;\r\n this.cancelButtonView = cancelButtonView;\r\n this.actionBarView = this._createActionBarView({ saveButtonView, cancelButtonView });\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck-color-picker-fragment',\r\n bind.if('isVisible', 'ck-hidden', value => !value)\r\n ]\r\n },\r\n children: this.items\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n const colorPickerView = new ColorPickerView(this.locale, {\r\n ...this._colorPickerViewConfig\r\n });\r\n this.colorPickerView = colorPickerView;\r\n this.colorPickerView.render();\r\n if (this.selectedColor) {\r\n colorPickerView.color = this.selectedColor;\r\n }\r\n this.listenTo(this, 'change:selectedColor', (evt, name, value) => {\r\n colorPickerView.color = value;\r\n });\r\n this.items.add(this.colorPickerView);\r\n this.items.add(this.actionBarView);\r\n this._addColorPickersElementsToFocusTracker();\r\n this._stopPropagationOnArrowsKeys();\r\n this._executeOnEnterPress();\r\n this._executeUponColorChange();\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n }\r\n /**\r\n * Focuses the color picker.\r\n */\r\n focus() {\r\n this.colorPickerView.focus();\r\n }\r\n /**\r\n * When color picker is focused and \"enter\" is pressed it executes command.\r\n */\r\n _executeOnEnterPress() {\r\n this.keystrokes.set('enter', evt => {\r\n if (this.isVisible && this.focusTracker.focusedElement !== this.cancelButtonView.element) {\r\n this.fire('execute', {\r\n value: this.selectedColor\r\n });\r\n evt.stopPropagation();\r\n evt.preventDefault();\r\n }\r\n });\r\n }\r\n /**\r\n * Removes default behavior of arrow keys in dropdown.\r\n */\r\n _stopPropagationOnArrowsKeys() {\r\n const stopPropagation = (data) => data.stopPropagation();\r\n this.keystrokes.set('arrowright', stopPropagation);\r\n this.keystrokes.set('arrowleft', stopPropagation);\r\n this.keystrokes.set('arrowup', stopPropagation);\r\n this.keystrokes.set('arrowdown', stopPropagation);\r\n }\r\n /**\r\n * Adds color picker elements to focus tracker.\r\n */\r\n _addColorPickersElementsToFocusTracker() {\r\n for (const slider of this.colorPickerView.slidersView) {\r\n this.focusTracker.add(slider.element);\r\n this._focusables.add(slider);\r\n }\r\n const input = this.colorPickerView.hexInputRow.children.get(1);\r\n if (input.element) {\r\n this.focusTracker.add(input.element);\r\n this._focusables.add(input);\r\n }\r\n this.focusTracker.add(this.saveButtonView.element);\r\n this._focusables.add(this.saveButtonView);\r\n this.focusTracker.add(this.cancelButtonView.element);\r\n this._focusables.add(this.cancelButtonView);\r\n }\r\n /**\r\n * Creates bar containing \"Save\" and \"Cancel\" buttons.\r\n */\r\n _createActionBarView({ saveButtonView, cancelButtonView }) {\r\n const actionBarRow = new View();\r\n const children = this.createCollection();\r\n children.add(saveButtonView);\r\n children.add(cancelButtonView);\r\n actionBarRow.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-color-selector_action-bar'\r\n ]\r\n },\r\n children\r\n });\r\n return actionBarRow;\r\n }\r\n /**\r\n * Creates \"Save\" and \"Cancel\" buttons.\r\n */\r\n _createActionButtons() {\r\n const locale = this.locale;\r\n const t = locale.t;\r\n const saveButtonView = new ButtonView(locale);\r\n const cancelButtonView = new ButtonView(locale);\r\n saveButtonView.set({\r\n icon: checkButtonIcon,\r\n class: 'ck-button-save',\r\n type: 'button',\r\n withText: false,\r\n label: t('Accept')\r\n });\r\n cancelButtonView.set({\r\n icon: cancelButtonIcon,\r\n class: 'ck-button-cancel',\r\n type: 'button',\r\n withText: false,\r\n label: t('Cancel')\r\n });\r\n saveButtonView.on('execute', () => {\r\n this.fire('execute', {\r\n source: 'colorPickerSaveButton',\r\n value: this.selectedColor\r\n });\r\n });\r\n cancelButtonView.on('execute', () => {\r\n this.fire('colorPicker:cancel');\r\n });\r\n return {\r\n saveButtonView, cancelButtonView\r\n };\r\n }\r\n /**\r\n * Fires the `execute` event if color in color picker has been changed\r\n * by the user.\r\n */\r\n _executeUponColorChange() {\r\n this.colorPickerView.on('colorSelected', (evt, data) => {\r\n this.fire('execute', {\r\n value: data.color,\r\n source: 'colorPicker'\r\n });\r\n this.set('selectedColor', data.color);\r\n });\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/colorselector/colorselectorview\r\n */\r\nimport FocusCycler from '../focuscycler';\r\nimport View from '../view';\r\nimport ViewCollection from '../viewcollection';\r\nimport { FocusTracker, KeystrokeHandler } from '@ckeditor/ckeditor5-utils';\r\nimport ColorGridsFragmentView from './colorgridsfragmentview';\r\nimport ColorPickerFragmentView from './colorpickerfragmentview';\r\nimport '../../theme/components/colorselector/colorselector.css';\r\n/**\r\n * The configurable color selector view class. It allows users to select colors from a predefined set of colors as well as from\r\n * a color picker.\r\n *\r\n * This meta-view is is made of two components (fragments):\r\n *\r\n * * {@link module:ui/colorselector/colorselectorview~ColorSelectorView#colorGridsFragmentView},\r\n * * {@link module:ui/colorselector/colorselectorview~ColorSelectorView#colorPickerFragmentView}.\r\n *\r\n * ```ts\r\n * const colorDefinitions = [\r\n * \t{ color: '#000', label: 'Black', options: { hasBorder: false } },\r\n * \t{ color: 'rgb(255, 255, 255)', label: 'White', options: { hasBorder: true } },\r\n * \t{ color: 'red', label: 'Red', options: { hasBorder: false } }\r\n * ];\r\n *\r\n * const selectorView = new ColorSelectorView( locale, {\r\n * \tcolors: colorDefinitions,\r\n * \tcolumns: 5,\r\n * \tremoveButtonLabel: 'Remove color',\r\n * \tdocumentColorsLabel: 'Document colors',\r\n * \tdocumentColorsCount: 4,\r\n * \tcolorPickerViewConfig: {\r\n * \t\tformat: 'hsl'\r\n * \t}\r\n * } );\r\n *\r\n * selectorView.appendUI();\r\n * selectorView.selectedColor = 'red';\r\n * selectorView.updateSelectedColors();\r\n *\r\n * selectorView.on( 'execute', ( evt, data ) => {\r\n * \tconsole.log( 'Color changed', data.value, data.source );\r\n * } );\r\n *\r\n * selectorView.on( 'colorPicker:show', ( evt ) => {\r\n * \tconsole.log( 'Color picker showed up', evt );\r\n * } );\r\n *\r\n * selectorView.on( 'colorPicker:cancel', ( evt ) => {\r\n * \tconsole.log( 'Color picker cancel', evt );\r\n * } );\r\n *\r\n * selectorView.render();\r\n *\r\n * document.body.appendChild( selectorView.element );\r\n * ```\r\n */\r\nexport default class ColorSelectorView extends View {\r\n /**\r\n * Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.\r\n *\r\n * @param locale The localization services instance.\r\n * @param colors An array with definitions of colors to be displayed in the table.\r\n * @param columns The number of columns in the color grid.\r\n * @param removeButtonLabel The label of the button responsible for removing the color.\r\n * @param colorPickerLabel The label of the button responsible for color picker appearing.\r\n * @param documentColorsLabel The label for the section with the document colors.\r\n * @param documentColorsCount The number of colors in the document colors section inside the color dropdown.\r\n * @param colorPickerViewConfig The configuration of color picker feature. If set to `false`, the color picker will be hidden.\r\n */\r\n constructor(locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount, colorPickerLabel, colorPickerViewConfig }) {\r\n super(locale);\r\n this.items = this.createCollection();\r\n this.focusTracker = new FocusTracker();\r\n this.keystrokes = new KeystrokeHandler();\r\n this._focusables = new ViewCollection();\r\n this._colorPickerViewConfig = colorPickerViewConfig;\r\n this._focusCycler = new FocusCycler({\r\n focusables: this._focusables,\r\n focusTracker: this.focusTracker,\r\n keystrokeHandler: this.keystrokes,\r\n actions: {\r\n // Navigate list items backwards using the Shift + Tab keystroke.\r\n focusPrevious: 'shift + tab',\r\n // Navigate list items forwards using the Tab key.\r\n focusNext: 'tab'\r\n }\r\n });\r\n this.colorGridsFragmentView = new ColorGridsFragmentView(locale, {\r\n colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount, colorPickerLabel,\r\n focusTracker: this.focusTracker,\r\n focusables: this._focusables\r\n });\r\n this.colorPickerFragmentView = new ColorPickerFragmentView(locale, {\r\n focusables: this._focusables,\r\n focusTracker: this.focusTracker,\r\n keystrokes: this.keystrokes,\r\n colorPickerViewConfig\r\n });\r\n this.set('_isColorGridsFragmentVisible', true);\r\n this.set('_isColorPickerFragmentVisible', false);\r\n this.set('selectedColor', undefined);\r\n this.colorGridsFragmentView.bind('isVisible').to(this, '_isColorGridsFragmentVisible');\r\n this.colorPickerFragmentView.bind('isVisible').to(this, '_isColorPickerFragmentVisible');\r\n /**\r\n * This is kind of bindings. Unfortunately we could not use this.bind() method because the same property\r\n * can not be bound twice. So this is work around how to bind 'selectedColor' property between components.\r\n */\r\n this.on('change:selectedColor', (evt, evtName, data) => {\r\n this.colorGridsFragmentView.set('selectedColor', data);\r\n this.colorPickerFragmentView.set('selectedColor', data);\r\n });\r\n this.colorGridsFragmentView.on('change:selectedColor', (evt, evtName, data) => {\r\n this.set('selectedColor', data);\r\n });\r\n this.colorPickerFragmentView.on('change:selectedColor', (evt, evtName, data) => {\r\n this.set('selectedColor', data);\r\n });\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-color-selector'\r\n ]\r\n },\r\n children: this.items\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n // Start listening for the keystrokes coming from #element.\r\n this.keystrokes.listenTo(this.element);\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n this.focusTracker.destroy();\r\n this.keystrokes.destroy();\r\n }\r\n /**\r\n * Renders the internals of the component on demand:\r\n * * {@link #colorPickerFragmentView},\r\n * * {@link #colorGridsFragmentView}.\r\n *\r\n * It allows for deferring component initialization to improve the performance.\r\n *\r\n * See {@link #showColorPickerFragment}, {@link #showColorGridsFragment}.\r\n */\r\n appendUI() {\r\n this._appendColorGridsFragment();\r\n if (this._colorPickerViewConfig) {\r\n this._appendColorPickerFragment();\r\n }\r\n }\r\n /**\r\n * Shows the {@link #colorPickerFragmentView} and hides the {@link #colorGridsFragmentView}.\r\n *\r\n * **Note**: It requires {@link #appendUI} to be called first.\r\n *\r\n * See {@link #showColorGridsFragment}, {@link ~ColorSelectorView#event:colorPicker:show}.\r\n */\r\n showColorPickerFragment() {\r\n if (!this.colorPickerFragmentView.colorPickerView || this._isColorPickerFragmentVisible) {\r\n return;\r\n }\r\n this._isColorPickerFragmentVisible = true;\r\n this.colorPickerFragmentView.focus();\r\n this._isColorGridsFragmentVisible = false;\r\n }\r\n /**\r\n * Shows the {@link #colorGridsFragmentView} and hides the {@link #colorPickerFragmentView}.\r\n *\r\n * See {@link #showColorPickerFragment}.\r\n *\r\n * **Note**: It requires {@link #appendUI} to be called first.\r\n */\r\n showColorGridsFragment() {\r\n if (this._isColorGridsFragmentVisible) {\r\n return;\r\n }\r\n this._isColorGridsFragmentVisible = true;\r\n this.colorGridsFragmentView.focus();\r\n this._isColorPickerFragmentVisible = false;\r\n }\r\n /**\r\n * Focuses the first focusable element in {@link #items}.\r\n */\r\n focus() {\r\n this._focusCycler.focusFirst();\r\n }\r\n /**\r\n * Focuses the last focusable element in {@link #items}.\r\n */\r\n focusLast() {\r\n this._focusCycler.focusLast();\r\n }\r\n /**\r\n * Scans through the editor model and searches for text node attributes with the given `attributeName`.\r\n * Found entries are set as document colors in {@link #colorGridsFragmentView}.\r\n *\r\n * All the previously stored document colors will be lost in the process.\r\n *\r\n * @param model The model used as a source to obtain the document colors.\r\n * @param attributeName Determines the name of the related model's attribute for a given dropdown.\r\n */\r\n updateDocumentColors(model, attributeName) {\r\n this.colorGridsFragmentView.updateDocumentColors(model, attributeName);\r\n }\r\n /**\r\n * Refreshes the state of the selected color in one or both grids located in {@link #colorGridsFragmentView}.\r\n *\r\n * It guarantees that the selection will occur only in one of them.\r\n */\r\n updateSelectedColors() {\r\n this.colorGridsFragmentView.updateSelectedColors();\r\n }\r\n /**\r\n * Appends the view containing static and document color grid views.\r\n */\r\n _appendColorGridsFragment() {\r\n if (this.items.length) {\r\n return;\r\n }\r\n this.items.add(this.colorGridsFragmentView);\r\n this.colorGridsFragmentView.delegate('execute').to(this);\r\n this.colorGridsFragmentView.delegate('colorPicker:show').to(this);\r\n }\r\n /**\r\n * Appends the view with the color picker.\r\n */\r\n _appendColorPickerFragment() {\r\n if (this.items.length === 2) {\r\n return;\r\n }\r\n this.items.add(this.colorPickerFragmentView);\r\n if (this.colorGridsFragmentView.colorPickerButtonView) {\r\n this.colorGridsFragmentView.colorPickerButtonView.on('execute', () => {\r\n this.showColorPickerFragment();\r\n });\r\n }\r\n this.colorGridsFragmentView.addColorPickerButton();\r\n this.colorPickerFragmentView.delegate('execute').to(this);\r\n this.colorPickerFragmentView.delegate('colorPicker:cancel').to(this);\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/componentfactory\r\n */\r\nimport { CKEditorError } from '@ckeditor/ckeditor5-utils';\r\n/**\r\n * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.\r\n *\r\n * It allows functions producing specific UI components to be registered under their unique names\r\n * in the factory. A registered component can be then instantiated by providing its name.\r\n * Note that the names are case insensitive.\r\n *\r\n * ```ts\r\n * // The editor provides localization tools for the factory.\r\n * const factory = new ComponentFactory( editor );\r\n *\r\n * factory.add( 'foo', locale => new FooView( locale ) );\r\n * factory.add( 'bar', locale => new BarView( locale ) );\r\n *\r\n * // An instance of FooView.\r\n * const fooInstance = factory.create( 'foo' );\r\n *\r\n * // Names are case insensitive so this is also allowed:\r\n * const barInstance = factory.create( 'Bar' );\r\n * ```\r\n *\r\n * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory\r\n * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.\r\n */\r\nexport default class ComponentFactory {\r\n /**\r\n * Creates an instance of the factory.\r\n *\r\n * @param editor The editor instance.\r\n */\r\n constructor(editor) {\r\n /**\r\n * Registered component factories.\r\n */\r\n this._components = new Map();\r\n this.editor = editor;\r\n }\r\n /**\r\n * Returns an iterator of registered component names. Names are returned in lower case.\r\n */\r\n *names() {\r\n for (const value of this._components.values()) {\r\n yield value.originalName;\r\n }\r\n }\r\n /**\r\n * Registers a component factory function that will be used by the\r\n * {@link #create create} method and called with the\r\n * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,\r\n * allowing localization of the {@link module:ui/view~View view}.\r\n *\r\n * @param name The name of the component.\r\n * @param callback The callback that returns the component.\r\n */\r\n add(name, callback) {\r\n this._components.set(getNormalized(name), { callback, originalName: name });\r\n }\r\n /**\r\n * Creates an instance of a component registered in the factory under a specific name.\r\n *\r\n * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to\r\n * the previously {@link #add added} factory function, allowing localization of the\r\n * {@link module:ui/view~View view}.\r\n *\r\n * @param name The name of the component.\r\n * @returns The instantiated component view.\r\n */\r\n create(name) {\r\n if (!this.has(name)) {\r\n /**\r\n * The required component is not registered in the component factory. Please make sure\r\n * the provided name is correct and the component has been correctly\r\n * {@link module:ui/componentfactory~ComponentFactory#add added} to the factory.\r\n *\r\n * @error componentfactory-item-missing\r\n * @param name The name of the missing component.\r\n */\r\n throw new CKEditorError('componentfactory-item-missing', this, { name });\r\n }\r\n return this._components.get(getNormalized(name)).callback(this.editor.locale);\r\n }\r\n /**\r\n * Checks if a component of a given name is registered in the factory.\r\n *\r\n * @param name The name of the component.\r\n */\r\n has(name) {\r\n return this._components.has(getNormalized(name));\r\n }\r\n}\r\n/**\r\n * Ensures that the component name used as the key in the internal map is in lower case.\r\n */\r\nfunction getNormalized(name) {\r\n return String(name).toLowerCase();\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/panel/balloon/balloonpanelview\r\n */\r\nimport View from '../../view';\r\nimport { getOptimalPosition, global, isRange, toUnit } from '@ckeditor/ckeditor5-utils';\r\nimport { isElement } from 'lodash-es';\r\nimport '../../../theme/components/panel/balloonpanel.css';\r\nconst toPx = toUnit('px');\r\nconst defaultLimiterElement = global.document.body;\r\n// A static balloon panel positioning function that moves the balloon far off the viewport.\r\n// It is used as a fallback when there is no way to position the balloon using provided\r\n// positioning functions (see: `getOptimalPosition()`), for instance, when the target the\r\n// balloon should be attached to gets obscured by scrollable containers or the viewport.\r\n//\r\n// It prevents the balloon from being attached to the void and possible degradation of the UX.\r\n// At the same time, it keeps the balloon physically visible in the DOM so the focus remains\r\n// uninterrupted.\r\nconst POSITION_OFF_SCREEN = {\r\n top: -99999,\r\n left: -99999,\r\n name: 'arrowless',\r\n config: {\r\n withArrow: false\r\n }\r\n};\r\n/**\r\n * The balloon panel view class.\r\n *\r\n * A floating container which can\r\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any\r\n * {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position\r\n * e.g. when the web page is scrolled.\r\n *\r\n * The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and\r\n * the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view\r\n * collection.\r\n *\r\n * There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}\r\n * that the balloon can use, automatically switching from one to another when the viewport space becomes\r\n * scarce to keep the balloon visible to the user as long as it is possible. The balloon will also\r\n * accept any custom position set provided by the user compatible with the\r\n * {@link module:utils/dom/position~Options options}.\r\n *\r\n * ```ts\r\n * const panel = new BalloonPanelView( locale );\r\n * const childView = new ChildView();\r\n * const positions = BalloonPanelView.defaultPositions;\r\n *\r\n * panel.render();\r\n *\r\n * // Add a child view to the panel's content collection.\r\n * panel.content.add( childView );\r\n *\r\n * // Start pinning the panel to an element with the \"target\" id DOM.\r\n * // The balloon will remain pinned until unpin() is called.\r\n * panel.pin( {\r\n * \ttarget: document.querySelector( '#target' ),\r\n * \tpositions: [\r\n * \t\tpositions.northArrowSouth,\r\n * \t\tpositions.southArrowNorth\r\n * \t]\r\n * } );\r\n * ```\r\n */\r\nexport default class BalloonPanelView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n this.set('top', 0);\r\n this.set('left', 0);\r\n this.set('position', 'arrow_nw');\r\n this.set('isVisible', false);\r\n this.set('withArrow', true);\r\n this.set('class', undefined);\r\n this._pinWhenIsVisibleCallback = null;\r\n this.content = this.createCollection();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-balloon-panel',\r\n bind.to('position', value => `ck-balloon-panel_${value}`),\r\n bind.if('isVisible', 'ck-balloon-panel_visible'),\r\n bind.if('withArrow', 'ck-balloon-panel_with-arrow'),\r\n bind.to('class')\r\n ],\r\n style: {\r\n top: bind.to('top', toPx),\r\n left: bind.to('left', toPx)\r\n }\r\n },\r\n children: this.content\r\n });\r\n }\r\n /**\r\n * Shows the panel.\r\n *\r\n * See {@link #isVisible}.\r\n */\r\n show() {\r\n this.isVisible = true;\r\n }\r\n /**\r\n * Hides the panel.\r\n *\r\n * See {@link #isVisible}.\r\n */\r\n hide() {\r\n this.isVisible = false;\r\n }\r\n /**\r\n * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a\r\n * smart positioning heuristics that chooses from available positions to make sure the panel\r\n * is visible to the user i.e. within the limits of the viewport.\r\n *\r\n * This method accepts configuration {@link module:utils/dom/position~Options options}\r\n * to set the `target`, optional `limiter` and `positions` the balloon should choose from.\r\n *\r\n * ```ts\r\n * const panel = new BalloonPanelView( locale );\r\n * const positions = BalloonPanelView.defaultPositions;\r\n *\r\n * panel.render();\r\n *\r\n * // Attach the panel to an element with the \"target\" id DOM.\r\n * panel.attachTo( {\r\n * \ttarget: document.querySelector( '#target' ),\r\n * \tpositions: [\r\n * \t\tpositions.northArrowSouth,\r\n * \t\tpositions.southArrowNorth\r\n * \t]\r\n * } );\r\n * ```\r\n *\r\n * **Note**: Attaching the panel will also automatically {@link #show} it.\r\n *\r\n * **Note**: An attached panel will not follow its target when the window is scrolled or resized.\r\n * See the {@link #pin} method for a more permanent positioning strategy.\r\n *\r\n * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.\r\n * Default `positions` array is {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\r\n */\r\n attachTo(options) {\r\n this.show();\r\n const defaultPositions = BalloonPanelView.defaultPositions;\r\n const positionOptions = Object.assign({}, {\r\n element: this.element,\r\n positions: [\r\n defaultPositions.southArrowNorth,\r\n defaultPositions.southArrowNorthMiddleWest,\r\n defaultPositions.southArrowNorthMiddleEast,\r\n defaultPositions.southArrowNorthWest,\r\n defaultPositions.southArrowNorthEast,\r\n defaultPositions.northArrowSouth,\r\n defaultPositions.northArrowSouthMiddleWest,\r\n defaultPositions.northArrowSouthMiddleEast,\r\n defaultPositions.northArrowSouthWest,\r\n defaultPositions.northArrowSouthEast,\r\n defaultPositions.viewportStickyNorth\r\n ],\r\n limiter: defaultLimiterElement,\r\n fitInViewport: true\r\n }, options);\r\n const optimalPosition = BalloonPanelView._getOptimalPosition(positionOptions) || POSITION_OFF_SCREEN;\r\n // Usually browsers make some problems with super accurate values like 104.345px\r\n // so it is better to use int values.\r\n const left = parseInt(optimalPosition.left);\r\n const top = parseInt(optimalPosition.top);\r\n const position = optimalPosition.name;\r\n const config = optimalPosition.config || {};\r\n const { withArrow = true } = config;\r\n this.top = top;\r\n this.left = left;\r\n this.position = position;\r\n this.withArrow = withArrow;\r\n }\r\n /**\r\n * Works the same way as the {@link #attachTo} method except that the position of the panel is\r\n * continuously updated when:\r\n *\r\n * * any ancestor of the {@link module:utils/dom/position~Options#target}\r\n * or {@link module:utils/dom/position~Options#limiter} is scrolled,\r\n * * the browser window gets resized or scrolled.\r\n *\r\n * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}\r\n * and is immune to the changing environment.\r\n *\r\n * ```ts\r\n * const panel = new BalloonPanelView( locale );\r\n * const positions = BalloonPanelView.defaultPositions;\r\n *\r\n * panel.render();\r\n *\r\n * // Pin the panel to an element with the \"target\" id DOM.\r\n * panel.pin( {\r\n * \ttarget: document.querySelector( '#target' ),\r\n * \tpositions: [\r\n * \t\tpositions.northArrowSouth,\r\n * \t\tpositions.southArrowNorth\r\n * \t]\r\n * } );\r\n * ```\r\n *\r\n * To leave the pinned state, use the {@link #unpin} method.\r\n *\r\n * **Note**: Pinning the panel will also automatically {@link #show} it.\r\n *\r\n * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.\r\n * Default `positions` array is {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\r\n */\r\n pin(options) {\r\n this.unpin();\r\n this._pinWhenIsVisibleCallback = () => {\r\n if (this.isVisible) {\r\n this._startPinning(options);\r\n }\r\n else {\r\n this._stopPinning();\r\n }\r\n };\r\n this._startPinning(options);\r\n // Control the state of the listeners depending on whether the panel is visible\r\n // or not.\r\n // TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\r\n this.listenTo(this, 'change:isVisible', this._pinWhenIsVisibleCallback);\r\n }\r\n /**\r\n * Stops pinning the panel, as set up by {@link #pin}.\r\n */\r\n unpin() {\r\n if (this._pinWhenIsVisibleCallback) {\r\n // Deactivate listeners attached by pin().\r\n this._stopPinning();\r\n // Deactivate the panel pin() control logic.\r\n // TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\r\n this.stopListening(this, 'change:isVisible', this._pinWhenIsVisibleCallback);\r\n this._pinWhenIsVisibleCallback = null;\r\n this.hide();\r\n }\r\n }\r\n /**\r\n * Starts managing the pinned state of the panel. See {@link #pin}.\r\n *\r\n * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.\r\n */\r\n _startPinning(options) {\r\n this.attachTo(options);\r\n const targetElement = getDomElement(options.target);\r\n const limiterElement = options.limiter ? getDomElement(options.limiter) : defaultLimiterElement;\r\n // Then we need to listen on scroll event of eny element in the document.\r\n this.listenTo(global.document, 'scroll', (evt, domEvt) => {\r\n const scrollTarget = domEvt.target;\r\n // The position needs to be updated if the positioning target is within the scrolled element.\r\n const isWithinScrollTarget = targetElement && scrollTarget.contains(targetElement);\r\n // The position needs to be updated if the positioning limiter is within the scrolled element.\r\n const isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains(limiterElement);\r\n // The positioning target and/or limiter can be a Rect, object etc..\r\n // There's no way to optimize the listener then.\r\n if (isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement) {\r\n this.attachTo(options);\r\n }\r\n }, { useCapture: true });\r\n // We need to listen on window resize event and update position.\r\n this.listenTo(global.window, 'resize', () => {\r\n this.attachTo(options);\r\n });\r\n }\r\n /**\r\n * Stops managing the pinned state of the panel. See {@link #pin}.\r\n */\r\n _stopPinning() {\r\n this.stopListening(global.document, 'scroll');\r\n this.stopListening(global.window, 'resize');\r\n }\r\n}\r\n/**\r\n * A side offset of the arrow tip from the edge of the balloon. Controlled by CSS.\r\n *\r\n * ```\r\n *\t\t ┌───────────────────────┐\r\n *\t\t │ │\r\n *\t\t │ Balloon │\r\n *\t\t │ Content │\r\n *\t\t │ │\r\n *\t\t └──+ +───────────────┘\r\n *\t\t | \\ /\r\n *\t\t | \\/\r\n *\t\t>┼─────┼< ─────────────────────── side offset\r\n *\r\n * ```\r\n *\r\n * @default 25\r\n */\r\nBalloonPanelView.arrowSideOffset = 25;\r\n/**\r\n * A height offset of the arrow from the edge of the balloon. Controlled by CSS.\r\n *\r\n * ```\r\n *\t\t ┌───────────────────────┐\r\n *\t\t │ │\r\n *\t\t │ Balloon │\r\n *\t\t │ Content │ ╱-- arrow height offset\r\n *\t\t │ │ V\r\n *\t\t └──+ +───────────────┘ --- ─┼───────\r\n *\t\t \\ / │\r\n *\t\t \\/ │\r\n *\t\t────────────────────────────────┼───────\r\n *\t\t ^\r\n *\r\n *\r\n *\t\t>┼────┼< arrow height offset\r\n *\t\t │ │\r\n *\t\t │ ┌────────────────────────┐\r\n *\t\t │ │ │\r\n *\t\t │ ╱ │\r\n *\t\t │ ╱ Balloon │\r\n *\t\t │ ╲ Content │\r\n *\t\t │ ╲ │\r\n *\t\t │ │ │\r\n *\t\t │ └────────────────────────┘\r\n * ```\r\n *\r\n * @default 10\r\n*/\r\nBalloonPanelView.arrowHeightOffset = 10;\r\n/**\r\n * A vertical offset of the balloon panel from the edge of the viewport if sticky.\r\n * It helps in accessing toolbar buttons underneath the balloon panel.\r\n *\r\n * ```\r\n *\t\t ┌───────────────────────────────────────────────────┐\r\n *\t\t │ Target │\r\n *\t\t │ │\r\n *\t\t │ /── vertical offset │\r\n *\t\t┌─────────────────────────────V─────────────────────────┐\r\n *\t\t│ Toolbar ┌─────────────┐ │\r\n *\t\t├────────────────────│ Balloon │────────────────────┤\r\n *\t\t│ │ └─────────────┘ │ │\r\n *\t\t│ │ │ │\r\n *\t\t│ │ │ │\r\n *\t\t│ │ │ │\r\n *\t\t│ └───────────────────────────────────────────────────┘ │\r\n *\t\t│ Viewport │\r\n *\t\t└───────────────────────────────────────────────────────┘\r\n * ```\r\n *\r\n * @default 20\r\n */\r\nBalloonPanelView.stickyVerticalOffset = 20;\r\n/**\r\n * Function used to calculate the optimal position for the balloon.\r\n */\r\nBalloonPanelView._getOptimalPosition = getOptimalPosition;\r\n/**\r\n * A default set of positioning functions used by the balloon panel view\r\n * when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\r\n *\r\n * The available positioning functions are as follows:\r\n *\r\n * **North west**\r\n *\r\n * * `northWestArrowSouthWest`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northWestArrowSouthMiddleWest`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northWestArrowSouth`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northWestArrowSouthMiddleEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northWestArrowSouthEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * **North**\r\n *\r\n * * `northArrowSouthWest`\r\n *\r\n * ```\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n *\t\t V\r\n *\t\t[ Target ]\r\n * ```\r\n *\r\n * * `northArrowSouthMiddleWest`\r\n *\r\n * ```\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n *\t\t V\r\n *\t\t[ Target ]\r\n * ```\r\n * * `northArrowSouth`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northArrowSouthMiddleEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northArrowSouthEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * **North east**\r\n *\r\n * * `northEastArrowSouthWest`\r\n *\r\n * ```\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n *\t\t V\r\n *\t\t[ Target ]\r\n * ```\r\n *\r\n * * `northEastArrowSouthMiddleWest`\r\n *\r\n * ```\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n *\t\t V\r\n *\t\t[ Target ]\r\n * ```\r\n *\r\n * * `northEastArrowSouth`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t[ Target ]\r\n * ```\r\n *\r\n * * `northEastArrowSouthMiddleEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * * `northEastArrowSouthEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n *\t\t V\r\n *\t\t [ Target ]\r\n * ```\r\n *\r\n * **South**\r\n *\r\n * * `southArrowNorthWest`\r\n *\r\n * ```\r\n *\t\t[ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southArrowNorthMiddleWest`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southArrowNorth`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southArrowNorthMiddleEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southArrowNorthEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * **South west**\r\n *\r\n * * `southWestArrowNorthWest`\r\n *\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southWestArrowNorthMiddleWest`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southWestArrowNorth`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southWestArrowNorthMiddleEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southWestArrowNorthEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * **South east**\r\n *\r\n * * `southEastArrowNorthWest`\r\n *\r\n * ```\r\n *\t\t[ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southEastArrowNorthMiddleWest`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t +-----------------+\r\n *\t\t | Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * * `southEastArrowNorth`\r\n *\r\n * ```\r\n *\t\t[ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southEastArrowNorthMiddleEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * * `southEastArrowNorthEast`\r\n *\r\n * ```\r\n *\t\t [ Target ]\r\n *\t\t ^\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * **West**\r\n *\r\n * * `westArrowEast`\r\n *\r\n * ```\r\n *\t\t+-----------------+\r\n *\t\t| Balloon |>[ Target ]\r\n *\t\t+-----------------+\r\n * ```\r\n *\r\n * **East**\r\n *\r\n * * `eastArrowWest`\r\n *\r\n * ```\r\n *\t\t +-----------------+\r\n *\t\t[ Target ]<| Balloon |\r\n *\t\t +-----------------+\r\n * ```\r\n *\r\n * **Sticky**\r\n *\r\n * * `viewportStickyNorth`\r\n *\r\n * ```\r\n *\t\t +---------------------------+\r\n *\t\t | [ Target ] |\r\n *\t\t | |\r\n *\t\t+-----------------------------------+\r\n *\t\t| | +-----------------+ | |\r\n *\t\t| | | Balloon | | |\r\n *\t\t| | +-----------------+ | |\r\n *\t\t| | | |\r\n *\t\t| | | |\r\n *\t\t| | | |\r\n *\t\t| | | |\r\n *\t\t| +---------------------------+ |\r\n *\t\t| Viewport |\r\n *\t\t+-----------------------------------+\r\n * ```\r\n *\r\n * See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.\r\n *\r\n * Positioning functions must be compatible with {@link module:utils/dom/position~Position}.\r\n *\r\n * Default positioning functions with customized offsets can be generated using\r\n * {@link module:ui/panel/balloon/balloonpanelview~generatePositions}.\r\n *\r\n * The name that the position function returns will be reflected in the balloon panel's class that\r\n * controls the placement of the \"arrow\". See {@link #position} to learn more.\r\n */\r\nBalloonPanelView.defaultPositions = generatePositions();\r\n/**\r\n * Returns the DOM element for given object or null, if there is none,\r\n * e.g. when the passed object is a Rect instance or so.\r\n */\r\nfunction getDomElement(object) {\r\n if (isElement(object)) {\r\n return object;\r\n }\r\n if (isRange(object)) {\r\n return object.commonAncestorContainer;\r\n }\r\n if (typeof object == 'function') {\r\n return getDomElement(object());\r\n }\r\n return null;\r\n}\r\n/**\r\n * Returns available {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\r\n * {@link module:utils/dom/position~PositioningFunction positioning functions} adjusted by the specific offsets.\r\n *\r\n * @internal\r\n * @param options Options to generate positions. If not specified, this helper will simply return\r\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\r\n * @param options.sideOffset A custom side offset (in pixels) of each position. If\r\n * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowSideOffset the default value}\r\n * will be used.\r\n * @param options.heightOffset A custom height offset (in pixels) of each position. If\r\n * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHeightOffset the default value}\r\n * will be used.\r\n * @param options.stickyVerticalOffset A custom offset (in pixels) of the `viewportStickyNorth` positioning function.\r\n * If not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.stickyVerticalOffset the default value}\r\n * will be used.\r\n * @param options.config Additional configuration of the balloon balloon panel view.\r\n * Currently only {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#withArrow} is supported. Learn more\r\n * about {@link module:utils/dom/position~PositioningFunction positioning functions}.\r\n */\r\nexport function generatePositions(options = {}) {\r\n const { sideOffset = BalloonPanelView.arrowSideOffset, heightOffset = BalloonPanelView.arrowHeightOffset, stickyVerticalOffset = BalloonPanelView.stickyVerticalOffset, config } = options;\r\n return {\r\n // ------- North west\r\n northWestArrowSouthWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left - sideOffset,\r\n name: 'arrow_sw',\r\n ...(config && { config })\r\n }),\r\n northWestArrowSouthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left - (balloonRect.width * .25) - sideOffset,\r\n name: 'arrow_smw',\r\n ...(config && { config })\r\n }),\r\n northWestArrowSouth: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left - balloonRect.width / 2,\r\n name: 'arrow_s',\r\n ...(config && { config })\r\n }),\r\n northWestArrowSouthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left - (balloonRect.width * .75) + sideOffset,\r\n name: 'arrow_sme',\r\n ...(config && { config })\r\n }),\r\n northWestArrowSouthEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left - balloonRect.width + sideOffset,\r\n name: 'arrow_se',\r\n ...(config && { config })\r\n }),\r\n // ------- North\r\n northArrowSouthWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left + targetRect.width / 2 - sideOffset,\r\n name: 'arrow_sw',\r\n ...(config && { config })\r\n }),\r\n northArrowSouthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left + targetRect.width / 2 - (balloonRect.width * .25) - sideOffset,\r\n name: 'arrow_smw',\r\n ...(config && { config })\r\n }),\r\n northArrowSouth: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\r\n name: 'arrow_s',\r\n ...(config && { config })\r\n }),\r\n northArrowSouthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left + targetRect.width / 2 - (balloonRect.width * .75) + sideOffset,\r\n name: 'arrow_sme',\r\n ...(config && { config })\r\n }),\r\n northArrowSouthEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.left + targetRect.width / 2 - balloonRect.width + sideOffset,\r\n name: 'arrow_se',\r\n ...(config && { config })\r\n }),\r\n // ------- North east\r\n northEastArrowSouthWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.right - sideOffset,\r\n name: 'arrow_sw',\r\n ...(config && { config })\r\n }),\r\n northEastArrowSouthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.right - (balloonRect.width * .25) - sideOffset,\r\n name: 'arrow_smw',\r\n ...(config && { config })\r\n }),\r\n northEastArrowSouth: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.right - balloonRect.width / 2,\r\n name: 'arrow_s',\r\n ...(config && { config })\r\n }),\r\n northEastArrowSouthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.right - (balloonRect.width * .75) + sideOffset,\r\n name: 'arrow_sme',\r\n ...(config && { config })\r\n }),\r\n northEastArrowSouthEast: (targetRect, balloonRect) => ({\r\n top: getNorthTop(targetRect, balloonRect),\r\n left: targetRect.right - balloonRect.width + sideOffset,\r\n name: 'arrow_se',\r\n ...(config && { config })\r\n }),\r\n // ------- South west\r\n southWestArrowNorthWest: targetRect => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left - sideOffset,\r\n name: 'arrow_nw',\r\n ...(config && { config })\r\n }),\r\n southWestArrowNorthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left - (balloonRect.width * .25) - sideOffset,\r\n name: 'arrow_nmw',\r\n ...(config && { config })\r\n }),\r\n southWestArrowNorth: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left - balloonRect.width / 2,\r\n name: 'arrow_n',\r\n ...(config && { config })\r\n }),\r\n southWestArrowNorthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left - (balloonRect.width * .75) + sideOffset,\r\n name: 'arrow_nme',\r\n ...(config && { config })\r\n }),\r\n southWestArrowNorthEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left - balloonRect.width + sideOffset,\r\n name: 'arrow_ne',\r\n ...(config && { config })\r\n }),\r\n // ------- South\r\n southArrowNorthWest: targetRect => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left + targetRect.width / 2 - sideOffset,\r\n name: 'arrow_nw',\r\n ...(config && { config })\r\n }),\r\n southArrowNorthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left + targetRect.width / 2 - (balloonRect.width * 0.25) - sideOffset,\r\n name: 'arrow_nmw',\r\n ...(config && { config })\r\n }),\r\n southArrowNorth: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\r\n name: 'arrow_n',\r\n ...(config && { config })\r\n }),\r\n southArrowNorthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left + targetRect.width / 2 - (balloonRect.width * 0.75) + sideOffset,\r\n name: 'arrow_nme',\r\n ...(config && { config })\r\n }),\r\n southArrowNorthEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.left + targetRect.width / 2 - balloonRect.width + sideOffset,\r\n name: 'arrow_ne',\r\n ...(config && { config })\r\n }),\r\n // ------- South east\r\n southEastArrowNorthWest: targetRect => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.right - sideOffset,\r\n name: 'arrow_nw',\r\n ...(config && { config })\r\n }),\r\n southEastArrowNorthMiddleWest: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.right - (balloonRect.width * .25) - sideOffset,\r\n name: 'arrow_nmw',\r\n ...(config && { config })\r\n }),\r\n southEastArrowNorth: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.right - balloonRect.width / 2,\r\n name: 'arrow_n',\r\n ...(config && { config })\r\n }),\r\n southEastArrowNorthMiddleEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.right - (balloonRect.width * .75) + sideOffset,\r\n name: 'arrow_nme',\r\n ...(config && { config })\r\n }),\r\n southEastArrowNorthEast: (targetRect, balloonRect) => ({\r\n top: getSouthTop(targetRect),\r\n left: targetRect.right - balloonRect.width + sideOffset,\r\n name: 'arrow_ne',\r\n ...(config && { config })\r\n }),\r\n // ------- West\r\n westArrowEast: (targetRect, balloonRect) => ({\r\n top: targetRect.top + targetRect.height / 2 - balloonRect.height / 2,\r\n left: targetRect.left - balloonRect.width - heightOffset,\r\n name: 'arrow_e',\r\n ...(config && { config })\r\n }),\r\n // ------- East\r\n eastArrowWest: (targetRect, balloonRect) => ({\r\n top: targetRect.top + targetRect.height / 2 - balloonRect.height / 2,\r\n left: targetRect.right + heightOffset,\r\n name: 'arrow_w',\r\n ...(config && { config })\r\n }),\r\n // ------- Sticky\r\n viewportStickyNorth: (targetRect, balloonRect, viewportRect, limiterRect) => {\r\n const boundaryRect = limiterRect || viewportRect;\r\n if (!targetRect.getIntersection(boundaryRect)) {\r\n return null;\r\n }\r\n // Engage when the target top and bottom edges are close or off the boundary.\r\n // By close, it means there's not enough space for the balloon arrow (offset).\r\n if (boundaryRect.height - targetRect.height > stickyVerticalOffset) {\r\n return null;\r\n }\r\n return {\r\n top: boundaryRect.top + stickyVerticalOffset,\r\n left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\r\n name: 'arrowless',\r\n config: {\r\n withArrow: false,\r\n ...config\r\n }\r\n };\r\n }\r\n };\r\n /**\r\n * Returns the top coordinate for positions starting with `north*`.\r\n *\r\n * @param targetRect A rect of the target.\r\n * @param balloonRect A rect of the balloon.\r\n */\r\n function getNorthTop(targetRect, balloonRect) {\r\n return targetRect.top - balloonRect.height - heightOffset;\r\n }\r\n /**\r\n * Returns the top coordinate for positions starting with `south*`.\r\n *\r\n * @param targetRect A rect of the target.\r\n */\r\n function getSouthTop(targetRect) {\r\n return targetRect.bottom + heightOffset;\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/tooltipmanager\r\n */\r\nimport View from './view';\r\nimport BalloonPanelView, { generatePositions } from './panel/balloon/balloonpanelview';\r\nimport { DomEmitterMixin, ResizeObserver, first, global, isVisible } from '@ckeditor/ckeditor5-utils';\r\nimport { isElement, debounce } from 'lodash-es';\r\nimport '../theme/components/tooltip/tooltip.css';\r\nconst BALLOON_CLASS = 'ck-tooltip';\r\n/**\r\n * A tooltip manager class for the UI of the editor.\r\n *\r\n * **Note**: Most likely you do not have to use the `TooltipManager` API listed below in order to display tooltips. Popular\r\n * {@glink framework/architecture/ui-library UI components} support tooltips out-of-the-box via observable properties\r\n * (see {@link module:ui/button/buttonview~ButtonView#tooltip} and {@link module:ui/button/buttonview~ButtonView#tooltipPosition}).\r\n *\r\n * # Displaying tooltips\r\n *\r\n * To display a tooltip, set `data-cke-tooltip-text` attribute on any DOM element:\r\n *\r\n * ```ts\r\n * domElement.dataset.ckeTooltipText = 'My tooltip';\r\n * ```\r\n *\r\n * The tooltip will show up whenever the user moves the mouse over the element or the element gets focus in DOM.\r\n *\r\n * # Positioning tooltips\r\n *\r\n * To change the position of the tooltip, use the `data-cke-tooltip-position` attribute (`s`, `se`, `sw`, `n`, `e`, or `w`):\r\n *\r\n * ```ts\r\n * domElement.dataset.ckeTooltipText = 'Tooltip to the north';\r\n * domElement.dataset.ckeTooltipPosition = 'n';\r\n * ```\r\n *\r\n * # Disabling tooltips\r\n *\r\n * In order to disable the tooltip temporarily, use the `data-cke-tooltip-disabled` attribute:\r\n *\r\n * ```ts\r\n * domElement.dataset.ckeTooltipText = 'Disabled. For now.';\r\n * domElement.dataset.ckeTooltipDisabled = 'true';\r\n * ```\r\n *\r\n * # Styling tooltips\r\n *\r\n * By default, the tooltip has `.ck-tooltip` class and its text inner `.ck-tooltip__text`.\r\n *\r\n * If your tooltip requires custom styling, using `data-cke-tooltip-class` attribute will add additional class to the balloon\r\n * displaying the tooltip:\r\n *\r\n * ```ts\r\n * domElement.dataset.ckeTooltipText = 'Tooltip with a red text';\r\n * domElement.dataset.ckeTooltipClass = 'my-class';\r\n * ```\r\n *\r\n * ```css\r\n * .ck.ck-tooltip.my-class { color: red }\r\n * ```\r\n *\r\n * **Note**: This class is a singleton. All editor instances re-use the same instance loaded by\r\n * {@link module:ui/editorui/editorui~EditorUI} of the first editor.\r\n */\r\nexport default class TooltipManager extends DomEmitterMixin() {\r\n /**\r\n * Creates an instance of the tooltip manager.\r\n */\r\n constructor(editor) {\r\n super();\r\n /**\r\n * Stores the reference to the DOM element the tooltip is attached to. `null` when there's no tooltip\r\n * in the UI.\r\n */\r\n this._currentElementWithTooltip = null;\r\n /**\r\n * Stores the current tooltip position. `null` when there's no tooltip in the UI.\r\n */\r\n this._currentTooltipPosition = null;\r\n /**\r\n * An instance of the resize observer that keeps track on target element visibility,\r\n * when it hides the tooltip should also disappear.\r\n *\r\n * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.\r\n */\r\n this._resizeObserver = null;\r\n TooltipManager._editors.add(editor);\r\n // TooltipManager must be a singleton. Multiple instances would mean multiple tooltips attached\r\n // to the same DOM element with data-cke-tooltip-* attributes.\r\n if (TooltipManager._instance) {\r\n return TooltipManager._instance;\r\n }\r\n TooltipManager._instance = this;\r\n this.tooltipTextView = new View(editor.locale);\r\n this.tooltipTextView.set('text', '');\r\n this.tooltipTextView.setTemplate({\r\n tag: 'span',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-tooltip__text'\r\n ]\r\n },\r\n children: [\r\n {\r\n text: this.tooltipTextView.bindTemplate.to('text')\r\n }\r\n ]\r\n });\r\n this.balloonPanelView = new BalloonPanelView(editor.locale);\r\n this.balloonPanelView.class = BALLOON_CLASS;\r\n this.balloonPanelView.content.add(this.tooltipTextView);\r\n this._pinTooltipDebounced = debounce(this._pinTooltip, 600);\r\n this.listenTo(global.document, 'mouseenter', this._onEnterOrFocus.bind(this), { useCapture: true });\r\n this.listenTo(global.document, 'mouseleave', this._onLeaveOrBlur.bind(this), { useCapture: true });\r\n this.listenTo(global.document, 'focus', this._onEnterOrFocus.bind(this), { useCapture: true });\r\n this.listenTo(global.document, 'blur', this._onLeaveOrBlur.bind(this), { useCapture: true });\r\n this.listenTo(global.document, 'scroll', this._onScroll.bind(this), { useCapture: true });\r\n // Because this class is a singleton, its only instance is shared across all editors and connects them through the reference.\r\n // This causes issues with the ContextWatchdog. When an error is thrown in one editor, the watchdog traverses the references\r\n // and (because of shared tooltip manager) figures that the error affects all editors and restarts them all.\r\n // This flag, excludes tooltip manager instance from the traversal and brings ContextWatchdog back to normal.\r\n // More in https://github.com/ckeditor/ckeditor5/issues/12292.\r\n this._watchdogExcluded = true;\r\n }\r\n /**\r\n * Destroys the tooltip manager.\r\n *\r\n * **Note**: The manager singleton cannot be destroyed until all editors that use it are destroyed.\r\n *\r\n * @param editor The editor the manager was created for.\r\n */\r\n destroy(editor) {\r\n const editorBodyViewCollection = editor.ui.view && editor.ui.view.body;\r\n TooltipManager._editors.delete(editor);\r\n this.stopListening(editor.ui);\r\n // Prevent the balloon panel from being destroyed in the EditorUI#destroy() cascade. It should be destroyed along\r\n // with the last editor only (https://github.com/ckeditor/ckeditor5/issues/12602).\r\n if (editorBodyViewCollection && editorBodyViewCollection.has(this.balloonPanelView)) {\r\n editorBodyViewCollection.remove(this.balloonPanelView);\r\n }\r\n if (!TooltipManager._editors.size) {\r\n this._unpinTooltip();\r\n this.balloonPanelView.destroy();\r\n this.stopListening();\r\n TooltipManager._instance = null;\r\n }\r\n }\r\n /**\r\n * Returns {@link #balloonPanelView} {@link module:utils/dom/position~PositioningFunction positioning functions} for a given position\r\n * name.\r\n *\r\n * @param position Name of the position (`s`, `se`, `sw`, `n`, `e`, or `w`).\r\n * @returns Positioning functions to be used by the {@link #balloonPanelView}.\r\n */\r\n static getPositioningFunctions(position) {\r\n const defaultPositions = TooltipManager.defaultBalloonPositions;\r\n return {\r\n // South is most popular. We can use positioning heuristics to avoid clipping by the viewport with the sane fallback.\r\n s: [\r\n defaultPositions.southArrowNorth,\r\n defaultPositions.southArrowNorthEast,\r\n defaultPositions.southArrowNorthWest\r\n ],\r\n n: [defaultPositions.northArrowSouth],\r\n e: [defaultPositions.eastArrowWest],\r\n w: [defaultPositions.westArrowEast],\r\n sw: [defaultPositions.southArrowNorthEast],\r\n se: [defaultPositions.southArrowNorthWest]\r\n }[position];\r\n }\r\n /**\r\n * Handles displaying tooltips on `mouseenter` and `focus` in DOM.\r\n *\r\n * @param evt An object containing information about the fired event.\r\n * @param domEvent The DOM event.\r\n */\r\n _onEnterOrFocus(evt, { target }) {\r\n const elementWithTooltipAttribute = getDescendantWithTooltip(target);\r\n // Abort when there's no descendant needing tooltip.\r\n if (!elementWithTooltipAttribute) {\r\n return;\r\n }\r\n // Abort to avoid flashing when, for instance:\r\n // * a tooltip is displayed for a focused element, then the same element gets mouseentered,\r\n // * a tooltip is displayed for an element via mouseenter, then the focus moves to the same element.\r\n if (elementWithTooltipAttribute === this._currentElementWithTooltip) {\r\n return;\r\n }\r\n this._unpinTooltip();\r\n this._pinTooltipDebounced(elementWithTooltipAttribute, getTooltipData(elementWithTooltipAttribute));\r\n }\r\n /**\r\n * Handles hiding tooltips on `mouseleave` and `blur` in DOM.\r\n *\r\n * @param evt An object containing information about the fired event.\r\n * @param domEvent The DOM event.\r\n */\r\n _onLeaveOrBlur(evt, { target, relatedTarget }) {\r\n if (evt.name === 'mouseleave') {\r\n // Don't act when the event does not concern a DOM element (e.g. a mouseleave out of an entire document),\r\n if (!isElement(target)) {\r\n return;\r\n }\r\n // If a tooltip is currently visible, don't act for a targets other than the one it is attached to.\r\n // For instance, a random mouseleave far away in the page should not unpin the tooltip that was pinned because\r\n // of a previous focus. Only leaving the same element should hide the tooltip.\r\n if (this._currentElementWithTooltip && target !== this._currentElementWithTooltip) {\r\n return;\r\n }\r\n const descendantWithTooltip = getDescendantWithTooltip(target);\r\n const relatedDescendantWithTooltip = getDescendantWithTooltip(relatedTarget);\r\n // Unpin when the mouse was leaving element with a tooltip to a place which does not have or has a different tooltip.\r\n // Note that this should happen whether the tooltip is already visible or not, for instance, it could be invisible but queued\r\n // (debounced): it should get canceled.\r\n if (descendantWithTooltip && descendantWithTooltip !== relatedDescendantWithTooltip) {\r\n this._unpinTooltip();\r\n }\r\n }\r\n else {\r\n // If a tooltip is currently visible, don't act for a targets other than the one it is attached to.\r\n // For instance, a random blur in the web page should not unpin the tooltip that was pinned because of a previous mouseenter.\r\n if (this._currentElementWithTooltip && target !== this._currentElementWithTooltip) {\r\n return;\r\n }\r\n // Note that unpinning should happen whether the tooltip is already visible or not, for instance, it could be invisible but\r\n // queued (debounced): it should get canceled (e.g. quick focus then quick blur using the keyboard).\r\n this._unpinTooltip();\r\n }\r\n }\r\n /**\r\n * Handles hiding tooltips on `scroll` in DOM.\r\n *\r\n * @param evt An object containing information about the fired event.\r\n * @param domEvent The DOM event.\r\n */\r\n _onScroll(evt, { target }) {\r\n // No tooltip, no reason to react on scroll.\r\n if (!this._currentElementWithTooltip) {\r\n return;\r\n }\r\n // When scrolling a container that has both the balloon and the current element (common ancestor), the balloon can remain\r\n // visible (e.g. scrolling ≤body>). Otherwise, to avoid glitches (clipping, lagging) better just hide the tooltip.\r\n // Also, don't do anything when scrolling an unrelated DOM element that has nothing to do with the current element and the balloon.\r\n if (target.contains(this.balloonPanelView.element) && target.contains(this._currentElementWithTooltip)) {\r\n return;\r\n }\r\n this._unpinTooltip();\r\n }\r\n /**\r\n * Pins the tooltip to a specific DOM element.\r\n *\r\n * @param options.text Text of the tooltip to display.\r\n * @param options.position The position of the tooltip.\r\n * @param options.cssClass Additional CSS class of the balloon with the tooltip.\r\n */\r\n _pinTooltip(targetDomElement, { text, position, cssClass }) {\r\n // Use the body collection of the first editor.\r\n const bodyViewCollection = first(TooltipManager._editors.values()).ui.view.body;\r\n if (!bodyViewCollection.has(this.balloonPanelView)) {\r\n bodyViewCollection.add(this.balloonPanelView);\r\n }\r\n this.tooltipTextView.text = text;\r\n this.balloonPanelView.pin({\r\n target: targetDomElement,\r\n positions: TooltipManager.getPositioningFunctions(position)\r\n });\r\n this._resizeObserver = new ResizeObserver(targetDomElement, () => {\r\n // The ResizeObserver will call its callback when the target element hides and the tooltip\r\n // should also disappear (https://github.com/ckeditor/ckeditor5/issues/12492).\r\n if (!isVisible(targetDomElement)) {\r\n this._unpinTooltip();\r\n }\r\n });\r\n this.balloonPanelView.class = [BALLOON_CLASS, cssClass]\r\n .filter(className => className)\r\n .join(' ');\r\n // Start responding to changes in editor UI or content layout. For instance, when collaborators change content\r\n // and a contextual toolbar attached to a content starts to move (and so should move the tooltip).\r\n // Note: Using low priority to let other listeners that position contextual toolbars etc. to react first.\r\n for (const editor of TooltipManager._editors) {\r\n this.listenTo(editor.ui, 'update', this._updateTooltipPosition.bind(this), { priority: 'low' });\r\n }\r\n this._currentElementWithTooltip = targetDomElement;\r\n this._currentTooltipPosition = position;\r\n }\r\n /**\r\n * Unpins the tooltip and cancels all queued pinning.\r\n */\r\n _unpinTooltip() {\r\n this._pinTooltipDebounced.cancel();\r\n this.balloonPanelView.unpin();\r\n for (const editor of TooltipManager._editors) {\r\n this.stopListening(editor.ui, 'update');\r\n }\r\n this._currentElementWithTooltip = null;\r\n this._currentTooltipPosition = null;\r\n if (this._resizeObserver) {\r\n this._resizeObserver.destroy();\r\n }\r\n }\r\n /**\r\n * Updates the position of the tooltip so it stays in sync with the element it is pinned to.\r\n *\r\n * Hides the tooltip when the element is no longer visible in DOM.\r\n */\r\n _updateTooltipPosition() {\r\n // This could happen if the tooltip was attached somewhere in a contextual content toolbar and the toolbar\r\n // disappeared (e.g. removed an image).\r\n if (!isVisible(this._currentElementWithTooltip)) {\r\n this._unpinTooltip();\r\n return;\r\n }\r\n this.balloonPanelView.pin({\r\n target: this._currentElementWithTooltip,\r\n positions: TooltipManager.getPositioningFunctions(this._currentTooltipPosition)\r\n });\r\n }\r\n}\r\n/**\r\n * A set of default {@link module:utils/dom/position~PositioningFunction positioning functions} used by the `TooltipManager`\r\n * to pin tooltips in different positions.\r\n */\r\nTooltipManager.defaultBalloonPositions = generatePositions({\r\n heightOffset: 5,\r\n sideOffset: 13\r\n});\r\n/**\r\n * A set of editors the single tooltip manager instance must listen to.\r\n * This is mostly to handle `EditorUI#update` listeners from individual editors.\r\n */\r\nTooltipManager._editors = new Set();\r\n/**\r\n * A reference to the `TooltipManager` instance. The class is a singleton and as such,\r\n * successive attempts at creating instances should return this instance.\r\n */\r\nTooltipManager._instance = null;\r\nfunction getDescendantWithTooltip(element) {\r\n if (!isElement(element)) {\r\n return null;\r\n }\r\n return element.closest('[data-cke-tooltip-text]:not([data-cke-tooltip-disabled])');\r\n}\r\nfunction getTooltipData(element) {\r\n return {\r\n text: element.dataset.ckeTooltipText,\r\n position: (element.dataset.ckeTooltipPosition || 's'),\r\n cssClass: element.dataset.ckeTooltipClass || ''\r\n };\r\n}\r\n","import debounce from './debounce.js';\nimport isObject from './isObject.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nexport default throttle;\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\nimport { DomEmitterMixin, Rect, verifyLicense } from '@ckeditor/ckeditor5-utils';\r\nimport BalloonPanelView from '../panel/balloon/balloonpanelview';\r\nimport IconView from '../icon/iconview';\r\nimport View from '../view';\r\nimport { throttle } from 'lodash-es';\r\nimport poweredByIcon from '../../theme/icons/project-logo.svg';\r\nconst ICON_WIDTH = 53;\r\nconst ICON_HEIGHT = 10;\r\n// ⚠ Note, whenever changing the threshold, make sure to update the docs/support/managing-ckeditor-logo.md docs\r\n// as this information is also mentioned there ⚠.\r\nconst NARROW_ROOT_HEIGHT_THRESHOLD = 50;\r\nconst NARROW_ROOT_WIDTH_THRESHOLD = 350;\r\nconst DEFAULT_LABEL = 'Powered by';\r\n/**\r\n * A helper that enables the \"powered by\" feature in the editor and renders a link to the project's\r\n * webpage next to the bottom of the editable element (editor root, source editing area, etc.) when the editor is focused.\r\n *\r\n * @private\r\n */\r\nexport default class PoweredBy extends DomEmitterMixin() {\r\n /**\r\n * Creates a \"powered by\" helper for a given editor. The feature is initialized on Editor#ready\r\n * event.\r\n *\r\n * @param editor\r\n */\r\n constructor(editor) {\r\n super();\r\n this.editor = editor;\r\n this._balloonView = null;\r\n this._lastFocusedEditableElement = null;\r\n this._showBalloonThrottled = throttle(this._showBalloon.bind(this), 50, { leading: true });\r\n editor.on('ready', this._handleEditorReady.bind(this));\r\n }\r\n /**\r\n * Destroys the \"powered by\" helper along with its view.\r\n */\r\n destroy() {\r\n const balloon = this._balloonView;\r\n if (balloon) {\r\n // Balloon gets destroyed by the body collection.\r\n // The powered by view gets destroyed by the balloon.\r\n balloon.unpin();\r\n this._balloonView = null;\r\n }\r\n this._showBalloonThrottled.cancel();\r\n this.stopListening();\r\n }\r\n /**\r\n * Enables \"powered by\" label once the editor (ui) is ready.\r\n */\r\n _handleEditorReady() {\r\n const editor = this.editor;\r\n const forceVisible = !!editor.config.get('ui.poweredBy.forceVisible');\r\n /* istanbul ignore next -- @preserve */\r\n if (!forceVisible && verifyLicense(editor.config.get('licenseKey')) === 'VALID') {\r\n return;\r\n }\r\n // No view means no body collection to append the powered by balloon to.\r\n if (!editor.ui.view) {\r\n return;\r\n }\r\n editor.ui.focusTracker.on('change:isFocused', (evt, data, isFocused) => {\r\n this._updateLastFocusedEditableElement();\r\n if (isFocused) {\r\n this._showBalloon();\r\n }\r\n else {\r\n this._hideBalloon();\r\n }\r\n });\r\n editor.ui.focusTracker.on('change:focusedElement', (evt, data, focusedElement) => {\r\n this._updateLastFocusedEditableElement();\r\n if (focusedElement) {\r\n this._showBalloon();\r\n }\r\n });\r\n editor.ui.on('update', () => {\r\n this._showBalloonThrottled();\r\n });\r\n }\r\n /**\r\n * Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}\r\n * with the \"powered by\" view inside ready for positioning.\r\n */\r\n _createBalloonView() {\r\n const editor = this.editor;\r\n const balloon = this._balloonView = new BalloonPanelView();\r\n const poweredByConfig = getNormalizedConfig(editor);\r\n const view = new PoweredByView(editor.locale, poweredByConfig.label);\r\n balloon.content.add(view);\r\n balloon.set({\r\n class: 'ck-powered-by-balloon'\r\n });\r\n editor.ui.view.body.add(balloon);\r\n editor.ui.focusTracker.add(balloon.element);\r\n this._balloonView = balloon;\r\n }\r\n /**\r\n * Attempts to display the balloon with the \"powered by\" view.\r\n */\r\n _showBalloon() {\r\n if (!this._lastFocusedEditableElement) {\r\n return;\r\n }\r\n const attachOptions = getBalloonAttachOptions(this.editor, this._lastFocusedEditableElement);\r\n if (attachOptions) {\r\n if (!this._balloonView) {\r\n this._createBalloonView();\r\n }\r\n this._balloonView.pin(attachOptions);\r\n }\r\n }\r\n /**\r\n * Hides the \"powered by\" balloon if already visible.\r\n */\r\n _hideBalloon() {\r\n if (this._balloonView) {\r\n this._balloonView.unpin();\r\n }\r\n }\r\n /**\r\n * Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.\r\n */\r\n _updateLastFocusedEditableElement() {\r\n const editor = this.editor;\r\n const isFocused = editor.ui.focusTracker.isFocused;\r\n const focusedElement = editor.ui.focusTracker.focusedElement;\r\n if (!isFocused || !focusedElement) {\r\n this._lastFocusedEditableElement = null;\r\n return;\r\n }\r\n const editableEditorElements = Array.from(editor.ui.getEditableElementsNames()).map(name => {\r\n return editor.ui.getEditableElement(name);\r\n });\r\n if (editableEditorElements.includes(focusedElement)) {\r\n this._lastFocusedEditableElement = focusedElement;\r\n }\r\n else {\r\n // If it's none of the editable element, then the focus is somewhere in the UI. Let's display powered by\r\n // over the first element then.\r\n this._lastFocusedEditableElement = editableEditorElements[0];\r\n }\r\n }\r\n}\r\n/**\r\n * A view displaying a \"powered by\" label and project logo wrapped in a link.\r\n */\r\nclass PoweredByView extends View {\r\n /**\r\n * Created an instance of the \"powered by\" view.\r\n *\r\n * @param locale The localization services instance.\r\n * @param label The label text.\r\n */\r\n constructor(locale, label) {\r\n super(locale);\r\n const iconView = new IconView();\r\n const bind = this.bindTemplate;\r\n iconView.set({\r\n content: poweredByIcon,\r\n isColorInherited: false\r\n });\r\n iconView.extendTemplate({\r\n attributes: {\r\n style: {\r\n width: ICON_WIDTH + 'px',\r\n height: ICON_HEIGHT + 'px'\r\n }\r\n }\r\n });\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: ['ck', 'ck-powered-by'],\r\n 'aria-hidden': true\r\n },\r\n children: [\r\n {\r\n tag: 'a',\r\n attributes: {\r\n href: 'https://ckeditor.com/?utm_source=ckeditor&' +\r\n 'utm_medium=referral&utm_campaign=701Dn000000hVgmIAE_powered_by_ckeditor_logo',\r\n target: '_blank',\r\n tabindex: '-1'\r\n },\r\n children: [\r\n ...label ? [\r\n {\r\n tag: 'span',\r\n attributes: {\r\n class: ['ck', 'ck-powered-by__label']\r\n },\r\n children: [label]\r\n }\r\n ] : [],\r\n iconView\r\n ],\r\n on: {\r\n dragstart: bind.to(evt => evt.preventDefault())\r\n }\r\n }\r\n ]\r\n });\r\n }\r\n}\r\nfunction getBalloonAttachOptions(editor, focusedEditableElement) {\r\n const poweredByConfig = getNormalizedConfig(editor);\r\n const positioningFunction = poweredByConfig.side === 'right' ?\r\n getLowerRightCornerPosition(focusedEditableElement, poweredByConfig) :\r\n getLowerLeftCornerPosition(focusedEditableElement, poweredByConfig);\r\n return {\r\n target: focusedEditableElement,\r\n positions: [positioningFunction]\r\n };\r\n}\r\nfunction getLowerRightCornerPosition(focusedEditableElement, config) {\r\n return getLowerCornerPosition(focusedEditableElement, config, (rootRect, balloonRect) => {\r\n return rootRect.left + rootRect.width - balloonRect.width - config.horizontalOffset;\r\n });\r\n}\r\nfunction getLowerLeftCornerPosition(focusedEditableElement, config) {\r\n return getLowerCornerPosition(focusedEditableElement, config, rootRect => rootRect.left + config.horizontalOffset);\r\n}\r\nfunction getLowerCornerPosition(focusedEditableElement, config, getBalloonLeft) {\r\n return (visibleEditableElementRect, balloonRect) => {\r\n const editableElementRect = new Rect(focusedEditableElement);\r\n if (editableElementRect.width < NARROW_ROOT_WIDTH_THRESHOLD || editableElementRect.height < NARROW_ROOT_HEIGHT_THRESHOLD) {\r\n return null;\r\n }\r\n let balloonTop;\r\n if (config.position === 'inside') {\r\n balloonTop = editableElementRect.bottom - balloonRect.height;\r\n }\r\n else {\r\n balloonTop = editableElementRect.bottom - balloonRect.height / 2;\r\n }\r\n balloonTop -= config.verticalOffset;\r\n const balloonLeft = getBalloonLeft(editableElementRect, balloonRect);\r\n // Clone the editable element rect and place it where the balloon would be placed.\r\n // This will allow getVisible() to work from editable element's perspective (rect source).\r\n // and yield a result as if the balloon was on the same (scrollable) layer as the editable element.\r\n const newBalloonPositionRect = visibleEditableElementRect\r\n .clone()\r\n .moveTo(balloonLeft, balloonTop)\r\n .getIntersection(balloonRect.clone().moveTo(balloonLeft, balloonTop));\r\n const newBalloonPositionVisibleRect = newBalloonPositionRect.getVisible();\r\n if (!newBalloonPositionVisibleRect || newBalloonPositionVisibleRect.getArea() < balloonRect.getArea()) {\r\n return null;\r\n }\r\n return {\r\n top: balloonTop,\r\n left: balloonLeft,\r\n name: `position_${config.position}-side_${config.side}`,\r\n config: {\r\n withArrow: false\r\n }\r\n };\r\n };\r\n}\r\nfunction getNormalizedConfig(editor) {\r\n const userConfig = editor.config.get('ui.poweredBy');\r\n const position = userConfig && userConfig.position || 'border';\r\n return {\r\n position,\r\n label: DEFAULT_LABEL,\r\n verticalOffset: position === 'inside' ? 5 : 0,\r\n horizontalOffset: 5,\r\n side: editor.locale.contentLanguageDirection === 'ltr' ? 'right' : 'left',\r\n ...userConfig\r\n };\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module utils/verifylicense\r\n */\r\nimport { releaseDate } from './version';\r\n/**\r\n * Checks whether the given string contains information that allows you to verify the license status.\r\n *\r\n * @param token The string to check.\r\n * @returns String that represents the state of given `token` parameter.\r\n */\r\nexport default function verifyLicense(token) {\r\n // This function implements naive and partial license key check mechanism,\r\n // used only to decide whether to show or hide the \"Powered by CKEditor\" logo.\r\n //\r\n // You can read the reasoning behind showing the logo to unlicensed (GPL) users\r\n // in this thread: https://github.com/ckeditor/ckeditor5/issues/14082.\r\n //\r\n // We firmly believe in the values behind creating open-source software, even when that\r\n // means keeping the license verification logic open for everyone to see.\r\n //\r\n // Please keep this code intact. Thank you for your understanding.\r\n function oldTokenCheck(token) {\r\n if (token.length >= 40 && token.length <= 255) {\r\n return 'VALID';\r\n }\r\n else {\r\n return 'INVALID';\r\n }\r\n }\r\n // TODO: issue ci#3175\r\n if (!token) {\r\n return 'INVALID';\r\n }\r\n let decryptedData = '';\r\n try {\r\n decryptedData = atob(token);\r\n }\r\n catch (e) {\r\n return 'INVALID';\r\n }\r\n const splittedDecryptedData = decryptedData.split('-');\r\n const firstElement = splittedDecryptedData[0];\r\n const secondElement = splittedDecryptedData[1];\r\n if (!secondElement) {\r\n return oldTokenCheck(token);\r\n }\r\n try {\r\n atob(secondElement);\r\n }\r\n catch (e) {\r\n try {\r\n atob(firstElement);\r\n if (!atob(firstElement).length) {\r\n return oldTokenCheck(token);\r\n }\r\n }\r\n catch (e) {\r\n return oldTokenCheck(token);\r\n }\r\n }\r\n if (firstElement.length < 40 || firstElement.length > 255) {\r\n return 'INVALID';\r\n }\r\n let decryptedSecondElement = '';\r\n try {\r\n atob(firstElement);\r\n decryptedSecondElement = atob(secondElement);\r\n }\r\n catch (e) {\r\n return 'INVALID';\r\n }\r\n if (decryptedSecondElement.length !== 8) {\r\n return 'INVALID';\r\n }\r\n const year = Number(decryptedSecondElement.substring(0, 4));\r\n const monthIndex = Number(decryptedSecondElement.substring(4, 6)) - 1;\r\n const day = Number(decryptedSecondElement.substring(6, 8));\r\n const date = new Date(year, monthIndex, day);\r\n if (date < releaseDate || isNaN(Number(date))) {\r\n return 'INVALID';\r\n }\r\n return 'VALID';\r\n}\r\n","export default \"\\n\";","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/editorui/editorui\r\n */\r\n/* globals console */\r\nimport ComponentFactory from '../componentfactory';\r\nimport TooltipManager from '../tooltipmanager';\r\nimport PoweredBy from './poweredby';\r\nimport { ObservableMixin, isVisible, FocusTracker } from '@ckeditor/ckeditor5-utils';\r\n/**\r\n * A class providing the minimal interface that is required to successfully bootstrap any editor UI.\r\n */\r\nexport default class EditorUI extends ObservableMixin() {\r\n /**\r\n * Creates an instance of the editor UI class.\r\n *\r\n * @param editor The editor instance.\r\n */\r\n constructor(editor) {\r\n super();\r\n /**\r\n * Indicates the UI is ready. Set `true` after {@link #event:ready} event is fired.\r\n *\r\n * @readonly\r\n * @default false\r\n */\r\n this.isReady = false;\r\n /**\r\n * Stores all editable elements used by the editor instance.\r\n */\r\n this._editableElementsMap = new Map();\r\n /**\r\n * All available & focusable toolbars.\r\n */\r\n this._focusableToolbarDefinitions = [];\r\n const editingView = editor.editing.view;\r\n this.editor = editor;\r\n this.componentFactory = new ComponentFactory(editor);\r\n this.focusTracker = new FocusTracker();\r\n this.tooltipManager = new TooltipManager(editor);\r\n this.poweredBy = new PoweredBy(editor);\r\n this.set('viewportOffset', this._readViewportOffsetFromConfig());\r\n this.once('ready', () => {\r\n this.isReady = true;\r\n });\r\n // Informs UI components that should be refreshed after layout change.\r\n this.listenTo(editingView.document, 'layoutChanged', this.update.bind(this));\r\n this.listenTo(editingView, 'scrollToTheSelection', this._handleScrollToTheSelection.bind(this));\r\n this._initFocusTracking();\r\n }\r\n /**\r\n * The main (outermost) DOM element of the editor UI.\r\n *\r\n * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `
      ` which\r\n * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}\r\n * it is the editable element itself (as there is no other wrapper). However, in\r\n * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not\r\n * come with a single \"main\" HTML element (its editable element and toolbar are separate).\r\n *\r\n * This property can be understood as a shorthand for retrieving the element that a specific editor integration\r\n * considers to be its main DOM element.\r\n */\r\n get element() {\r\n return null;\r\n }\r\n /**\r\n * Fires the {@link module:ui/editorui/editorui~EditorUI#event:update `update`} event.\r\n *\r\n * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to\r\n * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).\r\n */\r\n update() {\r\n this.fire('update');\r\n }\r\n /**\r\n * Destroys the UI.\r\n */\r\n destroy() {\r\n this.stopListening();\r\n this.focusTracker.destroy();\r\n this.tooltipManager.destroy(this.editor);\r\n this.poweredBy.destroy();\r\n // Clean–up the references to the CKEditor instance stored in the native editable DOM elements.\r\n for (const domElement of this._editableElementsMap.values()) {\r\n domElement.ckeditorInstance = null;\r\n this.editor.keystrokes.stopListening(domElement);\r\n }\r\n this._editableElementsMap = new Map();\r\n this._focusableToolbarDefinitions = [];\r\n }\r\n /**\r\n * Stores the native DOM editable element used by the editor under a unique name.\r\n *\r\n * Also, registers the element in the editor to maintain the accessibility of the UI. When the user is editing text in a focusable\r\n * editable area, they can use the Alt + F10 keystroke to navigate over editor toolbars. See {@link #addToolbar}.\r\n *\r\n * @param rootName The unique name of the editable element.\r\n * @param domElement The native DOM editable element.\r\n */\r\n setEditableElement(rootName, domElement) {\r\n this._editableElementsMap.set(rootName, domElement);\r\n // Put a reference to the CKEditor instance in the editable native DOM element.\r\n // It helps 3rd–party software (browser extensions, other libraries) access and recognize\r\n // CKEditor 5 instances (editing roots) and use their API (there is no global editor\r\n // instance registry).\r\n if (!domElement.ckeditorInstance) {\r\n domElement.ckeditorInstance = this.editor;\r\n }\r\n // Register the element, so it becomes available for Alt+F10 and Esc navigation.\r\n this.focusTracker.add(domElement);\r\n const setUpKeystrokeHandler = () => {\r\n // The editing view of the editor is already listening to keystrokes from DOM roots (see: KeyObserver).\r\n // Do not duplicate listeners.\r\n if (this.editor.editing.view.getDomRoot(rootName)) {\r\n return;\r\n }\r\n this.editor.keystrokes.listenTo(domElement);\r\n };\r\n // For editable elements set by features after EditorUI is ready (e.g. source editing).\r\n if (this.isReady) {\r\n setUpKeystrokeHandler();\r\n }\r\n // For editable elements set while the editor is being created (e.g. DOM roots).\r\n else {\r\n this.once('ready', setUpKeystrokeHandler);\r\n }\r\n }\r\n /**\r\n * Removes the editable from the editor UI. Removes all handlers added by {@link #setEditableElement}.\r\n *\r\n * @param rootName The name of the editable element to remove.\r\n */\r\n removeEditableElement(rootName) {\r\n const domElement = this._editableElementsMap.get(rootName);\r\n if (!domElement) {\r\n return;\r\n }\r\n this._editableElementsMap.delete(rootName);\r\n this.editor.keystrokes.stopListening(domElement);\r\n this.focusTracker.remove(domElement);\r\n domElement.ckeditorInstance = null;\r\n }\r\n /**\r\n * Returns the editable editor element with the given name or null if editable does not exist.\r\n *\r\n * @param rootName The editable name.\r\n */\r\n getEditableElement(rootName = 'main') {\r\n return this._editableElementsMap.get(rootName);\r\n }\r\n /**\r\n * Returns array of names of all editor editable elements.\r\n */\r\n getEditableElementsNames() {\r\n return this._editableElementsMap.keys();\r\n }\r\n /**\r\n * Adds a toolbar to the editor UI. Used primarily to maintain the accessibility of the UI.\r\n *\r\n * Focusable toolbars can be accessed (focused) by users by pressing the Alt + F10 keystroke.\r\n * Successive keystroke presses navigate over available toolbars.\r\n *\r\n * @param toolbarView A instance of the toolbar to be registered.\r\n */\r\n addToolbar(toolbarView, options = {}) {\r\n if (toolbarView.isRendered) {\r\n this.focusTracker.add(toolbarView.element);\r\n this.editor.keystrokes.listenTo(toolbarView.element);\r\n }\r\n else {\r\n toolbarView.once('render', () => {\r\n this.focusTracker.add(toolbarView.element);\r\n this.editor.keystrokes.listenTo(toolbarView.element);\r\n });\r\n }\r\n this._focusableToolbarDefinitions.push({ toolbarView, options });\r\n }\r\n /**\r\n * Stores all editable elements used by the editor instance.\r\n *\r\n * @deprecated\r\n */\r\n get _editableElements() {\r\n /**\r\n * The {@link module:ui/editorui/editorui~EditorUI#_editableElements `EditorUI#_editableElements`} property has been\r\n * deprecated and will be removed in the near future. Please use\r\n * {@link module:ui/editorui/editorui~EditorUI#setEditableElement `setEditableElement()`} and\r\n * {@link module:ui/editorui/editorui~EditorUI#getEditableElement `getEditableElement()`} methods instead.\r\n *\r\n * @error editor-ui-deprecated-editable-elements\r\n * @param editorUI Editor UI instance the deprecated property belongs to.\r\n */\r\n console.warn('editor-ui-deprecated-editable-elements: ' +\r\n 'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.', { editorUI: this });\r\n return this._editableElementsMap;\r\n }\r\n /**\r\n * Returns viewport offsets object:\r\n *\r\n * ```js\r\n * {\r\n * \ttop: Number,\r\n * \tright: Number,\r\n * \tbottom: Number,\r\n * \tleft: Number\r\n * }\r\n * ```\r\n *\r\n * Only top property is currently supported.\r\n */\r\n _readViewportOffsetFromConfig() {\r\n const editor = this.editor;\r\n const viewportOffsetConfig = editor.config.get('ui.viewportOffset');\r\n if (viewportOffsetConfig) {\r\n return viewportOffsetConfig;\r\n }\r\n // Not present in EditorConfig type, because it's legacy. Hence the `as` expression.\r\n const legacyOffsetConfig = editor.config.get('toolbar.viewportTopOffset');\r\n // Fall back to deprecated toolbar config.\r\n if (legacyOffsetConfig) {\r\n /**\r\n * The {@link module:core/editor/editorconfig~EditorConfig#toolbar `EditorConfig#toolbar.viewportTopOffset`}\r\n * property has been deprecated and will be removed in the near future. Please use\r\n * {@link module:core/editor/editorconfig~EditorConfig#ui `EditorConfig#ui.viewportOffset`} instead.\r\n *\r\n * @error editor-ui-deprecated-viewport-offset-config\r\n */\r\n console.warn('editor-ui-deprecated-viewport-offset-config: ' +\r\n 'The `toolbar.vieportTopOffset` configuration option is deprecated. ' +\r\n 'It will be removed from future CKEditor versions. Use `ui.viewportOffset.top` instead.');\r\n return { top: legacyOffsetConfig };\r\n }\r\n // More keys to come in the future.\r\n return { top: 0 };\r\n }\r\n /**\r\n * Starts listening for Alt + F10 and Esc keystrokes in the context of focusable\r\n * {@link #setEditableElement editable elements} and {@link #addToolbar toolbars}\r\n * to allow users navigate across the UI.\r\n */\r\n _initFocusTracking() {\r\n const editor = this.editor;\r\n const editingView = editor.editing.view;\r\n let lastFocusedForeignElement;\r\n let candidateDefinitions;\r\n // Focus the next focusable toolbar on Alt + F10.\r\n editor.keystrokes.set('Alt+F10', (data, cancel) => {\r\n const focusedElement = this.focusTracker.focusedElement;\r\n // Focus moved out of a DOM element that\r\n // * is not a toolbar,\r\n // * does not belong to the editing view (e.g. source editing).\r\n if (Array.from(this._editableElementsMap.values()).includes(focusedElement) &&\r\n !Array.from(editingView.domRoots.values()).includes(focusedElement)) {\r\n lastFocusedForeignElement = focusedElement;\r\n }\r\n const currentFocusedToolbarDefinition = this._getCurrentFocusedToolbarDefinition();\r\n // * When focusing a toolbar for the first time, set the array of definitions for successive presses of Alt+F10.\r\n // This ensures, the navigation works always the same and no pair of toolbars takes over\r\n // (e.g. image and table toolbars when a selected image is inside a cell).\r\n // * It could be that the focus went to the toolbar by clicking a toolbar item (e.g. a dropdown). In this case,\r\n // there were no candidates so they must be obtained (#12339).\r\n if (!currentFocusedToolbarDefinition || !candidateDefinitions) {\r\n candidateDefinitions = this._getFocusableCandidateToolbarDefinitions();\r\n }\r\n // In a single Alt+F10 press, check all candidates but if none were focused, don't go any further.\r\n // This prevents an infinite loop.\r\n for (let i = 0; i < candidateDefinitions.length; i++) {\r\n const candidateDefinition = candidateDefinitions.shift();\r\n // Put the first definition to the back of the array. This allows circular navigation over all toolbars\r\n // on successive presses of Alt+F10.\r\n candidateDefinitions.push(candidateDefinition);\r\n // Don't focus the same toolbar again. If you did, this would move focus from the nth focused toolbar item back to the\r\n // first item as per ToolbarView#focus() if the user navigated inside the toolbar.\r\n if (candidateDefinition !== currentFocusedToolbarDefinition &&\r\n this._focusFocusableCandidateToolbar(candidateDefinition)) {\r\n // Clean up after a current visible toolbar when switching to the next one.\r\n if (currentFocusedToolbarDefinition && currentFocusedToolbarDefinition.options.afterBlur) {\r\n currentFocusedToolbarDefinition.options.afterBlur();\r\n }\r\n break;\r\n }\r\n }\r\n cancel();\r\n });\r\n // Blur the focused toolbar on Esc and bring the focus back to its origin.\r\n editor.keystrokes.set('Esc', (data, cancel) => {\r\n const focusedToolbarDef = this._getCurrentFocusedToolbarDefinition();\r\n if (!focusedToolbarDef) {\r\n return;\r\n }\r\n // Bring focus back to where it came from before focusing the toolbar:\r\n // 1. If it came from outside the engine view (e.g. source editing), move it there.\r\n if (lastFocusedForeignElement) {\r\n lastFocusedForeignElement.focus();\r\n lastFocusedForeignElement = null;\r\n }\r\n // 2. There are two possibilities left:\r\n // 2.1. It could be that the focus went from an editable element in the view (root or nested).\r\n // 2.2. It could be the focus went straight to the toolbar before even focusing the editing area.\r\n // In either case, just focus the view editing. The focus will land where it belongs.\r\n else {\r\n editor.editing.view.focus();\r\n }\r\n // Clean up after the toolbar if there is anything to do there.\r\n if (focusedToolbarDef.options.afterBlur) {\r\n focusedToolbarDef.options.afterBlur();\r\n }\r\n cancel();\r\n });\r\n }\r\n /**\r\n * Returns definitions of toolbars that could potentially be focused, sorted by their importance for the user.\r\n *\r\n * Focusable toolbars candidates are either:\r\n * * already visible,\r\n * * have `beforeFocus()` set in their {@link module:ui/editorui/editorui~FocusableToolbarDefinition definition} that suggests that\r\n * they might show up when called. Keep in mind that determining whether a toolbar will show up (and become focusable) is impossible\r\n * at this stage because it depends on its implementation, that in turn depends on the editing context (selection).\r\n *\r\n * **Note**: Contextual toolbars take precedence over regular toolbars.\r\n */\r\n _getFocusableCandidateToolbarDefinitions() {\r\n const definitions = [];\r\n for (const toolbarDef of this._focusableToolbarDefinitions) {\r\n const { toolbarView, options } = toolbarDef;\r\n if (isVisible(toolbarView.element) || options.beforeFocus) {\r\n definitions.push(toolbarDef);\r\n }\r\n }\r\n // Contextual and already visible toolbars have higher priority. If both are true, the toolbar will always focus first.\r\n // For instance, a selected widget toolbar vs inline editor toolbar: both are visible but the widget toolbar is contextual.\r\n definitions.sort((defA, defB) => getToolbarDefinitionWeight(defA) - getToolbarDefinitionWeight(defB));\r\n return definitions;\r\n }\r\n /**\r\n * Returns a definition of the toolbar that is currently visible and focused (one of its children has focus).\r\n *\r\n * `null` is returned when no toolbar is currently focused.\r\n */\r\n _getCurrentFocusedToolbarDefinition() {\r\n for (const definition of this._focusableToolbarDefinitions) {\r\n if (definition.toolbarView.element && definition.toolbarView.element.contains(this.focusTracker.focusedElement)) {\r\n return definition;\r\n }\r\n }\r\n return null;\r\n }\r\n /**\r\n * Focuses a focusable toolbar candidate using its definition.\r\n *\r\n * @param candidateToolbarDefinition A definition of the toolbar to focus.\r\n * @returns `true` when the toolbar candidate was focused. `false` otherwise.\r\n */\r\n _focusFocusableCandidateToolbar(candidateToolbarDefinition) {\r\n const { toolbarView, options: { beforeFocus } } = candidateToolbarDefinition;\r\n if (beforeFocus) {\r\n beforeFocus();\r\n }\r\n // If it didn't show up after beforeFocus(), it's not focusable at all.\r\n if (!isVisible(toolbarView.element)) {\r\n return false;\r\n }\r\n toolbarView.focus();\r\n return true;\r\n }\r\n /**\r\n * Provides an integration between {@link #viewportOffset} and {@link module:utils/dom/scroll~scrollViewportToShowTarget}.\r\n * It allows the UI-agnostic engine method to consider user-configured viewport offsets specific for the integration.\r\n *\r\n * @param evt The `scrollToTheSelection` event info.\r\n * @param data The payload carried by the `scrollToTheSelection` event.\r\n */\r\n _handleScrollToTheSelection(evt, data) {\r\n const configuredViewportOffset = {\r\n top: 0,\r\n bottom: 0,\r\n left: 0,\r\n right: 0,\r\n ...this.viewportOffset\r\n };\r\n data.viewportOffset.top += configuredViewportOffset.top;\r\n data.viewportOffset.bottom += configuredViewportOffset.bottom;\r\n data.viewportOffset.left += configuredViewportOffset.left;\r\n data.viewportOffset.right += configuredViewportOffset.right;\r\n }\r\n}\r\n/**\r\n * Returns a number (weight) for a toolbar definition. Visible toolbars have a higher priority and so do\r\n * contextual toolbars (displayed in the context of a content, for instance, an image toolbar).\r\n *\r\n * A standard invisible toolbar is the heaviest. A visible contextual toolbar is the lightest.\r\n *\r\n * @param toolbarDef A toolbar definition to be weighted.\r\n */\r\nfunction getToolbarDefinitionWeight(toolbarDef) {\r\n const { toolbarView, options } = toolbarDef;\r\n let weight = 10;\r\n // Prioritize already visible toolbars. They should get focused first.\r\n if (isVisible(toolbarView.element)) {\r\n weight--;\r\n }\r\n // Prioritize contextual toolbars. They are displayed at the selection.\r\n if (options.isContextual) {\r\n weight--;\r\n }\r\n return weight;\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/editorui/editoruiview\r\n */\r\nimport View from '../view';\r\nimport BodyCollection from './bodycollection';\r\nimport '../../theme/components/editorui/editorui.css';\r\n/**\r\n * The editor UI view class. Base class for the editor main views.\r\n */\r\nexport default class EditorUIView extends View {\r\n /**\r\n * Creates an instance of the editor UI view class.\r\n *\r\n * @param locale The locale instance.\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n this.body = new BodyCollection(locale);\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n this.body.attachToDom();\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n this.body.detachFromDom();\r\n return super.destroy();\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/editorui/boxed/boxededitoruiview\r\n */\r\nimport EditorUIView from '../editoruiview';\r\nimport LabelView from '../../label/labelview';\r\n/**\r\n * The boxed editor UI view class. This class represents an editor interface\r\n * consisting of a toolbar and an editable area, enclosed within a box.\r\n */\r\nexport default class BoxedEditorUIView extends EditorUIView {\r\n /**\r\n * Creates an instance of the boxed editor UI view class.\r\n *\r\n * @param locale The locale instance..\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n this.top = this.createCollection();\r\n this.main = this.createCollection();\r\n this._voiceLabelView = this._createVoiceLabel();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-reset',\r\n 'ck-editor',\r\n 'ck-rounded-corners'\r\n ],\r\n role: 'application',\r\n dir: locale.uiLanguageDirection,\r\n lang: locale.uiLanguage,\r\n 'aria-labelledby': this._voiceLabelView.id\r\n },\r\n children: [\r\n this._voiceLabelView,\r\n {\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-editor__top',\r\n 'ck-reset_all'\r\n ],\r\n role: 'presentation'\r\n },\r\n children: this.top\r\n },\r\n {\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-editor__main'\r\n ],\r\n role: 'presentation'\r\n },\r\n children: this.main\r\n }\r\n ]\r\n });\r\n }\r\n /**\r\n * Creates a voice label view instance.\r\n */\r\n _createVoiceLabel() {\r\n const t = this.t;\r\n const voiceLabel = new LabelView();\r\n voiceLabel.text = t('Rich Text Editor');\r\n voiceLabel.extendTemplate({\r\n attributes: {\r\n class: 'ck-voice-label'\r\n }\r\n });\r\n return voiceLabel;\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/editableui/editableuiview\r\n */\r\nimport View from '../view';\r\n/**\r\n * The editable UI view class.\r\n */\r\nexport default class EditableUIView extends View {\r\n /**\r\n * Creates an instance of EditableUIView class.\r\n *\r\n * @param locale The locale instance.\r\n * @param editingView The editing view instance the editable is related to.\r\n * @param editableElement The editable element. If not specified, this view\r\n * should create it. Otherwise, the existing element should be used.\r\n */\r\n constructor(locale, editingView, editableElement) {\r\n super(locale);\r\n /**\r\n * The name of the editable UI view.\r\n */\r\n this.name = null;\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-content',\r\n 'ck-editor__editable',\r\n 'ck-rounded-corners'\r\n ],\r\n lang: locale.contentLanguage,\r\n dir: locale.contentLanguageDirection\r\n }\r\n });\r\n this.set('isFocused', false);\r\n this._editableElement = editableElement;\r\n this._hasExternalElement = !!this._editableElement;\r\n this._editingView = editingView;\r\n }\r\n /**\r\n * Renders the view by either applying the {@link #template} to the existing\r\n * {@link module:ui/editableui/editableuiview~EditableUIView#_editableElement} or assigning {@link #element}\r\n * as {@link module:ui/editableui/editableuiview~EditableUIView#_editableElement}.\r\n */\r\n render() {\r\n super.render();\r\n if (this._hasExternalElement) {\r\n this.template.apply(this.element = this._editableElement);\r\n }\r\n else {\r\n this._editableElement = this.element;\r\n }\r\n this.on('change:isFocused', () => this._updateIsFocusedClasses());\r\n this._updateIsFocusedClasses();\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n if (this._hasExternalElement) {\r\n this.template.revert(this._editableElement);\r\n }\r\n super.destroy();\r\n }\r\n /**\r\n * Whether an external {@link #_editableElement} was passed into the constructor, which also means\r\n * the view will not render its {@link #template}.\r\n */\r\n get hasExternalElement() {\r\n return this._hasExternalElement;\r\n }\r\n /**\r\n * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to\r\n * the {@link #isFocused} property value using the {@link #_editingView editing view} API.\r\n */\r\n _updateIsFocusedClasses() {\r\n const editingView = this._editingView;\r\n if (editingView.isRenderingInProgress) {\r\n updateAfterRender(this);\r\n }\r\n else {\r\n update(this);\r\n }\r\n function update(view) {\r\n editingView.change(writer => {\r\n const viewRoot = editingView.document.getRoot(view.name);\r\n writer.addClass(view.isFocused ? 'ck-focused' : 'ck-blurred', viewRoot);\r\n writer.removeClass(view.isFocused ? 'ck-blurred' : 'ck-focused', viewRoot);\r\n });\r\n }\r\n // In a case of a multi-root editor, a callback will be attached more than once (one callback for each root).\r\n // While executing one callback the `isRenderingInProgress` observable is changing what causes executing another\r\n // callback and render is called inside the already pending render.\r\n // We need to be sure that callback is executed only when the value has changed from `true` to `false`.\r\n // See https://github.com/ckeditor/ckeditor5/issues/1676.\r\n function updateAfterRender(view) {\r\n editingView.once('change:isRenderingInProgress', (evt, name, value) => {\r\n if (!value) {\r\n update(view);\r\n }\r\n else {\r\n updateAfterRender(view);\r\n }\r\n });\r\n }\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/editableui/inline/inlineeditableuiview\r\n */\r\nimport EditableUIView from '../editableuiview';\r\n/**\r\n * The inline editable UI class implementing an inline {@link module:ui/editableui/editableuiview~EditableUIView}.\r\n */\r\nexport default class InlineEditableUIView extends EditableUIView {\r\n /**\r\n * Creates an instance of the InlineEditableUIView class.\r\n *\r\n * @param locale The locale instance.\r\n * @param editingView The editing view instance the editable is related to.\r\n * @param editableElement The editable element. If not specified, the\r\n * {@link module:ui/editableui/editableuiview~EditableUIView}\r\n * will create it. Otherwise, the existing element will be used.\r\n * @param options Additional configuration of the view.\r\n * @param options.label A function that gets called with the instance of this view as an argument\r\n * and should return a string that represents the label of the editable for assistive technologies. If not provided,\r\n * a default label generator is used.\r\n */\r\n constructor(locale, editingView, editableElement, options = {}) {\r\n super(locale, editingView, editableElement);\r\n const t = locale.t;\r\n this.extendTemplate({\r\n attributes: {\r\n role: 'textbox',\r\n class: 'ck-editor__editable_inline'\r\n }\r\n });\r\n this._generateLabel = options.label || (() => t('Editor editing area: %0', this.name));\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n const editingView = this._editingView;\r\n editingView.change(writer => {\r\n const viewRoot = editingView.document.getRoot(this.name);\r\n writer.setAttribute('aria-label', this._generateLabel(this), viewRoot);\r\n });\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/formheader/formheaderview\r\n */\r\nimport View from '../view';\r\nimport IconView from '../icon/iconview';\r\nimport '../../theme/components/formheader/formheader.css';\r\n/**\r\n * The class component representing a form header view. It should be used in more advanced forms to\r\n * describe the main purpose of the form.\r\n *\r\n * By default the component contains a bolded label view that has to be set. The label is usually a short (at most 3-word) string.\r\n * The component can also be extended by any other elements, like: icons, dropdowns, etc.\r\n *\r\n * It is used i.a.\r\n * by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}\r\n * and {@link module:special-characters/ui/specialcharactersnavigationview~SpecialCharactersNavigationView}.\r\n *\r\n * The latter is an example, where the component has been extended by {@link module:ui/dropdown/dropdownview~DropdownView} view.\r\n */\r\nexport default class FormHeaderView extends View {\r\n /**\r\n * Creates an instance of the form header class.\r\n *\r\n * @param locale The locale instance.\r\n * @param options.label A label.\r\n * @param options.class An additional class.\r\n */\r\n constructor(locale, options = {}) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n this.set('label', options.label || '');\r\n this.set('class', options.class || null);\r\n this.children = this.createCollection();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-form__header',\r\n bind.to('class')\r\n ]\r\n },\r\n children: this.children\r\n });\r\n if (options.icon) {\r\n this.iconView = new IconView();\r\n this.iconView.content = options.icon;\r\n this.children.add(this.iconView);\r\n }\r\n const label = new View(locale);\r\n label.setTemplate({\r\n tag: 'h2',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-form__header__label'\r\n ]\r\n },\r\n children: [\r\n { text: bind.to('label') }\r\n ]\r\n });\r\n this.children.add(label);\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/notification/notification\r\n */\r\n/* globals window */\r\nimport { ContextPlugin } from '@ckeditor/ckeditor5-core';\r\n/**\r\n * The Notification plugin.\r\n *\r\n * This plugin sends a few types of notifications: `success`, `info` and `warning`. The notifications need to be\r\n * handled and displayed by a plugin responsible for showing the UI of the notifications. Using this plugin for dispatching\r\n * notifications makes it possible to switch the notifications UI.\r\n *\r\n * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert.\r\n * See {@link module:ui/notification/notification~Notification#showWarning}.\r\n */\r\nexport default class Notification extends ContextPlugin {\r\n /**\r\n * @inheritDoc\r\n */\r\n static get pluginName() {\r\n return 'Notification';\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n init() {\r\n // Each unhandled and not stopped `show:warning` event is displayed as a system alert.\r\n this.on('show:warning', (evt, data) => {\r\n window.alert(data.message); // eslint-disable-line no-alert\r\n }, { priority: 'lowest' });\r\n }\r\n /**\r\n * Shows a success notification.\r\n *\r\n * By default, it fires the {@link #event:show:success `show:success` event} with the given `data`. The event namespace can be extended\r\n * using the `data.namespace` option. For example:\r\n *\r\n * ```ts\r\n * showSuccess( 'Image is uploaded.', {\r\n * \tnamespace: 'upload:image'\r\n * } );\r\n * ```\r\n *\r\n * will fire the `show:success:upload:image` event.\r\n *\r\n * You can provide the title of the notification:\r\n *\r\n * ```ts\r\n * showSuccess( 'Image is uploaded.', {\r\n * \ttitle: 'Image upload success'\r\n * } );\r\n * ```\r\n *\r\n * @param message The content of the notification.\r\n * @param data Additional data.\r\n * @param data.namespace Additional event namespace.\r\n * @param data.title The title of the notification.\r\n */\r\n showSuccess(message, data = {}) {\r\n this._showNotification({\r\n message,\r\n type: 'success',\r\n namespace: data.namespace,\r\n title: data.title\r\n });\r\n }\r\n /**\r\n * Shows an information notification.\r\n *\r\n * By default, it fires the {@link #event:show:info `show:info` event} with the given `data`. The event namespace can be extended\r\n * using the `data.namespace` option. For example:\r\n *\r\n * ```ts\r\n * showInfo( 'Editor is offline.', {\r\n * \tnamespace: 'editor:status'\r\n * } );\r\n * ```\r\n *\r\n * will fire the `show:info:editor:status` event.\r\n *\r\n * You can provide the title of the notification:\r\n *\r\n * ```ts\r\n * showInfo( 'Editor is offline.', {\r\n * \ttitle: 'Network information'\r\n * } );\r\n * ```\r\n *\r\n * @param message The content of the notification.\r\n * @param data Additional data.\r\n * @param data.namespace Additional event namespace.\r\n * @param data.title The title of the notification.\r\n */\r\n showInfo(message, data = {}) {\r\n this._showNotification({\r\n message,\r\n type: 'info',\r\n namespace: data.namespace,\r\n title: data.title\r\n });\r\n }\r\n /**\r\n * Shows a warning notification.\r\n *\r\n * By default, it fires the {@link #event:show:warning `show:warning` event}\r\n * with the given `data`. The event namespace can be extended using the `data.namespace` option. For example:\r\n *\r\n * ```ts\r\n * showWarning( 'Image upload error.', {\r\n * \tnamespace: 'upload:image'\r\n * } );\r\n * ```\r\n *\r\n * will fire the `show:warning:upload:image` event.\r\n *\r\n * You can provide the title of the notification:\r\n *\r\n * ```ts\r\n * showWarning( 'Image upload error.', {\r\n * \ttitle: 'Upload failed'\r\n * } );\r\n * ```\r\n *\r\n * Note that each unhandled and not stopped `warning` notification will be displayed as a system alert.\r\n * The plugin responsible for displaying warnings should `stop()` the event to prevent displaying it as an alert:\r\n *\r\n * ```ts\r\n * notifications.on( 'show:warning', ( evt, data ) => {\r\n * \t// Do something with the data.\r\n *\r\n * \t// Stop this event to prevent displaying it as an alert.\r\n * \tevt.stop();\r\n * } );\r\n * ```\r\n *\r\n * You can attach many listeners to the same event and `stop()` this event in a listener with a low priority:\r\n *\r\n * ```ts\r\n * notifications.on( 'show:warning', ( evt, data ) => {\r\n * \t// Show the warning in the UI, but do not stop it.\r\n * } );\r\n *\r\n * notifications.on( 'show:warning', ( evt, data ) => {\r\n * \t// Log the warning to some error tracker.\r\n *\r\n * \t// Stop this event to prevent displaying it as an alert.\r\n * \tevt.stop();\r\n * }, { priority: 'low' } );\r\n * ```\r\n *\r\n * @param message The content of the notification.\r\n * @param data Additional data.\r\n * @param data.namespace Additional event namespace.\r\n * @param data.title The title of the notification.\r\n */\r\n showWarning(message, data = {}) {\r\n this._showNotification({\r\n message,\r\n type: 'warning',\r\n namespace: data.namespace,\r\n title: data.title\r\n });\r\n }\r\n /**\r\n * Fires the `show` event with the specified type, namespace and message.\r\n *\r\n * @param data The message data.\r\n * @param data.message The content of the notification.\r\n * @param data.type The type of the message.\r\n * @param data.namespace Additional event namespace.\r\n * @param data.title The title of the notification.\r\n */\r\n _showNotification(data) {\r\n const event = data.namespace ?\r\n `show:${data.type}:${data.namespace}` :\r\n `show:${data.type}`;\r\n this.fire(event, {\r\n message: data.message,\r\n type: data.type,\r\n title: data.title || ''\r\n });\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/model\r\n */\r\nimport { ObservableMixin } from '@ckeditor/ckeditor5-utils';\r\nimport { extend } from 'lodash-es';\r\n/**\r\n * The base MVC model class.\r\n */\r\nexport default class Model extends ObservableMixin() {\r\n /**\r\n * Creates a new Model instance.\r\n *\r\n * @param attributes The model state attributes to be defined during the instance creation.\r\n * @param properties The (out of state) properties to be appended to the instance during creation.\r\n */\r\n constructor(attributes, properties) {\r\n super();\r\n // Extend this instance with the additional (out of state) properties.\r\n if (properties) {\r\n extend(this, properties);\r\n }\r\n // Initialize the attributes.\r\n if (attributes) {\r\n this.set(attributes);\r\n }\r\n }\r\n}\r\n","export default \"\";","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/panel/balloon/contextualballoon\r\n */\r\nimport BalloonPanelView from './balloonpanelview';\r\nimport View from '../../view';\r\nimport ButtonView from '../../button/buttonview';\r\nimport { Plugin } from '@ckeditor/ckeditor5-core';\r\nimport { CKEditorError, FocusTracker, Rect, toUnit } from '@ckeditor/ckeditor5-utils';\r\nimport prevIcon from '../../../theme/icons/previous-arrow.svg';\r\nimport nextIcon from '../../../theme/icons/next-arrow.svg';\r\nimport '../../../theme/components/panel/balloonrotator.css';\r\nimport '../../../theme/components/panel/fakepanel.css';\r\nconst toPx = toUnit('px');\r\n/**\r\n * Provides the common contextual balloon for the editor.\r\n *\r\n * The role of this plugin is to unify the contextual balloons logic, simplify views management and help\r\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\r\n * instances in the editor.\r\n *\r\n * This plugin allows for creating single or multiple panel stacks.\r\n *\r\n * Each stack may have multiple views, with the one on the top being visible. When the visible view is removed from the stack,\r\n * the previous view becomes visible.\r\n *\r\n * It might be useful to implement nested navigation in a balloon. For instance, a toolbar view may contain a link button.\r\n * When you click it, a link view (which lets you set the URL) is created and put on top of the toolbar view, so the link panel\r\n * is displayed. When you finish editing the link and close (remove) the link view, the toolbar view is visible again.\r\n *\r\n * However, there are cases when there are multiple independent balloons to be displayed, for instance, if the selection\r\n * is inside two inline comments at the same time. For such cases, you can create two independent panel stacks.\r\n * The contextual balloon plugin will create a navigation bar to let the users switch between these panel stacks using the \"Next\"\r\n * and \"Previous\" buttons.\r\n *\r\n * If there are no views in the current stack, the balloon panel will try to switch to the next stack. If there are no\r\n * panels in any stack, the balloon panel will be hidden.\r\n *\r\n * **Note**: To force the balloon panel to show only one view, even if there are other stacks, use the `singleViewMode=true` option\r\n * when {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#add adding} a view to a panel.\r\n *\r\n * From the implementation point of view, the contextual ballon plugin is reusing a single\r\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance to display multiple contextual balloon\r\n * panels in the editor. It also creates a special {@link module:ui/panel/balloon/contextualballoon~RotatorView rotator view},\r\n * used to manage multiple panel stacks. Rotator view is a child of the balloon panel view and the parent of the specific\r\n * view you want to display. If there is more than one panel stack to be displayed, the rotator view will add a\r\n * navigation bar. If there is only one stack, the rotator view is transparent (it does not add any UI elements).\r\n */\r\nexport default class ContextualBalloon extends Plugin {\r\n /**\r\n * @inheritDoc\r\n */\r\n static get pluginName() {\r\n return 'ContextualBalloon';\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(editor) {\r\n super(editor);\r\n /**\r\n * The map of views and their stacks.\r\n */\r\n this._viewToStack = new Map();\r\n /**\r\n * The map of IDs and stacks.\r\n */\r\n this._idToStack = new Map();\r\n /**\r\n * The common balloon panel view.\r\n */\r\n this._view = null;\r\n /**\r\n * Rotator view embedded in the contextual balloon.\r\n * Displays the currently visible view in the balloon and provides navigation for switching stacks.\r\n */\r\n this._rotatorView = null;\r\n /**\r\n * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.\r\n */\r\n this._fakePanelsView = null;\r\n this.positionLimiter = () => {\r\n const view = this.editor.editing.view;\r\n const viewDocument = view.document;\r\n const editableElement = viewDocument.selection.editableElement;\r\n if (editableElement) {\r\n return view.domConverter.mapViewToDom(editableElement.root);\r\n }\r\n return null;\r\n };\r\n this.set('visibleView', null);\r\n this.set('_numberOfStacks', 0);\r\n this.set('_singleViewMode', false);\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n if (this._view) {\r\n this._view.destroy();\r\n }\r\n if (this._rotatorView) {\r\n this._rotatorView.destroy();\r\n }\r\n if (this._fakePanelsView) {\r\n this._fakePanelsView.destroy();\r\n }\r\n }\r\n /**\r\n * The common balloon panel view.\r\n */\r\n get view() {\r\n if (!this._view) {\r\n this._createPanelView();\r\n }\r\n return this._view;\r\n }\r\n /**\r\n * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.\r\n */\r\n hasView(view) {\r\n return Array.from(this._viewToStack.keys()).includes(view);\r\n }\r\n /**\r\n * Adds a new view to the stack and makes it visible if the current stack is visible\r\n * or it is the first view in the balloon.\r\n *\r\n * @param data The configuration of the view.\r\n * @param data.stackId The ID of the stack that the view is added to. Defaults to `'main'`.\r\n * @param data.view The content of the balloon.\r\n * @param data.position Positioning options.\r\n * @param data.balloonClassName An additional CSS class added to the {@link #view balloon} when visible.\r\n * @param data.withArrow Whether the {@link #view balloon} should be rendered with an arrow. Defaults to `true`.\r\n * @param data.singleViewMode Whether the view should be the only visible view even if other stacks were added. Defaults to `false`.\r\n */\r\n add(data) {\r\n if (!this._view) {\r\n this._createPanelView();\r\n }\r\n if (this.hasView(data.view)) {\r\n /**\r\n * Trying to add configuration of the same view more than once.\r\n *\r\n * @error contextualballoon-add-view-exist\r\n */\r\n throw new CKEditorError('contextualballoon-add-view-exist', [this, data]);\r\n }\r\n const stackId = data.stackId || 'main';\r\n // If new stack is added, creates it and show view from this stack.\r\n if (!this._idToStack.has(stackId)) {\r\n this._idToStack.set(stackId, new Map([[data.view, data]]));\r\n this._viewToStack.set(data.view, this._idToStack.get(stackId));\r\n this._numberOfStacks = this._idToStack.size;\r\n if (!this._visibleStack || data.singleViewMode) {\r\n this.showStack(stackId);\r\n }\r\n return;\r\n }\r\n const stack = this._idToStack.get(stackId);\r\n if (data.singleViewMode) {\r\n this.showStack(stackId);\r\n }\r\n // Add new view to the stack.\r\n stack.set(data.view, data);\r\n this._viewToStack.set(data.view, stack);\r\n // And display it if is added to the currently visible stack.\r\n if (stack === this._visibleStack) {\r\n this._showView(data);\r\n }\r\n }\r\n /**\r\n * Removes the given view from the stack. If the removed view was visible,\r\n * the view preceding it in the stack will become visible instead.\r\n * When there is no view in the stack, the next stack will be displayed.\r\n * When there are no more stacks, the balloon will hide.\r\n *\r\n * @param view A view to be removed from the balloon.\r\n */\r\n remove(view) {\r\n if (!this.hasView(view)) {\r\n /**\r\n * Trying to remove the configuration of the view not defined in the stack.\r\n *\r\n * @error contextualballoon-remove-view-not-exist\r\n */\r\n throw new CKEditorError('contextualballoon-remove-view-not-exist', [this, view]);\r\n }\r\n const stack = this._viewToStack.get(view);\r\n if (this._singleViewMode && this.visibleView === view) {\r\n this._singleViewMode = false;\r\n }\r\n // When visible view will be removed we need to show a preceding view or next stack\r\n // if a view is the only view in the stack.\r\n if (this.visibleView === view) {\r\n if (stack.size === 1) {\r\n if (this._idToStack.size > 1) {\r\n this._showNextStack();\r\n }\r\n else {\r\n this.view.hide();\r\n this.visibleView = null;\r\n this._rotatorView.hideView();\r\n }\r\n }\r\n else {\r\n this._showView(Array.from(stack.values())[stack.size - 2]);\r\n }\r\n }\r\n if (stack.size === 1) {\r\n this._idToStack.delete(this._getStackId(stack));\r\n this._numberOfStacks = this._idToStack.size;\r\n }\r\n else {\r\n stack.delete(view);\r\n }\r\n this._viewToStack.delete(view);\r\n }\r\n /**\r\n * Updates the position of the balloon using the position data of the first visible view in the stack.\r\n * When new position data is given, the position data of the currently visible view will be updated.\r\n *\r\n * @param position Position options.\r\n */\r\n updatePosition(position) {\r\n if (position) {\r\n this._visibleStack.get(this.visibleView).position = position;\r\n }\r\n this.view.pin(this._getBalloonPosition());\r\n this._fakePanelsView.updatePosition();\r\n }\r\n /**\r\n * Shows the last view from the stack of a given ID.\r\n */\r\n showStack(id) {\r\n this.visibleStack = id;\r\n const stack = this._idToStack.get(id);\r\n if (!stack) {\r\n /**\r\n * Trying to show a stack that does not exist.\r\n *\r\n * @error contextualballoon-showstack-stack-not-exist\r\n */\r\n throw new CKEditorError('contextualballoon-showstack-stack-not-exist', this);\r\n }\r\n if (this._visibleStack === stack) {\r\n return;\r\n }\r\n this._showView(Array.from(stack.values()).pop());\r\n }\r\n /**\r\n * Initializes view instances.\r\n */\r\n _createPanelView() {\r\n this._view = new BalloonPanelView(this.editor.locale);\r\n this.editor.ui.view.body.add(this._view);\r\n this.editor.ui.focusTracker.add(this._view.element);\r\n this._rotatorView = this._createRotatorView();\r\n this._fakePanelsView = this._createFakePanelsView();\r\n }\r\n /**\r\n * Returns the stack of the currently visible view.\r\n */\r\n get _visibleStack() {\r\n return this._viewToStack.get(this.visibleView);\r\n }\r\n /**\r\n * Returns the ID of the given stack.\r\n */\r\n _getStackId(stack) {\r\n const entry = Array.from(this._idToStack.entries()).find(entry => entry[1] === stack);\r\n return entry[0];\r\n }\r\n /**\r\n * Shows the last view from the next stack.\r\n */\r\n _showNextStack() {\r\n const stacks = Array.from(this._idToStack.values());\r\n let nextIndex = stacks.indexOf(this._visibleStack) + 1;\r\n if (!stacks[nextIndex]) {\r\n nextIndex = 0;\r\n }\r\n this.showStack(this._getStackId(stacks[nextIndex]));\r\n }\r\n /**\r\n * Shows the last view from the previous stack.\r\n */\r\n _showPrevStack() {\r\n const stacks = Array.from(this._idToStack.values());\r\n let nextIndex = stacks.indexOf(this._visibleStack) - 1;\r\n if (!stacks[nextIndex]) {\r\n nextIndex = stacks.length - 1;\r\n }\r\n this.showStack(this._getStackId(stacks[nextIndex]));\r\n }\r\n /**\r\n * Creates a rotator view.\r\n */\r\n _createRotatorView() {\r\n const view = new RotatorView(this.editor.locale);\r\n const t = this.editor.locale.t;\r\n this.view.content.add(view);\r\n // Hide navigation when there is only a one stack & not in single view mode.\r\n view.bind('isNavigationVisible').to(this, '_numberOfStacks', this, '_singleViewMode', (value, isSingleViewMode) => {\r\n return !isSingleViewMode && value > 1;\r\n });\r\n // Update balloon position after toggling navigation.\r\n view.on('change:isNavigationVisible', () => (this.updatePosition()), { priority: 'low' });\r\n // Update stacks counter value.\r\n view.bind('counter').to(this, 'visibleView', this, '_numberOfStacks', (visibleView, numberOfStacks) => {\r\n if (numberOfStacks < 2) {\r\n return '';\r\n }\r\n const current = Array.from(this._idToStack.values()).indexOf(this._visibleStack) + 1;\r\n return t('%0 of %1', [current, numberOfStacks]);\r\n });\r\n view.buttonNextView.on('execute', () => {\r\n // When current view has a focus then move focus to the editable before removing it,\r\n // otherwise editor will lost focus.\r\n if (view.focusTracker.isFocused) {\r\n this.editor.editing.view.focus();\r\n }\r\n this._showNextStack();\r\n });\r\n view.buttonPrevView.on('execute', () => {\r\n // When current view has a focus then move focus to the editable before removing it,\r\n // otherwise editor will lost focus.\r\n if (view.focusTracker.isFocused) {\r\n this.editor.editing.view.focus();\r\n }\r\n this._showPrevStack();\r\n });\r\n return view;\r\n }\r\n /**\r\n * Creates a fake panels view.\r\n */\r\n _createFakePanelsView() {\r\n const view = new FakePanelsView(this.editor.locale, this.view);\r\n view.bind('numberOfPanels').to(this, '_numberOfStacks', this, '_singleViewMode', (number, isSingleViewMode) => {\r\n const showPanels = !isSingleViewMode && number >= 2;\r\n return showPanels ? Math.min(number - 1, 2) : 0;\r\n });\r\n view.listenTo(this.view, 'change:top', () => view.updatePosition());\r\n view.listenTo(this.view, 'change:left', () => view.updatePosition());\r\n this.editor.ui.view.body.add(view);\r\n return view;\r\n }\r\n /**\r\n * Sets the view as the content of the balloon and attaches the balloon using position\r\n * options of the first view.\r\n *\r\n * @param data Configuration.\r\n * @param data.view The view to show in the balloon.\r\n * @param data.balloonClassName Additional class name which will be added to the {@link #view balloon}.\r\n * @param data.withArrow Whether the {@link #view balloon} should be rendered with an arrow.\r\n */\r\n _showView({ view, balloonClassName = '', withArrow = true, singleViewMode = false }) {\r\n this.view.class = balloonClassName;\r\n this.view.withArrow = withArrow;\r\n this._rotatorView.showView(view);\r\n this.visibleView = view;\r\n this.view.pin(this._getBalloonPosition());\r\n this._fakePanelsView.updatePosition();\r\n if (singleViewMode) {\r\n this._singleViewMode = true;\r\n }\r\n }\r\n /**\r\n * Returns position options of the last view in the stack.\r\n * This keeps the balloon in the same position when the view is changed.\r\n */\r\n _getBalloonPosition() {\r\n let position = Array.from(this._visibleStack.values()).pop().position;\r\n if (position) {\r\n // Use the default limiter if none has been specified.\r\n if (!position.limiter) {\r\n // Don't modify the original options object.\r\n position = Object.assign({}, position, {\r\n limiter: this.positionLimiter\r\n });\r\n }\r\n // Don't modify the original options object.\r\n position = Object.assign({}, position, {\r\n viewportOffsetConfig: this.editor.ui.viewportOffset\r\n });\r\n }\r\n return position;\r\n }\r\n}\r\n/**\r\n * Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.\r\n * It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.\r\n * See the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon} documentation to learn more.\r\n */\r\nexport class RotatorView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n const t = locale.t;\r\n const bind = this.bindTemplate;\r\n this.set('isNavigationVisible', true);\r\n this.focusTracker = new FocusTracker();\r\n this.buttonPrevView = this._createButtonView(t('Previous'), prevIcon);\r\n this.buttonNextView = this._createButtonView(t('Next'), nextIcon);\r\n this.content = this.createCollection();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-balloon-rotator'\r\n ],\r\n 'z-index': '-1'\r\n },\r\n children: [\r\n {\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck-balloon-rotator__navigation',\r\n bind.to('isNavigationVisible', value => value ? '' : 'ck-hidden')\r\n ]\r\n },\r\n children: [\r\n this.buttonPrevView,\r\n {\r\n tag: 'span',\r\n attributes: {\r\n class: [\r\n 'ck-balloon-rotator__counter'\r\n ]\r\n },\r\n children: [\r\n {\r\n text: bind.to('counter')\r\n }\r\n ]\r\n },\r\n this.buttonNextView\r\n ]\r\n },\r\n {\r\n tag: 'div',\r\n attributes: {\r\n class: 'ck-balloon-rotator__content'\r\n },\r\n children: this.content\r\n }\r\n ]\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n this.focusTracker.add(this.element);\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n this.focusTracker.destroy();\r\n }\r\n /**\r\n * Shows a given view.\r\n *\r\n * @param view The view to show.\r\n */\r\n showView(view) {\r\n this.hideView();\r\n this.content.add(view);\r\n }\r\n /**\r\n * Hides the currently displayed view.\r\n */\r\n hideView() {\r\n this.content.clear();\r\n }\r\n /**\r\n * Creates a navigation button view.\r\n *\r\n * @param label The button label.\r\n * @param icon The button icon.\r\n */\r\n _createButtonView(label, icon) {\r\n const view = new ButtonView(this.locale);\r\n view.set({\r\n label,\r\n icon,\r\n tooltip: true\r\n });\r\n return view;\r\n }\r\n}\r\n/**\r\n * Displays additional layers under the balloon when multiple stacks are added to the balloon.\r\n */\r\nclass FakePanelsView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale, balloonPanelView) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n this.set('top', 0);\r\n this.set('left', 0);\r\n this.set('height', 0);\r\n this.set('width', 0);\r\n this.set('numberOfPanels', 0);\r\n this.content = this.createCollection();\r\n this._balloonPanelView = balloonPanelView;\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck-fake-panel',\r\n bind.to('numberOfPanels', number => number ? '' : 'ck-hidden')\r\n ],\r\n style: {\r\n top: bind.to('top', toPx),\r\n left: bind.to('left', toPx),\r\n width: bind.to('width', toPx),\r\n height: bind.to('height', toPx)\r\n }\r\n },\r\n children: this.content\r\n });\r\n this.on('change:numberOfPanels', (evt, name, next, prev) => {\r\n if (next > prev) {\r\n this._addPanels(next - prev);\r\n }\r\n else {\r\n this._removePanels(prev - next);\r\n }\r\n this.updatePosition();\r\n });\r\n }\r\n _addPanels(number) {\r\n while (number--) {\r\n const view = new View();\r\n view.setTemplate({ tag: 'div' });\r\n this.content.add(view);\r\n this.registerChild(view);\r\n }\r\n }\r\n _removePanels(number) {\r\n while (number--) {\r\n const view = this.content.last;\r\n this.content.remove(view);\r\n this.deregisterChild(view);\r\n view.destroy();\r\n }\r\n }\r\n /**\r\n * Updates coordinates of fake panels.\r\n */\r\n updatePosition() {\r\n if (this.numberOfPanels) {\r\n const { top, left } = this._balloonPanelView;\r\n const { width, height } = new Rect(this._balloonPanelView.element);\r\n Object.assign(this, { top, left, width, height });\r\n }\r\n }\r\n}\r\n","export default \"\";","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/panel/sticky/stickypanelview\r\n */\r\nimport View from '../../view';\r\nimport Template from '../../template';\r\nimport { global, toUnit, Rect } from '@ckeditor/ckeditor5-utils';\r\n// @if CK_DEBUG_STICKYPANEL // const {\r\n// @if CK_DEBUG_STICKYPANEL // \tdefault: RectDrawer,\r\n// @if CK_DEBUG_STICKYPANEL // \tdiagonalStylesBlack\r\n// @if CK_DEBUG_STICKYPANEL // } = require( '@ckeditor/ckeditor5-utils/tests/_utils/rectdrawer' );\r\nimport '../../../theme/components/panel/stickypanel.css';\r\nconst toPx = toUnit('px');\r\n/**\r\n * The sticky panel view class.\r\n */\r\nexport default class StickyPanelView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n this.set('isActive', false);\r\n this.set('isSticky', false);\r\n this.set('limiterElement', null);\r\n this.set('limiterBottomOffset', 50);\r\n this.set('viewportTopOffset', 0);\r\n this.set('_marginLeft', null);\r\n this.set('_isStickyToTheBottomOfLimiter', false);\r\n this.set('_stickyTopOffset', null);\r\n this.set('_stickyBottomOffset', null);\r\n this.content = this.createCollection();\r\n this._contentPanelPlaceholder = new Template({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-sticky-panel__placeholder'\r\n ],\r\n style: {\r\n display: bind.to('isSticky', isSticky => isSticky ? 'block' : 'none'),\r\n height: bind.to('isSticky', isSticky => {\r\n return isSticky ? toPx(this._contentPanelRect.height) : null;\r\n })\r\n }\r\n }\r\n }).render();\r\n this._contentPanel = new Template({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-sticky-panel__content',\r\n // Toggle class of the panel when \"sticky\" state changes in the view.\r\n bind.if('isSticky', 'ck-sticky-panel__content_sticky'),\r\n bind.if('_isStickyToTheBottomOfLimiter', 'ck-sticky-panel__content_sticky_bottom-limit')\r\n ],\r\n style: {\r\n width: bind.to('isSticky', isSticky => {\r\n return isSticky ? toPx(this._contentPanelPlaceholder.getBoundingClientRect().width) : null;\r\n }),\r\n top: bind.to('_stickyTopOffset', value => value ? toPx(value) : value),\r\n bottom: bind.to('_stickyBottomOffset', value => value ? toPx(value) : value),\r\n marginLeft: bind.to('_marginLeft')\r\n }\r\n },\r\n children: this.content\r\n }).render();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-sticky-panel'\r\n ]\r\n },\r\n children: [\r\n this._contentPanelPlaceholder,\r\n this._contentPanel\r\n ]\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n // Check if the panel should go into the sticky state immediately.\r\n this.checkIfShouldBeSticky();\r\n // Update sticky state of the panel as the window and ancestors are being scrolled.\r\n this.listenTo(global.document, 'scroll', () => {\r\n this.checkIfShouldBeSticky();\r\n }, { useCapture: true });\r\n // Synchronize with `model.isActive` because sticking an inactive panel is pointless.\r\n this.listenTo(this, 'change:isActive', () => {\r\n this.checkIfShouldBeSticky();\r\n });\r\n }\r\n /**\r\n * Analyzes the environment to decide whether the panel should be sticky or not.\r\n * Then handles the positioning of the panel.\r\n */\r\n checkIfShouldBeSticky() {\r\n // @if CK_DEBUG_STICKYPANEL // RectDrawer.clear();\r\n if (!this.limiterElement || !this.isActive) {\r\n this._unstick();\r\n return;\r\n }\r\n const limiterRect = new Rect(this.limiterElement);\r\n let visibleLimiterRect = limiterRect.getVisible();\r\n if (visibleLimiterRect) {\r\n const windowRect = new Rect(global.window);\r\n windowRect.top += this.viewportTopOffset;\r\n windowRect.height -= this.viewportTopOffset;\r\n visibleLimiterRect = visibleLimiterRect.getIntersection(windowRect);\r\n }\r\n // @if CK_DEBUG_STICKYPANEL // if ( visibleLimiterRect ) {\r\n // @if CK_DEBUG_STICKYPANEL // \tRectDrawer.draw( visibleLimiterRect,\r\n // @if CK_DEBUG_STICKYPANEL // \t\t{ outlineWidth: '3px', opacity: '.8', outlineColor: 'red', outlineOffset: '-3px' },\r\n // @if CK_DEBUG_STICKYPANEL // \t\t'Visible anc'\r\n // @if CK_DEBUG_STICKYPANEL // \t);\r\n // @if CK_DEBUG_STICKYPANEL // }\r\n // @if CK_DEBUG_STICKYPANEL //\r\n // @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( limiterRect,\r\n // @if CK_DEBUG_STICKYPANEL // \t{ outlineWidth: '3px', opacity: '.8', outlineColor: 'green', outlineOffset: '-3px' },\r\n // @if CK_DEBUG_STICKYPANEL // \t'Limiter'\r\n // @if CK_DEBUG_STICKYPANEL // );\r\n // Stick the panel only if\r\n // * the limiter's ancestors are intersecting with each other so that some of their rects are visible,\r\n // * and the limiter's top edge is above the visible ancestors' top edge.\r\n if (visibleLimiterRect && limiterRect.top < visibleLimiterRect.top) {\r\n // @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect,\r\n // @if CK_DEBUG_STICKYPANEL // \t{ outlineWidth: '3px', opacity: '.8', outlineColor: 'fuchsia', outlineOffset: '-3px',\r\n // @if CK_DEBUG_STICKYPANEL // \t\tbackgroundColor: 'rgba(255, 0, 255, .3)' },\r\n // @if CK_DEBUG_STICKYPANEL // \t'Visible limiter'\r\n // @if CK_DEBUG_STICKYPANEL // );\r\n const visibleLimiterTop = visibleLimiterRect.top;\r\n // Check if there's a change the panel can be sticky to the bottom of the limiter.\r\n if (visibleLimiterTop + this._contentPanelRect.height + this.limiterBottomOffset > visibleLimiterRect.bottom) {\r\n const stickyBottomOffset = Math.max(limiterRect.bottom - visibleLimiterRect.bottom, 0) + this.limiterBottomOffset;\r\n // @if CK_DEBUG_STICKYPANEL // const stickyBottomOffsetRect = new Rect( {\r\n // @if CK_DEBUG_STICKYPANEL // \ttop: limiterRect.bottom - stickyBottomOffset, left: 0, right: 2000,\r\n // @if CK_DEBUG_STICKYPANEL // \tbottom: limiterRect.bottom - stickyBottomOffset, width: 2000, height: 1\r\n // @if CK_DEBUG_STICKYPANEL // } );\r\n // @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( stickyBottomOffsetRect,\r\n // @if CK_DEBUG_STICKYPANEL // \t{ outlineWidth: '1px', opacity: '.8', outlineColor: 'black' },\r\n // @if CK_DEBUG_STICKYPANEL // \t'Sticky bottom offset'\r\n // @if CK_DEBUG_STICKYPANEL // );\r\n // Check if sticking the panel to the bottom of the limiter does not cause it to suddenly\r\n // move upwards if there's not enough space for it.\r\n if (limiterRect.bottom - stickyBottomOffset > limiterRect.top + this._contentPanelRect.height) {\r\n this._stickToBottomOfLimiter(stickyBottomOffset);\r\n }\r\n else {\r\n this._unstick();\r\n }\r\n }\r\n else {\r\n if (this._contentPanelRect.height + this.limiterBottomOffset < limiterRect.height) {\r\n this._stickToTopOfAncestors(visibleLimiterTop);\r\n }\r\n else {\r\n this._unstick();\r\n }\r\n }\r\n }\r\n else {\r\n this._unstick();\r\n }\r\n // @if CK_DEBUG_STICKYPANEL // console.clear();\r\n // @if CK_DEBUG_STICKYPANEL // console.log( 'isSticky', this.isSticky );\r\n // @if CK_DEBUG_STICKYPANEL // console.log( '_isStickyToTheBottomOfLimiter', this._isStickyToTheBottomOfLimiter );\r\n // @if CK_DEBUG_STICKYPANEL // console.log( '_stickyTopOffset', this._stickyTopOffset );\r\n // @if CK_DEBUG_STICKYPANEL // console.log( '_stickyBottomOffset', this._stickyBottomOffset );\r\n // @if CK_DEBUG_STICKYPANEL // if ( visibleLimiterRect ) {\r\n // @if CK_DEBUG_STICKYPANEL // \tRectDrawer.draw( visibleLimiterRect,\r\n // @if CK_DEBUG_STICKYPANEL // \t\t{ ...diagonalStylesBlack,\r\n // @if CK_DEBUG_STICKYPANEL // \t\t\toutlineWidth: '3px', opacity: '.8', outlineColor: 'orange', outlineOffset: '-3px',\r\n // @if CK_DEBUG_STICKYPANEL // \t\t\tbackgroundColor: 'rgba(0, 0, 255, .2)' },\r\n // @if CK_DEBUG_STICKYPANEL // \t\t'visibleLimiterRect'\r\n // @if CK_DEBUG_STICKYPANEL // \t);\r\n // @if CK_DEBUG_STICKYPANEL // }\r\n }\r\n /**\r\n * Sticks the panel at the given CSS `top` offset.\r\n *\r\n * @private\r\n * @param topOffset\r\n */\r\n _stickToTopOfAncestors(topOffset) {\r\n this.isSticky = true;\r\n this._isStickyToTheBottomOfLimiter = false;\r\n this._stickyTopOffset = topOffset;\r\n this._stickyBottomOffset = null;\r\n this._marginLeft = toPx(-global.window.scrollX);\r\n }\r\n /**\r\n * Sticks the panel at the bottom of the limiter with a given CSS `bottom` offset.\r\n *\r\n * @private\r\n * @param stickyBottomOffset\r\n */\r\n _stickToBottomOfLimiter(stickyBottomOffset) {\r\n this.isSticky = true;\r\n this._isStickyToTheBottomOfLimiter = true;\r\n this._stickyTopOffset = null;\r\n this._stickyBottomOffset = stickyBottomOffset;\r\n this._marginLeft = toPx(-global.window.scrollX);\r\n }\r\n /**\r\n * Unsticks the panel putting it back to its original position.\r\n *\r\n * @private\r\n */\r\n _unstick() {\r\n this.isSticky = false;\r\n this._isStickyToTheBottomOfLimiter = false;\r\n this._stickyTopOffset = null;\r\n this._stickyBottomOffset = null;\r\n this._marginLeft = null;\r\n }\r\n /**\r\n * Returns the bounding rect of the {@link #_contentPanel}.\r\n *\r\n * @private\r\n */\r\n get _contentPanelRect() {\r\n return new Rect(this._contentPanel);\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/search/text/searchtextqueryview\r\n */\r\nimport ButtonView from '../../button/buttonview';\r\nimport IconView from '../../icon/iconview';\r\nimport LabeledFieldView from '../../labeledfield/labeledfieldview';\r\nimport { createLabeledInputText } from '../../labeledfield/utils';\r\nimport { icons } from '@ckeditor/ckeditor5-core';\r\n/**\r\n * A search input field for the {@link module:ui/search/text/searchtextview~SearchTextView} component.\r\n *\r\n * @internal\r\n * @extends module:ui/labeledfield/labeledfieldview~LabeledFieldView\r\n */\r\nexport default class SearchTextQueryView extends LabeledFieldView {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale, config) {\r\n const t = locale.t;\r\n const viewConfig = Object.assign({}, {\r\n showResetButton: true,\r\n showIcon: true,\r\n creator: createLabeledInputText\r\n }, config);\r\n super(locale, viewConfig.creator);\r\n this.label = config.label;\r\n this._viewConfig = viewConfig;\r\n if (this._viewConfig.showIcon) {\r\n this.iconView = new IconView();\r\n this.iconView.content = icons.loupe;\r\n this.fieldWrapperChildren.add(this.iconView, 0);\r\n this.extendTemplate({\r\n attributes: {\r\n class: 'ck-search__query_with-icon'\r\n }\r\n });\r\n }\r\n if (this._viewConfig.showResetButton) {\r\n this.resetButtonView = new ButtonView(locale);\r\n this.resetButtonView.set({\r\n label: t('Clear'),\r\n icon: icons.cancel,\r\n class: 'ck-search__reset',\r\n isVisible: false,\r\n tooltip: true\r\n });\r\n this.resetButtonView.on('execute', () => {\r\n this.reset();\r\n this.focus();\r\n this.fire('reset');\r\n });\r\n this.resetButtonView.bind('isVisible').to(this.fieldView, 'isEmpty', isEmpty => !isEmpty);\r\n this.fieldWrapperChildren.add(this.resetButtonView);\r\n this.extendTemplate({\r\n attributes: {\r\n class: 'ck-search__query_with-reset'\r\n }\r\n });\r\n }\r\n }\r\n /**\r\n * Resets the search field to its default state.\r\n */\r\n reset() {\r\n this.fieldView.reset();\r\n if (this._viewConfig.showResetButton) {\r\n this.resetButtonView.isVisible = false;\r\n }\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\nimport View from '../view';\r\n/**\r\n * A view displaying an information text related to different states of {@link module:ui/search/text/searchtextview~SearchTextView}.\r\n *\r\n * @internal\r\n */\r\nexport default class SearchInfoView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor() {\r\n super();\r\n const bind = this.bindTemplate;\r\n this.set({\r\n isVisible: false,\r\n primaryText: '',\r\n secondaryText: ''\r\n });\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-search__info',\r\n bind.if('isVisible', 'ck-hidden', value => !value)\r\n ],\r\n tabindex: -1\r\n },\r\n children: [\r\n {\r\n tag: 'span',\r\n children: [\r\n {\r\n text: [bind.to('primaryText')]\r\n }\r\n ]\r\n },\r\n {\r\n tag: 'span',\r\n children: [\r\n {\r\n text: [bind.to('secondaryText')]\r\n }\r\n ]\r\n }\r\n ]\r\n });\r\n }\r\n /**\r\n * Focuses the view\r\n */\r\n focus() {\r\n this.element.focus();\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/search/searchresultsview\r\n */\r\nimport View from '../view';\r\nimport { FocusTracker } from '@ckeditor/ckeditor5-utils';\r\nimport { default as FocusCycler } from '../focuscycler';\r\n/**\r\n * A sub-component of {@link module:ui/search/text/searchtextview~SearchTextView}. It hosts the filtered and the information views.\r\n */\r\nexport default class SearchResultsView extends View {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n this.children = this.createCollection();\r\n this.focusTracker = new FocusTracker();\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-search__results'\r\n ],\r\n tabindex: -1\r\n },\r\n children: this.children\r\n });\r\n this._focusCycler = new FocusCycler({\r\n focusables: this.children,\r\n focusTracker: this.focusTracker\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n for (const child of this.children) {\r\n this.focusTracker.add(child.element);\r\n }\r\n }\r\n /**\r\n * Focuses the view.\r\n */\r\n focus() {\r\n this._focusCycler.focusFirst();\r\n }\r\n /**\r\n * Focuses the first child view.\r\n */\r\n focusFirst() {\r\n this._focusCycler.focusFirst();\r\n }\r\n /**\r\n * Focuses the last child view.\r\n */\r\n focusLast() {\r\n this._focusCycler.focusLast();\r\n }\r\n}\r\n","import toString from './toString.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g,\n reHasRegExpChar = RegExp(reRegExpChar.source);\n\n/**\n * Escapes the `RegExp` special characters \"^\", \"$\", \"\\\", \".\", \"*\", \"+\",\n * \"?\", \"(\", \")\", \"[\", \"]\", \"{\", \"}\", and \"|\" in `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to escape.\n * @returns {string} Returns the escaped string.\n * @example\n *\n * _.escapeRegExp('[lodash](https://lodash.com/)');\n * // => '\\[lodash\\]\\(https://lodash\\.com/\\)'\n */\nfunction escapeRegExp(string) {\n string = toString(string);\n return (string && reHasRegExpChar.test(string))\n ? string.replace(reRegExpChar, '\\\\$&')\n : string;\n}\n\nexport default escapeRegExp;\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/search/text/searchtextview\r\n*/\r\nimport { FocusTracker, KeystrokeHandler } from '@ckeditor/ckeditor5-utils';\r\nimport View from '../../view';\r\nimport { default as SearchTextQueryView } from './searchtextqueryview';\r\nimport SearchInfoView from '../searchinfoview';\r\nimport SearchResultsView from '../searchresultsview';\r\nimport FocusCycler from '../../focuscycler';\r\nimport { escapeRegExp } from 'lodash-es';\r\nimport '../../../theme/components/search/search.css';\r\n/**\r\n * A search component that allows filtering of an arbitrary view based on a search query\r\n * specified by the user in a text field.\r\n *\r\n *```ts\r\n * // This view must specify the `filter()` and `focus()` methods.\r\n * const filteredView = ...;\r\n *\r\n * const searchView = new SearchTextView( locale, {\r\n * \tsearchFieldLabel: 'Search list items',\r\n * \tfilteredView\r\n * } );\r\n *\r\n * view.render();\r\n *\r\n * document.body.append( view.element );\r\n * ```\r\n */\r\nexport default class SearchTextView extends View {\r\n /**\r\n * Creates an instance of the {@link module:ui/search/text/searchtextview~SearchTextView} class.\r\n *\r\n * @param locale The localization services instance.\r\n * @param config Configuration of the view.\r\n */\r\n constructor(locale, config) {\r\n super(locale);\r\n this._config = config;\r\n this.filteredView = config.filteredView;\r\n this.queryView = this._createSearchTextQueryView();\r\n this.focusTracker = new FocusTracker();\r\n this.keystrokes = new KeystrokeHandler();\r\n this.resultsView = new SearchResultsView(locale);\r\n this.children = this.createCollection();\r\n this.focusableChildren = this.createCollection([this.queryView, this.resultsView]);\r\n this.set('isEnabled', true);\r\n this.set('resultsCount', 0);\r\n this.set('totalItemsCount', 0);\r\n if (config.infoView && config.infoView.instance) {\r\n this.infoView = config.infoView.instance;\r\n }\r\n else {\r\n this.infoView = new SearchInfoView();\r\n this._enableDefaultInfoViewBehavior();\r\n this.on('render', () => {\r\n // Initial search that determines if there are any searchable items\r\n // and displays the corresponding info text.\r\n this.search('');\r\n });\r\n }\r\n this.resultsView.children.addMany([this.infoView, this.filteredView]);\r\n this.focusCycler = new FocusCycler({\r\n focusables: this.focusableChildren,\r\n focusTracker: this.focusTracker,\r\n keystrokeHandler: this.keystrokes,\r\n actions: {\r\n // Navigate form fields backwards using the Shift + Tab keystroke.\r\n focusPrevious: 'shift + tab',\r\n // Navigate form fields forwards using the Tab key.\r\n focusNext: 'tab'\r\n }\r\n });\r\n this.on('search', (evt, { resultsCount, totalItemsCount }) => {\r\n this.resultsCount = resultsCount;\r\n this.totalItemsCount = totalItemsCount;\r\n });\r\n this.setTemplate({\r\n tag: 'div',\r\n attributes: {\r\n class: [\r\n 'ck',\r\n 'ck-search',\r\n config.class || null\r\n ],\r\n tabindex: '-1'\r\n },\r\n children: this.children\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n render() {\r\n super.render();\r\n this.children.addMany([\r\n this.queryView,\r\n this.resultsView\r\n ]);\r\n const stopPropagation = (data) => data.stopPropagation();\r\n for (const focusableChild of this.focusableChildren) {\r\n this.focusTracker.add(focusableChild.element);\r\n }\r\n // Start listening for the keystrokes coming from #element.\r\n this.keystrokes.listenTo(this.element);\r\n // Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's\r\n // keystroke handler would take over the key management in the URL input. We need to prevent\r\n // this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.\r\n this.keystrokes.set('arrowright', stopPropagation);\r\n this.keystrokes.set('arrowleft', stopPropagation);\r\n this.keystrokes.set('arrowup', stopPropagation);\r\n this.keystrokes.set('arrowdown', stopPropagation);\r\n }\r\n /**\r\n * Focuses the {@link #queryView}.\r\n */\r\n focus() {\r\n this.queryView.focus();\r\n }\r\n /**\r\n * Resets the component to its initial state.\r\n */\r\n reset() {\r\n this.queryView.reset();\r\n this.search('');\r\n }\r\n /**\r\n * Searches the {@link #filteredView} for the given query.\r\n *\r\n * @internal\r\n * @param query The search query string.\r\n */\r\n search(query) {\r\n const regExp = query ? new RegExp(escapeRegExp(query), 'ig') : null;\r\n const filteringResults = this.filteredView.filter(regExp);\r\n this.fire('search', { query, ...filteringResults });\r\n }\r\n /**\r\n * Creates a search field view based on configured creator..\r\n */\r\n _createSearchTextQueryView() {\r\n const queryView = new SearchTextQueryView(this.locale, this._config.queryView);\r\n this.listenTo(queryView.fieldView, 'input', () => {\r\n this.search(queryView.fieldView.element.value);\r\n });\r\n queryView.on('reset', () => this.reset());\r\n queryView.bind('isEnabled').to(this);\r\n return queryView;\r\n }\r\n /**\r\n * Initializes the default {@link #infoView} behavior with default text labels when no custom info view\r\n * was specified in the view config.\r\n */\r\n _enableDefaultInfoViewBehavior() {\r\n const t = this.locale.t;\r\n const infoView = this.infoView;\r\n this.on('search', (evt, data) => {\r\n if (!data.resultsCount) {\r\n const defaultTextConfig = this._config.infoView && this._config.infoView.text;\r\n let primaryText, secondaryText;\r\n if (data.totalItemsCount) {\r\n if (defaultTextConfig && defaultTextConfig.notFound) {\r\n primaryText = defaultTextConfig.notFound.primary;\r\n secondaryText = defaultTextConfig.notFound.secondary;\r\n }\r\n else {\r\n primaryText = t('No results found');\r\n secondaryText = '';\r\n }\r\n }\r\n else {\r\n if (defaultTextConfig && defaultTextConfig.noSearchableItems) {\r\n primaryText = defaultTextConfig.noSearchableItems.primary;\r\n secondaryText = defaultTextConfig.noSearchableItems.secondary;\r\n }\r\n else {\r\n primaryText = t('No searchable items');\r\n secondaryText = '';\r\n }\r\n }\r\n infoView.set({\r\n primaryText: normalizeInfoText(primaryText, data),\r\n secondaryText: normalizeInfoText(secondaryText, data),\r\n isVisible: true\r\n });\r\n }\r\n else {\r\n infoView.set({\r\n isVisible: false\r\n });\r\n }\r\n });\r\n function normalizeInfoText(text, { query, resultsCount, totalItemsCount }) {\r\n return typeof text === 'function' ? text(query, resultsCount, totalItemsCount) : text;\r\n }\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/autocomplete/autocompleteview\r\n*/\r\nimport { getOptimalPosition, global, toUnit, Rect } from '@ckeditor/ckeditor5-utils';\r\nimport SearchTextView from '../search/text/searchtextview';\r\nimport '../../theme/components/autocomplete/autocomplete.css';\r\n/**\r\n * The autocomplete component's view class. It extends the {@link module:ui/search/text/searchtextview~SearchTextView} class\r\n * with a floating {@link #resultsView} that shows up when the user starts typing and hides when they blur\r\n * the component.\r\n */\r\nexport default class AutocompleteView extends SearchTextView {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale, config) {\r\n super(locale, config);\r\n this._config = config;\r\n const toPx = toUnit('px');\r\n this.extendTemplate({\r\n attributes: {\r\n class: ['ck-autocomplete']\r\n }\r\n });\r\n const bindResultsView = this.resultsView.bindTemplate;\r\n this.resultsView.set('isVisible', false);\r\n this.resultsView.set('_position', 's');\r\n this.resultsView.set('_width', 0);\r\n this.resultsView.extendTemplate({\r\n attributes: {\r\n class: [\r\n bindResultsView.if('isVisible', 'ck-hidden', value => !value),\r\n bindResultsView.to('_position', value => `ck-search__results_${value}`)\r\n ],\r\n style: {\r\n width: bindResultsView.to('_width', toPx)\r\n }\r\n }\r\n });\r\n // Update the visibility of the results view when the user focuses or blurs the component.\r\n // This is also integration for the `resetOnBlur` configuration.\r\n this.focusTracker.on('change:isFocused', (evt, name, isFocused) => {\r\n this._updateResultsVisibility();\r\n if (isFocused) {\r\n // Reset the scroll position of the results view whenever the autocomplete reopens.\r\n this.resultsView.element.scrollTop = 0;\r\n }\r\n else if (config.resetOnBlur) {\r\n this.queryView.reset();\r\n }\r\n });\r\n // Update the visibility of the results view when the user types in the query field.\r\n // This is an integration for `queryMinChars` configuration.\r\n // This is an integration for search results changing length and the #resultsView requiring to be repositioned.\r\n this.on('search', () => {\r\n this._updateResultsVisibility();\r\n this._updateResultsViewWidthAndPosition();\r\n });\r\n // Hide the results view when the user presses the ESC key.\r\n this.keystrokes.set('esc', (evt, cancel) => {\r\n this.resultsView.isVisible = false;\r\n cancel();\r\n });\r\n // Update the position of the results view when the user scrolls the page.\r\n // TODO: This needs to be debounced down the road.\r\n this.listenTo(global.document, 'scroll', () => {\r\n this._updateResultsViewWidthAndPosition();\r\n });\r\n // Hide the results when the component becomes disabled.\r\n this.on('change:isEnabled', () => {\r\n this._updateResultsVisibility();\r\n });\r\n // Update the value of the query field when the user selects a result.\r\n this.filteredView.on('execute', (evt, { value }) => {\r\n // Focus the query view first to avoid losing the focus.\r\n this.focus();\r\n // Resetting the view will ensure that the #queryView will update its empty state correctly.\r\n // This prevents bugs related to dynamic labels or auto-grow when re-setting the same value\r\n // to #queryView.fieldView.value (which does not trigger empty state change) to an\r\n // #queryView.fieldView.element that has been changed by the user.\r\n this.reset();\r\n // Update the value of the query field.\r\n this.queryView.fieldView.value = this.queryView.fieldView.element.value = value;\r\n // Finally, hide the results view. The focus has been moved earlier so this is safe.\r\n this.resultsView.isVisible = false;\r\n });\r\n // Update the position and width of the results view when it becomes visible.\r\n this.resultsView.on('change:isVisible', () => {\r\n this._updateResultsViewWidthAndPosition();\r\n });\r\n }\r\n /**\r\n * Updates the position of the results view on demand.\r\n */\r\n _updateResultsViewWidthAndPosition() {\r\n if (!this.resultsView.isVisible) {\r\n return;\r\n }\r\n this.resultsView._width = new Rect(this.queryView.fieldView.element).width;\r\n const optimalResultsPosition = AutocompleteView._getOptimalPosition({\r\n element: this.resultsView.element,\r\n target: this.queryView.element,\r\n fitInViewport: true,\r\n positions: AutocompleteView.defaultResultsPositions\r\n });\r\n // _getOptimalPosition will return null if there is no optimal position found (e.g. target is off the viewport).\r\n this.resultsView._position = optimalResultsPosition ? optimalResultsPosition.name : 's';\r\n }\r\n /**\r\n * Updates the visibility of the results view on demand.\r\n */\r\n _updateResultsVisibility() {\r\n const queryMinChars = typeof this._config.queryMinChars === 'undefined' ? 0 : this._config.queryMinChars;\r\n const queryLength = this.queryView.fieldView.element.value.length;\r\n this.resultsView.isVisible = this.focusTracker.isFocused && this.isEnabled && queryLength >= queryMinChars;\r\n }\r\n}\r\n/**\r\n * Positions for the autocomplete results view. Two positions are defined by default:\r\n * * `s` - below the search field,\r\n * * `n` - above the search field.\r\n */\r\nAutocompleteView.defaultResultsPositions = [\r\n (fieldRect => {\r\n return {\r\n top: fieldRect.bottom,\r\n left: fieldRect.left,\r\n name: 's'\r\n };\r\n }),\r\n ((fieldRect, resultsRect) => {\r\n return {\r\n top: fieldRect.top - resultsRect.height,\r\n left: fieldRect.left,\r\n name: 'n'\r\n };\r\n })\r\n];\r\n/**\r\n * A function used to calculate the optimal position for the dropdown panel.\r\n */\r\nAutocompleteView._getOptimalPosition = getOptimalPosition;\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/toolbar/balloon/balloontoolbar\r\n */\r\nimport ContextualBalloon from '../../panel/balloon/contextualballoon';\r\nimport ToolbarView from '../toolbarview';\r\nimport BalloonPanelView, { generatePositions } from '../../panel/balloon/balloonpanelview';\r\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\r\nimport { Plugin } from '@ckeditor/ckeditor5-core';\r\nimport { FocusTracker, Rect, ResizeObserver, env, global, toUnit } from '@ckeditor/ckeditor5-utils';\r\nimport { debounce } from 'lodash-es';\r\nconst toPx = toUnit('px');\r\n/**\r\n * The contextual toolbar.\r\n *\r\n * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\r\n */\r\nexport default class BalloonToolbar extends Plugin {\r\n /**\r\n * @inheritDoc\r\n */\r\n static get pluginName() {\r\n return 'BalloonToolbar';\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n static get requires() {\r\n return [ContextualBalloon];\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(editor) {\r\n super(editor);\r\n /**\r\n * An instance of the resize observer that allows to respond to changes in editable's geometry\r\n * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\r\n *\r\n * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\r\n * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.\r\n *\r\n * **Note:** Created in {@link #init}.\r\n */\r\n this._resizeObserver = null;\r\n this._balloonConfig = normalizeToolbarConfig(editor.config.get('balloonToolbar'));\r\n this.toolbarView = this._createToolbarView();\r\n this.focusTracker = new FocusTracker();\r\n // Wait for the EditorUI#init. EditableElement is not available before.\r\n editor.ui.once('ready', () => {\r\n this.focusTracker.add(editor.ui.getEditableElement());\r\n this.focusTracker.add(this.toolbarView.element);\r\n });\r\n // Register the toolbar so it becomes available for Alt+F10 and Esc navigation.\r\n editor.ui.addToolbar(this.toolbarView, {\r\n beforeFocus: () => this.show(true),\r\n afterBlur: () => this.hide(),\r\n isContextual: true\r\n });\r\n this._balloon = editor.plugins.get(ContextualBalloon);\r\n this._fireSelectionChangeDebounced = debounce(() => this.fire('_selectionChangeDebounced'), 200);\r\n // The appearance of the BalloonToolbar method is event–driven.\r\n // It is possible to stop the #show event and this prevent the toolbar from showing up.\r\n this.decorate('show');\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n init() {\r\n const editor = this.editor;\r\n const selection = editor.model.document.selection;\r\n // Show/hide the toolbar on editable focus/blur.\r\n this.listenTo(this.focusTracker, 'change:isFocused', (evt, name, isFocused) => {\r\n const isToolbarVisible = this._balloon.visibleView === this.toolbarView;\r\n if (!isFocused && isToolbarVisible) {\r\n this.hide();\r\n }\r\n else if (isFocused) {\r\n this.show();\r\n }\r\n });\r\n // Hide the toolbar when the selection is changed by a direct change or has changed to collapsed.\r\n this.listenTo(selection, 'change:range', (evt, data) => {\r\n if (data.directChange || selection.isCollapsed) {\r\n this.hide();\r\n }\r\n // Fire internal `_selectionChangeDebounced` event to use it for showing\r\n // the toolbar after the selection stops changing.\r\n this._fireSelectionChangeDebounced();\r\n });\r\n // Show the toolbar when the selection stops changing.\r\n this.listenTo(this, '_selectionChangeDebounced', () => {\r\n if (this.editor.editing.view.document.isFocused) {\r\n this.show();\r\n }\r\n });\r\n if (!this._balloonConfig.shouldNotGroupWhenFull) {\r\n this.listenTo(editor, 'ready', () => {\r\n const editableElement = editor.ui.view.editable.element;\r\n // Set #toolbarView's max-width on the initialization and update it on the editable resize.\r\n this._resizeObserver = new ResizeObserver(editableElement, entry => {\r\n // The max-width equals 90% of the editable's width for the best user experience.\r\n // The value keeps the balloon very close to the boundaries of the editable and limits the cases\r\n // when the balloon juts out from the editable element it belongs to.\r\n this.toolbarView.maxWidth = toPx(entry.contentRect.width * .9);\r\n });\r\n });\r\n }\r\n // Listen to the toolbar view and whenever it changes its geometry due to some items being\r\n // grouped or ungrouped, update the position of the balloon because a shorter/longer toolbar\r\n // means the balloon could be pointing at the wrong place. Once updated, the balloon will point\r\n // at the right selection in the content again.\r\n // https://github.com/ckeditor/ckeditor5/issues/6444\r\n this.listenTo(this.toolbarView, 'groupedItemsUpdate', () => {\r\n this._updatePosition();\r\n });\r\n }\r\n /**\r\n * Creates toolbar components based on given configuration.\r\n * This needs to be done when all plugins are ready.\r\n */\r\n afterInit() {\r\n const factory = this.editor.ui.componentFactory;\r\n this.toolbarView.fillFromConfig(this._balloonConfig, factory);\r\n }\r\n /**\r\n * Creates the toolbar view instance.\r\n */\r\n _createToolbarView() {\r\n const t = this.editor.locale.t;\r\n const shouldGroupWhenFull = !this._balloonConfig.shouldNotGroupWhenFull;\r\n const toolbarView = new ToolbarView(this.editor.locale, {\r\n shouldGroupWhenFull,\r\n isFloating: true\r\n });\r\n toolbarView.ariaLabel = t('Editor contextual toolbar');\r\n toolbarView.render();\r\n return toolbarView;\r\n }\r\n /**\r\n * Shows the toolbar and attaches it to the selection.\r\n *\r\n * Fires {@link #event:show} event which can be stopped to prevent the toolbar from showing up.\r\n *\r\n * @param showForCollapsedSelection When set `true`, the toolbar will show despite collapsed selection in the\r\n * editing view.\r\n */\r\n show(showForCollapsedSelection = false) {\r\n const editor = this.editor;\r\n const selection = editor.model.document.selection;\r\n const schema = editor.model.schema;\r\n // Do not add the toolbar to the balloon stack twice.\r\n if (this._balloon.hasView(this.toolbarView)) {\r\n return;\r\n }\r\n // Do not show the toolbar when the selection is collapsed.\r\n if (selection.isCollapsed && !showForCollapsedSelection) {\r\n return;\r\n }\r\n // Do not show the toolbar when there is more than one range in the selection and they fully contain selectable elements.\r\n // See https://github.com/ckeditor/ckeditor5/issues/6443.\r\n if (selectionContainsOnlyMultipleSelectables(selection, schema)) {\r\n return;\r\n }\r\n // Don not show the toolbar when all components inside are disabled\r\n // see https://github.com/ckeditor/ckeditor5-ui/issues/269.\r\n if (Array.from(this.toolbarView.items).every((item) => item.isEnabled !== undefined && !item.isEnabled)) {\r\n return;\r\n }\r\n // Update the toolbar position when the editor ui should be refreshed.\r\n this.listenTo(this.editor.ui, 'update', () => {\r\n this._updatePosition();\r\n });\r\n // Add the toolbar to the common editor contextual balloon.\r\n this._balloon.add({\r\n view: this.toolbarView,\r\n position: this._getBalloonPositionData(),\r\n balloonClassName: 'ck-toolbar-container'\r\n });\r\n }\r\n /**\r\n * Hides the toolbar.\r\n */\r\n hide() {\r\n if (this._balloon.hasView(this.toolbarView)) {\r\n this.stopListening(this.editor.ui, 'update');\r\n this._balloon.remove(this.toolbarView);\r\n }\r\n }\r\n /**\r\n * Returns positioning options for the {@link #_balloon}. They control the way balloon is attached\r\n * to the selection.\r\n */\r\n _getBalloonPositionData() {\r\n const editor = this.editor;\r\n const view = editor.editing.view;\r\n const viewDocument = view.document;\r\n const viewSelection = viewDocument.selection;\r\n // Get direction of the selection.\r\n const isBackward = viewDocument.selection.isBackward;\r\n return {\r\n // Because the target for BalloonPanelView is a Rect (not DOMRange), it's geometry will stay fixed\r\n // as the window scrolls. To let the BalloonPanelView follow such Rect, is must be continuously\r\n // computed and hence, the target is defined as a function instead of a static value.\r\n // https://github.com/ckeditor/ckeditor5-ui/issues/195\r\n target: () => {\r\n const range = isBackward ? viewSelection.getFirstRange() : viewSelection.getLastRange();\r\n const rangeRects = Rect.getDomRangeRects(view.domConverter.viewRangeToDom(range));\r\n // Select the proper range rect depending on the direction of the selection.\r\n if (isBackward) {\r\n return rangeRects[0];\r\n }\r\n else {\r\n // Ditch the zero-width \"orphan\" rect in the next line for the forward selection if there's\r\n // another one preceding it. It is not rendered as a selection by the web browser anyway.\r\n // https://github.com/ckeditor/ckeditor5-ui/issues/308\r\n if (rangeRects.length > 1 && rangeRects[rangeRects.length - 1].width === 0) {\r\n rangeRects.pop();\r\n }\r\n return rangeRects[rangeRects.length - 1];\r\n }\r\n },\r\n positions: this._getBalloonPositions(isBackward)\r\n };\r\n }\r\n /**\r\n * Updates the position of the {@link #_balloon} to make up for changes:\r\n *\r\n * * in the geometry of the selection it is attached to (e.g. the selection moved in the viewport or expanded or shrunk),\r\n * * or the geometry of the balloon toolbar itself (e.g. the toolbar has grouped or ungrouped some items and it is shorter or longer).\r\n */\r\n _updatePosition() {\r\n this._balloon.updatePosition(this._getBalloonPositionData());\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n this.stopListening();\r\n this._fireSelectionChangeDebounced.cancel();\r\n this.toolbarView.destroy();\r\n this.focusTracker.destroy();\r\n if (this._resizeObserver) {\r\n this._resizeObserver.destroy();\r\n }\r\n }\r\n /**\r\n * Returns toolbar positions for the given direction of the selection.\r\n */\r\n _getBalloonPositions(isBackward) {\r\n const isSafariIniOS = env.isSafari && env.isiOS;\r\n // https://github.com/ckeditor/ckeditor5/issues/7707\r\n const positions = isSafariIniOS ? generatePositions({\r\n // 20px when zoomed out. Less then 20px when zoomed in; the \"radius\" of the native selection handle gets\r\n // smaller as the user zooms in. No less than the default v-offset, though.\r\n heightOffset: Math.max(BalloonPanelView.arrowHeightOffset, Math.round(20 / global.window.visualViewport.scale))\r\n }) : BalloonPanelView.defaultPositions;\r\n return isBackward ? [\r\n positions.northWestArrowSouth,\r\n positions.northWestArrowSouthWest,\r\n positions.northWestArrowSouthEast,\r\n positions.northWestArrowSouthMiddleEast,\r\n positions.northWestArrowSouthMiddleWest,\r\n positions.southWestArrowNorth,\r\n positions.southWestArrowNorthWest,\r\n positions.southWestArrowNorthEast,\r\n positions.southWestArrowNorthMiddleWest,\r\n positions.southWestArrowNorthMiddleEast\r\n ] : [\r\n positions.southEastArrowNorth,\r\n positions.southEastArrowNorthEast,\r\n positions.southEastArrowNorthWest,\r\n positions.southEastArrowNorthMiddleEast,\r\n positions.southEastArrowNorthMiddleWest,\r\n positions.northEastArrowSouth,\r\n positions.northEastArrowSouthEast,\r\n positions.northEastArrowSouthWest,\r\n positions.northEastArrowSouthMiddleEast,\r\n positions.northEastArrowSouthMiddleWest\r\n ];\r\n }\r\n}\r\n/**\r\n * Returns \"true\" when the selection has multiple ranges and each range contains a selectable element\r\n * and nothing else.\r\n */\r\nfunction selectionContainsOnlyMultipleSelectables(selection, schema) {\r\n // It doesn't contain multiple objects if there is only one range.\r\n if (selection.rangeCount === 1) {\r\n return false;\r\n }\r\n return [...selection.getRanges()].every(range => {\r\n const element = range.getContainedElement();\r\n return element && schema.isSelectable(element);\r\n });\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/toolbar/block/blockbuttonview\r\n */\r\nimport ButtonView from '../../button/buttonview';\r\nimport { toUnit } from '@ckeditor/ckeditor5-utils';\r\nimport '../../../theme/components/toolbar/blocktoolbar.css';\r\nconst toPx = toUnit('px');\r\n/**\r\n * The block button view class.\r\n *\r\n * This view represents a button attached next to block element where the selection is anchored.\r\n *\r\n * See {@link module:ui/toolbar/block/blocktoolbar~BlockToolbar}.\r\n */\r\nexport default class BlockButtonView extends ButtonView {\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(locale) {\r\n super(locale);\r\n const bind = this.bindTemplate;\r\n // Hide button on init.\r\n this.isVisible = false;\r\n this.isToggleable = true;\r\n this.set('top', 0);\r\n this.set('left', 0);\r\n this.extendTemplate({\r\n attributes: {\r\n class: 'ck-block-toolbar-button',\r\n style: {\r\n top: bind.to('top', val => toPx(val)),\r\n left: bind.to('left', val => toPx(val))\r\n }\r\n }\r\n });\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\n/**\r\n * @module ui/toolbar/block/blocktoolbar\r\n */\r\n/* global window */\r\nimport { Plugin } from '@ckeditor/ckeditor5-core';\r\nimport { Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils';\r\nimport BlockButtonView from './blockbuttonview';\r\nimport BalloonPanelView from '../../panel/balloon/balloonpanelview';\r\nimport ToolbarView, { NESTED_TOOLBAR_ICONS } from '../toolbarview';\r\nimport clickOutsideHandler from '../../bindings/clickoutsidehandler';\r\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\r\nconst toPx = toUnit('px');\r\n/**\r\n * The block toolbar plugin.\r\n *\r\n * This plugin provides a button positioned next to the block of content where the selection is anchored.\r\n * Upon clicking the button, a dropdown providing access to editor features shows up, as configured in\r\n * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar}.\r\n *\r\n * By default, the button is displayed next to all elements marked in {@link module:engine/model/schema~Schema}\r\n * as `$block` for which the toolbar provides at least one option.\r\n *\r\n * By default, the button is attached so its right boundary is touching the\r\n * {@link module:engine/view/editableelement~EditableElement}:\r\n *\r\n * ```\r\n * __ |\r\n * | || This is a block of content that the\r\n * ¯¯ | button is attached to. This is a\r\n * | block of content that the button is\r\n * | attached to.\r\n * ```\r\n *\r\n * The position of the button can be adjusted using the CSS `transform` property:\r\n *\r\n * ```css\r\n * .ck-block-toolbar-button {\r\n * \ttransform: translateX( -10px );\r\n * }\r\n * ```\r\n *\r\n * ```\r\n * __ |\r\n * | | | This is a block of content that the\r\n * ¯¯ | button is attached to. This is a\r\n * | block of content that the button is\r\n * | attached to.\r\n * ```\r\n *\r\n * **Note**: If you plan to run the editor in a right–to–left (RTL) language, keep in mind the button\r\n * will be attached to the **right** boundary of the editable area. In that case, make sure the\r\n * CSS position adjustment works properly by adding the following styles:\r\n *\r\n * ```css\r\n * .ck[dir=\"rtl\"] .ck-block-toolbar-button {\r\n * \ttransform: translateX( 10px );\r\n * }\r\n * ```\r\n */\r\nexport default class BlockToolbar extends Plugin {\r\n /**\r\n * @inheritDoc\r\n */\r\n static get pluginName() {\r\n return 'BlockToolbar';\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n constructor(editor) {\r\n super(editor);\r\n /**\r\n * An instance of the resize observer that allows to respond to changes in editable's geometry\r\n * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\r\n *\r\n * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\r\n * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar configuration}.\r\n *\r\n * **Note:** Created in {@link #afterInit}.\r\n */\r\n this._resizeObserver = null;\r\n this._blockToolbarConfig = normalizeToolbarConfig(this.editor.config.get('blockToolbar'));\r\n this.toolbarView = this._createToolbarView();\r\n this.panelView = this._createPanelView();\r\n this.buttonView = this._createButtonView();\r\n // Close the #panelView upon clicking outside of the plugin UI.\r\n clickOutsideHandler({\r\n emitter: this.panelView,\r\n contextElements: [this.panelView.element, this.buttonView.element],\r\n activator: () => this.panelView.isVisible,\r\n callback: () => this._hidePanel()\r\n });\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n init() {\r\n const editor = this.editor;\r\n const t = editor.t;\r\n const editBlockText = t('Click to edit block');\r\n const dragToMoveText = t('Drag to move');\r\n const editBlockLabel = t('Edit block');\r\n const isDragDropBlockToolbarPluginLoaded = editor.plugins.has('DragDropBlockToolbar');\r\n const label = isDragDropBlockToolbarPluginLoaded ? `${editBlockText}\\n${dragToMoveText}` : editBlockLabel;\r\n this.buttonView.label = label;\r\n if (isDragDropBlockToolbarPluginLoaded) {\r\n this.buttonView.element.dataset.ckeTooltipClass = 'ck-tooltip_multi-line';\r\n }\r\n // Hides panel on a direct selection change.\r\n this.listenTo(editor.model.document.selection, 'change:range', (evt, data) => {\r\n if (data.directChange) {\r\n this._hidePanel();\r\n }\r\n });\r\n this.listenTo(editor.ui, 'update', () => this._updateButton());\r\n // `low` priority is used because of https://github.com/ckeditor/ckeditor5-core/issues/133.\r\n this.listenTo(editor, 'change:isReadOnly', () => this._updateButton(), { priority: 'low' });\r\n this.listenTo(editor.ui.focusTracker, 'change:isFocused', () => this._updateButton());\r\n // Reposition button on resize.\r\n this.listenTo(this.buttonView, 'change:isVisible', (evt, name, isVisible) => {\r\n if (isVisible) {\r\n // Keep correct position of button and panel on window#resize.\r\n this.buttonView.listenTo(window, 'resize', () => this._updateButton());\r\n }\r\n else {\r\n // Stop repositioning button when is hidden.\r\n this.buttonView.stopListening(window, 'resize');\r\n // Hide the panel when the button disappears.\r\n this._hidePanel();\r\n }\r\n });\r\n // Register the toolbar so it becomes available for Alt+F10 and Esc navigation.\r\n editor.ui.addToolbar(this.toolbarView, {\r\n beforeFocus: () => this._showPanel(),\r\n afterBlur: () => this._hidePanel()\r\n });\r\n }\r\n /**\r\n * Fills the toolbar with its items based on the configuration.\r\n *\r\n * **Note:** This needs to be done after all plugins are ready.\r\n */\r\n afterInit() {\r\n this.toolbarView.fillFromConfig(this._blockToolbarConfig, this.editor.ui.componentFactory);\r\n // Hide panel before executing each button in the panel.\r\n for (const item of this.toolbarView.items) {\r\n item.on('execute', () => this._hidePanel(true), { priority: 'high' });\r\n }\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n destroy() {\r\n super.destroy();\r\n // Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\r\n this.panelView.destroy();\r\n this.buttonView.destroy();\r\n this.toolbarView.destroy();\r\n if (this._resizeObserver) {\r\n this._resizeObserver.destroy();\r\n }\r\n }\r\n /**\r\n * Creates the {@link #toolbarView}.\r\n */\r\n _createToolbarView() {\r\n const t = this.editor.locale.t;\r\n const shouldGroupWhenFull = !this._blockToolbarConfig.shouldNotGroupWhenFull;\r\n const toolbarView = new ToolbarView(this.editor.locale, {\r\n shouldGroupWhenFull,\r\n isFloating: true\r\n });\r\n toolbarView.ariaLabel = t('Editor block content toolbar');\r\n return toolbarView;\r\n }\r\n /**\r\n * Creates the {@link #panelView}.\r\n */\r\n _createPanelView() {\r\n const editor = this.editor;\r\n const panelView = new BalloonPanelView(editor.locale);\r\n panelView.content.add(this.toolbarView);\r\n panelView.class = 'ck-toolbar-container';\r\n editor.ui.view.body.add(panelView);\r\n editor.ui.focusTracker.add(panelView.element);\r\n // Close #panelView on `Esc` press.\r\n this.toolbarView.keystrokes.set('Esc', (evt, cancel) => {\r\n this._hidePanel(true);\r\n cancel();\r\n });\r\n return panelView;\r\n }\r\n /**\r\n * Creates the {@link #buttonView}.\r\n */\r\n _createButtonView() {\r\n const editor = this.editor;\r\n const t = editor.t;\r\n const buttonView = new BlockButtonView(editor.locale);\r\n const iconFromConfig = this._blockToolbarConfig.icon;\r\n const icon = NESTED_TOOLBAR_ICONS[iconFromConfig] || iconFromConfig || NESTED_TOOLBAR_ICONS.dragIndicator;\r\n buttonView.set({\r\n label: t('Edit block'),\r\n icon,\r\n withText: false\r\n });\r\n // Bind the panelView observable properties to the buttonView.\r\n buttonView.bind('isOn').to(this.panelView, 'isVisible');\r\n buttonView.bind('tooltip').to(this.panelView, 'isVisible', isVisible => !isVisible);\r\n // Toggle the panelView upon buttonView#execute.\r\n this.listenTo(buttonView, 'execute', () => {\r\n if (!this.panelView.isVisible) {\r\n this._showPanel();\r\n }\r\n else {\r\n this._hidePanel(true);\r\n }\r\n });\r\n editor.ui.view.body.add(buttonView);\r\n editor.ui.focusTracker.add(buttonView.element);\r\n return buttonView;\r\n }\r\n /**\r\n * Shows or hides the button.\r\n * When all the conditions for displaying the button are matched, it shows the button. Hides otherwise.\r\n */\r\n _updateButton() {\r\n const editor = this.editor;\r\n const model = editor.model;\r\n const view = editor.editing.view;\r\n // Hides the button when the editor is not focused.\r\n if (!editor.ui.focusTracker.isFocused) {\r\n this._hideButton();\r\n return;\r\n }\r\n // Hides the button when the selection is in non-editable place.\r\n if (!editor.model.canEditAt(editor.model.document.selection)) {\r\n this._hideButton();\r\n return;\r\n }\r\n // Get the first selected block, button will be attached to this element.\r\n const modelTarget = Array.from(model.document.selection.getSelectedBlocks())[0];\r\n // Hides the button when there is no enabled item in toolbar for the current block element.\r\n if (!modelTarget || Array.from(this.toolbarView.items).every((item) => !item.isEnabled)) {\r\n this._hideButton();\r\n return;\r\n }\r\n // Get DOM target element.\r\n const domTarget = view.domConverter.mapViewToDom(editor.editing.mapper.toViewElement(modelTarget));\r\n // Show block button.\r\n this.buttonView.isVisible = true;\r\n // Make sure that the block toolbar panel is resized properly.\r\n this._setupToolbarResize();\r\n // Attach block button to target DOM element.\r\n this._attachButtonToElement(domTarget);\r\n // When panel is opened then refresh it position to be properly aligned with block button.\r\n if (this.panelView.isVisible) {\r\n this._showPanel();\r\n }\r\n }\r\n /**\r\n * Hides the button.\r\n */\r\n _hideButton() {\r\n this.buttonView.isVisible = false;\r\n }\r\n /**\r\n * Shows the {@link #toolbarView} attached to the {@link #buttonView}.\r\n * If the toolbar is already visible, then it simply repositions it.\r\n */\r\n _showPanel() {\r\n // Usually, the only way to show the toolbar is by pressing the block button. It makes it impossible for\r\n // the toolbar to show up when the button is invisible (feature does not make sense for the selection then).\r\n // The toolbar navigation using Alt+F10 does not access the button but shows the panel directly using this method.\r\n // So we need to check whether this is possible first.\r\n if (!this.buttonView.isVisible) {\r\n return;\r\n }\r\n const wasVisible = this.panelView.isVisible;\r\n // So here's the thing: If there was no initial panelView#show() or these two were in different order, the toolbar\r\n // positioning will break in RTL editors. Weird, right? What you show know is that the toolbar\r\n // grouping works thanks to:\r\n //\r\n // * the ResizeObserver, which kicks in as soon as the toolbar shows up in DOM (becomes visible again).\r\n // * the observable ToolbarView#maxWidth, which triggers re-grouping when changed.\r\n //\r\n // Here are the possible scenarios:\r\n //\r\n // 1. (WRONG ❌) If the #maxWidth is set when the toolbar is invisible, it won't affect item grouping (no DOMRects, no grouping).\r\n // Then, when panelView.pin() is called, the position of the toolbar will be calculated for the old\r\n // items grouping state, and when finally ResizeObserver kicks in (hey, the toolbar is visible now, right?)\r\n // it will group/ungroup some items and the length of the toolbar will change. But since in RTL the toolbar\r\n // is attached on the right side and the positioning uses CSS \"left\", it will result in the toolbar shifting\r\n // to the left and being displayed in the wrong place.\r\n // 2. (WRONG ❌) If the panelView.pin() is called first and #maxWidth set next, then basically the story repeats. The balloon\r\n // calculates the position for the old toolbar grouping state, then the toolbar re-groups items and because\r\n // it is positioned using CSS \"left\" it will move.\r\n // 3. (RIGHT ✅) We show the panel first (the toolbar does re-grouping but it does not matter), then the #maxWidth\r\n // is set allowing the toolbar to re-group again and finally panelView.pin() does the positioning when the\r\n // items grouping state is stable and final.\r\n //\r\n // https://github.com/ckeditor/ckeditor5/issues/6449, https://github.com/ckeditor/ckeditor5/issues/6575\r\n this.panelView.show();\r\n const editableElement = this._getSelectedEditableElement();\r\n this.toolbarView.maxWidth = this._getToolbarMaxWidth(editableElement);\r\n this.panelView.pin({\r\n target: this.buttonView.element,\r\n limiter: editableElement\r\n });\r\n if (!wasVisible) {\r\n this.toolbarView.items.get(0).focus();\r\n }\r\n }\r\n /**\r\n * Returns currently selected editable, based on the model selection.\r\n */\r\n _getSelectedEditableElement() {\r\n const selectedModelRootName = this.editor.model.document.selection.getFirstRange().root.rootName;\r\n return this.editor.ui.getEditableElement(selectedModelRootName);\r\n }\r\n /**\r\n * Hides the {@link #toolbarView}.\r\n *\r\n * @param focusEditable When `true`, the editable will be focused after hiding the panel.\r\n */\r\n _hidePanel(focusEditable) {\r\n this.panelView.isVisible = false;\r\n if (focusEditable) {\r\n this.editor.editing.view.focus();\r\n }\r\n }\r\n /**\r\n * Attaches the {@link #buttonView} to the target block of content.\r\n *\r\n * @param targetElement Target element.\r\n */\r\n _attachButtonToElement(targetElement) {\r\n const contentStyles = window.getComputedStyle(targetElement);\r\n const editableRect = new Rect(this._getSelectedEditableElement());\r\n const contentPaddingTop = parseInt(contentStyles.paddingTop, 10);\r\n // When line height is not an integer then treat it as \"normal\".\r\n // MDN says that 'normal' == ~1.2 on desktop browsers.\r\n const contentLineHeight = parseInt(contentStyles.lineHeight, 10) || parseInt(contentStyles.fontSize, 10) * 1.2;\r\n const buttonRect = new Rect(this.buttonView.element);\r\n const contentRect = new Rect(targetElement);\r\n let positionLeft;\r\n if (this.editor.locale.uiLanguageDirection === 'ltr') {\r\n positionLeft = editableRect.left - buttonRect.width;\r\n }\r\n else {\r\n positionLeft = editableRect.right;\r\n }\r\n const positionTop = contentRect.top + contentPaddingTop + (contentLineHeight - buttonRect.height) / 2;\r\n buttonRect.moveTo(positionLeft, positionTop);\r\n const absoluteButtonRect = buttonRect.toAbsoluteRect();\r\n this.buttonView.top = absoluteButtonRect.top;\r\n this.buttonView.left = absoluteButtonRect.left;\r\n }\r\n /**\r\n * Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly.\r\n */\r\n _setupToolbarResize() {\r\n const editableElement = this._getSelectedEditableElement();\r\n // Do this only if the automatic grouping is turned on.\r\n if (!this._blockToolbarConfig.shouldNotGroupWhenFull) {\r\n // If resize observer is attached to a different editable than currently selected editable, re-attach it.\r\n if (this._resizeObserver && this._resizeObserver.element !== editableElement) {\r\n this._resizeObserver.destroy();\r\n this._resizeObserver = null;\r\n }\r\n if (!this._resizeObserver) {\r\n this._resizeObserver = new ResizeObserver(editableElement, () => {\r\n this.toolbarView.maxWidth = this._getToolbarMaxWidth(editableElement);\r\n });\r\n }\r\n }\r\n }\r\n /**\r\n * Gets the {@link #toolbarView} max-width, based on given `editableElement` width plus the distance between the farthest\r\n * edge of the {@link #buttonView} and the editable.\r\n *\r\n * @returns A maximum width that toolbar can have, in pixels.\r\n */\r\n _getToolbarMaxWidth(editableElement) {\r\n const editableRect = new Rect(editableElement);\r\n const buttonRect = new Rect(this.buttonView.element);\r\n const isRTL = this.editor.locale.uiLanguageDirection === 'rtl';\r\n const offset = isRTL ? (buttonRect.left - editableRect.right) + buttonRect.width : editableRect.left - buttonRect.left;\r\n return toPx(editableRect.width + offset);\r\n }\r\n}\r\n","/**\r\n * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.\r\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\r\n */\r\nimport { EditorUI, normalizeToolbarConfig } from 'ckeditor5/src/ui';\r\nimport { enablePlaceholder } from 'ckeditor5/src/engine';\r\nimport { ElementReplacer, Rect } from 'ckeditor5/src/utils';\r\n/**\r\n * The classic editor UI class.\r\n */\r\nexport default class ClassicEditorUI extends EditorUI {\r\n /**\r\n * Creates an instance of the classic editor UI class.\r\n *\r\n * @param editor The editor instance.\r\n * @param view The view of the UI.\r\n */\r\n constructor(editor, view) {\r\n super(editor);\r\n this.view = view;\r\n this._toolbarConfig = normalizeToolbarConfig(editor.config.get('toolbar'));\r\n this._elementReplacer = new ElementReplacer();\r\n this.listenTo(editor.editing.view, 'scrollToTheSelection', this._handleScrollToTheSelectionWithStickyPanel.bind(this));\r\n }\r\n /**\r\n * @inheritDoc\r\n */\r\n get element() {\r\n return this.view.element;\r\n }\r\n /**\r\n * Initializes the UI.\r\n *\r\n * @param replacementElement The DOM element that will be the source for the created editor.\r\n */\r\n init(replacementElement) {\r\n const editor = this.editor;\r\n const view = this.view;\r\n const editingView = editor.editing.view;\r\n const editable = view.editable;\r\n const editingRoot = editingView.document.getRoot();\r\n // The editable UI and editing root should share the same name. Then name is used\r\n // to recognize the particular editable, for instance in ARIA attributes.\r\n editable.name = editingRoot.rootName;\r\n view.render();\r\n // The editable UI element in DOM is available for sure only after the editor UI view has been rendered.\r\n // But it can be available earlier if a DOM element has been passed to BalloonEditor.create().\r\n const editableElement = editable.element;\r\n // Register the editable UI view in the editor. A single editor instance can aggregate multiple\r\n // editable areas (roots) but the classic editor has only one.\r\n this.setEditableElement(editable.name, editableElement);\r\n // Let the editable UI element respond to the changes in the global editor focus\r\n // tracker. It has been added to the same tracker a few lines above but, in reality, there are\r\n // many focusable areas in the editor, like balloons, toolbars or dropdowns and as long\r\n // as they have focus, the editable should act like it is focused too (although technically\r\n // it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.\r\n // Doing otherwise will result in editable focus styles disappearing, once e.g. the\r\n // toolbar gets focused.\r\n view.editable.bind('isFocused').to(this.focusTracker);\r\n // Bind the editable UI element to the editing view, making it an end– and entry–point\r\n // of the editor's engine. This is where the engine meets the UI.\r\n editingView.attachDomRoot(editableElement);\r\n // If an element containing the initial data of the editor was provided, replace it with\r\n // an editor instance's UI in DOM until the editor is destroyed. For instance, a ', 'Test'], ]; - - return $tests; } } diff --git a/engine/tests/phpunit/integration/Elgg/Integration/RouterIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Integration/RouterIntegrationTest.php index 7f98db1cb5e..d8c0f29d814 100644 --- a/engine/tests/phpunit/integration/Elgg/Integration/RouterIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Integration/RouterIntegrationTest.php @@ -62,7 +62,7 @@ public function testUrlGenerationSchemeCorrection($site_url) { $this->assertEquals("{$site_url}foo/bar/test", $url); } - public function urlProvider() { + public static function urlProvider() { return [ ['http://localhost/'], ['http://localhost/sub/'], diff --git a/engine/tests/phpunit/integration/Elgg/Lib/PageOwnerIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Lib/PageOwnerIntegrationTest.php index 5575cb27f8f..b5ca84402cc 100644 --- a/engine/tests/phpunit/integration/Elgg/Lib/PageOwnerIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Lib/PageOwnerIntegrationTest.php @@ -20,7 +20,7 @@ public function testSetPageOwner($initial_guid, $new_guid, $expected) { $this->assertEquals($expected, _elgg_services()->pageOwner->getPageOwnerGuid()); } - public function setterProvider() { + public static function setterProvider() { return [ [999, 1, 1], [999, 0, 0], @@ -40,7 +40,7 @@ public function testSetPageOwnerWithSetterLibFunction($initial_guid, $new_guid, $this->assertEquals($expected, _elgg_services()->pageOwner->getPageOwnerGuid()); } - public function libSetSetterProvider() { + public static function libSetSetterProvider() { return [ [999, 1, 1], [999, 0, 0], // different behaviour in getter function @@ -76,7 +76,7 @@ public function testPageOwnerDetectedFromRoute($url_part, $match_on) { } } - public function routeProvider() { + public static function routeProvider() { return [ ['view', 'username'], ['view', 'guid'], diff --git a/engine/tests/phpunit/integration/Elgg/Navigation/MenuRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Navigation/MenuRenderingIntegrationTest.php index 7260cdc6d29..1288c03fdb7 100644 --- a/engine/tests/phpunit/integration/Elgg/Navigation/MenuRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Navigation/MenuRenderingIntegrationTest.php @@ -20,7 +20,7 @@ public function up() { $this->group = $this->createGroup(); } - public function entityMenuNamesProvider() { + public static function entityMenuNamesProvider() { return [ ['entity'], ['user_hover'], @@ -69,7 +69,7 @@ public function testEntityMenus($menu) { } } - public function layoutMenuNamesProvider() { + public static function layoutMenuNamesProvider() { return [ ['title'], ['page'], diff --git a/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php index b086d6ec69d..7a65aecb768 100644 --- a/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php @@ -57,7 +57,7 @@ public function testViewsRegistration(string $view_name, string $expected_view_o $this->assertEquals($expected_view_output, elgg_view($view_name)); } - public function viewsRegistrationProvider() { + public static function viewsRegistrationProvider() { return [ ['custom_view', 'custom view'], ['custom_directory/view1', 'view1'], diff --git a/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerCanEditGatekeeperIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerCanEditGatekeeperIntegrationTest.php index 819fd6d322e..b054519fe6d 100644 --- a/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerCanEditGatekeeperIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerCanEditGatekeeperIntegrationTest.php @@ -93,11 +93,10 @@ public function testPageOwnerCanEdit($middleware, $content_type) { 'guid' => $entity->guid, ])); - $response = _elgg_services()->router->route($http_request); - $this->assertTrue($response); + _elgg_services()->router->route($http_request); } - public function getGatekeepers() { + public static function getGatekeepers() { return [ [PageOwnerCanEditGatekeeper::class, 'object'], [UserPageOwnerCanEditGatekeeper::class, 'user'], diff --git a/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerGatekeeperIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerGatekeeperIntegrationTest.php index 47455da9ea1..7991998144d 100644 --- a/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerGatekeeperIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Router/Middleware/PageOwnerGatekeeperIntegrationTest.php @@ -87,7 +87,7 @@ public function testPageOwnerThrowsOnInvalidType($middleware, $content_type) { _elgg_services()->router->route($http_request); } - public function getGatekeepers() { + public static function getGatekeepers() { return [ [PageOwnerGatekeeper::class, 'object'], [UserPageOwnerGatekeeper::class, 'user'], @@ -95,7 +95,7 @@ public function getGatekeepers() { ]; } - public function getInvalidGatekeepers() { + public static function getInvalidGatekeepers() { return [ [UserPageOwnerGatekeeper::class, 'group'], [GroupPageOwnerGatekeeper::class, 'user'], diff --git a/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php index 9c9445c7b99..f51e247a9eb 100644 --- a/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php @@ -64,7 +64,7 @@ public function testCanDetectPublicPage($path, $expected) { $this->assertEquals($expected, $method->invokeArgs($instance, [elgg_normalize_url($path)])); } - public function publicPagesProvider() { + public static function publicPagesProvider() { return [ ['ajax/view/languages.js', true], ['css/stylesheet.css', true], @@ -116,7 +116,7 @@ public function testCanRoutePublicPageInWalledGardenMode() { elgg_set_config('walled_garden', true); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -156,7 +156,7 @@ public function testIgnoresWalledGardenRulesWhenLoggedIn() { elgg_set_config('walled_garden', true); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); diff --git a/engine/tests/phpunit/integration/Elgg/Router/RouteRegistrationServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Router/RouteRegistrationServiceIntegrationTest.php index 0ef9e27ba28..dbcbad0815c 100644 --- a/engine/tests/phpunit/integration/Elgg/Router/RouteRegistrationServiceIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Router/RouteRegistrationServiceIntegrationTest.php @@ -65,7 +65,7 @@ public function testCanGenerateRouteForUsername($username) { ])); } - public function validUsernames() { + public static function validUsernames() { return [ ['username'], ['úsernâmé'], diff --git a/engine/tests/phpunit/integration/Elgg/Search/SearchServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Search/SearchServiceIntegrationTest.php index e046627b9c7..558e0b04ca9 100644 --- a/engine/tests/phpunit/integration/Elgg/Search/SearchServiceIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Search/SearchServiceIntegrationTest.php @@ -54,7 +54,7 @@ public function testSearch($needle, $haystack, $tokenize, $partial, $count, $ent $this->assertEquals($count, $results); } - public function searchDataProvider() { + public static function searchDataProvider() { $haystack = 'Lorem ipsum dolor sit amet consectetur adipiscing elit'; $tests = [ diff --git a/engine/tests/phpunit/integration/Elgg/Security/PasswordGeneratorServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Security/PasswordGeneratorServiceIntegrationTest.php index 7c1f17a6b50..f81dbd7820a 100644 --- a/engine/tests/phpunit/integration/Elgg/Security/PasswordGeneratorServiceIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Security/PasswordGeneratorServiceIntegrationTest.php @@ -56,7 +56,7 @@ public function testAssertInvalidPasswordRequirements($min_length, $lower, $uppe _elgg_services()->passwordGenerator->assertValidPassword($password); } - public function invalidPasswordProvider() { + public static function invalidPasswordProvider() { return [ [6, null, null, null, null, '12345'], [6, 1, null, null, null, '123456'], @@ -106,7 +106,7 @@ public function testAssertValidPasswordRequirements($min_length, $lower, $upper, $this->assertEmpty(_elgg_services()->passwordGenerator->assertValidPassword($password)); } - public function validPasswordProvider() { + public static function validPasswordProvider() { return [ [6, null, null, null, null, 'ac12CD#$'], [6, 1, null, null, null, 'ac12CD#$'], @@ -247,7 +247,7 @@ public function testGetPasswordRequirementsDescription($lower, $upper, $number, $this->assertEquals(implode(' ', $result), _elgg_services()->passwordGenerator->getPasswordRequirementsDescription()); } - public function getInputRegexProvider() { + public static function getInputRegexProvider() { return [ [null, null, null, null], [0, 0, 0, 0], diff --git a/engine/tests/phpunit/integration/Elgg/UserCapabilitiesIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/UserCapabilitiesIntegrationTest.php index 22b0c775f8a..870ae308f56 100644 --- a/engine/tests/phpunit/integration/Elgg/UserCapabilitiesIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/UserCapabilitiesIntegrationTest.php @@ -84,8 +84,8 @@ public function testCanOverrideEditPermissionsWithEvent() { $this->events->registerHandler('permissions_check', 'object', function(\Elgg\Event $event) use ($entity, $user) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($user, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($user, $event->getUserParam()); $this->assertTrue($event->getValue()); return false; }); @@ -131,8 +131,8 @@ public function testCanOverrideDeletePermissionsWithEvent() { $this->events->registerHandler('permissions_check:delete', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertTrue($event->getValue()); return false; }); @@ -186,8 +186,8 @@ public function testCanOverrideContainerPermissionsWithEvent() { $this->assertInstanceOf(\ElggEntity::class, $event->getParam('container')); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getParam('container')); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getParam('container')); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertTrue($event->getValue()); return false; }); @@ -300,16 +300,15 @@ public function testCanOverrideAnnotationPermissionsWithEvent() { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); $this->assertInstanceOf(\ElggAnnotation::class, $event->getParam('annotation')); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); - $this->assertEquals($annotation, $event->getParam('annotation')); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($annotation, $event->getParam('annotation')); $this->assertTrue($event->getValue()); return false; }); $this->assertFalse($annotation->canEdit($owner->guid)); - $admin_user = $this->createUser([ 'admin' => 'yes', ]); @@ -335,21 +334,21 @@ public function testDefaultCanCommentPermissions() { ]); $entity = $this->getMockBuilder(\ElggEntity::class) - ->setMethods(['__get', 'getDisplayName', 'setDisplayName', 'getSubtype', 'getType']) // keep origin canComment method + ->onlyMethods(['__get', 'getDisplayName', 'setDisplayName', 'getSubtype', 'getType']) // keep origin canComment method ->disableOriginalConstructor() ->getMock(); $entity->expects($this->any()) ->method('__get') - ->will($this->returnValueMap([ + ->willReturnMap([ ['owner_guid', $owner->guid] - ])); + ]); $entity->expects($this->any()) ->method('getSubtype') - ->will($this->returnValue('foo')); + ->willReturn('foo'); $entity->expects($this->any()) ->method('getType') - ->will($this->returnValue('object')); + ->willReturn('object'); $this->assertFalse($owner->canComment()); $this->assertFalse($object->canComment()); @@ -409,8 +408,8 @@ public function testCanOverrideCommentingPermissionsWithEvent() { $this->events->registerHandler('permissions_check:comment', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('object', $event->getType()); $this->assertIsBool($event->getValue()); // called from ElggObject, no default value return false; @@ -456,8 +455,8 @@ public function testCanOverrideAnnotationPermissionsWithEventByAnnotationName() $this->events->registerHandler('permissions_check:annotate:baz', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('baz', $event->getParam('annotation_name')); $this->assertEquals('object', $event->getType()); $this->assertTrue($event->getValue()); @@ -486,8 +485,8 @@ public function testCanOverrideAnnotationPermissionsWithAGenericEvent() { $this->events->registerHandler('permissions_check:annotate', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('baz', $event->getParam('annotation_name')); $this->assertEquals('object', $event->getType()); $this->assertTrue($event->getValue()); @@ -516,8 +515,8 @@ public function testCanAnnotateEventSequence() { $this->events->registerHandler('permissions_check:annotate:baz', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('baz', $event->getParam('annotation_name')); $this->assertEquals('object', $event->getType()); $this->assertTrue($event->getValue()); @@ -529,8 +528,8 @@ public function testCanAnnotateEventSequence() { $this->events->registerHandler('permissions_check:annotate', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getEntityParam()); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getEntityParam()); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getEntityParam()); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('baz', $event->getParam('annotation_name')); $this->assertEquals('object', $event->getType());// return from named event return true; @@ -551,8 +550,8 @@ public function testCanOverrideContainerLogicWithEvent() { $this->events->registerHandler('container_logic_check', 'object', function(\Elgg\Event $event) use ($entity, $owner) { $this->assertInstanceOf(\ElggEntity::class, $event->getParam('container')); $this->assertInstanceOf(\ElggUser::class, $event->getUserParam()); - $this->assertEquals($entity, $event->getParam('container')); - $this->assertEquals($owner, $event->getUserParam()); + $this->assertElggDataEquals($entity, $event->getParam('container')); + $this->assertElggDataEquals($owner, $event->getUserParam()); $this->assertEquals('object', $event->getType()); $this->assertEquals('bar', $event->getParam('subtype')); $this->assertNull($event->getValue()); diff --git a/engine/tests/phpunit/integration/Elgg/Views/CommentViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/CommentViewsRenderingIntegrationTest.php index 8ce73146bfb..3a1f584a1a0 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/CommentViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/CommentViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class CommentViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'object/comment', 'forms/comment/save', diff --git a/engine/tests/phpunit/integration/Elgg/Views/DateOutputIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/DateOutputIntegrationTest.php index dc9523023eb..2c9659f8f07 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/DateOutputIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/DateOutputIntegrationTest.php @@ -17,7 +17,7 @@ public function up() { } - public function getViewNames() { + public static function getViewNames() { return [ 'input/date', 'input/time', diff --git a/engine/tests/phpunit/integration/Elgg/Views/ElggIconMappingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/ElggIconMappingIntegrationTest.php index bbee009471e..50336799637 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/ElggIconMappingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/ElggIconMappingIntegrationTest.php @@ -4,7 +4,7 @@ class ElggIconMappingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'output/icon', ]; diff --git a/engine/tests/phpunit/integration/Elgg/Views/GroupViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/GroupViewsRenderingIntegrationTest.php index dd547512724..565f2da4da4 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/GroupViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/GroupViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class GroupViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'group/elements/summary', 'group/default', diff --git a/engine/tests/phpunit/integration/Elgg/Views/HtmlFormatterIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/HtmlFormatterIntegrationTest.php index d5f867e86bb..aabdb1f076c 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/HtmlFormatterIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/HtmlFormatterIntegrationTest.php @@ -17,21 +17,25 @@ public function up() { $this->service = _elgg_services()->html_formatter; } - /** - * @dataProvider mentionsProvider - */ - public function testParseMentions($input, $expected) { - $result = $this->service->parseMentions($input); - - $this->assertEquals($expected, $result); - - // doing this again shouldn't change anything - $result = $this->service->parseMentions($result); - - $this->assertEquals($expected, $result); + public function testParseMentions() { + $test_data = $this->getMentionsTestData(); + foreach ($test_data as $test_array) { + $input = $test_array['input']; + $expected = $test_array['expected']; + + $result = $this->service->parseMentions($input); + + $this->assertEquals($expected, $result); + + // doing this again shouldn't change anything + $result = $this->service->parseMentions($result); + + $this->assertEquals($expected, $result); + } } - public function mentionsProvider() { + // not using a static provider as we need an instanciated user + protected function getMentionsTestData() { $user = $this->createUser(); $mention_url = elgg_view_url($user->getURL(), "@{$user->username}"); diff --git a/engine/tests/phpunit/integration/Elgg/Views/ListingViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/ListingViewsRenderingIntegrationTest.php index 784d34bd70d..727eb496142 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/ListingViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/ListingViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class ListingViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'page/components/list', 'page/components/gallery', diff --git a/engine/tests/phpunit/integration/Elgg/Views/ObjectViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/ObjectViewsRenderingIntegrationTest.php index 0b71b503615..1d34c4b1a60 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/ObjectViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/ObjectViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class ObjectViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'object/default', 'object/elements/access', diff --git a/engine/tests/phpunit/integration/Elgg/Views/PageElementViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/PageElementViewsRenderingIntegrationTest.php index 1b413f6cd54..9feccc3fbff 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/PageElementViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/PageElementViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class PageElementViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'errors/400', 'errors/403', diff --git a/engine/tests/phpunit/integration/Elgg/Views/RiverViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/RiverViewsRenderingIntegrationTest.php index 08b922a5450..a41f51fe290 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/RiverViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/RiverViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class RiverViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'river/elements/body', 'river/elements/image', diff --git a/engine/tests/phpunit/integration/Elgg/Views/UrlOutputIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/UrlOutputIntegrationTest.php index 81a6a724b07..d71a0916096 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/UrlOutputIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/UrlOutputIntegrationTest.php @@ -4,7 +4,7 @@ class UrlOutputIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return ['output/url']; } @@ -49,8 +49,7 @@ public function testCanRenderAnchorWithText($text_input, $text_output) { ]); } - public function anchorTextProvider() { - + public static function anchorTextProvider() { return [ [ 'text_input' => 'sample text', diff --git a/engine/tests/phpunit/integration/Elgg/Views/UserViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/UserViewsRenderingIntegrationTest.php index 66756e4dbd4..80730ee3356 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/UserViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/UserViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class UserViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { return [ 'core/avatar/upload', 'core/settings/account/default_access', diff --git a/engine/tests/phpunit/integration/Elgg/Views/WidgetViewsRenderingIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Views/WidgetViewsRenderingIntegrationTest.php index 245c50e4da6..6a89130471e 100644 --- a/engine/tests/phpunit/integration/Elgg/Views/WidgetViewsRenderingIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Views/WidgetViewsRenderingIntegrationTest.php @@ -4,7 +4,7 @@ class WidgetViewsRenderingIntegrationTest extends ViewRenderingIntegrationTestCase { - public function getViewNames() { + public static function getViewNames() { $views = [ 'forms/widgets/save', 'object/widget', diff --git a/engine/tests/phpunit/integration/ElggMenuBuilderIntegrationTest.php b/engine/tests/phpunit/integration/ElggMenuBuilderIntegrationTest.php index 06aaaef9173..d79b9a5691e 100644 --- a/engine/tests/phpunit/integration/ElggMenuBuilderIntegrationTest.php +++ b/engine/tests/phpunit/integration/ElggMenuBuilderIntegrationTest.php @@ -95,7 +95,7 @@ public function testGetMenuSorting($sort_by, $expected) { $this->assertEquals($expected, $actual_order); } - public function getMenuSortingProvider() { + public static function getMenuSortingProvider() { return [ ['priority', ['b_menu_item', 'c_menu_item', 'a_menu_item']], ['text', ['c_menu_item', 'b_menu_item', 'a_menu_item']], @@ -127,7 +127,7 @@ public function testFilterByContext($context, $expected) { $this->assertEquals($expected, $actual_order); } - public function filterByContextProvider() { + public static function filterByContextProvider() { return [ [null, ['b_menu_item', 'c_menu_item', 'a_menu_item']], ['foo', ['b_menu_item', 'a_menu_item']], diff --git a/engine/tests/phpunit/integration/ElggRiverItemIntegrationTest.php b/engine/tests/phpunit/integration/ElggRiverItemIntegrationTest.php index 5f40d232420..d27793648b6 100644 --- a/engine/tests/phpunit/integration/ElggRiverItemIntegrationTest.php +++ b/engine/tests/phpunit/integration/ElggRiverItemIntegrationTest.php @@ -67,7 +67,7 @@ public function testGetSubjectEntity() { $subject = $item->getSubjectEntity(); $this->assertInstanceOf(\ElggEntity::class, $subject); - $this->assertEquals($this->subject, $subject); + $this->assertElggDataEquals($this->subject, $subject); } public function testGetTargetEntity() { @@ -75,7 +75,7 @@ public function testGetTargetEntity() { $target = $item->getTargetEntity(); $this->assertInstanceOf(\ElggEntity::class, $target); - $this->assertEquals($this->target, $target); + $this->assertElggDataEquals($this->target, $target); } public function testGetObjectEntity() { @@ -83,7 +83,7 @@ public function testGetObjectEntity() { $object = $item->getObjectEntity(); $this->assertInstanceOf(\ElggEntity::class, $object); - $this->assertEquals($this->object, $object); + $this->assertElggDataEquals($this->object, $object); } public function testGetAnnotation() { diff --git a/engine/tests/phpunit/integration/ElggUserIntegrationTest.php b/engine/tests/phpunit/integration/ElggUserIntegrationTest.php index f6dbe9917d9..c5498fed51b 100644 --- a/engine/tests/phpunit/integration/ElggUserIntegrationTest.php +++ b/engine/tests/phpunit/integration/ElggUserIntegrationTest.php @@ -43,7 +43,7 @@ public function testSetCorrectAdminValue($value, $boolean_value) { $this->assertEquals($boolean_value, $user->isAdmin()); } - public function correctAdminBannedValues() { + public static function correctAdminBannedValues() { return [ ['no', false], ['yes', true], diff --git a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ActionsRegistrationIntegrationTest.php b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ActionsRegistrationIntegrationTest.php index a7153ffe7b1..1e725450ee3 100644 --- a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ActionsRegistrationIntegrationTest.php +++ b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ActionsRegistrationIntegrationTest.php @@ -6,15 +6,15 @@ class ActionsRegistrationIntegrationTest extends RegistrationIntegrationTestCase { - protected function registerPluginActions(\ElggPlugin $plugin) { + protected static function registerPluginActions(\ElggPlugin $plugin) { $plugin->register(); $plugin->boot(); $plugin->init(); $plugin->getBootstrap()->ready(); } - public function actionsProvider(): array { - $this->createApplication([ + public static function actionsProvider(): array { + self::createApplication([ 'isolate' => true, ]); @@ -26,7 +26,7 @@ public function actionsProvider(): array { _elgg_services()->reset('routes'); _elgg_services()->reset('routeCollection'); - $this->registerPluginActions($plugin); + self::registerPluginActions($plugin); $actions = _elgg_services()->actions->getAllActions(); foreach ($actions as $name => $params) { diff --git a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/TranslationsIntegrationTest.php b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/TranslationsIntegrationTest.php index dd0e5e31e24..3f8b0cc9606 100644 --- a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/TranslationsIntegrationTest.php +++ b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/TranslationsIntegrationTest.php @@ -26,8 +26,8 @@ public function up() { * * @return array */ - public function languageProvider(): array { - $this->createApplication([ + public static function languageProvider(): array { + self::createApplication([ 'isolate' => true, ]); diff --git a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php index 65e4c540d56..a7c7efef7eb 100644 --- a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php +++ b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php @@ -15,6 +15,9 @@ class ViewStackIntegrationTest extends PluginsIntegrationTestCase { public function up() { parent::up(); + elgg_set_config('system_cache_loaded', false); + _elgg_services()->reset('views'); + $this->views = _elgg_services()->views; } @@ -23,7 +26,7 @@ public function up() { * * @return array */ - public function viewsProvider(): array { + public static function viewsProvider(): array { self::createApplication([ 'isolate' => true, ]); @@ -36,9 +39,13 @@ public function viewsProvider(): array { continue; } + elgg_set_config('system_cache_loaded', false); _elgg_services()->reset('views'); - $this->startPlugin($plugin->getID(), false); + // can not use ->startPlugin() as it needs to be static + $plugin->register(); + $plugin->boot(); + $plugin->init(); $data = _elgg_services()->views->getInspectorData(); foreach ($data['locations'] as $viewtype => $views) { @@ -49,7 +56,6 @@ public function viewsProvider(): array { $viewtype, $path, elgg_extract($view, $data['simplecache'], false), - $plugin->getID(), ]; } } diff --git a/engine/tests/phpunit/unit/Elgg/ActionsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/ActionsServiceUnitTest.php index c59db4bc50e..9c684116ea4 100644 --- a/engine/tests/phpunit/unit/Elgg/ActionsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/ActionsServiceUnitTest.php @@ -190,7 +190,7 @@ public function testCanCheckActionNamesForSanity($name) { _elgg_services()->actions->register($name, "{$this->actionsDir}/output.php", 'public'); } - public function invalidActionNamesDataProvider() { + public static function invalidActionNamesDataProvider() { return [ ['http://test/test'], ['test//test'], diff --git a/engine/tests/phpunit/unit/Elgg/Application/ServeFileHandlerUnitTest.php b/engine/tests/phpunit/unit/Elgg/Application/ServeFileHandlerUnitTest.php index 0fb2007800c..391690a0a2e 100644 --- a/engine/tests/phpunit/unit/Elgg/Application/ServeFileHandlerUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Application/ServeFileHandlerUnitTest.php @@ -26,7 +26,7 @@ public function down() { } } - function createRequest(\Elgg\FileService\File $file) { + protected function createRequest(\Elgg\FileService\File $file) { $site_url = elgg_get_site_url(); $url = $file->getURL(); $path = substr($url, strlen($site_url)); @@ -39,7 +39,7 @@ function createRequest(\Elgg\FileService\File $file) { return $request; } - function fileProvider() { + public static function fileProvider() { return [ // Using special characters to test against files that have been // uploaded prior to implementation of filename sanitization @@ -52,7 +52,7 @@ function fileProvider() { ]; } - function createFile($filename) { + protected function createFile($filename) { $this->assertNotEmpty($filename); $file = new \ElggFile(); @@ -270,5 +270,4 @@ public function testSends304WithIfNoneMatchHeadersIncludedAndDeflationEnabled($f $this->assertTrue($test_file->delete()); unset($this->file); } - } diff --git a/engine/tests/phpunit/unit/Elgg/Cache/LRUCacheUnitTest.php b/engine/tests/phpunit/unit/Elgg/Cache/LRUCacheUnitTest.php index b5d44844af3..251da01efcb 100644 --- a/engine/tests/phpunit/unit/Elgg/Cache/LRUCacheUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Cache/LRUCacheUnitTest.php @@ -80,7 +80,7 @@ public function testSetGetRemove($name, $value, $default_value) { $this->assertEquals($default_value, $pool->get($name, $default_value)); } - public function setGetRemoveProvider() { + public static function setGetRemoveProvider() { return [ ['foo', 'bar', false], ['foo', 1, 'bar'], diff --git a/engine/tests/phpunit/unit/Elgg/Cli/PluginsListCommandUnitTest.php b/engine/tests/phpunit/unit/Elgg/Cli/PluginsListCommandUnitTest.php index 8d56436b9f1..7ffd42d20f7 100644 --- a/engine/tests/phpunit/unit/Elgg/Cli/PluginsListCommandUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Cli/PluginsListCommandUnitTest.php @@ -31,7 +31,7 @@ public function testCanExecuteCommand($status, $exit_code) { $this->assertEquals($exit_code, $commandTester->getStatusCode()); } - public function statusProvider() { + public static function statusProvider() { return [ [null, 1], // should default to all ['all', 0], diff --git a/engine/tests/phpunit/unit/Elgg/Database/Clauses/ComparisonClauseUnitTest.php b/engine/tests/phpunit/unit/Elgg/Database/Clauses/ComparisonClauseUnitTest.php index cf739a932e1..6bd8976de1c 100644 --- a/engine/tests/phpunit/unit/Elgg/Database/Clauses/ComparisonClauseUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Database/Clauses/ComparisonClauseUnitTest.php @@ -28,7 +28,7 @@ public function testBuildEmptyClause($operator) { $this->assertEquals(null, $clause->prepare($this->qb)); } - public function operators() { + public static function operators() { return [ ['eq'], ['in'], @@ -429,7 +429,7 @@ public function testCanCompareUsingOtherOperators($input, $type, $normalized_inp $this->assertEquals($this->qb->getParameters(), $qb->getParameters()); } - public function operatorComparison() { + public static function operatorComparison() { return [ ['%elgg', ELGG_VALUE_STRING, '%elgg', 'LIKE', 'like', 'or'], ['%elgg', ELGG_VALUE_STRING, '%elgg', 'like', 'like', 'or'], diff --git a/engine/tests/phpunit/unit/Elgg/Database/EntityTableUnitTest.php b/engine/tests/phpunit/unit/Elgg/Database/EntityTableUnitTest.php index 56f3e889305..e3e4fb279d1 100644 --- a/engine/tests/phpunit/unit/Elgg/Database/EntityTableUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Database/EntityTableUnitTest.php @@ -10,19 +10,19 @@ public function testCanGetUserForPermissionsCheckWhileLoggedOut() { $this->assertNull(_elgg_services()->entityTable->getUserForPermissionsCheck()); $user = $this->createUser(); - $this->assertEquals($user, _elgg_services()->entityTable->getUserForPermissionsCheck($user->guid)); + $this->assertElggDataEquals($user, _elgg_services()->entityTable->getUserForPermissionsCheck($user->guid)); } public function testCanGetUserForPermissionsCheckWhileLoggedIn() { $user = $this->createUser(); _elgg_services()->session_manager->setLoggedInUser($user); - $this->assertEquals($user, _elgg_services()->session_manager->getLoggedInUser()); + $this->assertElggDataEquals($user, _elgg_services()->session_manager->getLoggedInUser()); - $this->assertEquals($user, _elgg_services()->entityTable->getUserForPermissionsCheck()); + $this->assertElggDataEquals($user, _elgg_services()->entityTable->getUserForPermissionsCheck()); $user2 = $this->createUser(); - $this->assertEquals($user2, _elgg_services()->entityTable->getUserForPermissionsCheck($user2->guid)); + $this->assertElggDataEquals($user2, _elgg_services()->entityTable->getUserForPermissionsCheck($user2->guid)); } public function testThrowsWhenGettingUserForPermissionsCheckWithNonUserGuid() { diff --git a/engine/tests/phpunit/unit/Elgg/Database/QueryOptionsUnitTest.php b/engine/tests/phpunit/unit/Elgg/Database/QueryOptionsUnitTest.php index ae7f1695a62..11ad128d7e4 100644 --- a/engine/tests/phpunit/unit/Elgg/Database/QueryOptionsUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Database/QueryOptionsUnitTest.php @@ -439,7 +439,7 @@ public function testNormalizesMetadataOptionsForSinglePairInRoot($case_sensitive $this->assertEquals($expected, $pair->case_sensitive); } - public function singlePairProvider() { + public static function singlePairProvider() { return [ [null, true], [true, true], diff --git a/engine/tests/phpunit/unit/Elgg/Email/AddressUnitTest.php b/engine/tests/phpunit/unit/Elgg/Email/AddressUnitTest.php index f209a49d654..f9704c39fbb 100644 --- a/engine/tests/phpunit/unit/Elgg/Email/AddressUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Email/AddressUnitTest.php @@ -188,7 +188,7 @@ public function testSetNameHtmlDecoding($input_name, $expected_output) { $this->assertEquals($expected_output, $address->getName()); } - public function nameHtmlDecodingProvider() { + public static function nameHtmlDecodingProvider() { return [ ['Doe, John', 'Doe, John'], ['John Doe', 'John Doe'], diff --git a/engine/tests/phpunit/unit/Elgg/EntityDirLocatorUnitTest.php b/engine/tests/phpunit/unit/Elgg/EntityDirLocatorUnitTest.php index afcb0e0a137..443bc006940 100644 --- a/engine/tests/phpunit/unit/Elgg/EntityDirLocatorUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/EntityDirLocatorUnitTest.php @@ -34,7 +34,7 @@ public function testConstructorThrowsWithBadGuid($guid) { new \Elgg\EntityDirLocator($guid); } - public function badGuidsProvider() { + public static function badGuidsProvider() { return [ [0], [-123] diff --git a/engine/tests/phpunit/unit/Elgg/EntityIconServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/EntityIconServiceUnitTest.php index f66312a3e86..72e115cad66 100644 --- a/engine/tests/phpunit/unit/Elgg/EntityIconServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/EntityIconServiceUnitTest.php @@ -743,7 +743,7 @@ public function testIconDimensionsAfterResize($sw, $sh, $size, $ew, $eh, $crop, $this->assertEquals($ch, $image_size[1]); } - public function iconDimensionsProvider() { + public static function iconDimensionsProvider() { return [ // resize 600x300 source image [600, 300, 'master', 600, 300, false], diff --git a/engine/tests/phpunit/unit/Elgg/Exceptions/ExceptionInstanceUnitTest.php b/engine/tests/phpunit/unit/Elgg/Exceptions/ExceptionInstanceUnitTest.php index 0cf59683a12..4c1eb1dd2cb 100644 --- a/engine/tests/phpunit/unit/Elgg/Exceptions/ExceptionInstanceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Exceptions/ExceptionInstanceUnitTest.php @@ -20,7 +20,7 @@ public function testImplementsInterface($exception_class) { $this->assertInstanceOf('\Elgg\Exceptions\ExceptionInterface', $exception); } - public function exceptionProvider() { + public static function exceptionProvider() { $result = []; $path = Paths::elgg() . 'engine/classes/Elgg/Exceptions/'; $path = Paths::sanitize($path); diff --git a/engine/tests/phpunit/unit/Elgg/Filesystem/Directory/FlyUnitTest.php b/engine/tests/phpunit/unit/Elgg/Filesystem/Directory/FlyUnitTest.php index 44b6e0c93e9..0728e34e796 100644 --- a/engine/tests/phpunit/unit/Elgg/Filesystem/Directory/FlyUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Filesystem/Directory/FlyUnitTest.php @@ -6,7 +6,7 @@ class FlyUnitTest extends DirectoryUnitTestCase { - public function emptyDirectoryProvider() { + public static function emptyDirectoryProvider() { return [ [Fly::createInMemory()], ]; diff --git a/engine/tests/phpunit/unit/Elgg/Filesystem/MimeTypeServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/Filesystem/MimeTypeServiceUnitTest.php index 293a61762c5..b818fea9f4b 100644 --- a/engine/tests/phpunit/unit/Elgg/Filesystem/MimeTypeServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Filesystem/MimeTypeServiceUnitTest.php @@ -26,11 +26,11 @@ public function testGetMimeTypeFromValidFile($filename, $expected) { $this->assertEquals($expected, $this->service->getMimeType($filename)); } - public function validFilenameProvider() { + public static function validFilenameProvider() { return [ - [$this->normalizeTestFilePath('dataroot/1/1/300x300.jpg'), 'image/jpeg'], - [$this->normalizeTestFilePath('dataroot/1/1/400x300.gif'), 'image/gif'], - [$this->normalizeTestFilePath('dataroot/1/1/foobar.txt'), 'text/plain'], + [self::normalizeTestFilePath('dataroot/1/1/300x300.jpg'), 'image/jpeg'], + [self::normalizeTestFilePath('dataroot/1/1/400x300.gif'), 'image/gif'], + [self::normalizeTestFilePath('dataroot/1/1/foobar.txt'), 'text/plain'], ]; } @@ -72,7 +72,7 @@ public function testGetSimpleType($mimetype, $expected) { $this->assertEquals($expected, $this->service->getSimpleType($mimetype)); } - public function getSimpleTypeProvider() { + public static function getSimpleTypeProvider() { return [ ['text/html', 'document'], ['image/jpg', 'image'], @@ -107,11 +107,11 @@ public function testGetSimpleTypeFromFile($filename, $expected) { $this->assertEquals($expected, $this->service->getSimpleTypeFromFile($filename)); } - public function validSimpleTypeFilenameProvider() { + public static function validSimpleTypeFilenameProvider() { return [ - [$this->normalizeTestFilePath('dataroot/1/1/300x300.jpg'), 'image'], - [$this->normalizeTestFilePath('dataroot/1/1/400x300.gif'), 'image'], - [$this->normalizeTestFilePath('dataroot/1/1/foobar.txt'), 'document'], + [self::normalizeTestFilePath('dataroot/1/1/300x300.jpg'), 'image'], + [self::normalizeTestFilePath('dataroot/1/1/400x300.gif'), 'image'], + [self::normalizeTestFilePath('dataroot/1/1/foobar.txt'), 'document'], ]; } } diff --git a/engine/tests/phpunit/unit/Elgg/HandlerServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/HandlerServiceUnitTest.php index 4ab2fb9a0ba..575ac46654d 100644 --- a/engine/tests/phpunit/unit/Elgg/HandlerServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/HandlerServiceUnitTest.php @@ -60,7 +60,7 @@ public function testCallRequest($object_type) { $this->validateCallResult($result, true, 'request', \Elgg\Request::class); } - public function callRequestProvider() { + public static function callRequestProvider() { return [ ['middleware'], ['controller'], @@ -84,6 +84,10 @@ public function testResolveCallable() { $this->assertNull($this->service->resolveCallable([$this, 'uncallable'])); } + public function testDescribeInstancedCallable() { + $this->assertStringContainsString('(Elgg\HandlerServiceUnitTest)->callableEvent', $this->service->describeCallable([$this, 'callableEvent'], '')); + } + /** * @dataProvider describeCallableProvider */ @@ -91,12 +95,11 @@ public function testDescribeCallable($callable, $fileroot, $expected) { $this->assertStringContainsString($expected, $this->service->describeCallable($callable, $fileroot)); } - public function describeCallableProvider() { + public static function describeCallableProvider() { return [ ['some_function_name', '', 'some_function_name'], - [[$this, 'callableEvent'], '', '(Elgg\HandlerServiceUnitTest)->callableEvent'], [[__CLASS__, 'callableEvent'], '', 'Elgg\HandlerServiceUnitTest::callableEvent'], - [function() {}, __DIR__, 'HandlerServiceUnitTest.php:99'], // this is very error prone. Please keep an eye on the line number + [function() {}, __DIR__, 'HandlerServiceUnitTest.php:102'], // this is very error prone. Please keep an eye on the line number [new \Elgg\Helpers\EventsServiceTestInvokable(), __FILE__, '(Elgg\Helpers\EventsServiceTestInvokable)->__invoke()'], ]; } diff --git a/engine/tests/phpunit/unit/Elgg/Http/RequestUnitTest.php b/engine/tests/phpunit/unit/Elgg/Http/RequestUnitTest.php index 16709eb4b24..e180913d541 100644 --- a/engine/tests/phpunit/unit/Elgg/Http/RequestUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Http/RequestUnitTest.php @@ -82,7 +82,7 @@ public function testTrustedProxySettings($proxy_ips, $proxy_headers) { $this->assertEquals($proxy_headers, $request->getTrustedHeaderSet()); } - public function trustedProxySettingsProvider() { + public static function trustedProxySettingsProvider() { return [ [['192.168.0.1'], Request::HEADER_X_FORWARDED_ALL], [['192.168.0.1', '192.168.0.2'], Request::HEADER_X_FORWARDED_AWS_ELB], diff --git a/engine/tests/phpunit/unit/Elgg/Http/ResponseFactoryUnitTest.php b/engine/tests/phpunit/unit/Elgg/Http/ResponseFactoryUnitTest.php index 957bc2c503e..dc98c10fe57 100644 --- a/engine/tests/phpunit/unit/Elgg/Http/ResponseFactoryUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Http/ResponseFactoryUnitTest.php @@ -368,7 +368,7 @@ public function testCanParseContext($path, $expected) { $this->assertEquals($expected, $service->parseContext()); } - public function requestContextDataProvider() { + public static function requestContextDataProvider() { return [ ['ajax/view/foo/bar/', 'view:foo/bar'], ['ajax/form/foo/bar/baz/', 'form:foo/bar/baz'], @@ -390,7 +390,7 @@ public function testStringify($input, $expected_output) { $this->assertEquals($expected_output, $this->response_factory->stringify($input)); } - public function stringifyProvider() { + public static function stringifyProvider() { $std = new \stdClass(); $std->foo = 'bar'; diff --git a/engine/tests/phpunit/unit/Elgg/I18n/DateTimeUnitTest.php b/engine/tests/phpunit/unit/Elgg/I18n/DateTimeUnitTest.php index 7295cf4ff14..acfc0fe31a3 100644 --- a/engine/tests/phpunit/unit/Elgg/I18n/DateTimeUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/I18n/DateTimeUnitTest.php @@ -29,7 +29,7 @@ public function testFormatLocale($time, $date_format, $language, $expected) { $this->assertEquals($expected, $date->formatLocale($date_format, $language)); } - public function formatLocaleProvider() { + public static function formatLocaleProvider() { return [ ['January 9, 2018 12:00', 'l d, F Y H:i:s', 'en', 'Tuesday 09, January 2018 12:00:00'], ['January 9, 2018 12:00', 'l d, F Y H:i:s', 'nl', 'dinsdag 09, januari 2018 12:00:00'], diff --git a/engine/tests/phpunit/unit/Elgg/I18n/TranslationLoadingUnitTest.php b/engine/tests/phpunit/unit/Elgg/I18n/TranslationLoadingUnitTest.php index ad36233f59b..0aaed5d664b 100644 --- a/engine/tests/phpunit/unit/Elgg/I18n/TranslationLoadingUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/I18n/TranslationLoadingUnitTest.php @@ -13,7 +13,7 @@ class TranslationLoadingUnitTest extends UnitTestCase { * * @return array */ - public function languageProvider() { + public static function languageProvider() { self::createApplication(); _elgg_services()->translator->reloadAllTranslations(); @@ -26,7 +26,7 @@ public function languageProvider() { return $provides; } - public function coreLanguageProvider() { + public static function coreLanguageProvider() { self::createApplication(); $path = Paths::elgg() . 'languages/'; @@ -53,7 +53,7 @@ public function coreLanguageProvider() { return $provides; } - public function installationLanguageProvider() { + public static function installationLanguageProvider() { self::createApplication(); $path = Paths::elgg() . 'install/languages/'; diff --git a/engine/tests/phpunit/unit/Elgg/Notifications/SubscriptionsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/Notifications/SubscriptionsServiceUnitTest.php index d55605941d4..9f567e5865a 100644 --- a/engine/tests/phpunit/unit/Elgg/Notifications/SubscriptionsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Notifications/SubscriptionsServiceUnitTest.php @@ -38,11 +38,11 @@ public function up() { $this->event->expects($this->any()) ->method('getObject') - ->will($this->returnValue($this->object)); + ->willReturn($this->object); $this->event->expects($this->any()) ->method('getActorGUID') - ->will($this->returnValue(0)); + ->willReturn(0); $this->db = $this->createMock('\Elgg\Database'); @@ -87,7 +87,7 @@ public function testGetSubscriptionsWithBadObject() { '\Elgg\Notifications\SubscriptionNotificationEvent', ['getObject'], [], '', false); $this->event->expects($this->any()) ->method('getObject') - ->will($this->returnValue(null)); + ->willReturn(null); $methods = [ 'one', @@ -113,7 +113,7 @@ public function testQueryGenerationForRetrievingSubscriptionRelationships() { $this->db->expects($this->once()) ->method('getData') ->with($this->equalTo($select)) - ->will($this->returnValue([])); + ->willReturn([]); $this->assertEquals([], $this->service->getNotificationEventSubscriptions($this->event, $methods)); } @@ -143,7 +143,7 @@ public function testGetSubscriptionsWithProperInput() { $this->db->expects($this->once()) ->method('getData') - ->will($this->returnValue($queryResult)); + ->willReturn($queryResult); $this->assertEquals($subscriptions, $this->service->getNotificationEventSubscriptions($this->event, $methods)); } @@ -180,7 +180,7 @@ public function testGetSubscriptionsForContainerWithProperInput() { ]; $this->db->expects($this->once()) ->method('getData') - ->will($this->returnValue($queryResult)); + ->willReturn($queryResult); $this->assertEquals($subscriptions, $this->service->getSubscriptionsForContainer($container_guid, $methods)); } @@ -217,7 +217,7 @@ public function testGetEntitySubscriptionsThrowsExceptionWithInvalidTypeSubtypeA $this->service->getEntitySubscriptions($this->object->guid, $this->object->owner_guid, ['apples'], $type, $subtype, $action); } - public function invalidTypeSubtypeActionProvider() { + public static function invalidTypeSubtypeActionProvider() { return [ ['foo', null, null], [null, 'foo', null], diff --git a/engine/tests/phpunit/unit/Elgg/Project/PathsUnitTest.php b/engine/tests/phpunit/unit/Elgg/Project/PathsUnitTest.php index 0c5b2a9a147..b17e689b4d8 100644 --- a/engine/tests/phpunit/unit/Elgg/Project/PathsUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Project/PathsUnitTest.php @@ -16,7 +16,7 @@ public function testSanitize($prefix) { $this->assertEquals($expected, $path); } - public function sanitizePathProvider() { + public static function sanitizePathProvider() { return [ [''], ['/'], diff --git a/engine/tests/phpunit/unit/Elgg/RouteMatchingUnitTest.php b/engine/tests/phpunit/unit/Elgg/RouteMatchingUnitTest.php index 5cf16ba984e..977cc0043bd 100644 --- a/engine/tests/phpunit/unit/Elgg/RouteMatchingUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/RouteMatchingUnitTest.php @@ -80,7 +80,7 @@ public function testPatterns($route, $match_path, $is_match) { elgg_unregister_route('foo'); } - public function patternProvider() { + public static function patternProvider() { $config = [ [ diff --git a/engine/tests/phpunit/unit/Elgg/Router/RouteRegistrationServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/Router/RouteRegistrationServiceUnitTest.php index 8bdda30acc4..a983651878a 100644 --- a/engine/tests/phpunit/unit/Elgg/Router/RouteRegistrationServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Router/RouteRegistrationServiceUnitTest.php @@ -185,7 +185,7 @@ public function testGenerateUrlWithValidUsername($username) { * * @return array */ - public function validUsernameProvider() { + public static function validUsernameProvider() { return [ ['username'], ['úsernâmé'], @@ -218,7 +218,7 @@ public function testGenerateUrlWithInvalidUsername($username) { * * @return array */ - public function invalidUsernameProvider() { + public static function invalidUsernameProvider() { return [ ['username#'], ['username@'], diff --git a/engine/tests/phpunit/unit/Elgg/RouterUnitTest.php b/engine/tests/phpunit/unit/Elgg/RouterUnitTest.php index b6de6314427..4ea89c2e61a 100644 --- a/engine/tests/phpunit/unit/Elgg/RouterUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/RouterUnitTest.php @@ -2,56 +2,20 @@ namespace Elgg; -use Elgg\Exceptions\Http\BadRequestException ; use Elgg\Exceptions\Http\PageNotFoundException; use Elgg\Http\OkResponse; use Elgg\Http\Request; -use Elgg\I18n\Translator; -use Elgg\Router\RouteRegistrationService; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Elgg\Exceptions\Http\Gatekeeper\AjaxGatekeeperException; class RouterUnitTest extends \Elgg\UnitTestCase { - /** - * @var Request - */ - protected $request; - - /** - * @var Router - */ - protected $router; - - /** - * @var RouteRegistrationService - */ - protected $routes; - - /** - * @var string - */ - protected $pages; + protected string $viewsDir; - /** - * @var Translator - */ - protected $translator; - - /** - * @var string - */ - protected $viewsDir; - - /** - * @var int - */ - protected $fooHandlerCalls = 0; + protected int $fooHandlerCalls = 0; public function up() { - - $this->pages = $this->normalizeTestFilePath('pages'); $this->fooHandlerCalls = 0; $this->viewsDir = $this->normalizeTestFilePath('views'); @@ -109,7 +73,7 @@ protected function route(Request $request) { } public function hello_page_handler($segments, $identifier) { - include "{$this->pages}/hello.php"; + include "{$this->normalizeTestFilePath('pages')}/hello.php"; return true; } @@ -193,7 +157,7 @@ public function testCanRespondToNonAjaxRequestFromOkResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -216,7 +180,7 @@ public function testCanRespondToNonAjaxRequestFromErrorResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -242,7 +206,7 @@ public function testCanRespondToNonAjaxRequestFromRedirectResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(RedirectResponse::class, $response); @@ -264,7 +228,7 @@ public function testCanRespondToNonAjaxRequestInNonDefaultViewtype() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -288,7 +252,7 @@ public function testCanRespondToNonAjaxRequestForPageThatForwards() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(RedirectResponse::class, $response); @@ -308,7 +272,7 @@ public function testCanRespondToNonAjaxRequestForPageThatForwardsToErrorPage() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -342,7 +306,7 @@ public function testCanSafelyRedirectWithinRedirect() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -371,7 +335,7 @@ public function testCanRespondToAjaxRequestFromOkResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -399,7 +363,7 @@ public function testCanRespondToAjaxRequestFromErrorResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -427,7 +391,7 @@ public function testCanRespondToAjaxRequestFromRedirectResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -456,7 +420,7 @@ public function testCanRespondToAjaxRequestInNonDefaultViewtype() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -481,7 +445,7 @@ public function testCanRespondToAjaxRequestForPageThatForwards() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -507,7 +471,7 @@ public function testCanRespondToAjaxRequestForPageThatForwardsToErrorPage() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -537,7 +501,7 @@ public function testCanRespondToAjax2RequestFromOkResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -571,7 +535,7 @@ public function testCanRespondToAjax2RequestFromErrorResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -601,7 +565,7 @@ public function testCanRespondToAjax2RequestFromRedirectResponseBuilder() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -637,7 +601,7 @@ public function testCanRespondToAjax2RequestInNonDefaultViewtype() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -674,7 +638,7 @@ public function testCanRespondToAjax2RequestForPageThatForwards() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -709,7 +673,7 @@ public function testCanRespondToAjax2RequestForPageThatForwardsToErrorPage() { }, ]); - $this->assertTrue($this->route($request)); + $this->route($request); $response = _elgg_services()->responseFactory->getSentResponse(); $this->assertInstanceOf(Response::class, $response); @@ -1070,7 +1034,10 @@ public function testCanRespondToAjax2ViewRequestForARegisteredViewWhichForwards( $this->assertInstanceOf(Response::class, $response); $this->assertEquals(ELGG_HTTP_BAD_REQUEST, $response->getStatusCode()); $this->assertStringContainsString('application/json', $response->headers->get('Content-Type')); - + + // compensate for fact that ResponseFactory::redirect closes a buffer it didn't open + ob_start(); + /** * @todo: decide what the output should be * Do we use the buffer output when responding with error to Ajax2? diff --git a/engine/tests/phpunit/unit/Elgg/Security/CryptoUnitTest.php b/engine/tests/phpunit/unit/Elgg/Security/CryptoUnitTest.php index d719028c619..d54be6091d1 100644 --- a/engine/tests/phpunit/unit/Elgg/Security/CryptoUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Security/CryptoUnitTest.php @@ -9,12 +9,12 @@ class CryptoUnitTest extends \Elgg\UnitTestCase { public function up() { $this->stub = $this->getMockBuilder('\Elgg\Security\Crypto') - ->setMethods(array('getRandomBytes')) + ->addMethods(['getRandomBytes']) ->getMock(); $this->stub->expects($this->any()) ->method('getRandomBytes') - ->will($this->returnCallback(array($this, 'mock_getRandomBytes'))); + ->willReturnCallback([$this, 'mock_getRandomBytes']); } protected function getCrypto() { diff --git a/engine/tests/phpunit/unit/Elgg/Security/UrlSignerUnitTest.php b/engine/tests/phpunit/unit/Elgg/Security/UrlSignerUnitTest.php index 8f37df40265..a4084ae240e 100644 --- a/engine/tests/phpunit/unit/Elgg/Security/UrlSignerUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Security/UrlSignerUnitTest.php @@ -5,7 +5,7 @@ use Elgg\Exceptions\HttpException; use Elgg\Exceptions\InvalidArgumentException; -class SignedUrlUnitTest extends \Elgg\UnitTestCase { +class UrlSignerUnitTest extends \Elgg\UnitTestCase { protected UrlSigner $service; protected string $url; diff --git a/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php b/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php index 2aa6ea62571..a0c27865cab 100644 --- a/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Traits/SeedingUnitTest.php @@ -68,7 +68,7 @@ public function testCreateObjectTags($input) { } } - public function propertyProvider() { + public static function propertyProvider() { return [ [true], [false], diff --git a/engine/tests/phpunit/unit/Elgg/Upgrade/LocatorUnitTest.php b/engine/tests/phpunit/unit/Elgg/Upgrade/LocatorUnitTest.php index 55826ce2520..29d774c92bc 100644 --- a/engine/tests/phpunit/unit/Elgg/Upgrade/LocatorUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Upgrade/LocatorUnitTest.php @@ -16,13 +16,13 @@ class LocatorUnitTest extends \Elgg\UnitTestCase { public function up() { $this->plugin = $this->getMockBuilder(\ElggPlugin::class) ->disableOriginalConstructor() - ->setMethods(['getStaticConfig', 'getID']) + ->onlyMethods(['getStaticConfig', 'getID']) ->getMock(); $this->plugin ->expects($this->any()) ->method('getID') - ->will($this->returnValue('test_plugin')); + ->willReturn('test_plugin'); } public function testRunner() { diff --git a/engine/tests/phpunit/unit/Elgg/Users/AccountsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/Users/AccountsServiceUnitTest.php index c7a3eb6f4f2..96389a618d5 100644 --- a/engine/tests/phpunit/unit/Elgg/Users/AccountsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Users/AccountsServiceUnitTest.php @@ -12,7 +12,7 @@ class AccountsServiceUnitTest extends UnitTestCase { /** * @var int minimal username length during testing */ - protected $minusername = 6; + protected const MINUSERNAME = 6; /** * @var int backup of the config setting for minimal username length @@ -21,7 +21,7 @@ class AccountsServiceUnitTest extends UnitTestCase { public function up() { $this->minusername_backup = elgg()->config->minusername; - elgg()->config->minusername = $this->minusername; + elgg()->config->minusername = self::MINUSERNAME; } public function down() { @@ -41,9 +41,9 @@ public function testInvalidUsernameFailsValidation($username) { * * @return array */ - public function invalidUsernameProvider() { + public static function invalidUsernameProvider() { return [ - [str_repeat('a', $this->minusername - 1)], // too short + [str_repeat('a', self::MINUSERNAME - 1)], // too short [str_repeat('a', 129)], // too long, this is hard coded ['username#'], ['username@'], @@ -68,7 +68,7 @@ public function testValidUsername($username) { * * @return array */ - public function validUsernameProvider() { + public static function validUsernameProvider() { return [ ['username'], ['úsernâmé'], diff --git a/engine/tests/phpunit/unit/Elgg/ValuesUnitTest.php b/engine/tests/phpunit/unit/Elgg/ValuesUnitTest.php index 9f07b79689a..dc8f9f35080 100644 --- a/engine/tests/phpunit/unit/Elgg/ValuesUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/ValuesUnitTest.php @@ -18,7 +18,7 @@ public function testCanNormalizeTime($time) { $this->assertEquals($dt->getTimestamp(), Values::normalizeTimestamp($time)); } - public function timeProvider() { + public static function timeProvider() { return [ ['January 9, 2018 12:00'], [1515496794], @@ -37,7 +37,7 @@ public function testIsEmpty($value, $expected_result) { $this->assertEquals($expected_result, Values::isEmpty($value)); } - public function emptyProvider() { + public static function emptyProvider() { return [ [0, false], [0.0, false], @@ -67,7 +67,7 @@ public function testSetTimeAfterNormalize($timezone) { $this->assertEquals($time, $dt->getTimestamp()); } - public function timezoneProvider() { + public static function timezoneProvider() { return [ ['UTC'], ['Australia/Adelaide'], @@ -83,7 +83,7 @@ public function testCanShortenNumber($number, $precision, $expected) { $this->assertEquals($expected, Values::shortFormatOutput($number, $precision)); } - public function shortNumberProvider() { + public static function shortNumberProvider() { return [ ['a', 1, 'a'], [1, 1, 1], diff --git a/engine/tests/phpunit/unit/Elgg/Views/AutoParagraphUnitTest.php b/engine/tests/phpunit/unit/Elgg/Views/AutoParagraphUnitTest.php index 56dcd33ca44..3367d1eab80 100644 --- a/engine/tests/phpunit/unit/Elgg/Views/AutoParagraphUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Views/AutoParagraphUnitTest.php @@ -42,8 +42,8 @@ public function testProcess($test, $in, $exp) { $this->assertEquals($exp, $out, "Equality case {$test}"); } - public function provider() { - $d = dir($this->normalizeTestFilePath('autop/')); + public static function provider() { + $d = dir(self::normalizeTestFilePath('autop/')); $tests = array(); while (false !== ($entry = $d->read())) { $matches = []; diff --git a/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php b/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php index 1699c7616e4..6ba7f9abdc2 100644 --- a/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php @@ -11,7 +11,7 @@ public function up() { _elgg_services()->views->registerPluginViews(Paths::elgg()); } - public function viewsProvider() { + public static function viewsProvider() { self::createApplication(); diff --git a/engine/tests/phpunit/unit/Elgg/Views/HtmlFormatterUnitTest.php b/engine/tests/phpunit/unit/Elgg/Views/HtmlFormatterUnitTest.php index 15770ef0129..0d7974e7946 100644 --- a/engine/tests/phpunit/unit/Elgg/Views/HtmlFormatterUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Views/HtmlFormatterUnitTest.php @@ -26,7 +26,7 @@ public function testCanFormatHTMLBlock($before, $after) { $this->assertXmlStringEqualsXmlString($after, $actual); } - public function htmlBlockProvider() { + public static function htmlBlockProvider() { $attrs = _elgg_services()->html_formatter->formatAttributes([ 'foo' => 'http://example.com', @@ -148,7 +148,7 @@ public function testElggFormatElementThrows() { elgg_format_element(''); } - function providerElggFormatElement() { + public static function providerElggFormatElement() { $data = [ 'a & b' => array( 'tag_name' => 'span', @@ -200,7 +200,7 @@ public function testElggGetFriendlyTime($num_seconds, $friendlytime) { $this->assertSame(elgg_get_friendly_time($current_time + $num_seconds, $current_time), $friendlytime); } - function providerElggGetFriendlyTime() { + public static function providerElggGetFriendlyTime() { self::createApplication(); return [ diff --git a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php index 5ff0306232b..9704d29c57a 100644 --- a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php @@ -239,7 +239,7 @@ public function testPreventUnExtendOfSelf() { ], $list); } - public function getExampleNormalizedViews() { + public static function getExampleNormalizedViews() { return [ // [canonical, alias] // js namespace should be removed and .js added to all JS views diff --git a/engine/tests/phpunit/unit/ElggAccessCollectionUnitTest.php b/engine/tests/phpunit/unit/ElggAccessCollectionUnitTest.php index 3148d435be6..82bc599b051 100644 --- a/engine/tests/phpunit/unit/ElggAccessCollectionUnitTest.php +++ b/engine/tests/phpunit/unit/ElggAccessCollectionUnitTest.php @@ -14,7 +14,7 @@ public function testSetterWithInvalidValues($name, $value) { $acl->$name = $value; } - public function invalidValuesProvider() { + public static function invalidValuesProvider() { return [ ['subtype', str_repeat('a', 300)], ['name', ''], diff --git a/engine/tests/phpunit/unit/ElggCallUnitTest.php b/engine/tests/phpunit/unit/ElggCallUnitTest.php index c40e8337b94..ebe39e705ec 100644 --- a/engine/tests/phpunit/unit/ElggCallUnitTest.php +++ b/engine/tests/phpunit/unit/ElggCallUnitTest.php @@ -69,7 +69,7 @@ public function testCanCallWithFlags($access_before, $disabled_before, $ignore_a elgg()->session_manager->setDisabledEntityVisibility($ha); } - public function flagsDataProvider() { + public static function flagsDataProvider() { return [ [false, false, false, false], [false, false, false, true], diff --git a/engine/tests/phpunit/unit/ElggCoreUrlHelpersUnitTest.php b/engine/tests/phpunit/unit/ElggCoreUrlHelpersUnitTest.php index 8033c76110e..dfc9db94b68 100644 --- a/engine/tests/phpunit/unit/ElggCoreUrlHelpersUnitTest.php +++ b/engine/tests/phpunit/unit/ElggCoreUrlHelpersUnitTest.php @@ -14,7 +14,7 @@ public function testElggHttpAddURLQueryElementsPreserveURL($input, $params, $out $this->assertEquals($output, elgg_http_add_url_query_elements($input, $params)); } - function providerElggHttpAddURLQueryElementsPreserveURL() { + public static function providerElggHttpAddURLQueryElementsPreserveURL() { return[ array('', array(), '?'), array('/', array(), '/'), @@ -48,7 +48,7 @@ public function testElggHttpAddURLQueryElementsAddElements($input, $params, $out $this->assertEquals($output, elgg_http_add_url_query_elements($input, $params)); } - function providerElggHttpAddURLQueryElementsAddElements() { + public static function providerElggHttpAddURLQueryElementsAddElements() { return [ array('', array('foo' => 'bar'), '?foo=bar'), array('/', array('foo' => 'bar'), '/?foo=bar'), @@ -86,7 +86,7 @@ public function testElggHttpAddURLQueryElementsRemoveElements($input, $params, $ } } - function providerElggHttpAddURLQueryElementsRemoveElements() { + public static function providerElggHttpAddURLQueryElementsRemoveElements() { return [ array('?foo=bar', array('foo' => ''), '?foo='), array('?foo=bar', array('foo' => 0), '?foo=0'), @@ -127,7 +127,7 @@ public function testHttpUrlIsIdentical($input, $output) { $this->assertTrue(elgg_http_url_is_identical($input, $output), "Failed to determine URLs as identical for: '$input' and '$output'"); } - function providerHttpUrlIsIdentical() { + public static function providerHttpUrlIsIdentical() { self::createApplication(); $data = [ @@ -187,7 +187,7 @@ public function testHttpUrlIsNotIdentical($input, $output) { $this->assertFalse(elgg_http_url_is_identical($input, $output), "Failed to determine URLs as NOT identical for: '$input' and '$output'"); } - function providerHttpUrlIsNotIdentical() { + public static function providerHttpUrlIsNotIdentical() { self::createApplication(); $data = [ @@ -219,7 +219,7 @@ public function testHttpUrlIsIdenticalIgnoreParamsHandling($url1, $url2, $ignore . ($result ? 'identical' : 'different') . " for: '$url2', '$url1' and ignore params set to " . print_r($ignore_params, true)); } - function providerHttpUrlIsIdenticalIgnoreParamsHandling() { + public static function providerHttpUrlIsIdenticalIgnoreParamsHandling() { self::createApplication(); return [ diff --git a/engine/tests/phpunit/unit/ElggEntityUnitTest.php b/engine/tests/phpunit/unit/ElggEntityUnitTest.php index ada96d829ad..bc3ab8db155 100644 --- a/engine/tests/phpunit/unit/ElggEntityUnitTest.php +++ b/engine/tests/phpunit/unit/ElggEntityUnitTest.php @@ -8,17 +8,11 @@ */ class ElggEntityUnitTest extends \Elgg\UnitTestCase { - /** @var \ElggEntity */ + /** @var \ElggObject */ protected $obj; public function up() { - $this->obj = $this->getMockForAbstractClass('\ElggObject'); - $reflection = new ReflectionClass('\ElggObject'); - $method = $reflection->getMethod('initializeAttributes'); - if (method_exists($method, 'setAccessible')) { - $method->setAccessible(true); - $method->invokeArgs($this->obj, array()); - } + $this->obj = new \ElggObject(); } public function testDefaultAttributes() { @@ -55,7 +49,7 @@ public function testUnsettingProtectedAttributeThrowsException($attribute) { unset($this->obj->$attribute); } - public function protectedAttributeProvider() { + public static function protectedAttributeProvider() { return [ ['subtype'], ['enabled'], @@ -76,7 +70,7 @@ public function testSettingIntegerAttributes($attribute) { $this->assertSame(77, $this->obj->$attribute); } - public function integerAttributeProvider() { + public static function integerAttributeProvider() { return [ ['access_id'], ['owner_guid'], @@ -92,7 +86,7 @@ public function testSettingUnsettableAttributes($attribute) { $this->assertNotEquals('foo', $this->obj->$attribute); } - public function unsettableAttributeProvider() { + public static function unsettableAttributeProvider() { return [ ['guid'], ['last_action'], @@ -142,7 +136,7 @@ public function testUnsetSuccessfullAttribute($attribute, $value) { $this->assertEquals('', $this->obj->$attribute); } - public function unsetSuccessfullProvider() { + public static function unsetSuccessfullProvider() { return [ ['access_id', 2], @@ -161,7 +155,7 @@ public function testUnsetUnsuccessfullAttribute($attribute, $value) { $this->assertEquals($current_value, $this->obj->$attribute); } - public function unsetUnsuccessfullProvider() { + public static function unsetUnsuccessfullProvider() { return [ ['guid', 123456], ['last_action', 1234], @@ -216,7 +210,7 @@ public function testSetLatLong($lat, $long) { $this->assertEquals($long, $this->obj->getLongitude()); } - public function latLongProvider() { + public static function latLongProvider() { return [ [1, 2], [1.13, 222.132], diff --git a/engine/tests/phpunit/unit/ElggExtenderUnitTest.php b/engine/tests/phpunit/unit/ElggExtenderUnitTest.php index bee4a82218a..f76d5c82d3d 100644 --- a/engine/tests/phpunit/unit/ElggExtenderUnitTest.php +++ b/engine/tests/phpunit/unit/ElggExtenderUnitTest.php @@ -1,22 +1,24 @@ getMockForAbstractClass('\ElggExtender'); + $obj = new ElggExtenderExtension(); + $obj->name = 'comment'; $this->assertEquals('comment', $obj->name); } public function testGettingNonexistentAttribute() { - $obj = $this->getMockForAbstractClass('\ElggExtender'); + $obj = new ElggExtenderExtension(); $this->assertNull($obj->foo); } public function testSettingValueAttribute() { - $obj = $this->getMockForAbstractClass('\ElggExtender'); + $obj = new ElggExtenderExtension(); $obj->value = '36'; $this->assertSame('36', $obj->value); $this->assertEquals('text', $obj->value_type); @@ -26,7 +28,7 @@ public function testSettingValueAttribute() { } public function testSettingValueExplicitly() { - $obj = $this->getMockForAbstractClass('\ElggExtender'); + $obj = new ElggExtenderExtension(); $obj->setValue('36', 'integer'); $this->assertSame(36, $obj->value); $this->assertEquals('integer', $obj->value_type); diff --git a/engine/tests/phpunit/unit/ElggFileUnitTest.php b/engine/tests/phpunit/unit/ElggFileUnitTest.php index ee6c23a5bc1..3cab97c5b4b 100644 --- a/engine/tests/phpunit/unit/ElggFileUnitTest.php +++ b/engine/tests/phpunit/unit/ElggFileUnitTest.php @@ -54,7 +54,7 @@ public function testCanParseSimpleType($mime_type, $simple_type) { $this->assertEquals($simple_type, $this->file->getSimpleType()); } - function providerSimpleTypeMap() { + public static function providerSimpleTypeMap() { return [ [ 'x-world/x-svr', @@ -471,7 +471,7 @@ public function testPathTraversal($filename, $expected_filename, $expected_path) $this->assertEquals($expected_path, $file->getFilenameOnFilestore()); } - public function pathTraversalProvider() { + public static function pathTraversalProvider() { $dataroot = elgg_get_data_path(); return [ diff --git a/engine/tests/phpunit/unit/ElggInstallerUnitTest.php b/engine/tests/phpunit/unit/ElggInstallerUnitTest.php index 0109cbab2e0..56218e32d17 100644 --- a/engine/tests/phpunit/unit/ElggInstallerUnitTest.php +++ b/engine/tests/phpunit/unit/ElggInstallerUnitTest.php @@ -30,7 +30,7 @@ protected function getMock(array $methods = []) { ->getMock(); foreach ($methods as $method => $callback) { - $mock->method($method)->will($this->returnCallback($callback)); + $mock->method($method)->willReturnCallback($callback); } return $mock; diff --git a/engine/tests/phpunit/unit/ElggMenuItemUnitTest.php b/engine/tests/phpunit/unit/ElggMenuItemUnitTest.php index 7a4b6d598cc..a4ddd4eb8f7 100644 --- a/engine/tests/phpunit/unit/ElggMenuItemUnitTest.php +++ b/engine/tests/phpunit/unit/ElggMenuItemUnitTest.php @@ -215,7 +215,7 @@ public function testArgumentTypeValidationOnItemRegistrationWithFails($options) elgg_register_menu_item('foo', $options); } - public function invalidMenuRegistrationOptions() { + public static function invalidMenuRegistrationOptions() { return [ [[]], [['text' => 'bar']], diff --git a/engine/tests/phpunit/unit/ElggRelationshipUnitTest.php b/engine/tests/phpunit/unit/ElggRelationshipUnitTest.php index 572ba336b4b..1f052537c4c 100644 --- a/engine/tests/phpunit/unit/ElggRelationshipUnitTest.php +++ b/engine/tests/phpunit/unit/ElggRelationshipUnitTest.php @@ -38,7 +38,7 @@ public function testSettingAndGettingAttribute($name, $value, $expected) { $this->assertEquals($expected, $rel->$name); } - public function setterDataProvider() { + public static function setterDataProvider() { return [ ['id', 123, null], ['guid_one', 123, 123], @@ -143,7 +143,7 @@ public function testOriginalAttributesOnChange($name, $value, bool $should_chang } } - public function originalAttributesProvider() { + public static function originalAttributesProvider() { return [ ['id', 123, false], ['guid_one', 123, true], diff --git a/engine/tests/phpunit/unit/ElggUpgradeUnitTest.php b/engine/tests/phpunit/unit/ElggUpgradeUnitTest.php index 70cb377d77e..5b20edd78e5 100644 --- a/engine/tests/phpunit/unit/ElggUpgradeUnitTest.php +++ b/engine/tests/phpunit/unit/ElggUpgradeUnitTest.php @@ -9,7 +9,7 @@ class ElggUpgradeUnitTest extends \Elgg\UnitTestCase { public function up() { $this->obj = $this->getMockBuilder('\ElggUpgrade') - ->setMethods(null) + ->onlyMethods([]) ->getMock(); } diff --git a/engine/tests/phpunit/unit/ElggUserUnitTest.php b/engine/tests/phpunit/unit/ElggUserUnitTest.php index ab8231d87d7..18e58975289 100644 --- a/engine/tests/phpunit/unit/ElggUserUnitTest.php +++ b/engine/tests/phpunit/unit/ElggUserUnitTest.php @@ -11,11 +11,11 @@ public function testCanConstructWithoutArguments() { public function testCanSetNotificationSettings() { $obj = $this->getMockBuilder(ElggUser::class) - ->setMethods(['save']) + ->onlyMethods(['save']) ->getMock(); $obj->expects($this->any()) ->method('save') - ->will($this->returnValue(true)); + ->willReturn(true); _elgg_services()->notifications->registerMethod('registered1'); _elgg_services()->notifications->registerMethod('registered2'); @@ -33,11 +33,11 @@ public function testCanSetNotificationSettings() { public function testCanSetNotificationSettingsWithPurpose() { $obj = $this->getMockBuilder(ElggUser::class) - ->setMethods(['save']) + ->onlyMethods(['save']) ->getMock(); $obj->expects($this->any()) ->method('save') - ->will($this->returnValue(true)); + ->willReturn(true); _elgg_services()->notifications->registerMethod('registered1'); _elgg_services()->notifications->registerMethod('registered2'); @@ -75,7 +75,7 @@ public function testCanSerialize() { $unserialized = unserialize($data); - $this->assertEquals($user, $unserialized); + $this->assertElggDataEquals($user, $unserialized); } public function testCanArrayAccessAttributes() { @@ -97,7 +97,7 @@ public function testIsLoggable() { $user = $this->createUser(); $this->assertEquals($user->guid, $user->getSystemLogID()); - $this->assertEquals($user, $user->getObjectFromID($user->guid)); + $this->assertElggDataEquals($user, $user->getObjectFromID($user->guid)); } public function testDefaultUserMetadata() { @@ -122,7 +122,7 @@ public function testSetProtectedValuesThrowsException($name) { $user->$name = 'foo'; } - public function protectedValues() { + public static function protectedValues() { return [ ['admin'], ['banned'], diff --git a/mod/blog/tests/phpunit/integration/Elgg/Blog/CanCommentIntegrationTest.php b/mod/blog/tests/phpunit/integration/Elgg/Blog/CanCommentIntegrationTest.php index a739d26f5e9..f4f9f92333b 100644 --- a/mod/blog/tests/phpunit/integration/Elgg/Blog/CanCommentIntegrationTest.php +++ b/mod/blog/tests/phpunit/integration/Elgg/Blog/CanCommentIntegrationTest.php @@ -26,7 +26,7 @@ public function testCanComment($enable_comments, $status, $expected) { $this->assertEquals($expected, $blog->canComment()); } - public function blogCommentStatusProvider() { + public static function blogCommentStatusProvider() { return [ ['On', 'published', true], ['On', 'draft', false], diff --git a/mod/blog/tests/phpunit/integration/Elgg/Blog/RouteResponseTest.php b/mod/blog/tests/phpunit/integration/Elgg/Blog/RouteResponseTest.php index 7eac36b33ce..fd9836804b7 100644 --- a/mod/blog/tests/phpunit/integration/Elgg/Blog/RouteResponseTest.php +++ b/mod/blog/tests/phpunit/integration/Elgg/Blog/RouteResponseTest.php @@ -4,14 +4,14 @@ class RouteResponseTest extends \Elgg\Plugins\RouteResponseIntegrationTestCase { - public function getSubtype() { + protected static function getSubtype() { return 'blog'; } - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return [ [ - 'route' => "collection:object:{$this->getSubtype()}:group", + 'route' => 'collection:object:' . self::getSubtype() . ':group', 'tool' => 'blog', ], ]; diff --git a/mod/bookmarks/tests/phpunit/integration/Elgg/Bookmarks/RouteResponseTest.php b/mod/bookmarks/tests/phpunit/integration/Elgg/Bookmarks/RouteResponseTest.php index 9f178ddc2d3..208d24c8981 100644 --- a/mod/bookmarks/tests/phpunit/integration/Elgg/Bookmarks/RouteResponseTest.php +++ b/mod/bookmarks/tests/phpunit/integration/Elgg/Bookmarks/RouteResponseTest.php @@ -4,14 +4,14 @@ class RouteResponseTest extends \Elgg\Plugins\RouteResponseIntegrationTestCase { - public function getSubtype() { + protected static function getSubtype() { return 'bookmarks'; } - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return [ [ - 'route' => "collection:object:{$this->getSubtype()}:group", + 'route' => 'collection:object:' . self::getSubtype() . ':group', 'tool' => 'bookmarks', ], ]; diff --git a/mod/discussions/tests/phpunit/integration/Elgg/Discussions/RouteResponseTest.php b/mod/discussions/tests/phpunit/integration/Elgg/Discussions/RouteResponseTest.php index 391aef939a3..e60ef3a4fc3 100644 --- a/mod/discussions/tests/phpunit/integration/Elgg/Discussions/RouteResponseTest.php +++ b/mod/discussions/tests/phpunit/integration/Elgg/Discussions/RouteResponseTest.php @@ -27,14 +27,14 @@ public function down() { parent::down(); } - public function getSubtype() { + protected static function getSubtype() { return 'discussion'; } - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return [ [ - 'route' => "collection:object:{$this->getSubtype()}:group", + 'route' => 'collection:object:' . self::getSubtype() . ':group', 'tool' => 'forum', ], ]; diff --git a/mod/file/tests/phpunit/integration/Elgg/File/RouteResponseTest.php b/mod/file/tests/phpunit/integration/Elgg/File/RouteResponseTest.php index 38728b40cdb..005bef418c5 100644 --- a/mod/file/tests/phpunit/integration/Elgg/File/RouteResponseTest.php +++ b/mod/file/tests/phpunit/integration/Elgg/File/RouteResponseTest.php @@ -4,14 +4,14 @@ class RouteResponseTest extends \Elgg\Plugins\RouteResponseIntegrationTestCase { - public function getSubtype() { + protected static function getSubtype() { return 'file'; } - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return [ [ - 'route' => "collection:object:{$this->getSubtype()}:group", + 'route' => 'collection:object:' . self::getSubtype() . ':group', 'tool' => 'file', ], ]; diff --git a/mod/messages/tests/phpunit/integration/Elgg/Messages/MessagesPluginTest.php b/mod/messages/tests/phpunit/integration/Elgg/Messages/MessagesPluginTest.php index f0a8d1247dc..ec4eeaf1787 100644 --- a/mod/messages/tests/phpunit/integration/Elgg/Messages/MessagesPluginTest.php +++ b/mod/messages/tests/phpunit/integration/Elgg/Messages/MessagesPluginTest.php @@ -41,10 +41,10 @@ public function testCanSendMessage() { $this->assertEquals($body, $message->description); $this->assertEquals($recipient->guid, $message->toId); - $this->assertEquals($recipient, $message->getRecipient()); + $this->assertElggDataEquals($recipient, $message->getRecipient()); $this->assertEquals($sender->guid, $message->fromId); - $this->assertEquals($sender, $message->getSender()); + $this->assertElggDataEquals($sender, $message->getSender()); }); $this->assertTrue($message->hasAccess($recipient->guid)); diff --git a/mod/pages/tests/phpunit/integration/Elgg/Pages/RouteResponseTest.php b/mod/pages/tests/phpunit/integration/Elgg/Pages/RouteResponseTest.php index d7dac26da3d..7aac976e6f9 100644 --- a/mod/pages/tests/phpunit/integration/Elgg/Pages/RouteResponseTest.php +++ b/mod/pages/tests/phpunit/integration/Elgg/Pages/RouteResponseTest.php @@ -4,14 +4,14 @@ class RouteResponseTest extends \Elgg\Plugins\RouteResponseIntegrationTestCase { - public function getSubtype() { + protected static function getSubtype() { return 'page'; } - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return [ [ - 'route' => "collection:object:{$this->getSubtype()}:group", + 'route' => 'collection:object:' . self::getSubtype() . ':group', 'tool' => 'pages', ], ]; diff --git a/mod/search/tests/phpunit/integration/Elgg/Search/SearchViewsRenderingIntegrationTest.php b/mod/search/tests/phpunit/integration/Elgg/Search/SearchViewsRenderingIntegrationTest.php index 7041ba23d1e..132ad112b8b 100644 --- a/mod/search/tests/phpunit/integration/Elgg/Search/SearchViewsRenderingIntegrationTest.php +++ b/mod/search/tests/phpunit/integration/Elgg/Search/SearchViewsRenderingIntegrationTest.php @@ -12,7 +12,7 @@ public function up() { $this->startPlugin(); } - public function getViewNames() { + public static function getViewNames() { return [ 'forms/search', 'resources/search/index', diff --git a/mod/system_log/tests/phpunit/integration/Elgg/SystemLog/ViewsRenderingIntegrationTest.php b/mod/system_log/tests/phpunit/integration/Elgg/SystemLog/ViewsRenderingIntegrationTest.php index bd580f4f951..a3aa14d37cb 100644 --- a/mod/system_log/tests/phpunit/integration/Elgg/SystemLog/ViewsRenderingIntegrationTest.php +++ b/mod/system_log/tests/phpunit/integration/Elgg/SystemLog/ViewsRenderingIntegrationTest.php @@ -12,7 +12,7 @@ public function up() { $this->startPlugin(); } - public function getViewNames() { + public static function getViewNames() { return [ 'admin/administer_utilities', 'core/settings/account/login_history', diff --git a/mod/thewire/tests/phpunit/integration/Elgg/TheWire/RegexIntegrationTest.php b/mod/thewire/tests/phpunit/integration/Elgg/TheWire/RegexIntegrationTest.php index a8a39167197..8b692b9feca 100644 --- a/mod/thewire/tests/phpunit/integration/Elgg/TheWire/RegexIntegrationTest.php +++ b/mod/thewire/tests/phpunit/integration/Elgg/TheWire/RegexIntegrationTest.php @@ -53,14 +53,14 @@ protected function getLink($address) { return elgg_parse_urls($address); } - /** - * @dataProvider filterDataProvider - */ - public function testTheWireFilter($input, $expected) { - $this->assertEquals($expected, thewire_filter($input)); + public function testTheWireFilter() { + foreach ($this->getFilterData() as $data) { + $this->assertEquals($data[1], thewire_filter($data[0])); + } } - public function filterDataProvider() { + // can't use dataprovider as we need instanciated users + protected function getFilterData() { $user = $this->createUser(); $user_digit = $this->createUser([ 'username' => 'username' . time(), diff --git a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php index e7d4400a77e..da667ff6f57 100644 --- a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php +++ b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php @@ -22,21 +22,11 @@ class ApiAuthenticationIntegrationTest extends IntegrationTestCase { * @var array backup of plugin settings */ protected $plugin_settings; - - /** - * @var bool - */ - protected $gc_enabled; - + /** * {@inheritDoc} */ public function up() { - // there is some wierd issue in the Memcache tests with the HMACTable destruct function. - // disabling the circular reference collector solves this - $this->gc_enabled = gc_enabled(); - gc_disable(); - $this->plugin = elgg_get_plugin_from_id('web_services'); $this->plugin_settings = $this->plugin->getAllSettings(); } @@ -49,10 +39,6 @@ public function down() { foreach ($this->plugin_settings as $name => $value) { $this->plugin->setSetting($name, $value); } - - if ($this->gc_enabled) { - gc_enable(); - } } /** diff --git a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiMethodIntegrationTest.php b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiMethodIntegrationTest.php index 7501a20a9d6..b7f58cfbd78 100644 --- a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiMethodIntegrationTest.php +++ b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiMethodIntegrationTest.php @@ -64,7 +64,7 @@ public function testArrayParams($name) { $api->$name = 'string'; } - public function setterArrayNameProvider() { + public static function setterArrayNameProvider() { return [ ['params'], ]; @@ -80,7 +80,7 @@ public function testStringParams($name) { $api->$name = []; } - public function setterStringNameProvider() { + public static function setterStringNameProvider() { return [ ['description'], ['call_method'], @@ -97,7 +97,7 @@ public function testBooleanParams($name) { $api->$name = 'foo'; } - public function setterBooleanNameProvider() { + public static function setterBooleanNameProvider() { return [ ['require_api_auth'], ['require_user_auth'], @@ -165,7 +165,7 @@ public function testSetCallMethodToSupportedValue($value) { $this->assertEquals(strtoupper($value), $api->call_method); } - public function supportedCallMethods() { + public static function supportedCallMethods() { return [ ['get'], ['GET'], @@ -189,7 +189,7 @@ public function testTypeCastParameter($key, $value, $type, $expected) { $this->assertEquals($expected, $result); } - public function typeCastParameterProvider() { + public static function typeCastParameterProvider() { return [ ['foo', null, 'string', null], ['foo', '1', 'int', 1], diff --git a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ElggApiClientIntegrationTest.php b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ElggApiClientIntegrationTest.php index 327ee161f15..1d6b419ab1a 100644 --- a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ElggApiClientIntegrationTest.php +++ b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ElggApiClientIntegrationTest.php @@ -46,7 +46,7 @@ public function testGetSetMethod($method) { $this->assertEquals(strtoupper($method), $client->getMethod()); } - public function validMethodProvider() { + public static function validMethodProvider() { return [ ['get'], ['GET'], @@ -73,7 +73,7 @@ public function testSetMethodWithInvalidMethod($method) { $client->setMethod($method); } - public function invalidMethodProvider() { + public static function invalidMethodProvider() { return [ ['PUT'], ['HEAD'], diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e1be904c57a..5cb541d9e35 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,33 +1,5 @@ - - - - ./actions - ./engine/classes - ./engine/lib - ./mod/*/actions - ./mod/*/lib - ./mod/*/classes - - - ./elgg-config - ./install - */vendor/* - */vendors/* - */tests/* - */bower_components/* - */node_modules/* - */docs/* - ./engine/schema/* - ./engine/vendor_classes/* - ./languages - ./views - ./mod/*/languages - ./mod/*/views - ./engine/lib/deprecated-*.php - ./engine/lib/constants.php - - + @@ -97,7 +71,6 @@ ./engine/tests/phpunit/integration/ - engine/tests/phpunit/integration/Elgg/Actions/ engine/tests/phpunit/integration/Elgg/Ajax/ engine/tests/phpunit/integration/Elgg/Assets/ @@ -118,4 +91,32 @@ engine/tests/phpunit/integration/Elgg/Security/ + + + ./actions + ./engine/classes + ./engine/lib + ./mod/*/actions + ./mod/*/lib + ./mod/*/classes + + + ./elgg-config + ./install + */vendor/* + */vendors/* + */tests/* + */bower_components/* + */node_modules/* + */docs/* + ./engine/schema/* + ./engine/vendor_classes/* + ./languages + ./views + ./mod/*/languages + ./mod/*/views + ./engine/lib/deprecated-*.php + ./engine/lib/constants.php + + From 603fa6bb9d7646b0946252f9efbf84bee55c38e2 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 15 Jan 2024 10:30:16 +0100 Subject: [PATCH 157/240] chore(tests): the minimal tested MariaDB version is now 10.6 --- .github/workflows/phpunit.yml | 4 ++-- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 9 +++++++++ docs/intro/install.rst | 2 +- engine/classes/ElggInstaller.php | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index ea3eb570c0e..75dbaacf8ee 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -67,13 +67,13 @@ jobs: experimental: false extra-title: '' memcache: 0 - db-image: 'mariadb:10.3' + db-image: 'mariadb:10.6' redis: 0 - php-versions: '8.1' experimental: false extra-title: '' memcache: 0 - db-image: 'mariadb:10.6' + db-image: 'mariadb:10.11' redis: 0 env: ELGG_MEMCACHE: ${{ matrix.memcache }} diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index 06bc6187c36..bd986b11bb0 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -5,6 +5,15 @@ From 5.x to 6.0 :local: :depth: 1 +Databases +--------- + +DB Requirements +~~~~~~~~~~~~~~~ + +The minimal MariaDB is now 10.6. + + Composer -------- diff --git a/docs/intro/install.rst b/docs/intro/install.rst index 3015586467a..9daebbcb987 100644 --- a/docs/intro/install.rst +++ b/docs/intro/install.rst @@ -10,7 +10,7 @@ Get your own instance of Elgg running in no time. Requirements ============ -- MySQL 5.7+ or MariaDB 10.3+ +- MySQL 5.7+ or MariaDB 10.6+ - PHP 8.1+ with the following extensions: - GD (for graphics processing) diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index 3f674df6854..70f3cf16cc8 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -40,7 +40,7 @@ */ class ElggInstaller { - public const MARIADB_MINIMAL_VERSION = '10.3'; + public const MARIADB_MINIMAL_VERSION = '10.6'; public const MYSQL_MINIMAL_VERSION = '5.7'; public const PHP_MINIMAL_VERSION = '8.1.0'; From ea4e7b1e4a43c074beb8b7e4b7fcfbdf9af6aa9b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 15 Jan 2024 11:15:32 +0100 Subject: [PATCH 158/240] chore(db): the minimal MySQL version is now 8.0 --- .github/workflows/codecoverage.yml | 2 +- .github/workflows/phpunit.yml | 8 +-- .github/workflows/upgrade.yml | 78 ++++------------------ docs/appendix/upgrade-notes/5.x-to-6.0.rst | 3 +- docs/intro/development.rst | 2 +- docs/intro/install.rst | 2 +- engine/classes/ElggInstaller.php | 2 +- install/languages/en.php | 1 - languages/en.php | 1 - 9 files changed, 22 insertions(+), 77 deletions(-) diff --git a/.github/workflows/codecoverage.yml b/.github/workflows/codecoverage.yml index bab1d8c8860..c21fb81059b 100644 --- a/.github/workflows/codecoverage.yml +++ b/.github/workflows/codecoverage.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 services: elggdb: - image: 'mysql:5.7' + image: 'mysql:8.0' env: MYSQL_DATABASE: elgg MYSQL_ROOT_PASSWORD: password diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 75dbaacf8ee..2028f041a9e 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -42,26 +42,26 @@ jobs: experimental: [false] extra-title: [''] memcache: [0] - db-image: ['mysql:5.7'] + db-image: ['mysql:8.0'] redis: [0] include: - php-versions: '8.1' experimental: false extra-title: '- Memcache' memcache: 1 - db-image: 'mysql:5.7' + db-image: 'mysql:8.0' redis: 0 - php-versions: '8.1' experimental: false extra-title: '- Redis' memcache: 0 - db-image: 'mysql:5.7' + db-image: 'mysql:8.0' redis: 1 - php-versions: '8.1' experimental: false extra-title: '' memcache: 0 - db-image: 'mysql:8.0' + db-image: 'mysql:8.2' redis: 0 - php-versions: '8.1' experimental: false diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml index 2a84a58186f..5332aa3a2bf 100644 --- a/.github/workflows/upgrade.yml +++ b/.github/workflows/upgrade.yml @@ -10,11 +10,11 @@ env: jobs: upgrade: - name: Upgrade from 2.3 + name: Upgrade from 4.3 runs-on: ubuntu-20.04 services: elggdb: - image: mysql:5.7 + image: 'mysql:8.0' env: MYSQL_DATABASE: elgg MYSQL_ROOT_PASSWORD: password @@ -25,92 +25,38 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.0' coverage: none extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring - - - name: Install Composer v1 - run: composer self-update --1 - - - name: Code checkout Elgg 2.3 + + - name: Code checkout Elgg 4.3 uses: actions/checkout@v3 with: repository: 'Elgg/Elgg' - ref: '2.3' + ref: '4.3' - name: Get Composer Cache Directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - - name: Restore Composer Cache for 2.3 + - name: Restore Composer Cache for 4.3 uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - - name: Composer install - run: | - composer global require fxp/composer-asset-plugin:^1.1.4 --prefer-dist - composer install - - - name: Install Elgg 2.3 - run: | - mkdir ${HOME}/elgg_data - php -f ./install/cli/ci_installer.php - - - name: Enable Elgg 2.3 plugins - run: php -f ./.scripts/ci/enable_plugins.php - - - name: Seed Elgg 2.3 database - run: php -f ./.scripts/seeder/seed.php - - - name: Code checkout Elgg 3.3 - uses: actions/checkout@v3 - with: - repository: 'Elgg/Elgg' - ref: '3.3' - clean: false - - - name: Composer install Elgg 3.3 dependencies - run: composer install --prefer-dist --no-suggest - - - name: Elgg CLI upgrade to 3.3 - run: php ./elgg-cli upgrade async --verbose - - - name: Enable Elgg 3.3 plugins - run: php -f ./.scripts/ci/enable_plugins.php - - - name: Install Composer v2 - # make sure to remove the global fxp/composer-asset-plugin package as it's no longer needed - # also remove the elgg/login_as plugin because after the Composer update it has a hard time removing it - run: | - composer global remove fxp/composer-asset-plugin - composer remove elgg/login_as - composer self-update --2 - - - name: Code checkout Elgg 4.3 - uses: actions/checkout@v3 - with: - repository: 'Elgg/Elgg' - ref: '4.3' - clean: false - name: Composer install Elgg 4.3 dependencies - run: composer install --prefer-dist --no-suggest + run: composer install - - name: Elgg CLI upgrade to 4.3 - run: php ./elgg-cli upgrade async --verbose + - name: Elgg CLI install Elgg 4.3 + run: php ./elgg-cli install --config ./install/cli/testing_app.php --verbose --no-ansi - name: Enable Elgg 4.3 plugins run: php -f ./.scripts/ci/enable_plugins.php - - name: Update PHP to 8.0 - uses: shivammathur/setup-php@v2 - with: - php-version: '8.0' - coverage: none - extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring + - name: Seed Elgg 4.3 database + run: php ./elgg-cli database:seed --limit=5 --image_folder=./.scripts/seeder/images/ -vv --no-ansi - name: Code checkout Elgg 5.1 uses: actions/checkout@v3 diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index bd986b11bb0..a9e7ff9d4b2 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -11,7 +11,8 @@ Databases DB Requirements ~~~~~~~~~~~~~~~ -The minimal MariaDB is now 10.6. + - The minimal MySQL version is now 8.0 + - The minimal MariaDB version is now 10.6 Composer diff --git a/docs/intro/development.rst b/docs/intro/development.rst index 054e789283f..d4f4848bc3f 100644 --- a/docs/intro/development.rst +++ b/docs/intro/development.rst @@ -9,7 +9,7 @@ See the :doc:`/guides/index` for tutorials or the :doc:`/design/index` for in-de Database and Persistence ======================== -Elgg uses MySQL 5.7 or higher for data persistence, and maps database values into Entities (a +Elgg uses MySQL for data persistence, and maps database values into Entities (a representation of an atomic unit of information) and Extenders (additional information and descriptions about Entities). Elgg supports additional information such as relationships between Entities, activity streams, and various types of settings. diff --git a/docs/intro/install.rst b/docs/intro/install.rst index 9daebbcb987..9ebe6207dd6 100644 --- a/docs/intro/install.rst +++ b/docs/intro/install.rst @@ -10,7 +10,7 @@ Get your own instance of Elgg running in no time. Requirements ============ -- MySQL 5.7+ or MariaDB 10.6+ +- MySQL 8.0+ or MariaDB 10.6+ - PHP 8.1+ with the following extensions: - GD (for graphics processing) diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index 70f3cf16cc8..9a2fb32526c 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -41,7 +41,7 @@ class ElggInstaller { public const MARIADB_MINIMAL_VERSION = '10.6'; - public const MYSQL_MINIMAL_VERSION = '5.7'; + public const MYSQL_MINIMAL_VERSION = '8.0'; public const PHP_MINIMAL_VERSION = '8.1.0'; protected array $steps = [ diff --git a/install/languages/en.php b/install/languages/en.php index ab69c5c0356..d22fadf9d30 100644 --- a/install/languages/en.php +++ b/install/languages/en.php @@ -138,7 +138,6 @@ 'install:error:settings_mismatch' => 'The settings file value for "%s" does not match the given $params. Expected: "%s" Actual: "%s"', 'install:error:databasesettings' => 'Unable to connect to the database with these settings.', 'install:error:database_prefix' => 'Invalid characters in database prefix', - 'install:error:oldmysql2' => 'MySQL must be version 5.5.3 or above. Your server is using %s.', 'install:error:mysql_version' => 'MySQL must be version %s or above. Your server is using %s.', 'install:error:database_version' => 'Database must be version %s or above. Your server is using %s.', 'install:error:nodatabase' => 'Unable to use database %s. It may not exist.', diff --git a/languages/en.php b/languages/en.php index 479fb78f16f..d7804249138 100644 --- a/languages/en.php +++ b/languages/en.php @@ -993,7 +993,6 @@ 'admin:server:requirements:rewrite:fail' => "Check your .htaccess for the correct rewrite rules", 'admin:server:requirements:database:server' => "Database server", - 'admin:server:requirements:database:server:required' => "Elgg requires MySQL v5.5.3 or higher for its database", 'admin:server:requirements:database:server:required_version' => "Elgg requires MySQL v%s or higher for its database", 'admin:server:requirements:database:client' => "Database client", 'admin:server:requirements:database:client:required' => "Elgg requires pdo_mysql to connect to the database server", From 12ddfd43380161013d2d5c8c6eb0b2abd2ce184e Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Mon, 15 Jan 2024 13:35:15 +0100 Subject: [PATCH 159/240] chore(tests): setAccessible is obsolete in PHP 8.1 --- engine/tests/classes/Elgg/BaseTestCase.php | 9 ++------- .../Elgg/EntityIconServiceIntegrationTest.php | 1 - .../integration/Elgg/Http/ClientIntegrationTest.php | 4 +--- .../Elgg/Integration/ElggDataFunctionsTest.php | 1 - .../NotificationEventHandlerIntegrationTest.php | 8 ++------ .../Router/Middleware/WalledGardenIntegrationTest.php | 2 -- engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php | 1 - 7 files changed, 5 insertions(+), 21 deletions(-) diff --git a/engine/tests/classes/Elgg/BaseTestCase.php b/engine/tests/classes/Elgg/BaseTestCase.php index 02334a56f76..9bb0861a0b8 100644 --- a/engine/tests/classes/Elgg/BaseTestCase.php +++ b/engine/tests/classes/Elgg/BaseTestCase.php @@ -307,10 +307,7 @@ public static function assertElggDataEquals(mixed $expected, mixed $actual, stri protected static function invokeInaccessableMethod($argument, string $method, ...$args) { $reflector = new \ReflectionClass($argument); - $inaccessable_method = $reflector->getMethod($method); - $inaccessable_method->setAccessible(true); - - return $inaccessable_method->invoke($argument, ...$args); + return $reflector->getMethod($method)->invoke($argument, ...$args); } /** @@ -323,9 +320,7 @@ protected static function invokeInaccessableMethod($argument, string $method, .. */ protected static function getInaccessableProperty($argument, string $property) { $reflector = new \ReflectionClass($argument); - $property = $reflector->getProperty($property); - $property->setAccessible(true); - return $property->getValue($argument); + return $reflector->getProperty($property)->getValue($argument); } } diff --git a/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php index ae3be2e2243..52fac87729f 100644 --- a/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php @@ -21,7 +21,6 @@ public function testInvalidDetectCroppingCoordinates($input_name, $params) { $service = _elgg_services()->iconService; $inspector = new \ReflectionClass($service); $method = $inspector->getMethod('detectCroppingCoordinates'); - $method->setAccessible(true); $this->assertFalse($method->invoke($service, $input_name)); } diff --git a/engine/tests/phpunit/integration/Elgg/Http/ClientIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Http/ClientIntegrationTest.php index 1eeabb8f0f3..e56f7b5a510 100644 --- a/engine/tests/phpunit/integration/Elgg/Http/ClientIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Http/ClientIntegrationTest.php @@ -15,10 +15,8 @@ public function testCanPassOptions() { $reflector = new \ReflectionClass($client); $reflector = $reflector->getParentClass(); - $property = $reflector->getProperty('config'); - $property->setAccessible(true); - $config = $property->getValue($client); + $config = $reflector->getProperty('config')->getValue($client); $this->assertArrayHasKey('foo', $config); $this->assertEquals('bar', $config['foo']); diff --git a/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php b/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php index ae56d2bd4ff..06214c8c9b2 100644 --- a/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php +++ b/engine/tests/phpunit/integration/Elgg/Integration/ElggDataFunctionsTest.php @@ -149,7 +149,6 @@ public function testCanDelayQuery() { $database = _elgg_services()->db; $reflector = new \ReflectionClass($database); $delayed_queries = $reflector->getProperty('delayed_queries'); - $delayed_queries->setAccessible(true); $delayed_value = $delayed_queries->getValue($database); // backup $delayed_queries->setValue($database, []); diff --git a/engine/tests/phpunit/integration/Elgg/Notifications/NotificationEventHandlerIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Notifications/NotificationEventHandlerIntegrationTest.php index 27c4b1f2ae2..29339f72691 100644 --- a/engine/tests/phpunit/integration/Elgg/Notifications/NotificationEventHandlerIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Notifications/NotificationEventHandlerIntegrationTest.php @@ -33,10 +33,8 @@ public function testFilterMutedSubscribers() { $filtered = $this->prepareNotificationEventHandler($event); $class = new \ReflectionClass($filtered); - $method = $class->getMethod('prepareSubscriptions'); - $method->setAccessible(true); - $subscribers = $method->invoke($filtered); + $subscribers = $class->getMethod('prepareSubscriptions')->invoke($filtered); $this->assertIsArray($subscribers); $this->assertArrayHasKey($subscribed->guid, $subscribers); $this->assertArrayNotHasKey($muted->guid, $subscribers); @@ -44,10 +42,8 @@ public function testFilterMutedSubscribers() { $not_filtered = $this->prepareNotificationEventHandler($event, ['apply_muting' => false]); $class = new \ReflectionClass($not_filtered); - $method = $class->getMethod('prepareSubscriptions'); - $method->setAccessible(true); - $subscribers = $method->invoke($not_filtered); + $subscribers = $class->getMethod('prepareSubscriptions')->invoke($not_filtered); $this->assertIsArray($subscribers); $this->assertArrayHasKey($subscribed->guid, $subscribers); $this->assertArrayHasKey($muted->guid, $subscribers); diff --git a/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php index f51e247a9eb..a478d00ebf0 100644 --- a/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Router/Middleware/WalledGardenIntegrationTest.php @@ -57,7 +57,6 @@ protected function route(Request $request) { public function testCanDetectPublicPage($path, $expected) { $class = new \ReflectionClass(WalledGarden::class); $method = $class->getMethod('isPublicPage'); - $method->setAccessible(true); $instance = new WalledGarden(); @@ -87,7 +86,6 @@ public function testCanFilterPublicPages() { $class = new \ReflectionClass(WalledGarden::class); $method = $class->getMethod('isPublicPage'); - $method->setAccessible(true); $instance = new WalledGarden(); diff --git a/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php b/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php index 2faf983da5f..dbccb06b3ab 100644 --- a/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/DatabaseUnitTest.php @@ -11,7 +11,6 @@ public function testFingerprintingOfCallbacks() { $db = $this->getDbMock(); $reflection_method = new \ReflectionMethod($db, 'fingerprintCallback'); - $reflection_method->setAccessible(true); $prints = []; $uniques = 0; From 5b5ddccb6e53cc369430a32beb2b6bcb2293fda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Tue, 30 Jan 2024 14:47:14 +0100 Subject: [PATCH 160/240] feat(php): require php intl module fixes #13901 --- composer.json | 5 +- composer.lock | 37 +++++---- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 2 +- docs/intro/install.rst | 4 +- engine/classes/Elgg/I18n/DateTime.php | 83 +-------------------- engine/classes/ElggInstaller.php | 1 + views/default/admin/server/requirements.php | 1 + 7 files changed, 31 insertions(+), 102 deletions(-) diff --git a/composer.json b/composer.json index 177abb55174..f601f82dbe1 100644 --- a/composer.json +++ b/composer.json @@ -8,9 +8,10 @@ "type": "project", "require": { "php": ">=8.1", - "ext-pdo": "*", - "ext-gd": "*", + "ext-intl": "*", "ext-json": "*", + "ext-gd": "*", + "ext-pdo": "*", "ext-xml": "*", "composer/installers": ">=1.0.8", "composer/semver": "~3.4.0", diff --git a/composer.lock b/composer.lock index a284cfac9d5..d20d518ebf3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4caf782ee1ab2e19b9a31ce81b7d8069", + "content-hash": "16793d5f6811a0130c67936aa5b92b75", "packages": [ { "name": "cakephp/cache", @@ -3878,7 +3878,7 @@ "backpack/crud": "<3.4.9", "bacula-web/bacula-web": "<8.0.0.0-RC2-dev", "badaso/core": "<2.7", - "bagisto/bagisto": "<0.1.5", + "bagisto/bagisto": "<1.3.2", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.2", @@ -3960,6 +3960,7 @@ "drupal/drupal": ">=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", + "ec-cube/ec-cube": "<2.4.4", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", "elefant/cms": "<2.0.7", @@ -4067,6 +4068,7 @@ "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", "impresscms/impresscms": "<=1.4.5", + "impresspages/impresspages": "<=1.0.12", "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", @@ -4095,7 +4097,7 @@ "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", - "kimai/kimai": "<=2.1", + "kimai/kimai": "<2.1", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -4124,11 +4126,12 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": "<2.4.2.0-patch1", - "magento/core": "<1.9.4.5-dev", + "magento/community-edition": "<2.4.3.0-patch3|>=2.4.4,<2.4.5", + "magento/core": "<=1.9.4.5", "magento/magento1ce": "<1.9.4.3-dev", "magento/magento1ee": ">=1,<1.14.4.3-dev", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2.0-patch2", + "magneto/core": "<1.9.4.4-dev", "maikuolan/phpmussel": ">=1,<1.6", "mainwp/mainwp": "<=4.4.3.3", "mantisbt/mantisbt": "<=2.25.7", @@ -4167,8 +4170,8 @@ "neorazorx/facturascripts": "<2022.04", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", + "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", - "neos/neos-ui": "<=8.3.3", "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", @@ -4218,6 +4221,7 @@ "phenx/php-svg-lib": "<0.5.1", "php-mod/curl": "<2.3.2", "phpbb/phpbb": "<3.2.10|>=3.3,<3.3.1", + "phpems/phpems": ">=6,<=6.1.3", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", @@ -4233,7 +4237,7 @@ "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<1.2.2", + "pimcore/admin-ui-classic-bundle": "<1.3.2", "pimcore/customer-management-framework-bundle": "<4.0.6", "pimcore/data-hub": "<1.2.4", "pimcore/demo": "<10.3", @@ -4257,7 +4261,7 @@ "prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_linklist": "<3.1", "privatebin/privatebin": "<1.4", - "processwire/processwire": "<=3.0.200", + "processwire/processwire": "<=3.0.210", "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pterodactyl/panel": "<1.7", @@ -4290,21 +4294,21 @@ "serluck/phpwhois": "<=4.2.6", "sfroemken/url_redirect": "<=1.2.1", "sheng/yiicms": "<=1.2", - "shopware/core": "<=6.4.20", - "shopware/platform": "<=6.4.20", + "shopware/core": "<=6.5.7.3", + "shopware/platform": "<=6.5.7.3", "shopware/production": "<=6.3.5.2", "shopware/shopware": "<=5.7.17", "shopware/storefront": "<=6.4.8.1", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", "silverstripe-australia/advancedreports": ">=1,<=2", - "silverstripe/admin": "<1.13.6", + "silverstripe/admin": "<1.13.19|>=2,<2.1.8", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.13.14|>=5,<5.0.13", - "silverstripe/graphql": "<3.8.2|>=4,<4.1.3|>=4.2,<4.2.5|>=4.3,<4.3.4|>=5,<5.0.3", + "silverstripe/framework": "<4.13.39|>=5,<5.1.11", + "silverstripe/graphql": "<3.8.2|>=4,<4.3.7|>=5,<5.1.3", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", @@ -8847,14 +8851,15 @@ "prefer-lowest": false, "platform": { "php": ">=8.1", - "ext-pdo": "*", - "ext-gd": "*", + "ext-intl": "*", "ext-json": "*", + "ext-gd": "*", + "ext-pdo": "*", "ext-xml": "*" }, "platform-dev": [], "platform-overrides": { "php": "8.1" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index a9e7ff9d4b2..eba6ac9f10d 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -21,7 +21,7 @@ Composer PHP Requirements ~~~~~~~~~~~~~~~~ -The minimal PHP version is now 8.1. +The minimal PHP version is now 8.1. Also the ``intl`` module is now required to be enabled. PHPUnit ~~~~~~~ diff --git a/docs/intro/install.rst b/docs/intro/install.rst index 9ebe6207dd6..68f086a3df8 100644 --- a/docs/intro/install.rst +++ b/docs/intro/install.rst @@ -14,11 +14,11 @@ Requirements - PHP 8.1+ with the following extensions: - GD (for graphics processing) - - PDO (for database connection) + - INTL (for internationalization) - JSON (for AJAX responses, etc.) + - PDO (for database connection) - XML (for xml resource and web services, etc.) - `Multibyte String support`_ (for i18n) - - (optional) intl (for i18n) - Proper configuration and ability to send email through an MTA - Web server with support for URL rewriting diff --git a/engine/classes/Elgg/I18n/DateTime.php b/engine/classes/Elgg/I18n/DateTime.php index 8bc2809fb8a..25d8c11f8fd 100644 --- a/engine/classes/Elgg/I18n/DateTime.php +++ b/engine/classes/Elgg/I18n/DateTime.php @@ -5,7 +5,7 @@ use DateTime as PHPDateTime; /** - * Extension of the DateTime class to support formating a date using the locale + * Extension of the DateTime class to support formatting a date using the locale * * @since 3.0 */ @@ -24,11 +24,7 @@ public function formatLocale(string $format, string $language = null) { $language = _elgg_services()->translator->getCurrentLanguage(); } - if (extension_loaded('intl')) { - $result = $this->formatIntl($format, $language); - } else { - $result = $this->formatStrftime($format, $language); - } + $result = $this->formatIntl($format, $language); if ($result === false) { elgg_log("Unable to generate locale representation for format: '{$format}', using non-locale version", 'INFO'); @@ -37,81 +33,6 @@ public function formatLocale(string $format, string $language = null) { return $result; } - - /** - * Convert a date format to a strftime format - * - * Timezone conversion is done for unix. Windows users must exchange %z and %Z. - * - * Unsupported date formats : n, t, L, B, u, e, I, P, Z, c, r - * Unsupported strftime formats : %U, %W, %C, %g, %r, %R, %T, %X, %c, %D, %F, %x - * - * @param string $dateFormat a date format - * - * @return false|string - * @see https://secure.php.net/manual/en/function.strftime.php#96424 - */ - protected function dateFormatToStrftime(string $dateFormat) { - if (preg_match('/(? '%d', 'D' => '%a', 'j' => '%e', 'l' => '%A', 'N' => '%u', 'w' => '%w', 'z' => '%j', - // Week - no date eq : %U, %W - 'W' => '%V', - // Month - no strf eq : n, t - 'F' => '%B', 'm' => '%m', 'M' => '%b', - // Year - no strf eq : L; no date eq : %C, %g - 'o' => '%G', 'Y' => '%Y', 'y' => '%y', - // Time - no strf eq : B, G, u; no date eq : %r, %R, %T, %X - 'a' => '%P', 'A' => '%p', 'g' => '%l', 'h' => '%I', 'H' => '%H', 'i' => '%M', 's' => '%S', - // Timezone - no strf eq : e, I, P, Z - 'O' => '%z', 'T' => '%Z', - // Full Date / Time - no strf eq : c, r; no date eq : %c, %D, %F, %x - 'U' => '%s', - // less supported replacements - // Day - 'S' => '', - // Time - 'G' => '%k', - ]; - - return strtr((string) $dateFormat, $caracs); - } - - /** - * Try to format to a locale using strftime() - * - * @param string $format output format, supports date() formatting - * @param string $language the output language - * - * @return string|false - * @since 4.1 - */ - protected function formatStrftime(string $format, string $language) { - // convert date() format to strftime() format - $correct_format = $this->dateFormatToStrftime($format); - if ($correct_format === false) { - return false; - } - - if (version_compare(PHP_VERSION, '8.1.0', '>=')) { - elgg_log('In order to get rid of the deprecated warnings about strftime() enable the "intl" PHP module', 'WARNING'); - } - - // switch locale - $current_locale = _elgg_services()->locale->setLocaleFromLanguageKey(LC_TIME, $language); - - $result = strftime($correct_format, $this->getTimestamp()); - - // restore locale - _elgg_services()->locale->setLocale(LC_TIME, $current_locale); - - return $result; - } /** * Convert a date format to a ICU format diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index 9a2fb32526c..d2c430b9d23 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -992,6 +992,7 @@ protected function checkPhpExtensions(array &$phpReport): void { 'json', 'xml', 'gd', + 'intl', ]; foreach ($requiredExtensions as $extension) { if (!in_array($extension, $extensions)) { diff --git a/views/default/admin/server/requirements.php b/views/default/admin/server/requirements.php index e6bf2cb9789..72543bd7697 100644 --- a/views/default/admin/server/requirements.php +++ b/views/default/admin/server/requirements.php @@ -47,6 +47,7 @@ 'json', 'xml', 'gd', + 'intl', ]; foreach ($requiredExtensions as $extension) { $icon = $icon_ok; From 99a723c4e7346ca92fd161ace18d0f34e2728418 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 31 Jan 2024 09:12:07 +0100 Subject: [PATCH 161/240] chore(views): elgg_get_simplecache_url subview argument has been removed --- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 8 ++++ engine/classes/Elgg/Cache/SimpleCache.php | 44 +++++-------------- engine/lib/cache.php | 17 ++----- .../unit/Elgg/Cache/SimpleCacheUnitTest.php | 19 -------- 4 files changed, 23 insertions(+), 65 deletions(-) diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index eba6ac9f10d..271a86c366e 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -36,3 +36,11 @@ alias for the ``annotations`` table has been changed from ``n_table`` to ``a_tab If your code uses very specific clauses (select, where, order_by, etc.) you need to update your code. If you use the ``\Elgg\Database\QueryBuilder`` for your query parts you should be ok. + +Changes in functions +-------------------- + +Lib functions function parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``elgg_get_simplecache_url()`` has the second argument (``$subview``) removed. The full ``$view`` name needs to be provided as the first argument. diff --git a/engine/classes/Elgg/Cache/SimpleCache.php b/engine/classes/Elgg/Cache/SimpleCache.php index 13a72c97b92..8165f7bc562 100644 --- a/engine/classes/Elgg/Cache/SimpleCache.php +++ b/engine/classes/Elgg/Cache/SimpleCache.php @@ -41,39 +41,18 @@ public function __construct( /** * Get the URL for the cached view. * - * Recommended usage is to just pass the entire view name as the first and only arg: - * * ``` * $blog_js = $simpleCache->getUrl('blog/save_draft.js'); * $favicon = $simpleCache->getUrl('graphics/favicon.ico'); * ``` * - * For backwards compatibility with older versions of Elgg, you can also pass - * "js" or "css" as the first arg, with the rest of the view name as the second arg: - * - * ``` - * $blog_js = $simpleCache->getUrl('js', 'blog/save_draft.js'); - * ``` - * * This automatically registers the view with Elgg's simplecache. * - * @param string $view The full view name - * @param string $subview If the first arg is "css" or "js", the rest of the view name + * @param string $view The full view name * * @return string */ - public function getUrl(string $view, string $subview = ''): string { - // handle `getUrl('js', 'js/blog/save_draft')` - if (($view === 'js' || $view === 'css') && str_starts_with($subview, $view . '/')) { - $view = $subview; - $subview = ''; - } - - // handle `getUrl('js', 'blog/save_draft')` - if (!empty($subview)) { - $view = "{$view}/{$subview}"; - } - + public function getUrl(string $view): string { $view = ViewsService::canonicalizeViewName($view); // should be normalized to canonical form by now: `getUrl('blog/save_draft.js')` @@ -87,7 +66,7 @@ public function getUrl(string $view, string $subview = ''): string { * * @return string The simplecache root url for the current viewtype */ - public function getRoot() { + public function getRoot(): string { $viewtype = $this->views->getViewtype(); if ($this->isEnabled()) { $lastcache = (int) $this->config->lastcache; @@ -103,7 +82,7 @@ public function getRoot() { * * @return bool */ - public function isEnabled() { + public function isEnabled(): bool { return (bool) $this->config->simplecache_enabled; } @@ -113,7 +92,7 @@ public function isEnabled() { * @return void * @see elgg_register_simplecache_view() */ - public function enable() { + public function enable(): void { $this->config->save('simplecache_enabled', 1); } @@ -123,7 +102,7 @@ public function enable() { * @return void * @see elgg_register_simplecache_view() */ - public function disable() { + public function disable(): void { if (!$this->isEnabled()) { return; } @@ -136,20 +115,19 @@ public function disable() { * * @return string */ - protected function getPath() { + protected function getPath(): string { return (string) $this->config->assetroot; } /** * Deletes all cached views in the simplecache * - * @return bool + * @return void + * * @since 3.3 */ - public function clear() { + public function clear(): void { elgg_delete_directory($this->getPath(), true); - - return true; } /** @@ -157,7 +135,7 @@ public function clear() { * * @return void */ - public function purge() { + public function purge(): void { $lastcache = (int) $this->config->lastcache; if (!is_dir($this->getPath())) { diff --git a/engine/lib/cache.php b/engine/lib/cache.php index 673d98796b7..da724235634 100644 --- a/engine/lib/cache.php +++ b/engine/lib/cache.php @@ -115,29 +115,20 @@ function elgg_register_simplecache_view(string $view_name): void { /** * Get the URL for the cached view. * - * Recommended usage is to just pass the entire view name as the first and only arg: - * * ``` * $blog_js = elgg_get_simplecache_url('elgg/blog/save_draft.js'); * $favicon = elgg_get_simplecache_url('favicon.ico'); * ``` * - * For backwards compatibility with older versions of Elgg, this function supports - * "js" or "css" as the first arg, with the rest of the view name as the second arg: - * - * ``` - * $blog_js = elgg_get_simplecache_url('js', 'elgg/blog/save_draft.js'); - * ``` - * * This automatically registers the view with Elgg's simplecache. * - * @param string $view The full view name - * @param string $subview If the first arg is "css" or "js", the rest of the view name + * @param string $view The full view name + * * @return string * @since 1.8.0 */ -function elgg_get_simplecache_url(string $view, string $subview = ''): string { - return _elgg_services()->simpleCache->getUrl($view, $subview); +function elgg_get_simplecache_url(string $view): string { + return _elgg_services()->simpleCache->getUrl($view); } /** diff --git a/engine/tests/phpunit/unit/Elgg/Cache/SimpleCacheUnitTest.php b/engine/tests/phpunit/unit/Elgg/Cache/SimpleCacheUnitTest.php index bd358c85cde..09cb7c2aa4b 100644 --- a/engine/tests/phpunit/unit/Elgg/Cache/SimpleCacheUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Cache/SimpleCacheUnitTest.php @@ -26,24 +26,6 @@ public function testGetUrlHandlesSingleArgument() { $this->assertMatchesRegularExpression("#default/view.js#", $url); } - public function testGetUrlHandlesTwoArguments() { - elgg_register_simplecache_view('js/view.js'); - $url = $this->service->getUrl('js', 'view.js'); - - $this->assertMatchesRegularExpression("#default/view.js$#", $url); - } - - public function testGetUrlHandlesTwoArgumentsWhereSecondArgHasRedundantPrefix() { - elgg_register_simplecache_view('js/view.js'); - $url = $this->service->getUrl('js', 'js/view.js'); - - $this->assertMatchesRegularExpression("#default/view.js$#", $url); - } - - public function testRespectsViewAliases() { - $this->markTestIncomplete(); - } - public function testCanEnableSimplecache() { $is_enabled = _elgg_services()->config->simplecache_enabled; @@ -59,7 +41,6 @@ public function testCanEnableSimplecache() { $this->assertTrue(elgg_is_simplecache_enabled()); _elgg_services()->config->save('simplecache_enabled', $is_enabled); - } public function testClearSimplecacheSymlinked() { From dde45d9793e089a9b6de1429800b958e10fac324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 1 Feb 2024 14:03:26 +0100 Subject: [PATCH 162/240] chore(entity): code cleanup of icon related functions --- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 5 + .../Entity/Icons.php} | 73 +++++++---- engine/classes/ElggEntity.php | 115 +++--------------- 3 files changed, 71 insertions(+), 122 deletions(-) rename engine/classes/Elgg/{EntityIcon.php => Traits/Entity/Icons.php} (60%) diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index 271a86c366e..9bff2fabf53 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -44,3 +44,8 @@ Lib functions function parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ``elgg_get_simplecache_url()`` has the second argument (``$subview``) removed. The full ``$view`` name needs to be provided as the first argument. + +Miscellaneous API changes +------------------------- + +* The interface ``\Elgg\EntityIcon`` has been removed. Implemented functions in ``\ElggEntity`` have been moved to ``\Elgg\Traits\Entity\Icons`` diff --git a/engine/classes/Elgg/EntityIcon.php b/engine/classes/Elgg/Traits/Entity/Icons.php similarity index 60% rename from engine/classes/Elgg/EntityIcon.php rename to engine/classes/Elgg/Traits/Entity/Icons.php index 4c383b70bb0..d9e91b14679 100644 --- a/engine/classes/Elgg/EntityIcon.php +++ b/engine/classes/Elgg/Traits/Entity/Icons.php @@ -1,20 +1,26 @@ iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); + } /** * Saves icons using a local file as the source. @@ -22,9 +28,12 @@ public function saveIconFromUploadedFile(string $input_name, string $type = 'ico * @param string $filename The full path to the local file * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * * @return bool */ - public function saveIconFromLocalFile(string $filename, string $type = 'icon', array $coords = []): bool; + public function saveIconFromLocalFile(string $filename, string $type = 'icon', array $coords = []): bool { + return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); + } /** * Saves icons using a file located in the data store as the source. @@ -32,9 +41,12 @@ public function saveIconFromLocalFile(string $filename, string $type = 'icon', a * @param string $file An ElggFile instance * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * * @return bool */ - public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', array $coords = []): bool; + public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', array $coords = []): bool { + return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); + } /** * Returns entity icon as an ElggIcon object @@ -42,27 +54,23 @@ public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', arr * * @param string $size Size of the icon * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * * @return \ElggIcon */ - public function getIcon(string $size, string $type = 'icon'): \ElggIcon; - + public function getIcon(string $size, string $type = 'icon'): \ElggIcon { + return _elgg_services()->iconService->getIcon($this, $size, $type); + } + /** * Removes all icon files and metadata for the passed type of icon. * * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function deleteIcon(string $type = 'icon'): bool; - - /** - * Returns a URL of the icon. * - * @param array $params An array of paramaters including: - * string 'size' => the size of the icon (default: medium) - * string 'type' => the icon type (default: icon) - * @return string + * @return bool */ - public function getIconURL(array $params): string; + public function deleteIcon(string $type = 'icon'): bool { + return _elgg_services()->iconService->deleteIcon($this, $type); + } /** * Returns the timestamp of when the icon was changed. @@ -72,14 +80,35 @@ public function getIconURL(array $params): string; * * @return int|null A unix timestamp of when the icon was last changed, or null if not set. */ - public function getIconLastChange(string $size, string $type = 'icon'): ?int; + public function getIconLastChange(string $size, string $type = 'icon'): ?int { + return _elgg_services()->iconService->getIconLastChange($this, $size, $type); + } /** * Returns if the entity has an icon of the passed type. * * @param string $size The size of the icon * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * * @return bool */ - public function hasIcon(string $size, string $type = 'icon'): bool; + public function hasIcon(string $size, string $type = 'icon'): bool { + return _elgg_services()->iconService->hasIcon($this, $size, $type); + } + + /** + * Get the URL for this entity's icon + * + * Plugins can register for the 'entity:icon:url', '' event + * to customize the icon for an entity. + * + * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) + * or an array of parameters including 'size' + * + * @return string The URL + * @since 1.8.0 + */ + public function getIconURL(string|array $params = []): string { + return _elgg_services()->iconService->getIconURL($this, $params); + } } diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index 441277f4774..f990fa1c708 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -1,11 +1,11 @@ iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); - } - - /** - * Saves icons using a local file as the source. - * - * @param string $filename The full path to the local file - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 - * @return bool - */ - public function saveIconFromLocalFile(string $filename, string $type = 'icon', array $coords = []): bool { - return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); - } - - /** - * Saves icons using a file located in the data store as the source. - * - * @param string $file An ElggFile instance - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 - * @return bool - */ - public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', array $coords = []): bool { - return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); - } - - /** - * Returns entity icon as an ElggIcon object - * The icon file may or may not exist on filestore - * - * @param string $size Size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return \ElggIcon - */ - public function getIcon(string $size, string $type = 'icon'): \ElggIcon { - return _elgg_services()->iconService->getIcon($this, $size, $type); - } - - /** - * Removes all icon files and metadata for the passed type of icon. - * - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function deleteIcon(string $type = 'icon'): bool { - return _elgg_services()->iconService->deleteIcon($this, $type); - } - - /** - * Returns the timestamp of when the icon was changed. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * - * @return int|null A unix timestamp of when the icon was last changed, or null if not set. - */ - public function getIconLastChange(string $size, string $type = 'icon'): ?int { - return _elgg_services()->iconService->getIconLastChange($this, $size, $type); - } - - /** - * Returns if the entity has an icon of the passed type. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function hasIcon(string $size, string $type = 'icon'): bool { - return _elgg_services()->iconService->hasIcon($this, $size, $type); - } - - /** - * Get the URL for this entity's icon - * - * Plugins can register for the 'entity:icon:url', '' event - * to customize the icon for an entity. - * - * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) - * or an array of parameters including 'size' - * @return string The URL - * @since 1.8.0 - */ - public function getIconURL(string|array $params = []): string { - return _elgg_services()->iconService->getIconURL($this, $params); - } - /** * {@inheritDoc} */ @@ -1582,7 +1494,7 @@ function(QueryBuilder $qb, $main_alias) use ($guid) { * Enable the entity * * @param bool $recursive Recursively enable all entities disabled with the entity? - * @see access_show_hiden_entities() + * * @return bool */ public function enable(bool $recursive = true): bool { @@ -1677,6 +1589,7 @@ public function delete(bool $recursive = true): bool { * Export an entity * * @param array $params Params to pass to the event + * * @return \Elgg\Export\Entity */ public function toObject(array $params = []) { @@ -1691,6 +1604,7 @@ public function toObject(array $params = []) { * Prepare an object copy for toObject() * * @param \Elgg\Export\Entity $object Object representation of the entity + * * @return \Elgg\Export\Entity */ protected function prepareObject(\Elgg\Export\Entity $object) { @@ -1858,6 +1772,7 @@ public function deleteOwnedAccessCollections() { * while last_action is only set when explicitly called. * * @param int $posted Timestamp of last action + * * @return int * @internal */ From cee682c2f0cd0e4bb1c05393ca47dfb01e398d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Thu, 1 Feb 2024 16:05:21 +0100 Subject: [PATCH 163/240] feat(icons): uniform storage of entity icon cropping coordinates ref #14547 --- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 9 ++ engine/classes/Elgg/Entity/CropIcon.php | 25 +-- engine/classes/Elgg/EntityIconService.php | 39 +---- engine/classes/Elgg/Traits/Entity/Icons.php | 65 ++++++++ .../MigrateEntityIconCroppingCoordinates.php | 94 ++++++++++++ .../Entity/IconsIntegrationTestCase.php | 144 ++++++++++++++++++ .../Entity/ElggGroupIconsIntegrationTest.php | 12 ++ .../Entity/ElggObjectIconsIntegrationTest.php | 12 ++ .../Entity/ElggSiteIconsIntegrationTest.php | 12 ++ .../Entity/ElggUserIconsIntegrationTest.php | 12 ++ engine/upgrades.php | 1 + languages/en.php | 3 + views/default/entity/edit/icon/crop.php | 25 +-- 13 files changed, 375 insertions(+), 78 deletions(-) create mode 100644 engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php create mode 100644 engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php create mode 100644 engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggGroupIconsIntegrationTest.php create mode 100644 engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggObjectIconsIntegrationTest.php create mode 100644 engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggSiteIconsIntegrationTest.php create mode 100644 engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggUserIconsIntegrationTest.php diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index 9bff2fabf53..0f261b4f314 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -37,6 +37,15 @@ alias for the ``annotations`` table has been changed from ``n_table`` to ``a_tab If your code uses very specific clauses (select, where, order_by, etc.) you need to update your code. If you use the ``\Elgg\Database\QueryBuilder`` for your query parts you should be ok. +Entity Icons +------------ + +Cropping coordinates +~~~~~~~~~~~~~~~~~~~~ + +The cropping coordinates of the default icon (``icon``) are now stored in a uniform way, same as those of the other icon types. +The metadata ``x1``, ``x2``, ``y1`` and ``y2`` no longer exist. Use the new ``\ElggEntity`` function ``getIconCoordinates()``. + Changes in functions -------------------- diff --git a/engine/classes/Elgg/Entity/CropIcon.php b/engine/classes/Elgg/Entity/CropIcon.php index 74afb1fdc6d..73881ff9f7d 100644 --- a/engine/classes/Elgg/Entity/CropIcon.php +++ b/engine/classes/Elgg/Entity/CropIcon.php @@ -71,30 +71,7 @@ protected function prepareUpload(int $entity_guid, string $input_name, string $i return; } - $current = []; - if ($icon_type === 'icon') { - $current = [ - 'x1' => $entity->x1, - 'y1' => $entity->y1, - 'x2' => $entity->x2, - 'y2' => $entity->y2, - ]; - } elseif (isset($entity->{"{$icon_type}_coords"})) { - $current = unserialize($entity->{"{$icon_type}_coords"}); - - if (!is_array($current)) { - $current = []; - } - } - - // cast to ints - array_walk($current, function(&$value) { - $value = (int) $value; - }); - // remove invalid values - $current = array_filter($current, function($value) { - return $value >= 0; - }); + $current = $entity->getIconCoordinates($icon_type); $input_cropping_coords = [ 'x1' => (int) get_input("{$input_name}_x1", get_input('x1')), diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index 03aae36a52f..6301e6360a9 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -277,21 +277,10 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a // save cropping coordinates if ($type == 'icon') { $entity->icontime = time(); - if ($x1 || $y1 || $x2 || $y2) { - $entity->x1 = $x1; - $entity->y1 = $y1; - $entity->x2 = $x2; - $entity->y2 = $y2; - } - } else { - if ($x1 || $y1 || $x2 || $y2) { - $entity->{"{$type}_coords"} = serialize([ - 'x1' => $x1, - 'y1' => $y1, - 'x2' => $x2, - 'y2' => $y2, - ]); - } + } + + if ($x1 || $y1 || $x2 || $y2) { + $entity->saveIconCoordinates($coords); } $this->events->triggerResults("entity:{$type}:saved", $entity->getType(), [ @@ -471,17 +460,7 @@ public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = return $icon; } - if ($type === 'icon') { - $coords = [ - 'x1' => $entity->x1, - 'y1' => $entity->y1, - 'x2' => $entity->x2, - 'y2' => $entity->y2, - ]; - } else { - $coords = $entity->{"{$type}_coords"}; - $coords = empty($coords) ? [] : unserialize($coords); - } + $coords = $entity->getIconCoordinates($type); $this->generateIcon($entity, $master_icon, $type, $coords, $size); @@ -546,14 +525,10 @@ public function deleteIcon(\ElggEntity $entity, string $type = 'icon', bool $ret if ($type == 'icon') { unset($entity->icontime); - unset($entity->x1); - unset($entity->y1); - unset($entity->x2); - unset($entity->y2); - } else { - unset($entity->{"{$type}_coords"}); } + $entity->removeIconCoordinates($type); + return $result; } diff --git a/engine/classes/Elgg/Traits/Entity/Icons.php b/engine/classes/Elgg/Traits/Entity/Icons.php index d9e91b14679..c6ec2e721dd 100644 --- a/engine/classes/Elgg/Traits/Entity/Icons.php +++ b/engine/classes/Elgg/Traits/Entity/Icons.php @@ -2,6 +2,9 @@ namespace Elgg\Traits\Entity; +use Elgg\Exceptions\InvalidArgumentException; +use Elgg\Exceptions\RangeException; + /** * Adds helper functions to \ElggEntity in relation to icons. * @@ -111,4 +114,66 @@ public function hasIcon(string $size, string $type = 'icon'): bool { public function getIconURL(string|array $params = []): string { return _elgg_services()->iconService->getIconURL($this, $params); } + + /** + * Save cropping coordinates for an icon type + * + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + */ + public function saveIconCoordinates(array $coords, string $type = 'icon'): void { + // remove noise from the coords array + $allowed_keys = ['x1', 'x2', 'y1', 'y2']; + $coords = array_filter($coords, function($value, $key) use ($allowed_keys) { + return in_array($key, $allowed_keys) && is_int($value); + }, ARRAY_FILTER_USE_BOTH); + + if (!isset($coords['x1']) || !isset($coords['x2']) || !isset($coords['y1']) || !isset($coords['y2'])) { + throw new InvalidArgumentException('Please provide correct coordinates [x1, x2, y1, y2]'); + } + + if ($coords['x1'] < 0 || $coords['x2'] < 0 || $coords['y1'] < 0 || $coords['y2'] < 0) { + throw new RangeException("Coordinates can't have negative numbers"); + } + + $this->{"{$type}_coords"} = serialize($coords); + } + + /** + * Get the cropping coordinates for an icon type + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return null|array + */ + public function getIconCoordinates(string $type = 'icon'): array { + if (!isset($this->{"{$type}_coords"})) { + return []; + } + + $coords = unserialize($this->{"{$type}_coords"}) ?: []; + + // cast to integers + array_walk($coords, function(&$value) { + $value = (int) $value; + }); + + // remove invalid values + return array_filter($coords, function($value) { + return $value >= 0; + }); + } + + /** + * Remove the cropping coordinates of an icon type + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + */ + public function removeIconCoordinates(string $type = 'icon'): void { + unset($this->{"{$type}_coords"}); + } } diff --git a/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php b/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php new file mode 100644 index 00000000000..eadc17fea64 --- /dev/null +++ b/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php @@ -0,0 +1,94 @@ +countItems()); + } + + /** + * {@inheritdoc} + */ + public function needsIncrementOffset(): bool { + return false; + } + + /** + * {@inheritdoc} + */ + public function countItems(): int { + return elgg_count_entities($this->getOptions()); + } + + /** + * {@inheritdoc} + */ + public function run(Result $result, $offset): Result { + /* @var $entities \ElggBatch */ + $entities = elgg_get_entities($this->getOptions([ + 'offset' => $offset, + ])); + /* @var $entity \ElggEntity */ + foreach ($entities as $entity) { + $coords = [ + 'x1' => (int) $entity->x1, + 'x2' => (int) $entity->x2, + 'y1' => (int) $entity->y1, + 'y2' => (int) $entity->y2, + ]; + + try { + $entity->saveIconCoordinates($coords, 'icon'); + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + // something went wrong with the coords, probably broken + } + + unset($entity->x1); + unset($entity->x2); + unset($entity->y1); + unset($entity->y2); + + $result->addSuccesses(); + } + + return $result; + } + + /** + * Get options for the upgrade + * + * @param array $options additional options + * + * @return array + * @see elgg_get_entities() + */ + protected function getOptions(array $options = []): array { + $defaults = [ + 'limit' => 50, + 'batch' => true, + 'batch_inc_offset' => $this->needsIncrementOffset(), + 'metadata_names' => [ + 'x1', + 'x2', + 'y1', + 'y2', + ], + ]; + + return array_merge($defaults, $options); + } +} diff --git a/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php new file mode 100644 index 00000000000..ee965faf4d5 --- /dev/null +++ b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php @@ -0,0 +1,144 @@ +entity = $this->getEntity(); + } + + abstract protected function getEntity(): \ElggEntity; + + /** + * @dataProvider tooFewCoordinatesProvider + */ + public function testSaveIconCoordinatesWithTooFewCoordinates($x1, $x2, $y1, $y2, $icon_type) { + $coords = [ + 'x1' => $x1, + 'x2' => $x2, + 'y1' => $y1, + 'y2' => $y2, + ]; + + $this->expectException(InvalidArgumentException::class); + $this->entity->saveIconCoordinates($coords, $icon_type); + } + + public static function tooFewCoordinatesProvider(): array { + return [ + [100, 100, 200, null, 'icon'], + [100, 100, null, 200, 'icon'], + [100, null, 200, 200, 'icon'], + [null, 100, 200, 200, 'icon'], + [100, 100, 200, null, 'avatar'], + [100, 100, null, 200, 'avatar'], + [100, null, 200, 200, 'avatar'], + [null, 100, 200, 200, 'avatar'], + ]; + } + + /** + * @dataProvider invalidCoordinatesProvider + */ + public function testSaveIconCoordinatesWithTooInvalidCoordinates($x1, $x2, $y1, $y2, $icon_type) { + $coords = [ + 'x1' => $x1, + 'x2' => $x2, + 'y1' => $y1, + 'y2' => $y2, + ]; + + $this->expectException(RangeException::class); + $this->entity->saveIconCoordinates($coords, $icon_type); + } + + public static function invalidCoordinatesProvider(): array { + return [ + [-100, 100, 200, 200, 'icon'], + [100, -100, 200, 200, 'icon'], + [100, 100, -200, 200, 'icon'], + [100, 100, 200, -200, 'icon'], + [-100, 100, 200, 200, 'avatar'], + [100, -100, 200, 200, 'avatar'], + [100, 100, -200, 200, 'avatar'], + [100, 100, 200, -200, 'avatar'], + ]; + } + + public function testCRUDIconCoordinates() { + $entity = $this->entity; + + $icon_type1 = 'icon'; + $icon_type2 = 'avatar'; + + // start empty + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertIsArray($current1); + $this->assertEmpty($current1); + + $current2 = $entity->getIconCoordinates($icon_type2); + $this->assertIsArray($current2); + $this->assertEmpty($current2); + + // save coordinates + $coords1 = [ + 'x1' => $this->faker()->numberBetween(1, 1000), + 'x2' => $this->faker()->numberBetween(1, 1000), + 'y1' => $this->faker()->numberBetween(1, 1000), + 'y2' => $this->faker()->numberBetween(1, 1000), + ]; + $coords2 = [ + 'x1' => $this->faker()->numberBetween(1, 1000), + 'x2' => $this->faker()->numberBetween(1, 1000), + 'y1' => $this->faker()->numberBetween(1, 1000), + 'y2' => $this->faker()->numberBetween(1, 1000), + ]; + + $entity->saveIconCoordinates($coords1, $icon_type1); + + $entity->invalidateCache(); + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertNotEmpty($current1); + $this->assertEquals($coords1, $current1); + + // shouldn't be saved to a different icon + $this->assertEmpty($entity->getIconCoordinates($icon_type2)); + + // update coordinates + $entity->saveIconCoordinates($coords2, $icon_type1); + + $entity->invalidateCache(); + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertNotEmpty($current1); + $this->assertEquals($coords2, $current1); + + // save to different icon + $entity->saveIconCoordinates($coords1, $icon_type2); + + $entity->invalidateCache(); + $current2 = $entity->getIconCoordinates($icon_type2); + $this->assertNotEmpty($current2); + $this->assertEquals($coords1, $current2); + + $this->assertNotEquals($current1, $current2); + + // remove coordinates + $entity->removeIconCoordinates($icon_type1); + + $entity->invalidateCache(); + $this->assertEmpty($entity->getIconCoordinates($icon_type1)); + $this->assertNotEmpty($entity->getIconCoordinates($icon_type2)); + + $entity->removeIconCoordinates($icon_type2); + $this->assertEmpty($entity->getIconCoordinates($icon_type2)); + } +} diff --git a/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggGroupIconsIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggGroupIconsIntegrationTest.php new file mode 100644 index 00000000000..50410d7440a --- /dev/null +++ b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggGroupIconsIntegrationTest.php @@ -0,0 +1,12 @@ +createGroup(); + } +} diff --git a/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggObjectIconsIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggObjectIconsIntegrationTest.php new file mode 100644 index 00000000000..00f337d247d --- /dev/null +++ b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggObjectIconsIntegrationTest.php @@ -0,0 +1,12 @@ +createObject(); + } +} diff --git a/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggSiteIconsIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggSiteIconsIntegrationTest.php new file mode 100644 index 00000000000..7e6ad7da858 --- /dev/null +++ b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggSiteIconsIntegrationTest.php @@ -0,0 +1,12 @@ +createSite(); + } +} diff --git a/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggUserIconsIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggUserIconsIntegrationTest.php new file mode 100644 index 00000000000..e2c7b39ad15 --- /dev/null +++ b/engine/tests/phpunit/integration/Elgg/Traits/Entity/ElggUserIconsIntegrationTest.php @@ -0,0 +1,12 @@ +createUser(); + } +} diff --git a/engine/upgrades.php b/engine/upgrades.php index ca4e570c600..e4cfdcd3647 100644 --- a/engine/upgrades.php +++ b/engine/upgrades.php @@ -13,6 +13,7 @@ \Elgg\Upgrades\DeleteDiagnosticsPlugin::class, \Elgg\Upgrades\DeleteNotificationsPlugin::class, \Elgg\Upgrades\MigrateACLNotificationPreferences::class, + \Elgg\Upgrades\MigrateEntityIconCroppingCoordinates::class, \Elgg\Upgrades\NotificationsPrefix::class, \Elgg\Upgrades\RemoveOrphanedThreadedComments::class, ]; diff --git a/languages/en.php b/languages/en.php index d7804249138..32f05e11d97 100644 --- a/languages/en.php +++ b/languages/en.php @@ -2071,4 +2071,7 @@ 'core:upgrade:2023011701:title' => "Remove orphaned threaded comments", 'core:upgrade:2023011701:description' => "Due to an error in how threaded comments were removed, there was a chance to create orphaned comments, this upgrade will remove those orphans.", + + 'core:upgrade:2024020101:title' => "Migrate icon cropping coordinates", + 'core:upgrade:2024020101:description' => "Cropping coordinates are stored in a uniform way, this upgrade migrates the old x1, x2, y1 and y2 metadata values", ); diff --git a/views/default/entity/edit/icon/crop.php b/views/default/entity/edit/icon/crop.php index 952de195d93..8ea827b5856 100644 --- a/views/default/entity/edit/icon/crop.php +++ b/views/default/entity/edit/icon/crop.php @@ -34,27 +34,8 @@ // determine current cropping coordinates $entity_coords = []; -if ($entity instanceof ElggEntity) { - if ($icon_type === 'icon') { - $entity_coords = [ - 'x1' => $entity->x1, - 'y1' => $entity->y1, - 'x2' => $entity->x2, - 'y2' => $entity->y2, - ]; - } elseif (isset($entity->{"{$icon_type}_coords"})) { - $entity_coords = unserialize($entity->{"{$icon_type}_coords"}); - } - - // cast to ints - array_walk($entity_coords, function(&$value) { - $value = (int) $value; - }); - - // remove invalid values - $entity_coords = array_filter($entity_coords, function($value) { - return $value >= 0; - }); +if ($entity instanceof \ElggEntity) { + $entity_coords = $entity->getIconCoordinates($icon_type); // still enough for cropping if (isset($entity_coords['x1'], $entity_coords['x2'], $entity_coords['y1'], $entity_coords['y2'])) { @@ -113,7 +94,7 @@ } $img_url = null; -if ($entity instanceof ElggEntity && $entity->hasIcon('master', $icon_type)) { +if ($entity instanceof \ElggEntity && $entity->hasIcon('master', $icon_type)) { $img_url = $entity->getIconURL([ 'size' => 'master', 'type' => $icon_type, From db2dce8441cfbf73d47f045727a15fb0560d9576 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 31 Jan 2024 15:47:59 +0100 Subject: [PATCH 164/240] chore(views): inject server cache directly in views service --- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 5 + .../Elgg/Application/SystemEventHandlers.php | 2 +- engine/classes/Elgg/BootService.php | 5 +- engine/classes/Elgg/Cache/SystemCache.php | 24 +--- engine/classes/Elgg/Cache/ViewCacher.php | 20 +--- engine/classes/Elgg/Config.php | 1 - engine/classes/Elgg/ViewsService.php | 113 +++++++++--------- engine/classes/ElggInstaller.php | 2 +- engine/classes/ElggPlugin.php | 4 +- engine/internal_services.php | 2 +- engine/tests/classes/Elgg/UnitTestCase.php | 1 + .../Elgg/Cache/SystemCacheIntegrationTest.php | 51 -------- .../ElggPluginStaticConfigIntegrationTest.php | 4 +- .../Elgg/ViewsServiceIntegrationTest.php | 62 ++++++++++ .../Elgg/Plugins/ViewStackIntegrationTest.php | 2 - .../unit/Elgg/Views/CoreViewStackUnitTest.php | 4 +- .../unit/Elgg/ViewsServiceUnitTest.php | 18 +-- .../phpunit/unit/ElggInstallerUnitTest.php | 2 +- .../unit/Elgg/Search/SearchRouterTest.php | 2 +- .../ApiAuthenticationIntegrationTest.php | 2 +- 20 files changed, 144 insertions(+), 182 deletions(-) delete mode 100644 engine/tests/phpunit/integration/Elgg/Cache/SystemCacheIntegrationTest.php create mode 100644 engine/tests/phpunit/integration/Elgg/ViewsServiceIntegrationTest.php diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index 9bff2fabf53..1a096f5b3a2 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -49,3 +49,8 @@ Miscellaneous API changes ------------------------- * The interface ``\Elgg\EntityIcon`` has been removed. Implemented functions in ``\ElggEntity`` have been moved to ``\Elgg\Traits\Entity\Icons`` + +Removed Config values +------------------------ + +* ``system_cache_loaded`` diff --git a/engine/classes/Elgg/Application/SystemEventHandlers.php b/engine/classes/Elgg/Application/SystemEventHandlers.php index fa984b7e759..400391b1b40 100644 --- a/engine/classes/Elgg/Application/SystemEventHandlers.php +++ b/engine/classes/Elgg/Application/SystemEventHandlers.php @@ -117,7 +117,7 @@ public static function initLate() { * @return void */ public static function ready() { - _elgg_services()->systemCache->init(); + _elgg_services()->views->cacheConfiguration(); } /** diff --git a/engine/classes/Elgg/BootService.php b/engine/classes/Elgg/BootService.php index c09109af066..7faee165eed 100644 --- a/engine/classes/Elgg/BootService.php +++ b/engine/classes/Elgg/BootService.php @@ -79,9 +79,7 @@ public function boot(InternalContainer $services) { $debug = $config->getInitialValue('debug') ?? ($config->debug ?: LogLevel::CRITICAL); $services->logger->setLevel($debug); - if ($config->system_cache_enabled) { - $config->system_cache_loaded = $services->views->configureFromCache($services->serverCache); - } + $services->views->configureFromCache(); } /** @@ -92,7 +90,6 @@ public function boot(InternalContainer $services) { public function clearCache() { $this->cache->clear(); _elgg_services()->plugins->setBootPlugins(null); - _elgg_services()->config->system_cache_loaded = false; _elgg_services()->config->_boot_cache_hit = false; } diff --git a/engine/classes/Elgg/Cache/SystemCache.php b/engine/classes/Elgg/Cache/SystemCache.php index 8ec5c7c2243..c161e2d1e12 100644 --- a/engine/classes/Elgg/Cache/SystemCache.php +++ b/engine/classes/Elgg/Cache/SystemCache.php @@ -15,20 +15,14 @@ class SystemCache { use Cacheable; - /** - * @var Config - */ - protected $config; - /** * Constructor * * @param BaseCache $cache Elgg disk cache * @param Config $config Elgg config */ - public function __construct(BaseCache $cache, Config $config) { + public function __construct(BaseCache $cache, protected Config $config) { $this->cache = $cache; - $this->config = $config; } /** @@ -119,20 +113,4 @@ public function disable() { $this->config->save('system_cache_enabled', 0); $this->reset(); } - - /** - * Initializes the system cache - * - * @return void - */ - public function init() { - if (!$this->isEnabled()) { - return; - } - - // cache system data if enabled and not loaded - if (!$this->config->system_cache_loaded) { - _elgg_services()->views->cacheConfiguration(_elgg_services()->serverCache); - } - } } diff --git a/engine/classes/Elgg/Cache/ViewCacher.php b/engine/classes/Elgg/Cache/ViewCacher.php index 546c6d3c2cd..e1d2a995785 100644 --- a/engine/classes/Elgg/Cache/ViewCacher.php +++ b/engine/classes/Elgg/Cache/ViewCacher.php @@ -11,25 +11,13 @@ */ class ViewCacher { - /** - * @var ViewsService - */ - private $views; - - /** - * @var Config - */ - private $config; - /** * Constructor * * @param ViewsService $views Views * @param Config $config Config */ - public function __construct(ViewsService $views, Config $config) { - $this->views = $views; - $this->config = $config; + public function __construct(protected ViewsService $views, protected Config $config) { } /** @@ -38,12 +26,12 @@ public function __construct(ViewsService $views, Config $config) { * @return void */ public function registerCoreViews() { - if ($this->config->system_cache_loaded) { + if ($this->views->isViewLocationsLoadedFromCache()) { return; } // Core view files in /views - $this->views->registerPluginViews(Paths::elgg()); + $this->views->registerViewsFromPath(Paths::elgg()); // Core view definitions in /engine/views.php $file = Paths::elgg() . 'engine/views.php'; @@ -54,7 +42,7 @@ public function registerCoreViews() { $spec = Includer::includeFile($file); if (is_array($spec)) { // check for uploaded fontawesome font - if (elgg_get_config('font_awesome_zip')) { + if ($this->config->font_awesome_zip) { $spec['default']['font-awesome/'] = elgg_get_data_path() . 'fontawesome/webfont/'; } diff --git a/engine/classes/Elgg/Config.php b/engine/classes/Elgg/Config.php index 0d66bdefcdd..0a2d90d780c 100644 --- a/engine/classes/Elgg/Config.php +++ b/engine/classes/Elgg/Config.php @@ -121,7 +121,6 @@ * @property string[] $site_featured_menu_names * @property bool $subresource_integrity_enabled Should subresources (js/css) get integrity information * @property bool $system_cache_enabled Is the system cache enabled? - * @property bool $system_cache_loaded * @property bool $testing_mode Is the current application running (PHPUnit) tests * @property string $time_format Preferred PHP time format * @property bool $user_joined_river Do we need to create a river event when a user joins the site diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 1191dc6c7c9..2d034ff99b7 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -28,70 +28,54 @@ class ViewsService { * @see ViewsService::fileExists() * @var array */ - protected $file_exists_cache = []; + protected array $file_exists_cache = []; /** * @var array * * [viewtype][view] => '/path/to/views/style.css' */ - private $locations = []; + protected array $locations = []; /** * @var array Tracks location changes for views * * [viewtype][view][] => '/path/to/views/style.css' */ - private $overrides = []; + protected array $overrides = []; /** * @var array Simplecache views (view names are keys) * * [view] = true */ - private $simplecache_views = []; + protected array $simplecache_views = []; /** * @var array * * [view][priority] = extension_view */ - private $extensions = []; + protected array $extensions = []; /** * @var string[] A list of fallback viewtypes */ - private $fallbacks = []; + protected array $fallbacks = []; - /** - * @var EventsService - */ - private $events; - - /** - * @var SystemCache|null This is set if the views are configured via cache - */ - private $cache; - - /** - * @var \Elgg\Http\Request - */ - private $request; - - /** - * @var string - */ - private $viewtype; + protected ?string $viewtype; + + protected bool $locations_loaded_from_cache = false; /** * Constructor * - * @param EventsService $events Events service - * @param \Elgg\Http\Request $request Http Request + * @param EventsService $events Events service + * @param \Elgg\Http\Request $request Http Request + * @param \Elgg\Config $config Elgg configuration + * @param \Elgg\Cache\SystemCache $server_cache Server cache */ - public function __construct(EventsService $events, HttpRequest $request) { - $this->events = $events; - $this->request = $request; + public function __construct(protected EventsService $events, protected HttpRequest $request, protected Config $config, protected SystemCache $server_cache) { } /** @@ -135,7 +119,7 @@ public function getViewtype(): string { * * @return string */ - private function resolveViewtype(): string { + protected function resolveViewtype(): string { if ($this->request) { $view = $this->request->getParam('view', '', false); if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { @@ -143,7 +127,7 @@ private function resolveViewtype(): string { } } - $view = (string) elgg_get_config('view'); + $view = (string) $this->config->view; if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { return $view; } @@ -473,7 +457,7 @@ protected function fileExists(string $path): bool { * * @return string|false output generated by view file inclusion or false */ - private function renderViewFile(string $view, array $vars, string $viewtype, bool $issue_missing_notice): string|false { + protected function renderViewFile(string $view, array $vars, string $viewtype, bool $issue_missing_notice): string|false { $file = $this->findViewFile($view, $viewtype); if (!$file) { if ($issue_missing_notice) { @@ -662,22 +646,22 @@ public function isCacheableView(string $view): bool { } /** - * Register a plugin's views + * Register all views in a given path * - * @param string $path Base path of the plugin + * @param string $path Base path to scan for views * * @return bool */ - public function registerPluginViews(string $path): bool { + public function registerViewsFromPath(string $path): bool { $path = Paths::sanitize($path); $view_dir = "{$path}views/"; - // plugins don't have to have views. + // do not fail on non existing views folder if (!is_dir($view_dir)) { return true; } - // but if they do, they have to be readable + // but if folder exists it has to be readable $handle = opendir($view_dir); if ($handle === false) { $this->getLogger()->notice("Unable to register views from the directory: {$view_dir}"); @@ -755,8 +739,8 @@ public function listViews(string $viewtype = 'default'): array { public function getInspectorData(): array { $overrides = $this->overrides; - if ($this->cache) { - $data = $this->cache->load('view_overrides'); + if ($this->server_cache) { + $data = $this->server_cache->load('view_overrides'); if (is_array($data)) { $overrides = $data; } @@ -773,39 +757,56 @@ public function getInspectorData(): array { /** * Configure locations from the cache * - * @param SystemCache $cache The system cache - * - * @return bool + * @return void */ - public function configureFromCache(SystemCache $cache): bool { - $data = $cache->load('view_locations'); + public function configureFromCache(): void { + if (!$this->server_cache->isEnabled()) { + return; + } + + $data = $this->server_cache->load('view_locations'); if (!is_array($data)) { - return false; + return; } $this->locations = $data['locations']; - $this->cache = $cache; - - return true; + $this->locations_loaded_from_cache = true; } /** * Cache the configuration * - * @param SystemCache $cache The system cache - * * @return void */ - public function cacheConfiguration(SystemCache $cache): void { + public function cacheConfiguration(): void { + if (!$this->server_cache->isEnabled()) { + return; + } + + // only cache if not already loaded + if ($this->isViewLocationsLoadedFromCache()) { + return; + } + if (empty($this->locations)) { - $cache->delete('view_locations'); + $this->server_cache->delete('view_locations'); return; } - $cache->save('view_locations', ['locations' => $this->locations]); + $this->server_cache->save('view_locations', ['locations' => $this->locations]); // this is saved just for the inspector and is not loaded in loadAll() - $cache->save('view_overrides', $this->overrides); + $this->server_cache->save('view_overrides', $this->overrides); + } + + /** + * Checks if view_locations have been loaded from cache. + * This can be used to determine if there is a need to (re)load view locations + * + * @return bool + */ + public function isViewLocationsLoadedFromCache(): bool { + return $this->locations_loaded_from_cache; } /** @@ -817,7 +818,7 @@ public function cacheConfiguration(SystemCache $cache): void { * * @return void */ - private function setViewLocation(string $view, string $viewtype, string $path): void { + protected function setViewLocation(string $view, string $viewtype, string $path): void { $view = self::canonicalizeViewName($view); $path = strtr($path, '\\', '/'); diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index d2c430b9d23..9380b3bbb4a 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -160,7 +160,7 @@ protected function getApp(): Application { $app->internal_services->views->setViewtype('installation'); $app->internal_services->views->registerViewtypeFallback('installation'); - $app->internal_services->views->registerPluginViews(Paths::elgg()); + $app->internal_services->views->registerViewsFromPath(Paths::elgg()); $app->internal_services->translator->registerTranslations(Paths::elgg() . 'install/languages/', true); return $this->app; diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index fc4840bc086..387a18ab2e1 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -887,7 +887,7 @@ protected function registerPublicServices(): void { * @throws \Elgg\Exceptions\PluginException */ protected function registerViews(): void { - if (_elgg_services()->config->system_cache_loaded) { + if (_elgg_services()->views->isViewLocationsLoadedFromCache()) { return; } @@ -900,7 +900,7 @@ protected function registerViews(): void { } // Allow /views directory files to override - if (!$views->registerPluginViews($this->getPath())) { + if (!$views->registerViewsFromPath($this->getPath())) { $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews', [$this->getID(), $this->guid, $this->getPath()]); throw PluginException::factory([ diff --git a/engine/internal_services.php b/engine/internal_services.php index 26079ee764d..b56305b7040 100644 --- a/engine/internal_services.php +++ b/engine/internal_services.php @@ -180,7 +180,7 @@ 'usersApiSessionsTable' => DI\autowire(\Elgg\Database\UsersApiSessionsTable::class), 'users_remember_me_cookies_table' => DI\autowire(\Elgg\Database\UsersRememberMeCookiesTable::class), 'upgradeLocator' => DI\autowire(\Elgg\Upgrade\Locator::class), - 'views' => DI\autowire(\Elgg\ViewsService::class), + 'views' => DI\autowire(\Elgg\ViewsService::class)->constructorParameter('server_cache', DI\get('serverCache')), 'viewCacher' => DI\autowire(\Elgg\Cache\ViewCacher::class), 'widgets' => DI\autowire(\Elgg\WidgetsService::class), diff --git a/engine/tests/classes/Elgg/UnitTestCase.php b/engine/tests/classes/Elgg/UnitTestCase.php index 7d7eff3c67e..e782c0cd1eb 100644 --- a/engine/tests/classes/Elgg/UnitTestCase.php +++ b/engine/tests/classes/Elgg/UnitTestCase.php @@ -55,6 +55,7 @@ public static function createApplication(array $params = []) { } // Invalidate caches + $app->internal_services->serverCache->reset(); $app->internal_services->dataCache->clear(); $app->internal_services->sessionCache->clear(); diff --git a/engine/tests/phpunit/integration/Elgg/Cache/SystemCacheIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Cache/SystemCacheIntegrationTest.php deleted file mode 100644 index 9ce0f76aa3b..00000000000 --- a/engine/tests/phpunit/integration/Elgg/Cache/SystemCacheIntegrationTest.php +++ /dev/null @@ -1,51 +0,0 @@ -createApplication([ - 'isolate' => true, - ]); - - $this->cache = _elgg_services()->serverCache; - $this->is_enabled = _elgg_services()->config->system_cache_enabled; - _elgg_services()->config->system_cache_enabled = false; - } - - public function down() { - _elgg_services()->config->system_cache_enabled = $this->is_enabled; - } - - public function testInitSavesViewLocations() { - $this->cache->enable(); - $this->cache->reset(); - - $this->assertEmpty($this->cache->load('view_locations')); - $this->assertEmpty($this->cache->load('view_overrides')); - - // make sure we register the core views - _elgg_services()->config->system_cache_loaded = false; - _elgg_services()->viewCacher->registerCoreViews(); - - $this->cache->init(); - - $this->assertNotNull($this->cache->load('view_locations')); - $this->assertNotNull($this->cache->load('view_overrides')); - - $this->cache->reset(); - } -} diff --git a/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php index 7a65aecb768..275bee4fb2c 100644 --- a/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/Plugin/ElggPluginStaticConfigIntegrationTest.php @@ -19,6 +19,8 @@ public function up() { 'isolate' => true, ]); + _elgg_services()->reset('views'); // needed to make sure views will get loaded correctly + $this->plugin = \ElggPlugin::fromId('static_config', $this->normalizeTestFilePath('mod/')); $this->plugin->autoload(); @@ -49,8 +51,6 @@ public function testBootstrapRegistration() { public function testViewsRegistration(string $view_name, string $expected_view_output) { $this->assertFalse(elgg_view_exists($view_name)); - elgg_set_config('system_cache_loaded', false); - $this->invokeInaccessableMethod($this->plugin, 'registerViews'); $this->assertTrue(elgg_view_exists($view_name)); diff --git a/engine/tests/phpunit/integration/Elgg/ViewsServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/ViewsServiceIntegrationTest.php new file mode 100644 index 00000000000..6b9fd8dff39 --- /dev/null +++ b/engine/tests/phpunit/integration/Elgg/ViewsServiceIntegrationTest.php @@ -0,0 +1,62 @@ +createApplication([ + 'isolate' => true, + ]); + + _elgg_services()->reset('views'); + + $this->cache = _elgg_services()->serverCache; + $this->views = _elgg_services()->views; + + $this->cache->enable(); + $this->cache->reset(); + } + + public function testConfigureFromCache() { + $test_data = ['locations' => [ + 'default' => [ + 'foo' => 'bar.php' + ], + ]]; + + $this->assertEmpty($this->cache->load('view_locations')); + $this->assertEmpty($this->views->listViews()); + + $this->cache->save('view_locations', $test_data); + + $this->assertFalse($this->views->isViewLocationsLoadedFromCache()); + + $this->views->configureFromCache(); + + $this->assertTrue($this->views->isViewLocationsLoadedFromCache()); + + $this->assertEquals(array_keys($test_data['locations']['default']), $this->views->listViews()); + + // assert that once loaded we do not load again + $this->cache->reset(); + $this->views->configureFromCache(); + $this->assertEquals(array_keys($test_data['locations']['default']), $this->views->listViews()); + } + + public function testCacheConfiguration() { + $this->assertEmpty($this->cache->load('view_locations')); + $this->assertEmpty($this->cache->load('view_overrides')); + + // make sure we register the core views + _elgg_services()->reset('viewCacher'); + _elgg_services()->viewCacher->registerCoreViews(); + + $this->views->cacheConfiguration(); + + $this->assertNotNull($this->cache->load('view_locations')); + $this->assertNotNull($this->cache->load('view_overrides')); + } +} diff --git a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php index a7c7efef7eb..2b27869286b 100644 --- a/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php +++ b/engine/tests/phpunit/plugins_integration/Elgg/Plugins/ViewStackIntegrationTest.php @@ -15,7 +15,6 @@ class ViewStackIntegrationTest extends PluginsIntegrationTestCase { public function up() { parent::up(); - elgg_set_config('system_cache_loaded', false); _elgg_services()->reset('views'); $this->views = _elgg_services()->views; @@ -39,7 +38,6 @@ public static function viewsProvider(): array { continue; } - elgg_set_config('system_cache_loaded', false); _elgg_services()->reset('views'); // can not use ->startPlugin() as it needs to be static diff --git a/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php b/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php index 6ba7f9abdc2..7a5868f4e57 100644 --- a/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/Views/CoreViewStackUnitTest.php @@ -8,7 +8,7 @@ class CoreViewStackUnitTest extends UnitTestCase { public function up() { - _elgg_services()->views->registerPluginViews(Paths::elgg()); + _elgg_services()->views->registerViewsFromPath(Paths::elgg()); } public static function viewsProvider() { @@ -17,7 +17,7 @@ public static function viewsProvider() { $provides = []; - _elgg_services()->views->registerPluginViews(Paths::elgg()); + _elgg_services()->views->registerViewsFromPath(Paths::elgg()); $data = _elgg_services()->views->getInspectorData(); foreach ($data['locations'] as $viewtype => $views) { diff --git a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php index 9704d29c57a..00515f68e1f 100644 --- a/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php +++ b/engine/tests/phpunit/unit/Elgg/ViewsServiceUnitTest.php @@ -23,7 +23,7 @@ public function up() { $this->events = new EventsService(_elgg_services()->handlers); $logger = $this->createMock('\Elgg\Logger', array(), array(), '', false); - $this->views = new ViewsService($this->events, _elgg_services()->request); + $this->views = new ViewsService($this->events, _elgg_services()->request, _elgg_services()->config, _elgg_services()->serverCache); $this->views->setLogger($logger); $this->views->autoregisterViews('', "{$this->viewsDir}/default", 'default'); $this->views->autoregisterViews('', "{$this->viewsDir}/json", 'json'); @@ -169,22 +169,6 @@ public function testCanReplaceViews() { $this->assertSame("123", $this->views->renderView('js/interpreted.js')); } - public function testThrowsOnCircularAliases() { - $this->markTestIncomplete(); - } - - public function testEmitsDeprecationWarningWhenOldViewNameIsReferenced() { - $this->markTestIncomplete(); - // elgg_view - // elgg_extend_view - // elgg_unextend_view - // views/* - // engine/views.php - // elgg_get_simplecache_url - // elgg_set_view_location - // elgg_get_view_location - } - /** * @dataProvider getExampleNormalizedViews */ diff --git a/engine/tests/phpunit/unit/ElggInstallerUnitTest.php b/engine/tests/phpunit/unit/ElggInstallerUnitTest.php index 56218e32d17..ba330c4c812 100644 --- a/engine/tests/phpunit/unit/ElggInstallerUnitTest.php +++ b/engine/tests/phpunit/unit/ElggInstallerUnitTest.php @@ -66,7 +66,7 @@ public function getApp() { $this->app = $app; $this->app->internal_services->views->setViewtype('installation'); - $this->app->internal_services->views->registerPluginViews(Paths::elgg()); + $this->app->internal_services->views->registerViewsFromPath(Paths::elgg()); $this->app->internal_services->translator->registerTranslations(Paths::elgg() . "install/languages/", true); return $this->app; diff --git a/mod/search/tests/phpunit/unit/Elgg/Search/SearchRouterTest.php b/mod/search/tests/phpunit/unit/Elgg/Search/SearchRouterTest.php index 9f80e01715a..b158ff31268 100644 --- a/mod/search/tests/phpunit/unit/Elgg/Search/SearchRouterTest.php +++ b/mod/search/tests/phpunit/unit/Elgg/Search/SearchRouterTest.php @@ -11,7 +11,7 @@ public function up() { $this->startPlugin(); elgg_entity_enable_capability('object', 'custom', 'searchable'); - _elgg_services()->views->registerPluginViews($this->getPath()); + _elgg_services()->views->registerViewsFromPath($this->getPath()); } public function testPageHandler() { diff --git a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php index 670fc9c9fa9..6cf5b08c380 100644 --- a/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php +++ b/mod/web_services/tests/phpunit/integration/Elgg/WebServices/ApiAuthenticationIntegrationTest.php @@ -74,7 +74,7 @@ protected function createService(Request $request): void { ]); // in some cases there was a failure with missing view - $app->internal_services->views->registerPluginViews($this->plugin->getPath()); + $app->internal_services->views->registerViewsFromPath($this->plugin->getPath()); } /** From 7e139b9352908407bf48edec343c96fbf317df35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Fri, 9 Feb 2024 16:04:09 +0100 Subject: [PATCH 165/240] removed(icons): icontime metadata is no longer available ref #14547 --- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 8 ++ docs/guides/events-list.rst | 13 +-- engine/classes/Elgg/EntityIconService.php | 8 -- .../classes/Elgg/Upgrades/RemoveIcontime.php | 81 +++++++++++++++++++ engine/upgrades.php | 1 + languages/en.php | 3 + 6 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 engine/classes/Elgg/Upgrades/RemoveIcontime.php diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index bce97c1ba86..4c520affba2 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -46,6 +46,14 @@ Cropping coordinates The cropping coordinates of the default icon (``icon``) are now stored in a uniform way, same as those of the other icon types. The metadata ``x1``, ``x2``, ``y1`` and ``y2`` no longer exist. Use the new ``\ElggEntity`` function ``getIconCoordinates()``. +Icontime +~~~~~~~~ + +The metadata ``icontime`` has been removed from the database. This was an unreliable way to check if an icon was uploaded. +This was only stored for the icon type ``icon``. + +A reliable way to check if an icon was uploaded is to use the ``\ElggEntity::hasIcon()`` function. + Changes in functions -------------------- diff --git a/docs/guides/events-list.rst b/docs/guides/events-list.rst index acb1f12d1c8..d005b7bd120 100644 --- a/docs/guides/events-list.rst +++ b/docs/guides/events-list.rst @@ -1151,14 +1151,15 @@ Other * * @param \Elgg\Event $event 'entity:icon:url', 'user' * - * @return string + * @return string|null */ - function gravatar_icon_handler(\Elgg\Event $event) { + function gravatar_icon_handler(\Elgg\Event $event): ?string { $entity = $event->getEntityParam(); - + $size = $event->getParam('size'); + // Allow users to upload avatars - if ($entity->icontime) { - return $url; + if ($entity->hasIcon($size)) { + return null; } // Generate gravatar hash for user email @@ -1175,7 +1176,7 @@ Other } // Produce URL used to retrieve icon - return "http://www.gravatar.com/avatar/$hash?s=$size"; + return "https://www.gravatar.com/avatar/{$hash}?s={$size}"; } **entity::url, ** |results| diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index 6301e6360a9..afe22b421e4 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -275,10 +275,6 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a $entity->invalidateCache(); // save cropping coordinates - if ($type == 'icon') { - $entity->icontime = time(); - } - if ($x1 || $y1 || $x2 || $y2) { $entity->saveIconCoordinates($coords); } @@ -523,10 +519,6 @@ public function deleteIcon(\ElggEntity $entity, string $type = 'icon', bool $ret } } - if ($type == 'icon') { - unset($entity->icontime); - } - $entity->removeIconCoordinates($type); return $result; diff --git a/engine/classes/Elgg/Upgrades/RemoveIcontime.php b/engine/classes/Elgg/Upgrades/RemoveIcontime.php new file mode 100644 index 00000000000..4323e1caafd --- /dev/null +++ b/engine/classes/Elgg/Upgrades/RemoveIcontime.php @@ -0,0 +1,81 @@ +countItems()); + } + + /** + * {@inheritdoc} + */ + public function needsIncrementOffset(): bool { + return false; + } + + /** + * {@inheritdoc} + */ + public function countItems(): int { + return elgg_get_metadata($this->getOptions([ + 'count' => true, + ])); + } + + /** + * {@inheritdoc} + */ + public function run(Result $result, $offset): Result { + /* @var $metadata \ElggBatch */ + $metadata = elgg_get_metadata($this->getOptions([ + 'offset' => $offset, + ])); + + /* @var $md \ElggMetadata */ + foreach ($metadata as $md) { + if (!$md->delete()) { + $metadata->reportFailure(); + $result->addFailures(); + continue; + } + + $result->addSuccesses(); + } + + return $result; + } + + /** + * Get options to metadata queries + * + * @param array $options additional options + * + * @return array + * @see elgg_get_metadata() + */ + protected function getOptions(array $options = []): array { + $defaults = [ + 'metadata_names' => 'icontime', + 'limit' => 50, + 'batch' => true, + 'batch_inc_offset' => $this->needsIncrementOffset(), + ]; + + return array_merge($defaults, $options); + } +} diff --git a/engine/upgrades.php b/engine/upgrades.php index e4cfdcd3647..86b60302481 100644 --- a/engine/upgrades.php +++ b/engine/upgrades.php @@ -15,5 +15,6 @@ \Elgg\Upgrades\MigrateACLNotificationPreferences::class, \Elgg\Upgrades\MigrateEntityIconCroppingCoordinates::class, \Elgg\Upgrades\NotificationsPrefix::class, + \Elgg\Upgrades\RemoveIcontime::class, \Elgg\Upgrades\RemoveOrphanedThreadedComments::class, ]; diff --git a/languages/en.php b/languages/en.php index 32f05e11d97..26892c80f53 100644 --- a/languages/en.php +++ b/languages/en.php @@ -2074,4 +2074,7 @@ 'core:upgrade:2024020101:title' => "Migrate icon cropping coordinates", 'core:upgrade:2024020101:description' => "Cropping coordinates are stored in a uniform way, this upgrade migrates the old x1, x2, y1 and y2 metadata values", + + 'core:upgrade:2024020901:title' => "Remove icontime metadata", + 'core:upgrade:2024020901:description' => "Remove the unreliable metadata icontime from the database", ); From 134a7b03c2118b0d9895eca829f813b2b6e02416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 14 Feb 2024 15:44:11 +0100 Subject: [PATCH 166/240] chore(tests): test unset entity metadata during unit tests --- .../Elgg/Mocks/Database/MetadataTable.php | 38 +++++++++++++++++-- .../tests/phpunit/unit/ElggEntityUnitTest.php | 28 ++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php b/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php index 8a5b64f7f2e..bc238fe5fed 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php @@ -8,7 +8,6 @@ use Elgg\Database\MetadataTable as DbMetadataTabe; use Elgg\Database\Select; use Elgg\Database\Update; -use ElggMetadata; class MetadataTable extends DbMetadataTabe { @@ -31,7 +30,7 @@ class MetadataTable extends DbMetadataTabe { /** * {@inheritdoc} */ - public function create(ElggMetadata $metadata, bool $allow_multiple = false): int|false { + public function create(\ElggMetadata $metadata, bool $allow_multiple = false): int|false { if (!isset($metadata->value) || !isset($metadata->entity_guid)) { elgg_log("Metadata must have a value and entity guid", 'ERROR'); return false; @@ -101,7 +100,7 @@ public function create(ElggMetadata $metadata, bool $allow_multiple = false): in /** * {@inheritdoc} */ - public function update(ElggMetadata $metadata): bool { + public function update(\ElggMetadata $metadata): bool { if (!$this->entityTable->exists($metadata->entity_guid)) { elgg_log("Can't updated metadata to a non-existing entity_guid", 'ERROR'); return false; @@ -144,7 +143,6 @@ public function getAll(array $options = array()) { * {@inheritdoc} */ public function getRowsForGuids(array $guids): array { - $rows = []; foreach ($this->rows as $row) { if (in_array($row->entity_guid, $guids)) { @@ -155,6 +153,38 @@ public function getRowsForGuids(array $guids): array { return $rows; } + /** + * {@inheritdoc} + */ + public function deleteAll(array $options): bool { + $guids = elgg_extract('guids', $options, (array) elgg_extract('guid', $options)); + + $rows = []; + foreach ($this->rows as $row) { + if (empty($guids) || in_array($row->entity_guid, $guids)) { + $rows[] = $row; + } + } + + if (empty($rows)) { + return parent::deleteAll($options); + } + + $names = elgg_extract('metadata_names', $options, (array) elgg_extract('metadata_name', $options)); + if (!empty($names)) { + $rows = array_filter($rows, function($row) use ($names) { + return in_array($row->name, $names); + }); + } + + foreach ($rows as $row) { + unset($this->rows[$row->id]); + $this->clearQuerySpecs($row); + } + + return parent::deleteAll($options); + } + /** * Clear query specs * diff --git a/engine/tests/phpunit/unit/ElggEntityUnitTest.php b/engine/tests/phpunit/unit/ElggEntityUnitTest.php index bc3ab8db155..bb15737d092 100644 --- a/engine/tests/phpunit/unit/ElggEntityUnitTest.php +++ b/engine/tests/phpunit/unit/ElggEntityUnitTest.php @@ -101,11 +101,39 @@ public function testSettingMetadataNoDatabase() { $this->obj->foo = 'overwrite'; $this->assertEquals('overwrite', $this->obj->foo); } + + public function testUnsettingMetadataNoDatabase() { + $this->obj->foo = 'bar'; + $this->assertEquals('bar', $this->obj->foo); + unset($this->obj->foo); + $this->assertNull($this->obj->foo); + } public function testGettingNonexistentMetadataNoDatabase() { $this->assertNull($this->obj->foo); } + public function testSettingMetadataWithDatabase() { + $entity = $this->createObject(); + $entity->foo = 'test'; + $this->assertEquals('test', $entity->foo); + $entity->foo = 'overwrite'; + $this->assertEquals('overwrite',$entity->foo); + } + + public function testUnsettingMetadataWithDatabase() { + $entity = $this->createObject(); + $entity->foo = 'bar'; + $this->assertEquals('bar', $entity->foo); + unset($entity->foo); + $this->assertNull($entity->foo); + } + + public function testGettingNonexistentMetadataWithDatabase() { + $entity = $this->createObject(); + $this->assertNull($entity->foo); + } + public function testAnnotationsNoDatabase() { $this->obj->annotate('foo', 'bar'); $this->assertEquals(['bar'], $this->obj->getAnnotations(['annotation_name' => 'foo'])); From 469dd1deb12ecf7e20771a5d99198244b3292fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 14 Feb 2024 14:15:41 +0100 Subject: [PATCH 167/240] chore(icons): lock icon thumbnail generation during upload / resize To prevent the thumbnails from being generated with the wrong information ref #14547 --- engine/classes/Elgg/EntityIconService.php | 8 ++++ engine/classes/Elgg/Traits/Entity/Icons.php | 48 +++++++++++++++++++ .../Entity/IconsIntegrationTestCase.php | 37 ++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index afe22b421e4..efd133a2bf7 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -223,6 +223,8 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a return false; } + $entity->lockIconThumbnailGeneration($type); + $this->prepareIcon($file->getFilenameOnFilestore()); $x1 = (int) elgg_extract('x1', $coords); @@ -287,6 +289,8 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a 'y2' => $y2, ]); + $entity->unlockIconThumbnailGeneration($type); + return true; } @@ -450,6 +454,10 @@ public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = return $icon; } + if ($entity->isIconThumbnailGenerationLocked($type)) { + return $icon; + } + // try to generate icon based on master size $master_icon = $this->getIcon($entity, 'master', $type, false); if (!$master_icon->exists()) { diff --git a/engine/classes/Elgg/Traits/Entity/Icons.php b/engine/classes/Elgg/Traits/Entity/Icons.php index c6ec2e721dd..b04a15750b2 100644 --- a/engine/classes/Elgg/Traits/Entity/Icons.php +++ b/engine/classes/Elgg/Traits/Entity/Icons.php @@ -122,6 +122,7 @@ public function getIconURL(string|array $params = []): string { * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' * * @return void + * @since 6.0 */ public function saveIconCoordinates(array $coords, string $type = 'icon'): void { // remove noise from the coords array @@ -147,6 +148,7 @@ public function saveIconCoordinates(array $coords, string $type = 'icon'): void * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' * * @return null|array + * @since 6.0 */ public function getIconCoordinates(string $type = 'icon'): array { if (!isset($this->{"{$type}_coords"})) { @@ -172,8 +174,54 @@ public function getIconCoordinates(string $type = 'icon'): array { * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' * * @return void + * @since 6.0 */ public function removeIconCoordinates(string $type = 'icon'): void { unset($this->{"{$type}_coords"}); } + + /** + * Lock thumbnail generation during icon upload/resize + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function lockIconThumbnailGeneration(string $type = 'icon'): void { + $this->{"{$type}_thumbnail_locked"} = time(); + } + + /** + * Is thumbnail generation prevented + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * @param int $ttl Time-to-live for the lock in seconds (in case of errors) + * + * @return bool + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function isIconThumbnailGenerationLocked(string $type = 'icon', int $ttl = 30): bool { + if (!isset($this->{"{$type}_thumbnail_locked"})) { + return false; + } + + $locked = (int) $this->{"{$type}_thumbnail_locked"}; + return $locked > (time() - $ttl); + } + + /** + * Unlock thumbnail generation when upload/resize is complete + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function unlockIconThumbnailGeneration(string $type = 'icon'): void { + unset($this->{"{$type}_thumbnail_locked"}); + } } diff --git a/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php index ee965faf4d5..69bcc2feeed 100644 --- a/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php @@ -141,4 +141,41 @@ public function testCRUDIconCoordinates() { $entity->removeIconCoordinates($icon_type2); $this->assertEmpty($entity->getIconCoordinates($icon_type2)); } + + public function testIconGenerationLocking() { + $entity = $this->entity; + + $icon_type1 = 'icon'; + $icon_type2 = 'avatar'; + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // lock generation + $entity->lockIconThumbnailGeneration($icon_type1); + + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // check ttl + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1, -1)); + + // lock other icon generation + $entity->lockIconThumbnailGeneration($icon_type2); + + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // unlock + $entity->unlockIconThumbnailGeneration($icon_type1); + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // unlock other icon + $entity->unlockIconThumbnailGeneration($icon_type2); + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + } } From 68924ec496a9501244f296db678aa04ad797e87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B4me=20Bakker?= Date: Wed, 14 Feb 2024 14:27:17 +0100 Subject: [PATCH 168/240] chore(icons): code cleanup --- engine/classes/Elgg/EntityIconService.php | 95 +++++-------------- .../Elgg/EntityIconServiceIntegrationTest.php | 2 +- 2 files changed, 26 insertions(+), 71 deletions(-) diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index efd133a2bf7..9dc67d4b0f5 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -22,41 +22,6 @@ class EntityIconService { use Loggable; use TimeUsing; - /** - * @var Config - */ - private $config; - - /** - * @var EventsService - */ - private $events; - - /** - * @var EntityTable - */ - private $entities; - - /** - * @var UploadService - */ - private $uploads; - - /** - * @var ImageService - */ - private $images; - - /** - * @var MimeTypeService - */ - protected $mimetype; - - /** - * @var HttpRequest - */ - protected $request; - /** * Constructor * @@ -69,21 +34,14 @@ class EntityIconService { * @param Request $request Http Request service */ public function __construct( - Config $config, - EventsService $events, - EntityTable $entities, - UploadService $uploads, - ImageService $images, - MimeTypeService $mimetype, - HttpRequest $request + protected Config $config, + protected EventsService $events, + protected EntityTable $entities, + protected UploadService $uploads, + protected ImageService $images, + protected MimeTypeService $mimetype, + protected HttpRequest $request ) { - $this->config = $config; - $this->events = $events; - $this->entities = $entities; - $this->uploads = $uploads; - $this->images = $images; - $this->mimetype = $mimetype; - $this->request = $request; } /** @@ -96,7 +54,7 @@ public function __construct( * * @return bool */ - public function saveIconFromUploadedFile(\ElggEntity $entity, $input_name, $type = 'icon', array $coords = []) { + public function saveIconFromUploadedFile(\ElggEntity $entity, string $input_name, string $type = 'icon', array $coords = []): bool { $input = $this->uploads->getFile($input_name); if (empty($input)) { return false; @@ -138,7 +96,7 @@ public function saveIconFromUploadedFile(\ElggEntity $entity, $input_name, $type * @return bool * @throws InvalidArgumentException */ - public function saveIconFromLocalFile(\ElggEntity $entity, $filename, $type = 'icon', array $coords = []) { + public function saveIconFromLocalFile(\ElggEntity $entity, string $filename, string $type = 'icon', array $coords = []): bool { if (!file_exists($filename) || !is_readable($filename)) { throw new InvalidArgumentException(__METHOD__ . " expects a readable local file. {$filename} is not readable"); } @@ -171,7 +129,7 @@ public function saveIconFromLocalFile(\ElggEntity $entity, $filename, $type = 'i * @return bool * @throws InvalidArgumentException */ - public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, $type = 'icon', array $coords = []) { + public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = []): bool { if (!$file->exists()) { throw new InvalidArgumentException(__METHOD__ . ' expects an instance of ElggFile with an existing file on filestore'); } @@ -203,9 +161,7 @@ public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, $type * * @return bool */ - public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', array $coords = []) { - - $type = (string) $type; + public function saveIcon(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = []): bool { if (!strlen($type)) { $this->getLogger()->error('Icon type passed to ' . __METHOD__ . ' can not be empty'); return false; @@ -276,7 +232,6 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a // the coordinates in deleteIcon() and the new save here $entity->invalidateCache(); - // save cropping coordinates if ($x1 || $y1 || $x2 || $y2) { $entity->saveIconCoordinates($coords); } @@ -301,8 +256,7 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a * * @return void */ - protected function prepareIcon($filename) { - + protected function prepareIcon(string $filename): void { // fix orientation $temp_file = new \ElggTempFile(); $temp_file->setFilename(uniqid() . basename($filename)); @@ -329,8 +283,7 @@ protected function prepareIcon($filename) { * * @return bool */ - protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', $coords = [], $icon_size = '') { - + protected function generateIcon(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = [], string $icon_size = ''): bool { if (!$file->exists()) { $this->getLogger()->error('Trying to generate an icon from a non-existing file'); return false; @@ -418,8 +371,7 @@ protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'i * * @throws UnexpectedValueException */ - public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = true) { - + public function getIcon(\ElggEntity $entity, string $size, string $type = 'icon', bool $generate = true): \ElggIcon { $size = elgg_strtolower($size); $params = [ @@ -585,7 +537,7 @@ public function getIconURL(\ElggEntity $entity, string|array $params = []): stri * * @return string */ - public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { + public function getFallbackIconUrl(\ElggEntity $entity, array $params = []): string { $type = elgg_extract('type', $params, 'icon', false); $size = elgg_extract('size', $params, 'medium', false); @@ -609,6 +561,8 @@ public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { if (elgg_view_exists("{$type}/default/{$size}.png", 'default')) { return elgg_get_simplecache_url("{$type}/default/{$size}.png"); } + + return ''; } /** @@ -620,11 +574,13 @@ public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { * * @return int|null A unix timestamp of when the icon was last changed, or null if not set. */ - public function getIconLastChange(\ElggEntity $entity, $size, $type = 'icon') { + public function getIconLastChange(\ElggEntity $entity, string $size, string $type = 'icon'): ?int { $icon = $this->getIcon($entity, $size, $type); if ($icon->exists()) { return $icon->getModifiedTime(); } + + return null; } /** @@ -636,7 +592,7 @@ public function getIconLastChange(\ElggEntity $entity, $size, $type = 'icon') { * * @return bool */ - public function hasIcon(\ElggEntity $entity, $size, $type = 'icon') { + public function hasIcon(\ElggEntity $entity, string $size, string $type = 'icon'): bool { $icon = $this->getIcon($entity, $size, $type); return $icon->exists() && $icon->getSize() > 0; } @@ -697,10 +653,9 @@ public function getSizes(string $entity_type = null, string $entity_subtype = nu * * @param string $input_name the file input name which is the prefix for the cropping coordinates * - * @return false|array + * @return null|array */ - protected function detectCroppingCoordinates(string $input_name) { - + protected function detectCroppingCoordinates(string $input_name): ?array { $auto_coords = [ 'x1' => get_input("{$input_name}_x1", get_input('x1')), // x1 is BC fallback 'x2' => get_input("{$input_name}_x2", get_input('x2')), // x2 is BC fallback @@ -713,7 +668,7 @@ protected function detectCroppingCoordinates(string $input_name) { }); if (count($auto_coords) !== 4) { - return false; + return null; } // make ints @@ -723,7 +678,7 @@ protected function detectCroppingCoordinates(string $input_name) { // make sure coords make sense x2 > x1 && y2 > y1 if ($auto_coords['x2'] <= $auto_coords['x1'] || $auto_coords['y2'] <= $auto_coords['y1']) { - return false; + return null; } return $auto_coords; diff --git a/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php b/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php index 52fac87729f..184c3e5c970 100644 --- a/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php +++ b/engine/tests/phpunit/integration/Elgg/EntityIconServiceIntegrationTest.php @@ -22,7 +22,7 @@ public function testInvalidDetectCroppingCoordinates($input_name, $params) { $inspector = new \ReflectionClass($service); $method = $inspector->getMethod('detectCroppingCoordinates'); - $this->assertFalse($method->invoke($service, $input_name)); + $this->assertNull($method->invoke($service, $input_name)); } public static function invalidCoordinatesProvider() { From e2e998c2c6c42759518829be0ba0182aee9a411b Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 31 Jan 2024 13:47:36 +0100 Subject: [PATCH 169/240] feat(js): dropped RequireJS in favor of ECMAScript modules --- .github/workflows/javascript.yml | 53 - README.md | 6 +- composer.json | 2 - composer.lock | 28 +- docs/appendix/upgrade-notes/5.x-to-6.0.rst | 23 + docs/contribute/code.rst | 76 +- docs/design/amd.rst | 58 - docs/design/index.rst | 1 - docs/guides/ajax.rst | 14 +- docs/guides/events-list.rst | 10 +- docs/guides/i18n.rst | 10 +- docs/guides/javascript.rst | 187 +- docs/guides/menus.rst | 14 +- docs/guides/plugins.rst | 3 - docs/guides/views/foot-vs-footer.rst | 3 +- docs/index.rst | 4 +- docs/intro/development.rst | 7 +- engine/classes/Elgg/Ajax/Service.php | 56 +- engine/classes/Elgg/Amd/Config.php | 273 - engine/classes/Elgg/Amd/ViewFilter.php | 59 - .../classes/Elgg/Application/CacheHandler.php | 7 + engine/classes/Elgg/Di/InternalContainer.php | 2 +- engine/classes/Elgg/FormsService.php | 25 +- engine/classes/Elgg/Http/Request.php | 2 +- .../classes/Elgg/Javascript/AddSRIConfig.php | 34 - engine/classes/Elgg/Javascript/ESMService.php | 83 + .../Javascript/SetLightboxConfigHandler.php | 2 +- engine/classes/Elgg/Menus/Entity.php | 2 +- .../Elgg/Views/AddAmdModuleNameHandler.php | 23 - engine/classes/Elgg/ViewsService.php | 25 + engine/classes/ElggMenuItem.php | 14 +- engine/events.php | 7 - engine/internal_services.php | 8 +- engine/lib/external_files.php | 59 +- engine/lib/navigation.php | 2 +- engine/lib/views.php | 85 +- engine/tests/js/ElggAjaxTest.js | 596 -- engine/tests/js/ElggHooksTest.js | 93 - engine/tests/js/ElggLanguagesTest.js | 42 - engine/tests/js/ElggLibTest.js | 146 - engine/tests/js/ElggSecurityTest.js | 69 - engine/tests/js/ElggSpinnerTest.js | 100 - engine/tests/js/README.md | 1 - engine/tests/js/karma.conf.js | 78 - engine/tests/js/prepare.js | 16 - engine/tests/js/requirejs.config.js | 23 - .../Javascript/ESMServiceIntegrationTest.php | 33 + .../phpunit/unit/Elgg/Amd/ConfigUnitTest.php | 153 - .../unit/Elgg/Amd/ViewFilterUnitTest.php | 56 - .../Elgg/Http/ResponseFactoryUnitTest.php | 9 +- engine/views.php | 16 +- install/config/htaccess.dist | 2 +- mod/activity/views/default/river/filter.js | 16 - mod/activity/views/default/river/filter.mjs | 15 + mod/activity/views/default/river/filter.php | 2 +- mod/blog/views/default/forms/blog/save.js | 28 - mod/blog/views/default/forms/blog/save.mjs | 30 + mod/blog/views/default/forms/blog/save.php | 2 +- .../classes/Elgg/Bookmarks/Menus/Footer.php | 1 + mod/bookmarks/elgg-plugin.php | 5 - mod/bookmarks/views/default/bookmarks.js | 5 - .../views/default/bookmarks/bookmarks.mjs | 5 + mod/ckeditor/classes/Elgg/CKEditor/Views.php | 2 +- mod/ckeditor/elgg-plugin.php | 2 +- .../views/default/ckeditor/config/base.js | 34 - .../views/default/ckeditor/config/base.mjs | 34 + .../views/default/ckeditor/config/default.js | 22 - .../views/default/ckeditor/config/default.mjs | 25 + .../default/ckeditor/config/file_upload.js | 8 - .../default/ckeditor/config/file_upload.mjs | 8 + .../views/default/ckeditor/config/mentions.js | 160 - .../default/ckeditor/config/mentions.mjs | 159 + .../views/default/ckeditor/config/simple.js | 9 - .../views/default/ckeditor/config/simple.mjs | 13 + mod/ckeditor/views/default/ckeditor/editor.js | 78 - .../views/default/ckeditor/editor.mjs | 76 + mod/ckeditor/views/default/ckeditor/init.php | 13 +- .../classes/Elgg/Developers/Bootstrap.php | 4 - mod/developers/elgg-plugin.php | 1 - mod/developers/languages/en.php | 4 - .../views/default/developers/amd_monitor.js | 30 - .../default/plugins/developers/settings.js | 9 - .../default/plugins/developers/settings.mjs | 9 + .../default/plugins/developers/settings.php | 12 +- .../views/default/forms/discussion/save.js | 15 - .../views/default/forms/discussion/save.mjs | 14 + .../views/default/forms/discussion/save.php | 2 +- .../default/forms/groups/create_navigation.js | 36 - .../forms/groups/create_navigation.mjs | 36 + .../views/default/forms/groups/edit.php | 2 +- .../views/default/groups/edit/access.js | 32 - .../views/default/groups/edit/access.mjs | 32 + .../views/default/groups/edit/access.php | 2 +- .../classes/Elgg/Likes/JsConfigHandler.php | 2 +- mod/likes/elgg-plugin.php | 2 +- mod/likes/views/default/elgg/likes.js | 51 - mod/likes/views/default/elgg/likes.mjs | 50 + .../views/default/elgg/messageboard.js | 30 - .../views/default/elgg/messageboard.mjs | 25 + .../views/default/forms/messageboard/add.php | 2 +- .../default/resources/messageboard/owner.php | 2 +- .../default/widgets/messageboard/content.php | 2 +- .../views/default/forms/messages/process.js | 5 - .../views/default/forms/messages/process.mjs | 5 + .../views/default/forms/messages/process.php | 2 +- .../configure_utilities/profile_fields.js | 19 - .../configure_utilities/profile_fields.mjs | 21 + .../configure_utilities/profile_fields.php | 2 +- .../views/default/elgg/reportedcontent.js | 31 - .../views/default/elgg/reportedcontent.mjs | 32 + .../forms/site_notifications/process.js | 41 - .../forms/site_notifications/process.mjs | 40 + .../forms/site_notifications/process.php | 2 +- .../default/forms/theme_sandbox/ajax_demo.php | 2 +- .../default/resources/theme_sandbox/index.php | 2 +- .../default/theme_sandbox/components/tabs.php | 25 +- .../default/theme_sandbox/demo/ajax_demo.js | 86 - .../default/theme_sandbox/demo/ajax_demo.mjs | 88 + .../theme_sandbox/javascript/lightbox.js | 16 - .../theme_sandbox/javascript/lightbox.mjs | 15 + .../theme_sandbox/javascript/lightbox.php | 2 +- .../default/theme_sandbox/javascript/popup.js | 22 - .../theme_sandbox/javascript/popup.mjs | 21 + .../theme_sandbox/javascript/popup.php | 4 +- .../default/theme_sandbox/modules/widgets.php | 23 +- .../default/theme_sandbox/navigation.php | 2 +- .../theme_sandbox/navigation/require.js | 6 - .../theme_sandbox/navigation/require.mjs | 6 + .../default/theme_sandbox/theme_sandbox.js | 15 - .../default/theme_sandbox/theme_sandbox.mjs | 16 + .../views/default/ckeditor/config/thewire.js | 50 - .../views/default/ckeditor/config/thewire.mjs | 53 + .../views/default/forms/thewire/add.js | 39 - .../views/default/forms/thewire/add.mjs | 38 + .../views/default/forms/thewire/add.php | 2 +- .../views/default/elgg/webservices.js | 43 - .../views/default/elgg/webservices.mjs | 43 + package-lock.json | 5175 ++++------------- package.json | 25 +- views/default/admin/header.php | 2 +- views/default/admin/plugins.js | 119 - views/default/admin/plugins.mjs | 125 + views/default/admin/plugins.php | 2 +- views/default/admin/upgrades.mjs | 303 + views/default/admin/upgrades.php | 2 +- views/default/core/js/upgrader.js | 301 - views/default/elgg.js.php | 73 - .../default/{core/js/elgglib.js => elgg.mjs} | 25 +- views/default/elgg/Ajax.js | 433 -- views/default/elgg/Ajax.mjs | 436 ++ views/default/elgg/admin_notices.js | 27 - views/default/elgg/admin_notices.mjs | 28 + views/default/elgg/autocomplete.js | 23 - views/default/elgg/autocomplete.mjs | 25 + views/default/elgg/comments.js | 218 - views/default/elgg/comments.mjs | 219 + views/default/elgg/hooks.js | 142 - views/default/elgg/hooks.mjs | 143 + views/default/elgg/i18n.js | 83 - views/default/elgg/i18n.mjs | 84 + views/default/elgg/lightbox.js | 178 - views/default/elgg/lightbox.mjs | 182 + views/default/elgg/menus/dropdown.js | 73 - views/default/elgg/menus/dropdown.mjs | 73 + views/default/elgg/menus/toggle.js | 55 - views/default/elgg/menus/toggle.mjs | 55 + views/default/elgg/popup.js | 202 - views/default/elgg/popup.mjs | 198 + views/default/elgg/require_config.js.php | 21 - views/default/elgg/security.js | 157 - views/default/elgg/security.mjs | 159 + views/default/elgg/spinner.js | 58 - views/default/elgg/spinner.mjs | 58 + views/default/elgg/system_messages.js | 109 - views/default/elgg/system_messages.mjs | 109 + views/default/elgg/toggle.js | 44 - views/default/elgg/toggle.mjs | 44 + views/default/elgg/touch_punch.js.php | 23 - views/default/elgg/widgets.js | 91 - views/default/elgg/widgets.mjs | 93 + views/default/entity/edit/icon/crop.js | 166 - views/default/entity/edit/icon/crop.mjs | 170 + views/default/entity/edit/icon/crop.php | 5 +- views/default/forms/admin/site/settings.js | 22 - views/default/forms/admin/site/settings.mjs | 21 + views/default/forms/admin/site/settings.php | 2 +- views/default/forms/admin/site/theme.js | 8 - views/default/forms/admin/site/theme.mjs | 7 + views/default/forms/admin/site/theme.php | 2 +- .../default/forms/admin/users/bulk_actions.js | 40 - .../forms/admin/users/bulk_actions.mjs | 40 + .../forms/admin/users/bulk_actions.php | 2 +- views/default/forms/comment/save.php | 2 +- views/default/forms/settings/notifications.js | 15 - .../default/forms/settings/notifications.mjs | 15 + .../default/forms/settings/notifications.php | 2 +- views/default/forms/useradd.js | 35 - views/default/forms/useradd.mjs | 35 + views/default/forms/useradd.php | 2 +- views/default/icon/user/default.js | 89 - views/default/icon/user/default.mjs | 88 + views/default/icon/user/default.php | 2 +- views/default/initialize_elgg.js.php | 4 +- views/default/input/autocomplete.php | 4 +- views/default/input/date.js | 79 - views/default/input/date.mjs | 81 + views/default/input/date.php | 4 +- views/default/input/entitypicker.js | 162 - views/default/input/entitypicker.mjs | 166 + views/default/input/entitypicker.php | 4 +- views/default/input/file.js | 23 - views/default/input/file.mjs | 24 + views/default/input/file.php | 2 +- views/default/input/form-ajax.js | 32 - views/default/input/form-ajax.mjs | 33 + views/default/input/form-double-submit.js | 5 - views/default/input/form-double-submit.mjs | 5 + views/default/input/form.php | 2 +- views/default/input/tags.js | 30 - views/default/input/tags.mjs | 29 + views/default/input/tags.php | 4 +- views/default/input/url.js | 19 - views/default/input/url.mjs | 19 + views/default/input/url.php | 2 +- .../default/navigation/menu/elements/item.php | 2 +- .../navigation/menu/elements/item_toggle.js | 44 - .../navigation/menu/elements/item_toggle.mjs | 46 + .../notifications/subscriptions/record.js | 55 - .../notifications/subscriptions/record.mjs | 56 + .../notifications/subscriptions/record.php | 2 +- views/default/object/admin_notice.php | 2 +- views/default/object/comment.php | 2 +- views/default/output/url.php | 4 +- views/default/page/components/list.php | 4 +- .../page/components/list/ajax-append-auto.js | 45 - .../page/components/list/ajax-append-auto.mjs | 46 + .../page/components/list/ajax-append.js | 48 - .../page/components/list/ajax-append.mjs | 50 + .../page/components/list/ajax-replace.js | 44 - .../page/components/list/ajax-replace.mjs | 47 + views/default/page/components/tabs.js | 125 - views/default/page/components/tabs.mjs | 126 + views/default/page/components/tabs.php | 2 +- views/default/page/elements/foot.php | 4 - views/default/page/elements/head.php | 23 +- .../default/page/elements/importmap.json.php | 5 + views/default/page/elements/messages.php | 2 +- views/default/page/elements/topbar.js | 5 - views/default/page/elements/topbar.mjs | 5 + views/default/page/elements/topbar.php | 35 +- views/default/page/layouts/widgets.php | 2 +- views/default/resources/widgets/add_panel.js | 63 - views/default/resources/widgets/add_panel.mjs | 64 + views/default/resources/widgets/add_panel.php | 2 +- yarn.lock | 2967 ++-------- 255 files changed, 6526 insertions(+), 13576 deletions(-) delete mode 100644 .github/workflows/javascript.yml delete mode 100644 docs/design/amd.rst delete mode 100644 engine/classes/Elgg/Amd/Config.php delete mode 100644 engine/classes/Elgg/Amd/ViewFilter.php delete mode 100644 engine/classes/Elgg/Javascript/AddSRIConfig.php create mode 100644 engine/classes/Elgg/Javascript/ESMService.php delete mode 100644 engine/classes/Elgg/Views/AddAmdModuleNameHandler.php delete mode 100644 engine/tests/js/ElggAjaxTest.js delete mode 100644 engine/tests/js/ElggHooksTest.js delete mode 100644 engine/tests/js/ElggLanguagesTest.js delete mode 100644 engine/tests/js/ElggLibTest.js delete mode 100644 engine/tests/js/ElggSecurityTest.js delete mode 100644 engine/tests/js/ElggSpinnerTest.js delete mode 100644 engine/tests/js/README.md delete mode 100644 engine/tests/js/karma.conf.js delete mode 100644 engine/tests/js/prepare.js delete mode 100644 engine/tests/js/requirejs.config.js create mode 100644 engine/tests/phpunit/integration/Elgg/Javascript/ESMServiceIntegrationTest.php delete mode 100644 engine/tests/phpunit/unit/Elgg/Amd/ConfigUnitTest.php delete mode 100644 engine/tests/phpunit/unit/Elgg/Amd/ViewFilterUnitTest.php delete mode 100644 mod/activity/views/default/river/filter.js create mode 100644 mod/activity/views/default/river/filter.mjs delete mode 100644 mod/blog/views/default/forms/blog/save.js create mode 100644 mod/blog/views/default/forms/blog/save.mjs delete mode 100644 mod/bookmarks/views/default/bookmarks.js create mode 100644 mod/bookmarks/views/default/bookmarks/bookmarks.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/config/base.js create mode 100644 mod/ckeditor/views/default/ckeditor/config/base.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/config/default.js create mode 100644 mod/ckeditor/views/default/ckeditor/config/default.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/config/file_upload.js create mode 100644 mod/ckeditor/views/default/ckeditor/config/file_upload.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/config/mentions.js create mode 100644 mod/ckeditor/views/default/ckeditor/config/mentions.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/config/simple.js create mode 100644 mod/ckeditor/views/default/ckeditor/config/simple.mjs delete mode 100644 mod/ckeditor/views/default/ckeditor/editor.js create mode 100644 mod/ckeditor/views/default/ckeditor/editor.mjs delete mode 100644 mod/developers/views/default/developers/amd_monitor.js delete mode 100644 mod/developers/views/default/plugins/developers/settings.js create mode 100644 mod/developers/views/default/plugins/developers/settings.mjs delete mode 100644 mod/discussions/views/default/forms/discussion/save.js create mode 100644 mod/discussions/views/default/forms/discussion/save.mjs delete mode 100644 mod/groups/views/default/forms/groups/create_navigation.js create mode 100644 mod/groups/views/default/forms/groups/create_navigation.mjs delete mode 100644 mod/groups/views/default/groups/edit/access.js create mode 100644 mod/groups/views/default/groups/edit/access.mjs delete mode 100644 mod/likes/views/default/elgg/likes.js create mode 100644 mod/likes/views/default/elgg/likes.mjs delete mode 100644 mod/messageboard/views/default/elgg/messageboard.js create mode 100644 mod/messageboard/views/default/elgg/messageboard.mjs delete mode 100644 mod/messages/views/default/forms/messages/process.js create mode 100644 mod/messages/views/default/forms/messages/process.mjs delete mode 100644 mod/profile/views/default/admin/configure_utilities/profile_fields.js create mode 100644 mod/profile/views/default/admin/configure_utilities/profile_fields.mjs delete mode 100644 mod/reportedcontent/views/default/elgg/reportedcontent.js create mode 100644 mod/reportedcontent/views/default/elgg/reportedcontent.mjs delete mode 100644 mod/site_notifications/views/default/forms/site_notifications/process.js create mode 100644 mod/site_notifications/views/default/forms/site_notifications/process.mjs delete mode 100644 mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.js create mode 100644 mod/theme_sandbox/views/default/theme_sandbox/demo/ajax_demo.mjs delete mode 100644 mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.js create mode 100644 mod/theme_sandbox/views/default/theme_sandbox/javascript/lightbox.mjs delete mode 100644 mod/theme_sandbox/views/default/theme_sandbox/javascript/popup.js create mode 100644 mod/theme_sandbox/views/default/theme_sandbox/javascript/popup.mjs delete mode 100644 mod/theme_sandbox/views/default/theme_sandbox/navigation/require.js create mode 100644 mod/theme_sandbox/views/default/theme_sandbox/navigation/require.mjs delete mode 100644 mod/theme_sandbox/views/default/theme_sandbox/theme_sandbox.js create mode 100644 mod/theme_sandbox/views/default/theme_sandbox/theme_sandbox.mjs delete mode 100644 mod/thewire/views/default/ckeditor/config/thewire.js create mode 100644 mod/thewire/views/default/ckeditor/config/thewire.mjs delete mode 100644 mod/thewire/views/default/forms/thewire/add.js create mode 100644 mod/thewire/views/default/forms/thewire/add.mjs delete mode 100644 mod/web_services/views/default/elgg/webservices.js create mode 100644 mod/web_services/views/default/elgg/webservices.mjs delete mode 100644 views/default/admin/plugins.js create mode 100644 views/default/admin/plugins.mjs create mode 100644 views/default/admin/upgrades.mjs delete mode 100644 views/default/core/js/upgrader.js delete mode 100644 views/default/elgg.js.php rename views/default/{core/js/elgglib.js => elgg.mjs} (94%) delete mode 100644 views/default/elgg/Ajax.js create mode 100644 views/default/elgg/Ajax.mjs delete mode 100644 views/default/elgg/admin_notices.js create mode 100644 views/default/elgg/admin_notices.mjs delete mode 100644 views/default/elgg/autocomplete.js create mode 100644 views/default/elgg/autocomplete.mjs delete mode 100644 views/default/elgg/comments.js create mode 100644 views/default/elgg/comments.mjs delete mode 100644 views/default/elgg/hooks.js create mode 100644 views/default/elgg/hooks.mjs delete mode 100644 views/default/elgg/i18n.js create mode 100644 views/default/elgg/i18n.mjs delete mode 100644 views/default/elgg/lightbox.js create mode 100644 views/default/elgg/lightbox.mjs delete mode 100644 views/default/elgg/menus/dropdown.js create mode 100644 views/default/elgg/menus/dropdown.mjs delete mode 100644 views/default/elgg/menus/toggle.js create mode 100644 views/default/elgg/menus/toggle.mjs delete mode 100644 views/default/elgg/popup.js create mode 100644 views/default/elgg/popup.mjs delete mode 100644 views/default/elgg/require_config.js.php delete mode 100644 views/default/elgg/security.js create mode 100644 views/default/elgg/security.mjs delete mode 100644 views/default/elgg/spinner.js create mode 100644 views/default/elgg/spinner.mjs delete mode 100644 views/default/elgg/system_messages.js create mode 100644 views/default/elgg/system_messages.mjs delete mode 100644 views/default/elgg/toggle.js create mode 100644 views/default/elgg/toggle.mjs delete mode 100644 views/default/elgg/touch_punch.js.php delete mode 100644 views/default/elgg/widgets.js create mode 100644 views/default/elgg/widgets.mjs delete mode 100644 views/default/entity/edit/icon/crop.js create mode 100644 views/default/entity/edit/icon/crop.mjs delete mode 100644 views/default/forms/admin/site/settings.js create mode 100644 views/default/forms/admin/site/settings.mjs delete mode 100644 views/default/forms/admin/site/theme.js create mode 100644 views/default/forms/admin/site/theme.mjs delete mode 100644 views/default/forms/admin/users/bulk_actions.js create mode 100644 views/default/forms/admin/users/bulk_actions.mjs delete mode 100644 views/default/forms/settings/notifications.js create mode 100644 views/default/forms/settings/notifications.mjs delete mode 100644 views/default/forms/useradd.js create mode 100644 views/default/forms/useradd.mjs delete mode 100644 views/default/icon/user/default.js create mode 100644 views/default/icon/user/default.mjs delete mode 100644 views/default/input/date.js create mode 100644 views/default/input/date.mjs delete mode 100644 views/default/input/entitypicker.js create mode 100644 views/default/input/entitypicker.mjs delete mode 100644 views/default/input/file.js create mode 100644 views/default/input/file.mjs delete mode 100644 views/default/input/form-ajax.js create mode 100644 views/default/input/form-ajax.mjs delete mode 100644 views/default/input/form-double-submit.js create mode 100644 views/default/input/form-double-submit.mjs delete mode 100644 views/default/input/tags.js create mode 100644 views/default/input/tags.mjs delete mode 100644 views/default/input/url.js create mode 100644 views/default/input/url.mjs delete mode 100644 views/default/navigation/menu/elements/item_toggle.js create mode 100644 views/default/navigation/menu/elements/item_toggle.mjs delete mode 100644 views/default/notifications/subscriptions/record.js create mode 100644 views/default/notifications/subscriptions/record.mjs delete mode 100644 views/default/page/components/list/ajax-append-auto.js create mode 100644 views/default/page/components/list/ajax-append-auto.mjs delete mode 100644 views/default/page/components/list/ajax-append.js create mode 100644 views/default/page/components/list/ajax-append.mjs delete mode 100644 views/default/page/components/list/ajax-replace.js create mode 100644 views/default/page/components/list/ajax-replace.mjs delete mode 100644 views/default/page/components/tabs.js create mode 100644 views/default/page/components/tabs.mjs create mode 100644 views/default/page/elements/importmap.json.php delete mode 100644 views/default/page/elements/topbar.js create mode 100644 views/default/page/elements/topbar.mjs delete mode 100644 views/default/resources/widgets/add_panel.js create mode 100644 views/default/resources/widgets/add_panel.mjs diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml deleted file mode 100644 index 791641eb5c5..00000000000 --- a/.github/workflows/javascript.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Javascript test suite -on: [pull_request] -jobs: - karma: - name: Karma tests - runs-on: ubuntu-20.04 - - steps: - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.1' - coverage: none - extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring - - - name: Install NodeJS - uses: actions/setup-node@v2 - with: - node-version: 8 - - - name: Code checkout - uses: actions/checkout@v3 - - - name: Restore NPM cache - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: ${{ runner.os }}-node- - - - name: Get Composer Cache Directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - - - name: Restore Composer Cache - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Composer install - run: composer install - - - name: Yarn install - run: yarn install - - - name: Yarn check - continue-on-error: true - run: yarn check - - - name: Run Karma tests - run: yarn test diff --git a/README.md b/README.md index 86efcf8dca0..f546c0fc629 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Features - **Cacheable system of static assets** that allows themes and plugins to serve images, stylesheets, fonts and scripts bypassing the engine - **User authentication** is powered by pluggable auth modules, which allow applications to implement custom authentication protocols - **Security** is ensured by built-in anti CSRF validation, strict XSS filters, HMAC signatures, latest cryptographic approaches to password hashing -- **Client-side API** powered by asynchronous JavaScript modules via RequireJS and a build-in Ajax service for easy communication with the server +- **Client-side API** powered by asynchronous ES modules and a built-in Ajax service for easy communication with the server - **Flexible entity system** that allows applications to prototype new types of content and user interactions - **Opinionated data model** with a consolidated API layer that allows the developers to easily interface with the database - **Access control system** that allows applications to build granular content access policies, as well as create private networks and intranets @@ -34,14 +34,14 @@ Under the hood: - Elgg is a modular OOP framework that is driven by DI services - NGINX or Apache compatible - Symfony2 HTTP Foundation handles requests and responses -- RequireJS handles AMD +- modular javascript with ECMAScript modules - Laminas Mail handles outgoing email - htmLawed XSS filters - DBAL - Phinx database migrations - CSS-Crush for CSS preprocessing - Imagine for image manipulation -* Persistent caching with Memcached and/or Redis +- Persistent caching with Memcached and/or Redis - Error handling with Monolog Elgg Foundation diff --git a/composer.json b/composer.json index f601f82dbe1..ae714ed725c 100644 --- a/composer.json +++ b/composer.json @@ -39,8 +39,6 @@ "npm-asset/jquery-ui": "~1.13.1", "npm-asset/jquery-ui-touch-punch": "~0.2.3", "npm-asset/normalize.css": "~8.0.1", - "npm-asset/requirejs": "^2.3.6", - "npm-asset/requirejs-text": "^2.0.4", "npm-asset/sprintf-js": "~1.1.2", "npm-asset/yaireo--tagify": "~4.17.0", "pelago/emogrifier": "~7.0.0", diff --git a/composer.lock b/composer.lock index d20d518ebf3..3ee9628c813 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "16793d5f6811a0130c67936aa5b92b75", + "content-hash": "d0f7c27cb8c6eef4baafaffa67001011", "packages": [ { "name": "cakephp/cache", @@ -2868,30 +2868,6 @@ "MIT" ] }, - { - "name": "npm-asset/requirejs", - "version": "2.3.6", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/requirejs-text", - "version": "2.0.16", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/requirejs-text/-/requirejs-text-2.0.16.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, { "name": "npm-asset/sprintf-js", "version": "1.1.2", @@ -8861,5 +8837,5 @@ "platform-overrides": { "php": "8.1" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst index bce97c1ba86..93516a98a2d 100644 --- a/docs/appendix/upgrade-notes/5.x-to-6.0.rst +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -14,6 +14,29 @@ DB Requirements - The minimal MySQL version is now 8.0 - The minimal MariaDB version is now 10.6 +ES Modules +---------- + +We no longer use RequireJS for inclusion of AMD JavaScript modules. Instead we now rely on the native use of ECMAScript modules. +All modules can be referenced under the same name as an importable module. + +Related functions changes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``elgg_define_js()`` this function has been removed. You might need ``elgg_register_esm()`` as a replacement. +* ``elgg_require_js()`` this function has been removed. You might need ``elgg_import_esm()`` as a replacement. +* ``elgg_unrequire_js()`` this function has been removed + +The event 'config', 'amd' has been removed. +The event 'elgg.data', 'site' has been removed. You can switch to the 'elgg.data', 'page' event. + +.. note:: + + With the switch to ECMAScript modules we can no longer add Sub-Resource Integrity checks to the imported modules. + +.. note:: + + With the switch to ECMAScript modules we temporarily dropped Javascript testing features. This will be added in the future. Composer -------- diff --git a/docs/contribute/code.rst b/docs/contribute/code.rst index 73470c635a5..3f75c01b062 100644 --- a/docs/contribute/code.rst +++ b/docs/contribute/code.rst @@ -242,70 +242,6 @@ Due to these local references, replacing services on the SP within a test often * The ``events`` service has methods ``backup()`` and ``restore()``. * The ``logger`` service has methods ``disable()`` and ``enable()``. -Jasmine Tests -------------- - -Test files must be named ``*Test.js`` and should go in either ``js/tests/`` or next -to their source files in ``views/default/**.js``. Karma will automatically pick up -on new ``*Test.js`` files and run those tests. - -Test boilerplate ----------------- - -.. code-block:: js - - define(['elgg'], function(elgg) { - describe("This new test", function() { - it("fails automatically", function() { - expect(true).toBe(false); - }); - }); - }); - -Running the tests ------------------ -Elgg uses `Karma`_ with `Jasmine`_ to run JS unit tests. - -.. _Karma: http://karma-runner.github.io/0.8/index.html -.. _Jasmine: http://pivotal.github.io/jasmine/ - -You will need to have nodejs and yarn installed. - -First install all the development dependencies: - -.. code-block:: sh - - yarn - -Run through the tests just once and then quit: - -.. code-block:: sh - - yarn test - -You can also run tests continuously during development so they run on each save: - -.. code-block:: sh - - karma start js/tests/karma.conf.js - -Debugging JS tests -^^^^^^^^^^^^^^^^^^ - -You can run the test suite inside Chrome dev tools: - -.. code-block:: sh - - yarn run chrome - -This will output a URL like ``http://localhost:9876/``. - -#. Open the URL in Chrome, and click "Debug". -#. Open Chrome dev tools and the Console tab. -#. Reload the page. - -If you alter a test you'll have to quit Karma with ``Ctrl-c`` and restart it. - Coding best practices ===================== @@ -780,20 +716,10 @@ Javascript guidelines Same formatting standards as PHP apply. -Related functions should be in a namespaced ``AMD`` module. +Related functions should be in a namespaced ``ECMAScript`` module. Function expressions should end with a semi-colon. -.. code-block:: js - - define(['elgg'], function(elgg) { - function toggles(event) { - event.preventDefault(); - $(target).slideToggle('medium'); - }; - }); - - Deprecating APIs ================ diff --git a/docs/design/amd.rst b/docs/design/amd.rst deleted file mode 100644 index 37e2b605416..00000000000 --- a/docs/design/amd.rst +++ /dev/null @@ -1,58 +0,0 @@ -AMD -### - -.. toctree:: - :maxdepth: 2 - -Overview -======== - -If you want to use JavaScript in Elgg: we use a `AMD (Asynchronous Module -Definition) `_ compatible system. - -This discusses the benefits of using AMD in Elgg. - -Why AMD? -======== - -We have been working hard to make Elgg's JavaScript more maintainable and useful. -We made some strides in 1.8 with the introduction of the "``elgg``" JavaScript object and library, but -have quickly realized the approach we were taking was not scalable. - -The size of `JS on the web is growing -`_ -quickly, and JS in Elgg is growing too. We want Elgg to be able to offer a solution that makes JS -development as productive and maintainable as possible going forward. - -The `reasons to choose AMD `_ are plenteous and -well-documented. Let's highlight just a few of the most relevant reasons as they relate to Elgg -specifically. - -1. Simplified dependency management ------------------------------------ -AMD modules load asynchronously and execute as soon as their dependencies are available, so this -eliminates the need to specify "priority" and "location" when registering JS libs in Elgg. Also, you -don't need to worry about explicitly loading a module's dependencies in PHP. The AMD loader (RequireJS in this -case) takes care of all that hassle for you. It's also possible have -`text dependencies `_ with the RequireJS text plugin, -so client-side templating should be a breeze. - -2. AMD works in all browsers. Today. ------------------------------------- -Elgg developers are already writing lots of JavaScript. We know you want to write more. We cannot -accept waiting 5-10 years for a native JS modules solution to be available in all browsers before -we can organize our JavaScript in a maintainable way. - -3. You do not need a build step to develop in AMD. --------------------------------------------------- -We like the edit-refresh cycle of web development. We wanted to make sure everyone developing in -Elgg could continue experiencing that joy. Synchronous module formats like Closure or CommonJS just -weren't an option for us. But even though AMD doesn't require a build step, *it is still very -build-friendly*. Because of the ``define()`` wrapper, it's possible to concatenate multiple modules -into a single file and ship them all at once in a production environment. [#]_ - -AMD is a battle-tested and well thought out module loading system for the web today. We're very -thankful for the work that has gone into it, and are excited to offer it as the standard solution -for JavaScript development in Elgg starting with Elgg 1.9. - -.. [#] This is not currently supported by Elgg core, but we'll be looking into it since reducing round-trips is critical for a good first-view experience, especially on mobile devices. diff --git a/docs/design/index.rst b/docs/design/index.rst index b31a6c03d12..70dd4e69810 100644 --- a/docs/design/index.rst +++ b/docs/design/index.rst @@ -11,6 +11,5 @@ and why it's built the way it is. database events i18n - amd security loggable diff --git a/docs/guides/ajax.rst b/docs/guides/ajax.rst index 352ebbdfc4f..b163b1ad9ba 100644 --- a/docs/guides/ajax.rst +++ b/docs/guides/ajax.rst @@ -1,7 +1,7 @@ Ajax #### -The ``elgg/Ajax`` AMD module (introduced in Elgg 2.1) provides a set of methods for communicating with the server in a concise and uniform way, which allows plugins to collaborate on the request data, the server response, and the returned client-side data. +The ``elgg/Ajax`` module (introduced in Elgg 2.1) provides a set of methods for communicating with the server in a concise and uniform way, which allows plugins to collaborate on the request data, the server response, and the returned client-side data. .. contents:: Contents :local: @@ -32,7 +32,7 @@ More notes: * If a non-empty ``options.data`` is given, the default method is always ``POST``. * For client caching, set ``options.method`` to ``"GET"`` and ``options.data.elgg_response_ttl`` to the max-age you want in seconds. * To save system messages for the next page load, set ``options.data.elgg_fetch_messages = 0``. You may want to do this if you intent to redirect the user based on the response. -* To stop client-side API from requiring AMD modules required server-side with ``elgg_require_js()``, set ``options.data.elgg_fetch_deps = 0``. +* To stop client-side API from requiring modules required server-side with ``elgg_import_esm()``, set ``options.data.elgg_fetch_deps = 0``. * All methods accept a query string in the first argument. This is passed on to the fetch URL, but does not appear in the hook types. Performing actions @@ -350,12 +350,12 @@ The first and third case are the most common cases in the system. Use the ``done // handle error condition if needed }); -Requiring AMD modules ---------------------- +Requiring ES modules +-------------------- -Each response from an Ajax service will contain a list of AMD modules required server side with `elgg_require_js()`. +Each response from an Ajax service will contain a list of ES modules required server side with `elgg_import_esm()`. When response data is unwrapped, these modules will be loaded asynchronously - plugins should not expect these -modules to be loaded in their `$.done()` and `$.then()` handlers and must use `require()` for any modules they depend on. -Additionally AMD modules should not expect the DOM to have been altered by an Ajax request when they are loaded - +modules to be loaded in their `$.done()` and `$.then()` handlers and must use `import` for any modules they depend on. +Additionally modules should not expect the DOM to have been altered by an Ajax request when they are loaded - DOM events should be delegated and manipulations on DOM elements should be delayed until all Ajax requests have been resolved. diff --git a/docs/guides/events-list.rst b/docs/guides/events-list.rst index acb1f12d1c8..5cfb2693a30 100644 --- a/docs/guides/events-list.rst +++ b/docs/guides/events-list.rst @@ -57,10 +57,7 @@ System events Filter the output for the diagnostics report download. **elgg.data, page** |results| - Filters uncached, page-specific configuration data to pass to the client. :ref:`More info ` - -**elgg.data, site** |results| - Filters cached configuration data to pass to the client. :ref:`More info ` + Filters uncached, page-specific configuration data to pass to the client. :doc:`More info ` **format, friendly:title** |results| Formats the "friendly" title for strings. This is used for generating URLs. @@ -868,7 +865,7 @@ Ajax ==== **ajax_response, \*** |results| - When the ``elgg/Ajax`` AMD module is used, this event gives access to the response object + When the ``elgg/Ajax`` module is used, this event gives access to the response object (``\Elgg\Services\AjaxResponse``) so it can be altered/extended. The event type depends on the method call: @@ -1084,9 +1081,6 @@ Other **classes, icon** |results| Can be used to filter CSS classes applied to icon glyphs. By default, Elgg uses FontAwesome. Plugins can use this event to switch to a different font family and remap icon classes. - -**config, amd** |results| - Filter the AMD config for the requirejs library. **entity:icon:sizes, ** |results| Triggered by ``elgg_get_icon_sizes()`` and sets entity type/subtype specific icon sizes. diff --git a/docs/guides/i18n.rst b/docs/guides/i18n.rst index c067419fa1f..b8f2c5b714d 100644 --- a/docs/guides/i18n.rst +++ b/docs/guides/i18n.rst @@ -93,12 +93,10 @@ Javascript API This function is like ``elgg_echo`` in PHP. -Client-side translations are loaded asynchronously. Ensure translations are available by requiring the "elgg" AMD module: +Client-side translations are loaded asynchronously. Ensure translations are available by requiring the "elgg/i18n" module: .. code-block:: js - define(['elgg/i18n'], function(i18n) { - alert(i18n.echo('my_key')); - }); - -Translations are also available after the ``init, system`` JavaScript event. + import i18n from 'elgg/i18n'; + + alert(i18n.echo('my_key')); diff --git a/docs/guides/javascript.rst b/docs/guides/javascript.rst index 14a5e03b1e4..63ca155bc3a 100644 --- a/docs/guides/javascript.rst +++ b/docs/guides/javascript.rst @@ -5,14 +5,12 @@ JavaScript :local: :depth: 2 -AMD -=== +JavaScript Modules +================== -Developers should use the `AMD (Asynchronous Module -Definition) `_ standard for writing JavaScript code in Elgg. +Developers should use the browser native `ECMAScript modules `_ for writing JavaScript code in Elgg. -Here we'll describe making and executing AMD modules. The RequireJS documentation for -`defining modules `_ may also be of use. +Here we'll describe making and importing these modules in Elgg. Executing a module in the current page -------------------------------------- @@ -22,54 +20,26 @@ Telling Elgg to load an existing module in the current page is easy: .. code-block:: php getValue(); - - // this will be cached client-side $value['myplugin']['api'] = elgg_get_site_url() . 'myplugin-api'; $value['myplugin']['key'] = 'none'; - return $value; - } - - function myplugin_config_page(\Elgg\Event $event) { $user = elgg_get_logged_in_user_entity(); - if (!$user) { - return; + if ($user) { + $value['myplugin']['key'] = $user->myplugin_api_key; } - $value = $event->getValue(); - - $value['myplugin']['key'] = $user->myplugin_api_key; - return $value; } - elgg_register_event_handler('elgg.data', 'site', 'myplugin_config_site'); elgg_register_event_handler('elgg.data', 'page', 'myplugin_config_page'); .. code-block:: js @@ -123,43 +81,6 @@ Let's pass some data to a module: // ... }); -.. note:: - - In ``elgg.data``, page data overrides site data. Also note ``json_encode()`` is used to copy - data client-side, so the data must be JSON-encodable. - -Making a config module -^^^^^^^^^^^^^^^^^^^^^^ - -You can use a PHP-based module to pass values from the server. To make the module ``myplugin/settings``, -create the view file ``views/default/myplugin/settings.js.php`` (note the double extension -``.js.php``). - -.. code-block:: php - - elgg_get_site_url() . 'myplugin-api', - 'key' => null, - ]; - ?> - define(); - -You must also manually register the view as an external resource: - -.. code-block:: php - - ['jquery'], - 'exports' => 'jQuery.fn.ajaxForm', - ]); - -When this is requested client-side: - -#. The jQuery module is loaded, as it's marked as a dependency. -#. ``https://elgg.example.org/cache/125235034/views/default/jquery.form.js`` is loaded and executed. -#. The value of ``window.jQuery.fn.ajaxForm`` is returned by the module. - -.. warning:: Calls to ``elgg_define_js()`` must be in an ``init, system`` event handler. - -Some things to note -^^^^^^^^^^^^^^^^^^^ - -#. Return the value of the module instead of adding to a global variable. -#. Static (.js,.css,etc.) files are automatically minified and cached by Elgg's simplecache system. -#. The configuration is also cached in simplecache, and should not rely on user-specific values - like ``elgg_get_current_language()``. - Modules provided with Elgg ========================== @@ -405,7 +294,7 @@ attribute and defining target module with a ``href`` (or ``data-href``) attribut ]); // Button with custom positioning of the popup - elgg_require_js('elgg/popup'); + elgg_import_esm('elgg/popup'); echo elgg_format_element('button', [ 'class' => 'elgg-button elgg-button-submit elgg-popup', 'text' => 'Show popup', @@ -480,8 +369,8 @@ Plugins that load a widget layout via Ajax should initialize via this module: .. code-block:: js - require(['elgg/widgets'], function (widgets) { - widgets.init(); + import('elgg/widgets').then((widgets) => { + widgets.default.init(); }); Module ``elgg/lightbox`` @@ -533,12 +422,12 @@ To support gallery sets (via ``rel`` attribute), you need to bind colorbox direc .. code-block:: js - require(['elgg/lightbox'], function(lightbox) { + import('elgg/lightbox').then((lightbox) => { var options = { photo: true, width: 500 }; - lightbox.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies + lightbox.default.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies }); You can also resize the lightbox programmatically if needed: @@ -570,19 +459,19 @@ Note that WYSIWYG will be automatically attached to all instances of ``.elgg-inp .. code-block:: js - require(['elgg/ckeditor'], function (elggCKEditor) { - elggCKEditor.bind('#my-text-area'); + import('elgg/ckeditor').then((elggCKEditor) => { + elggCKEditor.default.bind('#my-text-area'); // Toggle CKEditor - elggCKEditor.toggle('#my-text-area'); + elggCKEditor.default.toggle('#my-text-area'); // Focus on CKEditor input - elggCKEditor.focus('#my-text-area'); + elggCKEditor.default.focus('#my-text-area'); // or $('#my-text-area').trigger('focus'); // Reset CKEditor input - elggCKEditor.reset('#my-text-area'); + elggCKEditor.default.reset('#my-text-area'); // or $('#my-text-area').trigger('reset'); @@ -597,17 +486,15 @@ Inline tabs component fires an ``open`` event whenever a tabs is open and, in ca .. code-block:: js // Add custom animation to tab content - require(['jquery'], function($) { - $(document).on('open', '.theme-sandbox-tab-callback', function() { - $(this).find('a').text('Clicked!'); - $(this).data('target').hide().show('slide', { - duration: 2000, - direction: 'right', - complete: function() { - alert('Thank you for clicking. We hope you enjoyed the show!'); - $(this).css('display', ''); // .show() adds display property - } - }); + $(document).on('open', '.theme-sandbox-tab-callback', function() { + $(this).find('a').text('Clicked!'); + $(this).data('target').hide().show('slide', { + duration: 2000, + direction: 'right', + complete: function() { + alert('Thank you for clicking. We hope you enjoyed the show!'); + $(this).css('display', ''); // .show() adds display property + } }); }); diff --git a/docs/guides/menus.rst b/docs/guides/menus.rst index 9917abd1025..772a94585e6 100644 --- a/docs/guides/menus.rst +++ b/docs/guides/menus.rst @@ -299,7 +299,7 @@ JavaScript ========== It is common that menu items rely on JavaScript. You can bind client-side events -to menu items by placing your JavaScript into AMD module and defining the +to menu items by placing your JavaScript into a module and defining the requirement during the registration. .. code-block:: php @@ -315,12 +315,10 @@ requirement during the registration. .. code-block:: js - // in navigation/menu/item/hide_on_click.js - define(function(require) { - var $ = require('jquery'); + // in navigation/menu/item/hide_on_click.mjs + import 'jquery'; - $(document).on('click', '.hide-on-click', function(e) { - e.preventDefault(); - $(this).hide(); - }); + $(document).on('click', '.hide-on-click', function(e) { + e.preventDefault(); + $(this).hide(); }); diff --git a/docs/guides/plugins.rst b/docs/guides/plugins.rst index 9d0c2b4a241..72f351ce4a9 100644 --- a/docs/guides/plugins.rst +++ b/docs/guides/plugins.rst @@ -169,9 +169,6 @@ Besides magic constants like ``__DIR__``, its return value should not change. Th ], 'view_extensions' => [ - 'elgg.js' => [ - 'bookmarks.js' => [], - ], 'page/components/list' => [ 'list/extension' => [ 'priority' => 600, diff --git a/docs/guides/views/foot-vs-footer.rst b/docs/guides/views/foot-vs-footer.rst index ace5d3a044c..2522da6facb 100644 --- a/docs/guides/views/foot-vs-footer.rst +++ b/docs/guides/views/foot-vs-footer.rst @@ -13,4 +13,5 @@ Page/elements/foot vs footer Its content is visible to end users and usually where you would put a sitemap or other secondary global navigation, copyright info, powered by elgg, etc. -``page/elements/foot`` is inserted just before the ending ```` tag and is mostly meant as a place to insert scripts that don't already work with ``elgg_require_js('amd/module');``. In other words, you should never override this view and probably don't need to extend it either. Just use the ``elgg_*_js`` functions instead +``page/elements/foot`` is inserted just before the ending ```` tag and is mostly meant as a place to insert scripts that don't already work with ``elgg_import_esm('my/module');``. +In other words, you should never override this view and probably don't need to extend it either. Just use the ``elgg_*_esm`` functions instead diff --git a/docs/index.rst b/docs/index.rst index 045470511df..bb95900f4d6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,7 +14,7 @@ Features * **Cacheable system of static assets** that allows themes and plugins to serve images, stylesheets, fonts and scripts bypassing the engine * **User authentication** is powered by pluggable auth modules, which allow applications to implement custom authentication protocols * **Security** is ensured by built-in anti CSRF validation, strict XSS filters, HMAC signatures, latest cryptographic approaches to password hashing - * **Client-side API** powered by asynchronous JavaScript modules via RequireJS and a build-in Ajax service for easy communication with the server + * **Client-side API** powered by asynchronous ES modules and a built-in Ajax service for easy communication with the server * **Flexible entity system** that allows applications to prototype new types of content and user interactions * **Opinionated data model** with a consolidated API layer that allows the developers to easily interface with the database * **Access control system** that allows applications to build granular content access policies, as well as create private networks and intranets @@ -30,7 +30,7 @@ Under the hood: * Elgg is a modular OOP framework that is driven by DI services * NGINX or Apache compatible * Symfony2 HTTP Foundation handles requests and responses - * RequireJS handles AMD + * modular javascript with ECMAScript modules * Laminas Mail handles outgoing email * htmLawed XSS filters * DBAL diff --git a/docs/intro/development.rst b/docs/intro/development.rst index d4f4848bc3f..b17d9473b14 100644 --- a/docs/intro/development.rst +++ b/docs/intro/development.rst @@ -42,10 +42,7 @@ view. JavaScript ========== -Elgg uses an AMD-compatible JavaScript system provided by RequireJs. Bundled with Elgg are jQuery, jQuery UI, -jQuery Form, and jQuery UI Autocomplete. - -Plugins can load their own JS libs. +Elgg uses native ES modules. Plugins can register their own modules or load their own JS libs. Internationalization ==================== @@ -61,7 +58,7 @@ Elgg uses two caches to improve performance: a system cache and SimpleCache. =================== The use of 3rd party libraries in Elgg is managed by using `Composer`_ dependencies. Examples of 3rd party libraries are -jQuery, RequireJs or Laminas mail. +jQuery, CSS Crush or Laminas mail. To get a list of all the Elgg dependencies check out the `Packagist`_ page for Elgg. diff --git a/engine/classes/Elgg/Ajax/Service.php b/engine/classes/Elgg/Ajax/Service.php index 861047c541b..baf1bb23383 100644 --- a/engine/classes/Elgg/Ajax/Service.php +++ b/engine/classes/Elgg/Ajax/Service.php @@ -2,10 +2,10 @@ namespace Elgg\Ajax; -use Elgg\Amd\Config; use Elgg\EventsService; use Elgg\Exceptions\RuntimeException; use Elgg\Http\Request; +use Elgg\Javascript\ESMService; use Elgg\Services\AjaxResponse; use Elgg\SystemMessagesService; use Symfony\Component\HttpFoundation\JsonResponse; @@ -18,50 +18,24 @@ */ class Service { - /** - * @var EventsService - */ - private $events; + protected bool $response_sent = false; - /** - * @var SystemMessagesService - */ - private $msgs; - - /** - * @var Request - */ - private $request; - - /** - * @var Config - */ - private $amd_config; - - /** - * @var bool - */ - private $response_sent = false; - - /** - * @var array - */ - private $allowed_views = []; + protected array $allowed_views = []; /** * Constructor * - * @param EventsService $events Events service - * @param SystemMessagesService $msgs System messages service - * @param Request $request Http Request - * @param Config $amdConfig AMD config + * @param EventsService $events Events service + * @param SystemMessagesService $msgs System messages service + * @param Request $request Http Request + * @param ESMService $esm ESM service */ - public function __construct(EventsService $events, SystemMessagesService $msgs, Request $request, Config $amdConfig) { - $this->events = $events; - $this->msgs = $msgs; - $this->request = $request; - $this->amd_config = $amdConfig; - + public function __construct( + protected EventsService $events, + protected SystemMessagesService $msgs, + protected Request $request, + protected ESMService $esm + ) { $message_filter = [$this, 'prepareResponse']; $this->events->registerHandler(AjaxResponse::RESPONSE_EVENT, 'all', $message_filter, 999); } @@ -222,7 +196,7 @@ private function buildHttpResponse(AjaxResponse $api_response): JsonResponse { } /** - * Prepare the response with additional metadata, like system messages and required AMD modules + * Prepare the response with additional metadata, like system messages and required ES modules * * @param \Elgg\Event $event "ajax_response", "all" * @@ -247,7 +221,7 @@ public function prepareResponse(\Elgg\Event $event) { } if ($this->request->getParam('elgg_fetch_deps', true)) { - $response->getData()->_elgg_deps = (array) $this->amd_config->getDependencies(); + $response->getData()->_elgg_deps = $this->esm->getImports(); } return $response; diff --git a/engine/classes/Elgg/Amd/Config.php b/engine/classes/Elgg/Amd/Config.php deleted file mode 100644 index 35fd57d7e57..00000000000 --- a/engine/classes/Elgg/Amd/Config.php +++ /dev/null @@ -1,273 +0,0 @@ -events = $events; - } - - /** - * Set the base URL for the site - * - * @param string $url URL - * - * @return void - */ - public function setBaseUrl($url) { - $this->baseUrl = $url; - } - - /** - * Add a path mapping for a module. If a path is already defined, sets - * current path as preferred. - * - * @param string $name Module name - * @param string $path Full URL of the module - * - * @return void - */ - public function addPath(string $name, string $path): void { - if (preg_match('/\.js$/', $path)) { - $path = preg_replace('/\.js$/', '', $path); - } - - if (!isset($this->paths[$name])) { - $this->paths[$name] = []; - } - - array_unshift($this->paths[$name], $path); - } - - /** - * Remove a path for a module - * - * @param string $name Module name - * @param mixed $path The path to remove. If null, removes all paths (default). - * - * @return void - */ - public function removePath($name, $path = null) { - if (!$path) { - unset($this->paths[$name]); - } else { - if (preg_match('/\.js$/', $path)) { - $path = preg_replace('/\.js$/', '', $path); - } - - $key = array_search($path, $this->paths[$name]); - unset($this->paths[$name][$key]); - - if (empty($this->paths[$name])) { - unset($this->paths[$name]); - } - } - } - - /** - * Configures a shimmed module - * - * @param string $name Module name - * @param array $config Configuration for the module - * - deps: array Dependencies - * - exports: string Name of the shimmed module to export - * - * @return void - * @throws InvalidArgumentException - */ - public function addShim(string $name, array $config): void { - $deps = elgg_extract('deps', $config, []); - $exports = elgg_extract('exports', $config); - - if (empty($deps) && empty($exports)) { - throw new InvalidArgumentException('Shimmed modules must have deps or exports'); - } - - $this->shim[$name] = []; - - if (!empty($deps)) { - $this->shim[$name]['deps'] = $deps; - } - - if (!empty($exports)) { - $this->shim[$name]['exports'] = $exports; - } - } - - /** - * Is this shim defined - * - * @param string $name The name of the shim - * - * @return bool - */ - public function hasShim($name) { - return isset($this->shim[$name]); - } - - /** - * Unregister the shim config for a module - * - * @param string $name Module name - * - * @return void - */ - public function removeShim($name) { - unset($this->shim[$name]); - } - - /** - * Add a dependency - * - * @param string $name Name of the dependency - * - * @return void - */ - public function addDependency(string $name): void { - $this->dependencies[$name] = true; - } - - /** - * Removes a dependency - * - * @param string $name Name of the dependency - * - * @return void - */ - public function removeDependency(string $name): void { - unset($this->dependencies[$name]); - } - - /** - * Get registered dependencies - * - * @return array - */ - public function getDependencies() { - return array_keys($this->dependencies); - } - - /** - * Is this dependency registered - * - * @param string $name Module name - * - * @return bool - */ - public function hasDependency($name) { - return isset($this->dependencies[$name]); - } - - /** - * Adds a standard AMD or shimmed module to the config. - * - * @param string $name The name of the module - * @param array $config Configuration for the module - * - url: string The full URL for the module if not resolvable from baseUrl - * - deps: array Shimmed module's dependencies - * - exports: string Name of the shimmed module to export - * - * @return void - */ - public function addModule($name, array $config = []) { - $url = elgg_extract('url', $config); - $deps = elgg_extract('deps', $config, []); - $exports = elgg_extract('exports', $config); - - if (!empty($url)) { - $this->addPath($name, $url); - } - - // this is a shimmed module - // some jQuery modules don't need to export anything when shimmed, - // so check for deps too - if (!empty($deps) || !empty($exports)) { - $this->addShim($name, $config); - } else { - $this->addDependency($name); - } - } - - /** - * Removes all config for a module - * - * @param string $name The module name - * - * @return void - */ - public function removeModule($name) { - $this->removeDependency($name); - $this->removeShim($name); - $this->removePath($name); - } - - /** - * Is module configured? - * - * @param string $name Module name - * - * @return bool - */ - public function hasModule($name) { - if (in_array($name, $this->getDependencies())) { - return true; - } - - if (isset($this->shim[$name])) { - return true; - } - - if (isset($this->paths[$name])) { - return true; - } - - return false; - } - - /** - * Get the configuration of AMD - * - * @return array - */ - public function getConfig() { - $defaults = [ - 'baseUrl' => $this->baseUrl, - 'paths' => $this->paths, - 'shim' => $this->shim, - 'deps' => $this->getDependencies(), - 'waitSeconds' => 20, - ]; - - $params = [ - 'defaults' => $defaults - ]; - - return $this->events->triggerResults('config', 'amd', $params, $defaults); - } -} diff --git a/engine/classes/Elgg/Amd/ViewFilter.php b/engine/classes/Elgg/Amd/ViewFilter.php deleted file mode 100644 index 473071e0990..00000000000 --- a/engine/classes/Elgg/Amd/ViewFilter.php +++ /dev/null @@ -1,59 +0,0 @@ -getAmdName($viewName); - - if (!empty($amdName)) { - $content = preg_replace('/^(\s*)define\(([^\'"])/m', "\${1}define(\"$amdName\", \$2", $content, 1); - } - - return $content; - } -} diff --git a/engine/classes/Elgg/Application/CacheHandler.php b/engine/classes/Elgg/Application/CacheHandler.php index 359247e4273..265187ae40b 100644 --- a/engine/classes/Elgg/Application/CacheHandler.php +++ b/engine/classes/Elgg/Application/CacheHandler.php @@ -29,6 +29,7 @@ class CacheHandler { 'js' => 'application/javascript', 'json' => 'application/json', 'map' => 'application/json', + 'mjs' => 'application/javascript', 'otf' => 'application/font-otf', 'png' => 'image/png', 'svg' => 'image/svg+xml', @@ -355,6 +356,12 @@ protected function getProcessedView($view, $viewtype) { $name = $this->simplecache_enabled ? 'simplecache:generate' : 'cache:generate'; $type = $this->getViewFileType($view); + + // treat mjs as js + if ($type === 'mjs') { + $type = 'js'; + } + $params = [ 'view' => $view, 'viewtype' => $viewtype, diff --git a/engine/classes/Elgg/Di/InternalContainer.php b/engine/classes/Elgg/Di/InternalContainer.php index 0adc88404ac..e105ec9b810 100644 --- a/engine/classes/Elgg/Di/InternalContainer.php +++ b/engine/classes/Elgg/Di/InternalContainer.php @@ -21,7 +21,6 @@ * @property-read \Elgg\Users\Accounts $accounts * @property-read \Elgg\Database\AdminNotices $adminNotices * @property-read \Elgg\Ajax\Service $ajax - * @property-read \Elgg\Amd\Config $amdConfig * @property-read \Elgg\Database\AnnotationsTable $annotationsTable * @property-read \Elgg\Database\ApiUsersTable $apiUsersTable * @property-read \Elgg\AuthenticationService $authentication @@ -51,6 +50,7 @@ * @property-read \Elgg\EntityCapabilitiesService $entity_capabilities * @property-read \Elgg\EntityPreloader $entityPreloader * @property-read \Elgg\Database\EntityTable $entityTable + * @property-read \Elgg\Javascript\ESMService $esm * @property-read \Elgg\EventsService $events * @property-read \Elgg\Assets\ExternalFiles $externalFiles * @property-read \Elgg\Forms\FieldsService $fields diff --git a/engine/classes/Elgg/FormsService.php b/engine/classes/Elgg/FormsService.php index 4a955afaf9c..c03d118ed9a 100644 --- a/engine/classes/Elgg/FormsService.php +++ b/engine/classes/Elgg/FormsService.php @@ -2,8 +2,8 @@ namespace Elgg; -use Elgg\Amd\Config as AmdConfig; use Elgg\Exceptions\LogicException; +use Elgg\Javascript\ESMService; use Elgg\Traits\Loggable; /** @@ -16,12 +16,6 @@ class FormsService { use Loggable; - protected EventsService $events; - - protected ViewsService $views; - - protected AmdConfig $amdConfig; - protected bool $rendering = false; protected string $footer = ''; @@ -29,14 +23,15 @@ class FormsService { /** * Constructor * - * @param ViewsService $views Views service - * @param EventsService $events Events service - * @param AmdConfig $amdConfig AMD Configuration + * @param ViewsService $views Views service + * @param EventsService $events Events service + * @param ESMService $esm ESM service */ - public function __construct(ViewsService $views, EventsService $events, AmdConfig $amdConfig) { - $this->views = $views; - $this->events = $events; - $this->amdConfig = $amdConfig; + public function __construct( + protected ViewsService $views, + protected EventsService $events, + protected ESMService $esm + ) { } /** @@ -97,7 +92,7 @@ public function render(string $action, array $form_vars = [], array $body_vars = } if (elgg_extract('ajax', $form_vars)) { - $this->amdConfig->addDependency('input/form-ajax'); + $this->esm->import('input/form-ajax'); $form_vars['class'][] = 'elgg-js-ajax-form'; unset($form_vars['ajax']); } diff --git a/engine/classes/Elgg/Http/Request.php b/engine/classes/Elgg/Http/Request.php index b6a66e57bc4..24bb87c27d8 100644 --- a/engine/classes/Elgg/Http/Request.php +++ b/engine/classes/Elgg/Http/Request.php @@ -394,7 +394,7 @@ public function isCliServable($root) { // http://php.net/manual/en/features.commandline.webserver.php $extensions = '.3gp, .apk, .avi, .bmp, .css, .csv, .doc, .docx, .flac, .gif, .gz, .gzip, .htm, .html, .ics,'; - $extensions .= ' .jpe, .jpeg, .jpg, .js, .kml, .kmz, .m4a, .mov, .mp3, .mp4, .mpeg, .mpg, .odp, .ods, .odt,'; + $extensions .= ' .jpe, .jpeg, .jpg, .js, .kml, .kmz, .m4a, .mjs, .mov, .mp3, .mp4, .mpeg, .mpg, .odp, .ods, .odt,'; $extensions .= ' .oga, .ogg, .ogv, .pdf, .pdf, .png, .pps, .pptx, .qt, .svg, .swf, .tar, .text, .tif, .txt,'; $extensions .= ' .wav, .webm, .wmv, .xls, .xlsx, .xml, .xsl, .xsd, and .zip'; diff --git a/engine/classes/Elgg/Javascript/AddSRIConfig.php b/engine/classes/Elgg/Javascript/AddSRIConfig.php deleted file mode 100644 index cf3a1f3629f..00000000000 --- a/engine/classes/Elgg/Javascript/AddSRIConfig.php +++ /dev/null @@ -1,34 +0,0 @@ -getValue(); - - $data = _elgg_services()->serverCache->load('sri') ?? []; - - $return['sri'] = $data['js'] ?? []; - - return $return; - } -} diff --git a/engine/classes/Elgg/Javascript/ESMService.php b/engine/classes/Elgg/Javascript/ESMService.php new file mode 100644 index 00000000000..d48aae956e1 --- /dev/null +++ b/engine/classes/Elgg/Javascript/ESMService.php @@ -0,0 +1,83 @@ +views->getESModules(); + $imports = []; + if (!empty($modules)) { + foreach ($modules as $name) { + $short_name = str_replace('.mjs', '', $name); + $imports[$short_name] = $this->cache->getUrl($name); + } + } + + $imports = array_merge($imports, $this->runtime_modules); + + return ['imports' => $imports]; + } + + /** + * Registers a module to the import map + * + * @param string $name name of the module + * @param string $href location from where to download the module (usually a simplecache location) + * + * @return void + */ + public function register(string $name, string $href): void { + $this->runtime_modules[$name] = $href; + } + + /** + * Request a module to be loaded on the page + * + * @param string $name name of the module + * + * @return void + */ + public function import(string $name): void { + $this->imports[$name] = true; + } + + /** + * Returns all modules that requested to be loaded + * + * @return array + */ + public function getImports(): array { + return array_keys($this->imports); + } +} diff --git a/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php b/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php index 704c95fe700..438a6bfe62e 100644 --- a/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php +++ b/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php @@ -12,7 +12,7 @@ class SetLightboxConfigHandler { /** * Set lightbox config * - * @param \Elgg\Event $event 'elgg.data', 'site' + * @param \Elgg\Event $event 'elgg.data', 'page' * * @return array */ diff --git a/engine/classes/Elgg/Menus/Entity.php b/engine/classes/Elgg/Menus/Entity.php index 691347694f9..27c72adca96 100644 --- a/engine/classes/Elgg/Menus/Entity.php +++ b/engine/classes/Elgg/Menus/Entity.php @@ -243,7 +243,7 @@ public static function registerUpgrade(\Elgg\Event $event) { 'text' => elgg_echo('admin:upgrades:menu:run_single'), 'href' => false, 'deps' => [ - 'core/js/upgrader', + 'admin/upgrades', ], 'data-guid' => $entity->guid, 'priority' => 600, diff --git a/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php b/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php deleted file mode 100644 index 02bb4021236..00000000000 --- a/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php +++ /dev/null @@ -1,23 +0,0 @@ -filter($event->getParam('view'), $event->getValue()); - } -} diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 2d034ff99b7..3345fb4ddf5 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -808,6 +808,31 @@ public function cacheConfiguration(): void { public function isViewLocationsLoadedFromCache(): bool { return $this->locations_loaded_from_cache; } + + /** + * Returns an array of names of ES modules detected based on view location + * + * @return array + */ + public function getESModules(): array { + $modules = $this->server_cache->load('esmodules'); + if (is_array($modules)) { + return $modules; + } + + $modules = []; + foreach ($this->locations['default'] as $name => $path) { + if (!str_ends_with($name, '.mjs')) { + continue; + } + + $modules[] = $name; + } + + $this->server_cache->save('esmodules', $modules); + + return $modules; + } /** * Update the location of a view file diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index ef2cb0f5575..9c7291815d4 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -53,7 +53,7 @@ class ElggMenuItem implements \Elgg\Collections\CollectionItemInterface { // array Classes to apply to the anchor tag 'linkClass' => [], - // array AMD modules required by this menu item + // array ES modules required by this menu item 'deps' => [], // which view should be used to output the menu item contents @@ -118,7 +118,7 @@ public function __construct($name, $text, $href) { * title => STR Menu item tooltip * selected => BOOL Is this menu item currently selected? * confirm => STR If set, the link will be drawn with the output/confirmlink view instead of output/url. - * deps => ARR AMD modules required by this menu item + * deps => ARR ES modules required by this menu item * child_menu => ARR Options for the child menu * data => ARR Custom attributes stored in the menu item. * @@ -423,9 +423,9 @@ public function addLinkClass($class) { } /** - * Set required AMD modules + * Set required ES modules * - * @param string[]|string $modules One or more required AMD modules + * @param string[]|string $modules One or more required ES modules * * @return void */ @@ -434,7 +434,7 @@ public function setDeps($modules) { } /** - * Get required AMD modules + * Get required ES modules * * @return string[] */ @@ -446,9 +446,9 @@ public function getDeps() { } /** - * Add required AMD modules + * Add required ES modules * - * @param string[]|string $modules One or more required AMD modules + * @param string[]|string $modules One or more required ES modules * * @return void */ diff --git a/engine/events.php b/engine/events.php index 8852aa059f7..ac558bfc9d5 100644 --- a/engine/events.php +++ b/engine/events.php @@ -51,9 +51,6 @@ 'css' => [ \Elgg\Views\PreProcessCssHandler::class => [], ], - 'js' => [ - \Elgg\Views\AddAmdModuleNameHandler::class => [], - ], ], 'cache:invalidate' => [ 'system' => [ @@ -136,9 +133,6 @@ ], 'elgg.data' => [ 'page' => [ - \Elgg\Javascript\AddSRIConfig::class => [], - ], - 'site' => [ \Elgg\Javascript\SetLightboxConfigHandler::class => [], ], ], @@ -410,7 +404,6 @@ \Elgg\Views\MinifyHandler::class => [], ], 'js' => [ - \Elgg\Views\AddAmdModuleNameHandler::class => [], \Elgg\Views\CalculateSRI::class => ['priority' => 999], \Elgg\Views\MinifyHandler::class => [], ], diff --git a/engine/internal_services.php b/engine/internal_services.php index b56305b7040..1fe63d3153e 100644 --- a/engine/internal_services.php +++ b/engine/internal_services.php @@ -12,11 +12,6 @@ 'accounts' => DI\autowire(\Elgg\Users\Accounts::class), 'adminNotices' => DI\autowire(\Elgg\Database\AdminNotices::class), 'ajax' => DI\autowire(\Elgg\Ajax\Service::class), - 'amdConfig' => DI\factory(function (ContainerInterface $c) { - $obj = new \Elgg\Amd\Config($c->events); - $obj->setBaseUrl($c->simpleCache->getRoot()); - return $obj; - }), 'annotationsTable' => DI\autowire(\Elgg\Database\AnnotationsTable::class), 'apiUsersTable' => DI\autowire(\Elgg\Database\ApiUsersTable::class), 'authentication' => DI\autowire(\Elgg\AuthenticationService::class), @@ -54,6 +49,7 @@ 'entity_capabilities' => DI\autowire(\Elgg\EntityCapabilitiesService::class), 'entityPreloader' => DI\autowire(\Elgg\EntityPreloader::class), 'entityTable' => DI\autowire(\Elgg\Database\EntityTable::class), + 'esm' => DI\autowire(\Elgg\Javascript\ESMService::class), 'events' => DI\autowire(\Elgg\EventsService::class), 'externalFiles' => DI\autowire(\Elgg\Assets\ExternalFiles::class)->constructorParameter('serverCache', DI\get('serverCache')), 'fields' => DI\autowire(\Elgg\Forms\FieldsService::class), @@ -188,7 +184,6 @@ \ElggSession::class => DI\get('session'), \Elgg\ActionsService::class => DI\get('actions'), \Elgg\Ajax\Service::class => DI\get('ajax'), - \Elgg\Amd\Config::class => DI\get('amdConfig'), \Elgg\Application\CacheHandler::class => DI\get('cacheHandler'), \Elgg\Application\Database::class => DI\get('publicDb'), \Elgg\Application\ServeFileHandler::class => DI\get('serveFileHandler'), @@ -249,6 +244,7 @@ \Elgg\I18n\LocaleService::class => DI\get('locale'), \Elgg\I18n\Translator::class => DI\get('translator'), \Elgg\ImageService::class => DI\get('imageService'), + \Elgg\Javascript\ESMService::class => DI\get('esm'), \Elgg\Invoker::class => DI\get('invoker'), \Elgg\Logger::class => DI\get('logger'), \Elgg\Menu\Service::class => DI\get('menus'), diff --git a/engine/lib/external_files.php b/engine/lib/external_files.php index 6d9402c1884..480f94c1f27 100644 --- a/engine/lib/external_files.php +++ b/engine/lib/external_files.php @@ -4,65 +4,30 @@ */ /** - * Defines a JS lib as an AMD module. This is useful for shimming - * traditional JS or for setting the paths of AMD modules. + * Request that Elgg load an ES module onto the page. * - * Calling multiple times for the same name will: - * * set the preferred path to the last call setting a path - * * overwrite the shimmed AMD modules with the last call setting a shimmed module - * - * Use elgg_require_js($name) to load on the current page. - * - * Calling this function is not needed if your JS are in views named like `module/name.js` - * Instead, simply call elgg_require_js("module/name"). - * - * @note The configuration is cached in simplecache, so logic should not depend on user- - * specific values like elgg_get_current_language(). - * - * @param string $name The module name - * @param array $config An array like the following: - * array 'deps' An array of AMD module dependencies - * string 'exports' The name of the exported module - * string 'src' The URL to the JS. Can be relative. + * @param string $name The ES module name * * @return void - */ -function elgg_define_js(string $name, array $config): void { - $src = elgg_extract('src', $config); - - if (!empty($src)) { - $url = elgg_normalize_url($src); - _elgg_services()->amdConfig->addPath($name, $url); - } - - // shimmed module - if (isset($config['deps']) || isset($config['exports'])) { - _elgg_services()->amdConfig->addShim($name, $config); - } -} - -/** - * Request that Elgg load an AMD module onto the page. * - * @param string $name The AMD module name - * - * @return void - * @since 1.9.0 + * @since 6.0 */ -function elgg_require_js(string $name): void { - _elgg_services()->amdConfig->addDependency($name); +function elgg_import_esm(string $name): void { + _elgg_services()->esm->import($name); } /** - * Cancel a request to load an AMD module onto the page. + * Registers an ES module to the import map * - * @param string $name The AMD module name + * @param string $name name of the module + * @param string $href location where the module should be imported from * * @return void - * @since 2.1.0 + * + * @since 6.0 */ -function elgg_unrequire_js(string $name): void { - _elgg_services()->amdConfig->removeDependency($name); +function elgg_register_esm(string $name, string $href): void { + _elgg_services()->esm->register($name, $href); } /** diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index 15a104423ee..84d78c83ca3 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -68,7 +68,7 @@ * parent_name => STR Identifier of the parent menu item * link_class => STR A class or classes for the tag * item_class => STR A class or classes for the
    1. tag - * deps => STR One or more AMD modules to require + * deps => STR One or more ES modules to require * * Additional options that the view output/url takes can be * passed in the array. Custom options can be added by using diff --git a/engine/lib/views.php b/engine/lib/views.php index 80adf6a37d7..b6027306631 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1327,74 +1327,29 @@ function _elgg_has_rss_link(): bool { function elgg_views_boot(): void { _elgg_services()->viewCacher->registerCoreViews(); - // jQuery and UI must come before require. See #9024 - elgg_register_external_file('js', 'jquery', elgg_get_simplecache_url('jquery.js')); - elgg_load_external_file('js', 'jquery'); - - elgg_extend_view('require.js', 'elgg/require_config.js', 100); - - elgg_register_external_file('js', 'require', elgg_get_simplecache_url('require.js')); - elgg_load_external_file('js', 'require'); - - elgg_register_external_file('js', 'elgg', elgg_get_simplecache_url('elgg.js')); - elgg_load_external_file('js', 'elgg'); - elgg_register_external_file('css', 'font-awesome', elgg_get_simplecache_url('font-awesome/css/all.min.css')); elgg_load_external_file('css', 'font-awesome'); - elgg_define_js('cropperjs', [ - 'src' => elgg_get_simplecache_url('cropperjs/cropper.min.js'), - ]); - elgg_define_js('jquery-cropper/jquery-cropper', [ - 'src' => elgg_get_simplecache_url('jquery-cropper/jquery-cropper.min.js'), - ]); - - elgg_require_css('elgg'); - - elgg_extend_view('initialize_elgg.js', 'elgg/prevent_clicks.js', 1); - elgg_extend_view('elgg.css', 'lightbox/elgg-colorbox-theme/colorbox.css'); elgg_extend_view('elgg.css', 'entity/edit/icon/crop.css'); + + elgg_require_css('elgg'); + + elgg_register_esm('cropperjs', elgg_get_simplecache_url('cropperjs/cropper.min.js')); + elgg_register_esm('jquery', elgg_get_simplecache_url('jquery.js')); + elgg_register_esm('jquery-ui', elgg_get_simplecache_url('jquery-ui.js')); + elgg_register_esm('jquery-cropper/jquery-cropper', elgg_get_simplecache_url('jquery-cropper/jquery-cropper.min.js')); + + elgg_import_esm('elgg'); + elgg_import_esm('elgg/lightbox'); + elgg_import_esm('elgg/security'); - elgg_define_js('jquery.ui.autocomplete.html', [ - 'deps' => ['jquery-ui/widgets/autocomplete'], - ]); - - elgg_register_simplecache_view('elgg/touch_punch.js'); - elgg_define_js('jquery-ui/widgets/sortable', [ - 'deps' => ['elgg/touch_punch'], - ]); + elgg_extend_view('jquery-ui.js', 'jquery.ui.touch-punch.js'); + elgg_extend_view('initialize_elgg.js', 'elgg/prevent_clicks.js', 1); elgg_register_ajax_view('languages.js'); } -/** - * Get the site data to be merged into "elgg" in elgg.js. - * - * Unlike _elgg_get_js_page_data(), the keys returned are literal expressions. - * - * @return array - * @internal - */ -function _elgg_get_js_site_data(): array { - - $message_delay = (int) elgg_get_config('message_delay'); - if ($message_delay < 1) { - $message_delay = 6; - } - - return [ - 'elgg.data' => (object) elgg_trigger_event_results('elgg.data', 'site', [], []), - 'elgg.release' => elgg_get_release(), - 'elgg.config.wwwroot' => elgg_get_site_url(), - 'elgg.config.message_delay' => $message_delay * 1000, - - // refresh token 3 times during its lifetime (in microseconds 1000 * 1/3) - 'elgg.security.interval' => (int) _elgg_services()->csrf->getActionTokenTimeout() * 333, - 'elgg.config.language' => _elgg_services()->config->language ?: 'en', - ]; -} - /** * Get the initial contents of "elgg" client side. Will be extended by elgg.js. * @@ -1409,6 +1364,11 @@ function _elgg_get_js_page_data(array $params = []): array { elgg_log('"elgg.data" Event handlers must return an array. Returned ' . gettype($data) . '.', 'ERROR'); $data = []; } + + $message_delay = (int) elgg_get_config('message_delay'); + if ($message_delay < 1) { + $message_delay = 6; + } $elgg = [ 'config' => [ @@ -1416,8 +1376,15 @@ function _elgg_get_js_page_data(array $params = []): array { 'viewtype' => elgg_get_viewtype(), 'simplecache_enabled' => (int) elgg_is_simplecache_enabled(), 'current_language' => elgg_get_current_language(), + 'language' => _elgg_services()->config->language ?: 'en', + 'wwwroot' => elgg_get_site_url(), + 'message_delay' => $message_delay * 1000, ], + 'release' => elgg_get_release(), 'security' => [ + // refresh token 3 times during its lifetime (in microseconds 1000 * 1/3) + 'interval' => (int) _elgg_services()->csrf->getActionTokenTimeout() * 333, + 'token' => [ '__elgg_ts' => $ts = _elgg_services()->csrf->getCurrentTime()->getTimestamp(), '__elgg_token' => _elgg_services()->csrf->generateActionToken($ts), @@ -1427,7 +1394,7 @@ function _elgg_get_js_page_data(array $params = []): array { 'user' => null, 'token' => _elgg_services()->session->get('__elgg_session'), ], - '_data' => (object) $data, + 'data' => $data, ]; $user = elgg_get_logged_in_user_entity(); diff --git a/engine/tests/js/ElggAjaxTest.js b/engine/tests/js/ElggAjaxTest.js deleted file mode 100644 index 3b92a507681..00000000000 --- a/engine/tests/js/ElggAjaxTest.js +++ /dev/null @@ -1,596 +0,0 @@ -define(function(require) { - - var elgg = require('elgg'); - var $ = require('jquery'); - require('jquery-mockjax'); - var security = require('elgg/security'); - var i18n = require('elgg/i18n'); - var Ajax = require('elgg/Ajax'); - var hooks = require('elgg/hooks'); - var system_messages = require('elgg/system_messages'); - var ajax = new Ajax(); - - $.mockjaxSettings.responseTime = 10; - - describe("elgg/ajax", function() { - var captured_hook, - root = elgg.get_site_url(); - - beforeEach(function() { - captured_hook = null; - - $.mockjaxSettings.logging = false; - $.mockjax.clear(); - - hooks.reset(); - - // note, "all" type > always higher priority than specific types - hooks.register(Ajax.REQUEST_DATA_HOOK, 'all', function (h, t, p, v) { - captured_hook = { - t: t, - p: p, - v: v - }; - }); - }); - - it("passes unwrapped value to both success and deferred", function(done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1 - } - }); - - var def1 = $.Deferred(), - def2 = $.Deferred(); - - ajax.path('foo', { - success: function (val) { - expect(val).toBe(1); - def1.resolve(); - } - }).done(function (val) { - expect(val).toBe(1); - def2.resolve(); - }); - - $.when(def1, def2).then(done); - }); - - it("allows filtering response wrapper by hook, called only once", function(done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - foo: 2 - } - }); - - var hook_calls = 0; - - hooks.register(Ajax.RESPONSE_DATA_HOOK, 'path:foo', function (h, t, p, v) { - hook_calls++; - expect(v).toEqual({ - value: 1, - foo: 2, - status: 0 - }); - expect(p.options.url).toBe('foo'); - v.value = 3; - return v; - }); - - var def1 = $.Deferred(), - def2 = $.Deferred(); - - ajax.path('foo', { - success: function (val) { - expect(val).toBe(3); - def1.resolve(); - } - }).done(function (val) { - expect(val).toBe(3); - def2.resolve(); - }); - - $.when(def1, def2).then(function () { - expect(hook_calls).toBe(1); - done(); - }); - }); - - $.each(['path', 'action', 'form', 'view'], function (i, method) { - it("method " + method + "() sends special header", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.headers).toEqual({ 'X-Elgg-Ajax-API' : '2' }); - }); - - it("method " + method + "() uses dataType json", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.dataType).toEqual('json'); - }); - }); - - it("action() defaults to POST", function() { - ajax.action('foo'); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - it("path(): non-empty object data changes default to POST", function() { - ajax.path('foo', { - data: {bar: 'bar'} - }); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - it("path(): non-empty string data changes default to POST", function() { - ajax.path('foo', { - data: '?bar=bar' - }); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - $.each(['form', 'view'], function (i, method) { - it(method + "(): non-empty object data left as GET", function() { - ajax[method]('foo', { - data: {bar: 'bar'} - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - }); - - $.each(['path', 'form', 'view'], function (i, method) { - - it(method + "() defaults to GET", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - - it(method + "(): empty string data leaves default as GET", function() { - ajax[method]('foo', { - data: '' - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - - it(method + "(): empty object data leaves default as GET", function() { - ajax[method]('foo', { - data: {} - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - }); - - it("allows altering value via hook", function(done) { - hooks.register(Ajax.REQUEST_DATA_HOOK, 'path:foo/bar', function (h, t, p, v) { - v.arg3 = 3; - return v; - }, 900); - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo/bar/?arg1=1"), - responseText: { - value: 1, - foo: 2 - } - }); - - ajax.path('/foo/bar/?arg1=1#target', { - data: {arg2: 2} - }).done(function () { - expect(captured_hook.v).toEqual({arg2: 2, arg3: 3}); - expect(captured_hook.p.options.data).toEqual({arg2: 2, arg3: 3}); - done(); - }); - - expect(ajax._ajax_options.data).toEqual({ - arg2: 2, - arg3: 3 - }); - }); - - it("normalizes argument paths/URLs", function() { - ajax.path('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('path:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'foo/bar/?arg1=1'); - - ajax.path(root + 'foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('path:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'foo/bar/?arg1=1'); - - ajax.action('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('action:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'action/foo/bar/?arg1=1'); - - ajax.action(root + 'action/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('action:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'action/foo/bar/?arg1=1'); - - ajax.view('foo/bar?arg1=1'); - expect(ajax._fetch_args.hook_type).toEqual('view:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'ajax/view/foo/bar?arg1=1'); - - ajax.form('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('form:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'ajax/form/foo/bar/?arg1=1'); - }); - - it("refuses to accept external URLs", function() { - expect(function () { - ajax.action('http://other.com/action/foo'); - }).toThrowError(); - - expect(function () { - ajax.path('http://other.com/foo'); - }).toThrowError(); - }); - - it("form() and view() refuse to accept any URL", function() { - expect(function () { - ajax.view(root + 'ajax/view/foo'); - }).toThrowError(); - - expect(function () { - ajax.form(root + 'action/foo'); - }).toThrowError(); - }); - - it("adds CSRF tokens to action data", function() { - var ts = elgg.security.token.__elgg_ts; - - ajax.action('foo'); - expect(ajax._ajax_options.data.__elgg_ts).toBe(ts); - - ajax.action('foo', { - data: "?arg1=1" - }); - expect(ajax._ajax_options.data).toContain('__elgg_ts=' + ts); - }); - - it("does not add tokens if already in action URL", function() { - var ts = elgg.security.token.__elgg_ts; - - var url = security.addToken(root + 'action/foo'); - - ajax.action(url); - expect(ajax._ajax_options.data.__elgg_ts).toBe(undefined); - }); - - it("path() accepts empty argument for fetching home page", function() { - ajax.path(""); - }); - - $.each(['action', 'form', 'view'], function (i, method) { - it(method + "() does not accept empty argument", function () { - expect(function () { - ajax[method](''); - }).toThrowError(); - }); - }); - - it("handles server-sent messages and dependencies", function(done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo').done(function () { - expect(captured).toEqual({ - msg: ['yay'], - error: ['fail'], - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("can prevent output of server-sent messages and dependencies", function(done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo', {showErrorMessages: false, showSuccessMessages: false}).done(function () { - expect(captured).toEqual({ - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("error handler still handles server-sent messages and dependencies", function (done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: { - value: null, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - msg: ['yay'], - error: ['fail'], - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("outputs the generic error if no server-sent message", function (done) { - var tmp_register_error = system_messages.error; - var captured = {}; - - system_messages.error = function (arg) { - captured.error = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: {} - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - error: i18n.echo('ajax:error') - }); - - system_messages.error = tmp_register_error; - - done(); - }); - }); - - it("outputs the error message of the non-200 response", function (done) { - var tmp_register_error = system_messages.error; - var captured = {}; - - system_messages.error = function (arg) { - captured.error = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: { - error: 'Server throws' - } - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - error: 'Server throws' - }); - - system_messages.error = tmp_register_error; - - done(); - }); - }); - - it("copies data to jqXHR.AjaxData", function (done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - other: 2 - } - }); - - ajax.path('foo').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData).toEqual({ - value: 1, - other: 2, - status: 0 - }); - done(); - }); - }); - - it("sets jqXHR.AjaxData.status to 0 or -1 depending on presence of server error", function (done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("good"), - responseText: { - value: 1 - } - }); - $.mockjax({ - url: elgg.normalize_url("bad"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'] - } - } - }); - - ajax.path('good').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData.status).toBe(0); - - ajax.path('bad').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData.status).toBe(-1); - done(); - }); - }); - }); - - describe("ajax.objectify", function() { - - var $form = $("" + - "